1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/net/spdyproxy/http_auth_handler_spdyproxy.h"
11 #include "base/i18n/icu_string_conversions.h"
12 #include "base/metrics/histogram.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "net/base/net_errors.h"
16 #include "net/http/http_auth.h"
17 #include "net/http/http_auth_challenge_tokenizer.h"
18 #include "net/http/http_request_info.h"
22 using net::AuthCredentials;
23 using net::BoundNetLog;
24 using net::CompletionCallback;
26 using net::HttpAuthChallengeTokenizer;
27 using net::HttpAuthHandler;
28 using net::HttpAuthHandlerFactory;
29 using net::HttpRequestInfo;
32 HttpAuthHandlerSpdyProxy::Factory::Factory(
33 const std::vector<GURL>& authorized_spdyproxy_origins) {
34 for (unsigned int i = 0; i < authorized_spdyproxy_origins.size(); ++i) {
35 if (authorized_spdyproxy_origins[i].possibly_invalid_spec().empty()) {
36 VLOG(1) << "SpdyProxy auth without configuring authorized origin.";
40 authorized_spdyproxy_origins_ = authorized_spdyproxy_origins;
43 HttpAuthHandlerSpdyProxy::Factory::~Factory() {
46 int HttpAuthHandlerSpdyProxy::Factory::CreateAuthHandler(
47 HttpAuthChallengeTokenizer* challenge,
48 HttpAuth::Target target,
51 int digest_nonce_count,
52 const BoundNetLog& net_log,
53 scoped_ptr<HttpAuthHandler>* handler) {
54 // If a spdyproxy auth proxy has not been set, refuse all requests to use this
56 if (authorized_spdyproxy_origins_.empty())
57 return net::ERR_UNSUPPORTED_AUTH_SCHEME;
59 // We ensure that this authentication handler is used only with an authorized
60 // SPDY proxy, since otherwise a user's authentication token can be
61 // sniffed by a malicious proxy that presents an appropriate challenge.
62 const GURL origin_origin = origin.GetOrigin();
63 if (!(std::find(authorized_spdyproxy_origins_.begin(),
64 authorized_spdyproxy_origins_.end(),
65 origin_origin) != authorized_spdyproxy_origins_.end())) {
66 UMA_HISTOGRAM_COUNTS("Net.UnexpectedSpdyProxyAuth", 1);
67 VLOG(1) << "SpdyProxy auth request with an unexpected config."
68 << " origin: " << origin_origin.possibly_invalid_spec();
69 return net::ERR_UNSUPPORTED_AUTH_SCHEME;
72 scoped_ptr<HttpAuthHandler> tmp_handler(new HttpAuthHandlerSpdyProxy());
73 if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log))
74 return net::ERR_INVALID_RESPONSE;
75 handler->swap(tmp_handler);
79 HttpAuth::AuthorizationResult
80 HttpAuthHandlerSpdyProxy::HandleAnotherChallenge(
81 HttpAuthChallengeTokenizer* challenge) {
82 // SpdyProxy authentication is always a single round, so any responses
83 // should be treated as a rejection.
84 return HttpAuth::AUTHORIZATION_RESULT_REJECT;
87 bool HttpAuthHandlerSpdyProxy::NeedsIdentity() {
91 bool HttpAuthHandlerSpdyProxy::AllowsDefaultCredentials() {
95 bool HttpAuthHandlerSpdyProxy::AllowsExplicitCredentials() {
99 HttpAuthHandlerSpdyProxy::~HttpAuthHandlerSpdyProxy() {}
101 bool HttpAuthHandlerSpdyProxy::Init(
102 HttpAuthChallengeTokenizer* challenge) {
103 auth_scheme_ = HttpAuth::AUTH_SCHEME_SPDYPROXY;
105 properties_ = ENCRYPTS_IDENTITY;
106 return ParseChallenge(challenge);
109 int HttpAuthHandlerSpdyProxy::GenerateAuthTokenImpl(
110 const AuthCredentials* credentials, const HttpRequestInfo* request,
111 const CompletionCallback&, std::string* auth_token) {
113 if (credentials->password().length() == 0) {
114 DVLOG(1) << "Received a SpdyProxy auth token request without an "
115 << "available token.";
118 *auth_token = "SpdyProxy ps=\"" + ps_token_ + "\", sid=\"" +
119 base::UTF16ToUTF8(credentials->password()) + "\"";
123 bool HttpAuthHandlerSpdyProxy::ParseChallenge(
124 HttpAuthChallengeTokenizer* challenge) {
126 // Verify the challenge's auth-scheme.
127 if (!LowerCaseEqualsASCII(challenge->scheme(), "spdyproxy")) {
128 VLOG(1) << "Parsed challenge without SpdyProxy type";
132 HttpUtil::NameValuePairsIterator parameters = challenge->param_pairs();
134 // Loop through all the properties.
135 while (parameters.GetNext()) {
136 // FAIL -- couldn't parse a property.
137 if (!ParseChallengeProperty(parameters.name(),
141 // Check if tokenizer failed.
142 if (!parameters.valid())
145 // Check that the required properties were provided.
149 if (ps_token_.empty())
155 bool HttpAuthHandlerSpdyProxy::ParseChallengeProperty(
156 const std::string& name, const std::string& value) {
157 if (LowerCaseEqualsASCII(name, "realm")) {
159 if (!base::ConvertToUtf8AndNormalize(value, base::kCodepageLatin1, &realm))
162 } else if (LowerCaseEqualsASCII(name, "ps")) {
165 VLOG(1) << "Skipping unrecognized SpdyProxy auth property, " << name;
170 } // namespace spdyproxy