OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/http/http_auth.h" | 5 #include "net/http/http_auth.h" |
6 | 6 |
7 #include <algorithm> | |
8 | |
9 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
10 #include "base/bind.h" | |
11 #include "base/strings/string_tokenizer.h" | |
12 #include "base/strings/string_util.h" | 8 #include "base/strings/string_util.h" |
13 #include "base/values.h" | |
14 #include "net/base/net_errors.h" | |
15 #include "net/http/http_auth_challenge_tokenizer.h" | |
16 #include "net/http/http_auth_handler.h" | |
17 #include "net/http/http_auth_handler_factory.h" | |
18 #include "net/http/http_auth_scheme_set.h" | |
19 #include "net/http/http_request_headers.h" | 9 #include "net/http/http_request_headers.h" |
20 #include "net/http/http_response_headers.h" | |
21 #include "net/http/http_util.h" | |
22 | 10 |
23 namespace net { | 11 namespace net { |
24 | 12 |
25 namespace { | |
26 | |
27 // Hardcoded map of HTTP authentication scheme priorities. Higher priorities are | |
28 // preferred over lower. | |
29 struct SchemePriority { | |
30 const char* scheme; | |
31 int priority; | |
32 } kSchemeScores[] = { | |
33 {"basic", 1}, | |
34 {"digest", 2}, | |
35 {"ntlm", 3}, | |
36 {"negotiate", 4}, | |
37 }; | |
38 | |
39 // Priority assigned to unknown authentication schemes. They are currently | |
40 // ranked lower than Basic, which might be a bit too conservative. | |
41 const int kSchemePriorityDefault = 0; | |
42 | |
43 // Not a valid priority. | |
44 const int kSchemePriorityInvalid = -1; | |
45 | |
46 // Higher priority schemes are preferred over lower priority schemes. | |
47 int GetSchemePriority(const std::string& scheme) { | |
48 DCHECK(HttpAuth::IsValidNormalizedScheme(scheme)); | |
49 for (const auto& iter : kSchemeScores) { | |
50 if (scheme == iter.scheme) | |
51 return iter.priority; | |
52 } | |
53 return kSchemePriorityDefault; | |
54 } | |
55 | |
56 scoped_ptr<base::Value> AuthHandlerCreationFailureParams( | |
57 const std::string* challenge, | |
58 int error, | |
59 NetLogCaptureMode capture_mode) { | |
60 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | |
61 dict->SetString("challenge", *challenge); | |
62 dict->SetInteger("net_error", error); | |
63 return dict.Pass(); | |
64 } | |
65 | |
66 } // namespace | |
67 | |
68 HttpAuth::Identity::Identity() : source(IDENT_SRC_NONE), invalid(true) {} | 13 HttpAuth::Identity::Identity() : source(IDENT_SRC_NONE), invalid(true) {} |
69 | 14 |
70 HttpAuth::Identity::~Identity() {} | 15 HttpAuth::Identity::~Identity() {} |
71 | 16 |
72 // static | 17 // static |
73 void HttpAuth::ChooseBestChallenge( | |
74 HttpAuthHandlerFactory* http_auth_handler_factory, | |
75 const HttpResponseHeaders* headers, | |
76 Target target, | |
77 const GURL& origin, | |
78 const HttpAuthSchemeSet& disabled_schemes, | |
79 const BoundNetLog& net_log, | |
80 scoped_ptr<HttpAuthHandler>* handler) { | |
81 DCHECK(http_auth_handler_factory); | |
82 DCHECK(!handler->get()); | |
83 | |
84 int best_priority = kSchemePriorityInvalid; | |
85 scoped_ptr<HttpAuthHandler> best; | |
86 const std::string header_name = GetChallengeHeaderName(target); | |
87 std::string cur_challenge; | |
88 void* iter = nullptr; | |
89 | |
90 while (headers->EnumerateHeader(&iter, header_name, &cur_challenge)) { | |
91 HttpAuthChallengeTokenizer challenge_tokenizer(cur_challenge.begin(), | |
92 cur_challenge.end()); | |
93 std::string cur_auth_scheme = challenge_tokenizer.NormalizedScheme(); | |
94 if (cur_auth_scheme.empty()) | |
95 continue; | |
96 | |
97 if (disabled_schemes.Contains(cur_auth_scheme)) | |
98 continue; | |
99 | |
100 // Always prefer the highest priority scheme available. If two handlers are | |
101 // of equal priority, then the handler based on the earlier challenge wins. | |
102 int cur_priority = GetSchemePriority(cur_auth_scheme); | |
103 if (best.get() && best_priority >= cur_priority) | |
104 continue; | |
105 | |
106 // Immediately trying to create a handler may be wasteful because we may see | |
107 // a higher ranking challenge later on in the headers. However, this is | |
108 // rare. Servers typically specify higher priority schemes before lower | |
109 // priority schemes. | |
110 scoped_ptr<HttpAuthHandler> current_handler; | |
111 current_handler = http_auth_handler_factory->CreateAuthHandlerForScheme( | |
112 challenge_tokenizer.NormalizedScheme()); | |
113 if (!current_handler) { | |
114 net_log.AddEvent(NetLog::TYPE_AUTH_HANDLER_CREATION_FAILURE, | |
115 base::Bind(&AuthHandlerCreationFailureParams, | |
116 &cur_challenge, ERR_UNSUPPORTED_AUTH_SCHEME)); | |
117 continue; | |
118 } | |
119 int rv = current_handler->HandleInitialChallenge(challenge_tokenizer, | |
120 target, origin, net_log); | |
121 if (rv != OK) { | |
122 net_log.AddEvent( | |
123 NetLog::TYPE_AUTH_HANDLER_CREATION_FAILURE, | |
124 base::Bind(&AuthHandlerCreationFailureParams, &cur_challenge, rv)); | |
125 continue; | |
126 } | |
127 DCHECK(current_handler.get()); | |
128 DCHECK_EQ(cur_auth_scheme, current_handler->auth_scheme()); | |
129 best.swap(current_handler); | |
130 best_priority = cur_priority; | |
131 } | |
132 handler->swap(best); | |
133 } | |
134 | |
135 // static | |
136 HttpAuth::AuthorizationResult HttpAuth::HandleChallengeResponse( | |
137 HttpAuthHandler* handler, | |
138 const HttpResponseHeaders* headers, | |
139 Target target, | |
140 const HttpAuthSchemeSet& disabled_schemes, | |
141 std::string* challenge_used) { | |
142 DCHECK(handler); | |
143 DCHECK(headers); | |
144 DCHECK(challenge_used); | |
145 challenge_used->clear(); | |
146 const std::string& current_scheme = handler->auth_scheme(); | |
147 if (disabled_schemes.Contains(current_scheme)) | |
148 return HttpAuth::AUTHORIZATION_RESULT_REJECT; | |
149 const std::string header_name = GetChallengeHeaderName(target); | |
150 void* iter = NULL; | |
151 std::string challenge; | |
152 HttpAuth::AuthorizationResult authorization_result = | |
153 HttpAuth::AUTHORIZATION_RESULT_INVALID; | |
154 while (headers->EnumerateHeader(&iter, header_name, &challenge)) { | |
155 HttpAuthChallengeTokenizer props(challenge.begin(), challenge.end()); | |
156 if (!props.SchemeIs(current_scheme)) | |
157 continue; | |
158 authorization_result = handler->HandleAnotherChallenge(props); | |
159 if (authorization_result != HttpAuth::AUTHORIZATION_RESULT_INVALID) { | |
160 *challenge_used = challenge; | |
161 return authorization_result; | |
162 } | |
163 } | |
164 // Finding no matches is equivalent to rejection. | |
165 return HttpAuth::AUTHORIZATION_RESULT_REJECT; | |
166 } | |
167 | |
168 // static | |
169 std::string HttpAuth::GetChallengeHeaderName(Target target) { | 18 std::string HttpAuth::GetChallengeHeaderName(Target target) { |
170 switch (target) { | 19 switch (target) { |
171 case AUTH_PROXY: | 20 case AUTH_PROXY: |
172 return "Proxy-Authenticate"; | 21 return "Proxy-Authenticate"; |
173 case AUTH_SERVER: | 22 case AUTH_SERVER: |
174 return "WWW-Authenticate"; | 23 return "WWW-Authenticate"; |
175 default: | 24 default: |
176 NOTREACHED(); | 25 NOTREACHED(); |
177 return std::string(); | 26 return std::string(); |
178 } | 27 } |
(...skipping 25 matching lines...) Expand all Loading... |
204 } | 53 } |
205 } | 54 } |
206 | 55 |
207 // static | 56 // static |
208 bool HttpAuth::IsValidNormalizedScheme(const std::string& scheme) { | 57 bool HttpAuth::IsValidNormalizedScheme(const std::string& scheme) { |
209 return HttpUtil::IsToken(scheme.begin(), scheme.end()) && | 58 return HttpUtil::IsToken(scheme.begin(), scheme.end()) && |
210 base::ToLowerASCII(scheme) == scheme; | 59 base::ToLowerASCII(scheme) == scheme; |
211 } | 60 } |
212 | 61 |
213 } // namespace net | 62 } // namespace net |
OLD | NEW |