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> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 10 #include "base/bind.h" |
10 #include "base/strings/string_tokenizer.h" | 11 #include "base/strings/string_tokenizer.h" |
11 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
| 13 #include "base/values.h" |
12 #include "net/base/net_errors.h" | 14 #include "net/base/net_errors.h" |
13 #include "net/http/http_auth_challenge_tokenizer.h" | 15 #include "net/http/http_auth_challenge_tokenizer.h" |
14 #include "net/http/http_auth_handler.h" | 16 #include "net/http/http_auth_handler.h" |
15 #include "net/http/http_auth_handler_factory.h" | 17 #include "net/http/http_auth_handler_factory.h" |
| 18 #include "net/http/http_auth_scheme_set.h" |
16 #include "net/http/http_request_headers.h" | 19 #include "net/http/http_request_headers.h" |
17 #include "net/http/http_response_headers.h" | 20 #include "net/http/http_response_headers.h" |
18 #include "net/http/http_util.h" | 21 #include "net/http/http_util.h" |
19 | 22 |
20 namespace net { | 23 namespace net { |
21 | 24 |
| 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 |
22 HttpAuth::Identity::Identity() : source(IDENT_SRC_NONE), invalid(true) {} | 68 HttpAuth::Identity::Identity() : source(IDENT_SRC_NONE), invalid(true) {} |
23 | 69 |
| 70 HttpAuth::Identity::~Identity() {} |
| 71 |
24 // static | 72 // static |
25 void HttpAuth::ChooseBestChallenge( | 73 void HttpAuth::ChooseBestChallenge( |
26 HttpAuthHandlerFactory* http_auth_handler_factory, | 74 HttpAuthHandlerFactory* http_auth_handler_factory, |
27 const HttpResponseHeaders* headers, | 75 const HttpResponseHeaders* headers, |
28 Target target, | 76 Target target, |
29 const GURL& origin, | 77 const GURL& origin, |
30 const std::set<Scheme>& disabled_schemes, | 78 const HttpAuthSchemeSet& disabled_schemes, |
31 const BoundNetLog& net_log, | 79 const BoundNetLog& net_log, |
32 scoped_ptr<HttpAuthHandler>* handler) { | 80 scoped_ptr<HttpAuthHandler>* handler) { |
33 DCHECK(http_auth_handler_factory); | 81 DCHECK(http_auth_handler_factory); |
34 DCHECK(handler->get() == NULL); | 82 DCHECK(!handler->get()); |
35 | 83 |
36 // Choose the challenge whose authentication handler gives the maximum score. | 84 int best_priority = kSchemePriorityInvalid; |
37 scoped_ptr<HttpAuthHandler> best; | 85 scoped_ptr<HttpAuthHandler> best; |
38 const std::string header_name = GetChallengeHeaderName(target); | 86 const std::string header_name = GetChallengeHeaderName(target); |
39 std::string cur_challenge; | 87 std::string cur_challenge; |
40 void* iter = NULL; | 88 void* iter = nullptr; |
| 89 |
41 while (headers->EnumerateHeader(&iter, header_name, &cur_challenge)) { | 90 while (headers->EnumerateHeader(&iter, header_name, &cur_challenge)) { |
42 scoped_ptr<HttpAuthHandler> cur; | 91 HttpAuthChallengeTokenizer challenge_tokenizer(cur_challenge.begin(), |
43 int rv = http_auth_handler_factory->CreateAuthHandlerFromString( | 92 cur_challenge.end()); |
44 cur_challenge, target, origin, net_log, &cur); | 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 int rv = http_auth_handler_factory->CreateAuthHandler( |
| 112 &challenge_tokenizer, target, origin, |
| 113 HttpAuthHandlerFactory::CREATE_CHALLENGE, 1, net_log, ¤t_handler); |
45 if (rv != OK) { | 114 if (rv != OK) { |
46 VLOG(1) << "Unable to create AuthHandler. Status: " | 115 net_log.AddEvent( |
47 << ErrorToString(rv) << " Challenge: " << cur_challenge; | 116 NetLog::TYPE_AUTH_HANDLER_CREATION_FAILURE, |
| 117 base::Bind(&AuthHandlerCreationFailureParams, &cur_challenge, rv)); |
48 continue; | 118 continue; |
49 } | 119 } |
50 if (cur.get() && (!best.get() || best->score() < cur->score()) && | 120 DCHECK(current_handler.get()); |
51 (disabled_schemes.find(cur->auth_scheme()) == disabled_schemes.end())) | 121 DCHECK_EQ(cur_auth_scheme, current_handler->auth_scheme()); |
52 best.swap(cur); | 122 best.swap(current_handler); |
| 123 best_priority = cur_priority; |
53 } | 124 } |
54 handler->swap(best); | 125 handler->swap(best); |
55 } | 126 } |
56 | 127 |
57 // static | 128 // static |
58 HttpAuth::AuthorizationResult HttpAuth::HandleChallengeResponse( | 129 HttpAuth::AuthorizationResult HttpAuth::HandleChallengeResponse( |
59 HttpAuthHandler* handler, | 130 HttpAuthHandler* handler, |
60 const HttpResponseHeaders* headers, | 131 const HttpResponseHeaders* headers, |
61 Target target, | 132 Target target, |
62 const std::set<Scheme>& disabled_schemes, | 133 const HttpAuthSchemeSet& disabled_schemes, |
63 std::string* challenge_used) { | 134 std::string* challenge_used) { |
64 DCHECK(handler); | 135 DCHECK(handler); |
65 DCHECK(headers); | 136 DCHECK(headers); |
66 DCHECK(challenge_used); | 137 DCHECK(challenge_used); |
67 challenge_used->clear(); | 138 challenge_used->clear(); |
68 HttpAuth::Scheme current_scheme = handler->auth_scheme(); | 139 const std::string& current_scheme = handler->auth_scheme(); |
69 if (disabled_schemes.find(current_scheme) != disabled_schemes.end()) | 140 if (disabled_schemes.Contains(current_scheme)) |
70 return HttpAuth::AUTHORIZATION_RESULT_REJECT; | 141 return HttpAuth::AUTHORIZATION_RESULT_REJECT; |
71 std::string current_scheme_name = SchemeToString(current_scheme); | |
72 const std::string header_name = GetChallengeHeaderName(target); | 142 const std::string header_name = GetChallengeHeaderName(target); |
73 void* iter = NULL; | 143 void* iter = NULL; |
74 std::string challenge; | 144 std::string challenge; |
75 HttpAuth::AuthorizationResult authorization_result = | 145 HttpAuth::AuthorizationResult authorization_result = |
76 HttpAuth::AUTHORIZATION_RESULT_INVALID; | 146 HttpAuth::AUTHORIZATION_RESULT_INVALID; |
77 while (headers->EnumerateHeader(&iter, header_name, &challenge)) { | 147 while (headers->EnumerateHeader(&iter, header_name, &challenge)) { |
78 HttpAuthChallengeTokenizer props(challenge.begin(), challenge.end()); | 148 HttpAuthChallengeTokenizer props(challenge.begin(), challenge.end()); |
79 if (!base::LowerCaseEqualsASCII(props.scheme(), | 149 if (!props.SchemeIs(current_scheme)) |
80 current_scheme_name.c_str())) | |
81 continue; | 150 continue; |
82 authorization_result = handler->HandleAnotherChallenge(&props); | 151 authorization_result = handler->HandleAnotherChallenge(&props); |
83 if (authorization_result != HttpAuth::AUTHORIZATION_RESULT_INVALID) { | 152 if (authorization_result != HttpAuth::AUTHORIZATION_RESULT_INVALID) { |
84 *challenge_used = challenge; | 153 *challenge_used = challenge; |
85 return authorization_result; | 154 return authorization_result; |
86 } | 155 } |
87 } | 156 } |
88 // Finding no matches is equivalent to rejection. | 157 // Finding no matches is equivalent to rejection. |
89 return HttpAuth::AUTHORIZATION_RESULT_REJECT; | 158 return HttpAuth::AUTHORIZATION_RESULT_REJECT; |
90 } | 159 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 return "proxy"; | 191 return "proxy"; |
123 case AUTH_SERVER: | 192 case AUTH_SERVER: |
124 return "server"; | 193 return "server"; |
125 default: | 194 default: |
126 NOTREACHED(); | 195 NOTREACHED(); |
127 return std::string(); | 196 return std::string(); |
128 } | 197 } |
129 } | 198 } |
130 | 199 |
131 // static | 200 // static |
132 const char* HttpAuth::SchemeToString(Scheme scheme) { | 201 bool HttpAuth::IsValidNormalizedScheme(const std::string& scheme) { |
133 static const char* const kSchemeNames[] = { | 202 return HttpUtil::IsToken(scheme.begin(), scheme.end()) && |
134 "basic", | 203 base::ToLowerASCII(scheme) == scheme; |
135 "digest", | |
136 "ntlm", | |
137 "negotiate", | |
138 "spdyproxy", | |
139 "mock", | |
140 }; | |
141 static_assert(arraysize(kSchemeNames) == AUTH_SCHEME_MAX, | |
142 "http auth scheme names incorrect size"); | |
143 if (scheme < AUTH_SCHEME_BASIC || scheme >= AUTH_SCHEME_MAX) { | |
144 NOTREACHED(); | |
145 return "invalid_scheme"; | |
146 } | |
147 return kSchemeNames[scheme]; | |
148 } | 204 } |
149 | 205 |
150 } // namespace net | 206 } // namespace net |
OLD | NEW |