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_request_info.h"
21 using net::AuthCredentials
;
22 using net::BoundNetLog
;
23 using net::CompletionCallback
;
25 using net::HttpAuthHandler
;
26 using net::HttpAuthHandlerFactory
;
27 using net::HttpRequestInfo
;
30 HttpAuthHandlerSpdyProxy::Factory::Factory(
31 const std::vector
<GURL
>& authorized_spdyproxy_origins
) {
32 for (unsigned int i
= 0; i
< authorized_spdyproxy_origins
.size(); ++i
) {
33 if (authorized_spdyproxy_origins
[i
].possibly_invalid_spec().empty()) {
34 VLOG(1) << "SpdyProxy auth without configuring authorized origin.";
38 authorized_spdyproxy_origins_
= authorized_spdyproxy_origins
;
41 HttpAuthHandlerSpdyProxy::Factory::~Factory() {
44 int HttpAuthHandlerSpdyProxy::Factory::CreateAuthHandler(
45 HttpAuth::ChallengeTokenizer
* challenge
,
46 HttpAuth::Target target
,
49 int digest_nonce_count
,
50 const BoundNetLog
& net_log
,
51 scoped_ptr
<HttpAuthHandler
>* handler
) {
52 // If a spdyproxy auth proxy has not been set, refuse all requests to use this
54 if (authorized_spdyproxy_origins_
.empty())
55 return net::ERR_UNSUPPORTED_AUTH_SCHEME
;
57 // We ensure that this authentication handler is used only with an authorized
58 // SPDY proxy, since otherwise a user's authentication token can be
59 // sniffed by a malicious proxy that presents an appropriate challenge.
60 const GURL origin_origin
= origin
.GetOrigin();
61 if (!(std::find(authorized_spdyproxy_origins_
.begin(),
62 authorized_spdyproxy_origins_
.end(),
63 origin_origin
) != authorized_spdyproxy_origins_
.end())) {
64 UMA_HISTOGRAM_COUNTS("Net.UnexpectedSpdyProxyAuth", 1);
65 VLOG(1) << "SpdyProxy auth request with an unexpected config."
66 << " origin: " << origin_origin
.possibly_invalid_spec();
67 return net::ERR_UNSUPPORTED_AUTH_SCHEME
;
70 scoped_ptr
<HttpAuthHandler
> tmp_handler(new HttpAuthHandlerSpdyProxy());
71 if (!tmp_handler
->InitFromChallenge(challenge
, target
, origin
, net_log
))
72 return net::ERR_INVALID_RESPONSE
;
73 handler
->swap(tmp_handler
);
77 HttpAuth::AuthorizationResult
78 HttpAuthHandlerSpdyProxy::HandleAnotherChallenge(
79 HttpAuth::ChallengeTokenizer
* challenge
) {
80 // SpdyProxy authentication is always a single round, so any responses
81 // should be treated as a rejection.
82 return HttpAuth::AUTHORIZATION_RESULT_REJECT
;
85 bool HttpAuthHandlerSpdyProxy::NeedsIdentity() {
89 bool HttpAuthHandlerSpdyProxy::AllowsDefaultCredentials() {
93 bool HttpAuthHandlerSpdyProxy::AllowsExplicitCredentials() {
97 HttpAuthHandlerSpdyProxy::~HttpAuthHandlerSpdyProxy() {}
99 bool HttpAuthHandlerSpdyProxy::Init(
100 HttpAuth::ChallengeTokenizer
* challenge
) {
101 auth_scheme_
= HttpAuth::AUTH_SCHEME_SPDYPROXY
;
103 properties_
= ENCRYPTS_IDENTITY
;
104 return ParseChallenge(challenge
);
107 int HttpAuthHandlerSpdyProxy::GenerateAuthTokenImpl(
108 const AuthCredentials
* credentials
, const HttpRequestInfo
* request
,
109 const CompletionCallback
&, std::string
* auth_token
) {
111 if (credentials
->password().length() == 0) {
112 DVLOG(1) << "Received a SpdyProxy auth token request without an "
113 << "available token.";
116 *auth_token
= "SpdyProxy ps=\"" + ps_token_
+ "\", sid=\"" +
117 base::UTF16ToUTF8(credentials
->password()) + "\"";
121 bool HttpAuthHandlerSpdyProxy::ParseChallenge(
122 HttpAuth::ChallengeTokenizer
* challenge
) {
124 // Verify the challenge's auth-scheme.
125 if (!LowerCaseEqualsASCII(challenge
->scheme(), "spdyproxy")) {
126 VLOG(1) << "Parsed challenge without SpdyProxy type";
130 HttpUtil::NameValuePairsIterator parameters
= challenge
->param_pairs();
132 // Loop through all the properties.
133 while (parameters
.GetNext()) {
134 // FAIL -- couldn't parse a property.
135 if (!ParseChallengeProperty(parameters
.name(),
139 // Check if tokenizer failed.
140 if (!parameters
.valid())
143 // Check that the required properties were provided.
147 if (ps_token_
.empty())
153 bool HttpAuthHandlerSpdyProxy::ParseChallengeProperty(
154 const std::string
& name
, const std::string
& value
) {
155 if (LowerCaseEqualsASCII(name
, "realm")) {
157 if (!base::ConvertToUtf8AndNormalize(value
, base::kCodepageLatin1
, &realm
))
160 } else if (LowerCaseEqualsASCII(name
, "ps")) {
163 VLOG(1) << "Skipping unrecognized SpdyProxy auth property, " << name
;
168 } // namespace spdyproxy