| 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 |