Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / net / spdyproxy / http_auth_handler_spdyproxy.cc
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.
4
5 #include "chrome/browser/net/spdyproxy/http_auth_handler_spdyproxy.h"
6
7 #include <algorithm>
8 #include <string>
9 #include <vector>
10
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"
19
20 namespace spdyproxy {
21
22 using net::AuthCredentials;
23 using net::BoundNetLog;
24 using net::CompletionCallback;
25 using net::HttpAuth;
26 using net::HttpAuthChallengeTokenizer;
27 using net::HttpAuthHandler;
28 using net::HttpAuthHandlerFactory;
29 using net::HttpRequestInfo;
30 using net::HttpUtil;
31
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.";
37       return;
38     }
39   }
40   authorized_spdyproxy_origins_ = authorized_spdyproxy_origins;
41 }
42
43 HttpAuthHandlerSpdyProxy::Factory::~Factory() {
44 }
45
46 int HttpAuthHandlerSpdyProxy::Factory::CreateAuthHandler(
47     HttpAuthChallengeTokenizer* challenge,
48     HttpAuth::Target target,
49     const GURL& origin,
50     CreateReason reason,
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
55   // auth handler.
56   if (authorized_spdyproxy_origins_.empty())
57     return net::ERR_UNSUPPORTED_AUTH_SCHEME;
58
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;
70   }
71
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);
76   return net::OK;
77 }
78
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;
85 }
86
87 bool HttpAuthHandlerSpdyProxy::NeedsIdentity() {
88   return true;
89 }
90
91 bool HttpAuthHandlerSpdyProxy::AllowsDefaultCredentials() {
92   return false;
93 }
94
95 bool HttpAuthHandlerSpdyProxy::AllowsExplicitCredentials() {
96   return true;
97 }
98
99 HttpAuthHandlerSpdyProxy::~HttpAuthHandlerSpdyProxy() {}
100
101 bool HttpAuthHandlerSpdyProxy::Init(
102     HttpAuthChallengeTokenizer* challenge) {
103   auth_scheme_ = HttpAuth::AUTH_SCHEME_SPDYPROXY;
104   score_ = 5;
105   properties_ = ENCRYPTS_IDENTITY;
106   return ParseChallenge(challenge);
107 }
108
109 int HttpAuthHandlerSpdyProxy::GenerateAuthTokenImpl(
110     const AuthCredentials* credentials, const HttpRequestInfo* request,
111     const CompletionCallback&, std::string* auth_token) {
112   DCHECK(credentials);
113   if (credentials->password().length() == 0) {
114     DVLOG(1) << "Received a SpdyProxy auth token request without an "
115              << "available token.";
116     return -1;
117   }
118   *auth_token = "SpdyProxy ps=\"" + ps_token_ + "\", sid=\"" +
119       base::UTF16ToUTF8(credentials->password()) + "\"";
120   return net::OK;
121 }
122
123 bool HttpAuthHandlerSpdyProxy::ParseChallenge(
124     HttpAuthChallengeTokenizer* challenge) {
125
126   // Verify the challenge's auth-scheme.
127   if (!LowerCaseEqualsASCII(challenge->scheme(), "spdyproxy")) {
128     VLOG(1) << "Parsed challenge without SpdyProxy type";
129     return false;
130   }
131
132   HttpUtil::NameValuePairsIterator parameters = challenge->param_pairs();
133
134   // Loop through all the properties.
135   while (parameters.GetNext()) {
136     // FAIL -- couldn't parse a property.
137     if (!ParseChallengeProperty(parameters.name(),
138                                 parameters.value()))
139       return false;
140   }
141   // Check if tokenizer failed.
142   if (!parameters.valid())
143     return false;
144
145   // Check that the required properties were provided.
146   if (realm_.empty())
147     return false;
148
149   if (ps_token_.empty())
150     return false;
151
152   return true;
153 }
154
155 bool HttpAuthHandlerSpdyProxy::ParseChallengeProperty(
156     const std::string& name, const std::string& value) {
157   if (LowerCaseEqualsASCII(name, "realm")) {
158     std::string realm;
159     if (!base::ConvertToUtf8AndNormalize(value, base::kCodepageLatin1, &realm))
160       return false;
161     realm_ = realm;
162   } else if (LowerCaseEqualsASCII(name, "ps")) {
163     ps_token_ = value;
164   } else {
165     VLOG(1) << "Skipping unrecognized SpdyProxy auth property, " << name;
166   }
167   return true;
168 }
169
170 }  // namespace spdyproxy