| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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/string_util.h" | 10 #include "base/string_util.h" |
| 11 #include "net/http/http_auth_handler_basic.h" | 11 #include "net/http/http_auth_handler_basic.h" |
| 12 #include "net/http/http_auth_handler_digest.h" | 12 #include "net/http/http_auth_handler_digest.h" |
| 13 #include "net/http/http_auth_handler_ntlm.h" |
| 13 #include "net/http/http_response_headers.h" | 14 #include "net/http/http_response_headers.h" |
| 14 #include "net/http/http_util.h" | 15 #include "net/http/http_util.h" |
| 15 | 16 |
| 16 namespace net { | 17 namespace net { |
| 17 | 18 |
| 18 // static | 19 // static |
| 19 void HttpAuth::ChooseBestChallenge(const HttpResponseHeaders* headers, | 20 void HttpAuth::ChooseBestChallenge(const HttpResponseHeaders* headers, |
| 20 Target target, | 21 Target target, |
| 21 scoped_refptr<HttpAuthHandler>* handler) { | 22 scoped_refptr<HttpAuthHandler>* handler) { |
| 23 // A connection-based authentication scheme must continue to use the |
| 24 // existing handler object in |*handler|. |
| 25 if (*handler && (*handler)->is_connection_based()) { |
| 26 const std::string header_name = GetChallengeHeaderName(target); |
| 27 std::string challenge; |
| 28 void* iter = NULL; |
| 29 while (headers->EnumerateHeader(&iter, header_name, &challenge)) { |
| 30 ChallengeTokenizer props(challenge.begin(), challenge.end()); |
| 31 if (LowerCaseEqualsASCII(props.scheme(), (*handler)->scheme().c_str()) && |
| 32 (*handler)->InitFromChallenge(challenge.begin(), challenge.end(), |
| 33 target)) |
| 34 return; |
| 35 } |
| 36 } |
| 37 |
| 22 // Choose the challenge whose authentication handler gives the maximum score. | 38 // Choose the challenge whose authentication handler gives the maximum score. |
| 23 scoped_refptr<HttpAuthHandler> best; | 39 scoped_refptr<HttpAuthHandler> best; |
| 24 const std::string header_name = GetChallengeHeaderName(target); | 40 const std::string header_name = GetChallengeHeaderName(target); |
| 25 std::string cur_challenge; | 41 std::string cur_challenge; |
| 26 void* iter = NULL; | 42 void* iter = NULL; |
| 27 while (headers->EnumerateHeader(&iter, header_name, &cur_challenge)) { | 43 while (headers->EnumerateHeader(&iter, header_name, &cur_challenge)) { |
| 28 scoped_refptr<HttpAuthHandler> cur; | 44 scoped_refptr<HttpAuthHandler> cur; |
| 29 CreateAuthHandler(cur_challenge, target, &cur); | 45 CreateAuthHandler(cur_challenge, target, &cur); |
| 30 if (cur && (!best || best->score() < cur->score())) | 46 if (cur && (!best || best->score() < cur->score())) |
| 31 best.swap(cur); | 47 best.swap(cur); |
| 32 } | 48 } |
| 33 handler->swap(best); | 49 handler->swap(best); |
| 34 } | 50 } |
| 35 | 51 |
| 36 // static | 52 // static |
| 37 void HttpAuth::CreateAuthHandler(const std::string& challenge, | 53 void HttpAuth::CreateAuthHandler(const std::string& challenge, |
| 38 Target target, | 54 Target target, |
| 39 scoped_refptr<HttpAuthHandler>* handler) { | 55 scoped_refptr<HttpAuthHandler>* handler) { |
| 40 // Find the right auth handler for the challenge's scheme. | 56 // Find the right auth handler for the challenge's scheme. |
| 41 ChallengeTokenizer props(challenge.begin(), challenge.end()); | 57 ChallengeTokenizer props(challenge.begin(), challenge.end()); |
| 42 scoped_refptr<HttpAuthHandler> tmp_handler; | 58 scoped_refptr<HttpAuthHandler> tmp_handler; |
| 43 | 59 |
| 44 if (LowerCaseEqualsASCII(props.scheme(), "basic")) { | 60 if (LowerCaseEqualsASCII(props.scheme(), "basic")) { |
| 45 tmp_handler = new HttpAuthHandlerBasic(); | 61 tmp_handler = new HttpAuthHandlerBasic(); |
| 46 } else if (LowerCaseEqualsASCII(props.scheme(), "digest")) { | 62 } else if (LowerCaseEqualsASCII(props.scheme(), "digest")) { |
| 47 tmp_handler = new HttpAuthHandlerDigest(); | 63 tmp_handler = new HttpAuthHandlerDigest(); |
| 64 } else if (LowerCaseEqualsASCII(props.scheme(), "ntlm")) { |
| 65 tmp_handler = new HttpAuthHandlerNTLM(); |
| 48 } | 66 } |
| 49 if (tmp_handler) { | 67 if (tmp_handler) { |
| 50 if (!tmp_handler->InitFromChallenge(challenge.begin(), challenge.end(), | 68 if (!tmp_handler->InitFromChallenge(challenge.begin(), challenge.end(), |
| 51 target)) { | 69 target)) { |
| 52 // Invalid/unsupported challenge. | 70 // Invalid/unsupported challenge. |
| 53 tmp_handler = NULL; | 71 tmp_handler = NULL; |
| 54 } | 72 } |
| 55 } | 73 } |
| 56 handler->swap(tmp_handler); | 74 handler->swap(tmp_handler); |
| 57 } | 75 } |
| 58 | 76 |
| 59 void HttpAuth::ChallengeTokenizer::Init(std::string::const_iterator begin, | 77 void HttpAuth::ChallengeTokenizer::Init(std::string::const_iterator begin, |
| 60 std::string::const_iterator end) { | 78 std::string::const_iterator end) { |
| 61 // The first space-separated token is the auth-scheme. | 79 // The first space-separated token is the auth-scheme. |
| 62 // NOTE: we are more permissive than RFC 2617 which says auth-scheme | 80 // NOTE: we are more permissive than RFC 2617 which says auth-scheme |
| 63 // is separated by 1*SP. | 81 // is separated by 1*SP. |
| 64 StringTokenizer tok(begin, end, HTTP_LWS); | 82 StringTokenizer tok(begin, end, HTTP_LWS); |
| 65 if (!tok.GetNext()) { | 83 if (!tok.GetNext()) { |
| 66 valid_ = false; | 84 valid_ = false; |
| 67 return; | 85 return; |
| 68 } | 86 } |
| 69 | 87 |
| 70 // Save the scheme's position. | 88 // Save the scheme's position. |
| 71 scheme_begin_ = tok.token_begin(); | 89 scheme_begin_ = tok.token_begin(); |
| 72 scheme_end_ = tok.token_end(); | 90 scheme_end_ = tok.token_end(); |
| 73 | 91 |
| 74 // Everything past scheme_end_ is a (comma separated) value list. | 92 // Everything past scheme_end_ is a (comma separated) value list. |
| 75 if (scheme_end_ != end) | 93 props_ = HttpUtil::ValuesIterator(scheme_end_, end, ','); |
| 76 props_ = HttpUtil::ValuesIterator(scheme_end_ + 1, end, ','); | |
| 77 } | 94 } |
| 78 | 95 |
| 79 // We expect properties to be formatted as one of: | 96 // We expect properties to be formatted as one of: |
| 80 // name="value" | 97 // name="value" |
| 81 // name=value | 98 // name=value |
| 82 // name= | 99 // name= |
| 83 bool HttpAuth::ChallengeTokenizer::GetNext() { | 100 bool HttpAuth::ChallengeTokenizer::GetNext() { |
| 84 if (!props_.GetNext()) | 101 if (!props_.GetNext()) |
| 85 return false; | 102 return false; |
| 86 | 103 |
| 87 // Set the value as everything. Next we will split out the name. | 104 // Set the value as everything. Next we will split out the name. |
| 88 value_begin_ = props_.value_begin(); | 105 value_begin_ = props_.value_begin(); |
| 89 value_end_ = props_.value_end(); | 106 value_end_ = props_.value_end(); |
| 90 name_begin_ = name_end_ = value_end_; | 107 name_begin_ = name_end_ = value_end_; |
| 91 | 108 |
| 92 // Scan for the equals sign. | 109 // Scan for the equals sign. |
| 93 std::string::const_iterator equals = std::find(value_begin_, value_end_, '='); | 110 std::string::const_iterator equals = std::find(value_begin_, value_end_, '='); |
| 94 if (equals == value_end_ || equals == value_begin_) | 111 if (equals == value_end_ || equals == value_begin_) |
| 95 return valid_ = false; // Malformed | 112 return valid_ = false; // Malformed |
| 96 | 113 |
| 97 // Verify that the equals sign we found wasn't inside of quote marks. | 114 // Verify that the equals sign we found wasn't inside of quote marks. |
| 98 for (std::string::const_iterator it = value_begin_; it != equals; ++it) { | 115 for (std::string::const_iterator it = value_begin_; it != equals; ++it) { |
| 99 if (HttpUtil::IsQuote(*it)) | 116 if (HttpUtil::IsQuote(*it)) |
| 100 return valid_ = false; // Malformed | 117 return valid_ = false; // Malformed |
| 101 } | 118 } |
| 102 | 119 |
| 103 name_begin_ = value_begin_; | 120 name_begin_ = value_begin_; |
| 104 name_end_ = equals; | 121 name_end_ = equals; |
| 105 value_begin_ = equals + 1; | 122 value_begin_ = equals + 1; |
| 106 | 123 |
| 107 if (value_begin_ != value_end_ && HttpUtil::IsQuote(*value_begin_)) { | 124 if (value_begin_ != value_end_ && HttpUtil::IsQuote(*value_begin_)) { |
| 108 // Trim surrounding quotemarks off the value | 125 // Trim surrounding quotemarks off the value |
| 109 if (*value_begin_ != *(value_end_ - 1)) | 126 if (*value_begin_ != *(value_end_ - 1)) |
| 110 return valid_ = false; // Malformed -- mismatching quotes. | 127 return valid_ = false; // Malformed -- mismatching quotes. |
| 111 value_is_quoted_ = true; | 128 value_is_quoted_ = true; |
| 112 } else { | 129 } else { |
| 113 value_is_quoted_ = false; | 130 value_is_quoted_ = false; |
| 114 } | 131 } |
| 115 return true; | 132 return true; |
| 116 } | 133 } |
| 117 | 134 |
| 118 // If value() has quotemarks, unquote it. | 135 // If value() has quotemarks, unquote it. |
| 119 std::string HttpAuth::ChallengeTokenizer::unquoted_value() const { | 136 std::string HttpAuth::ChallengeTokenizer::unquoted_value() const { |
| 120 return HttpUtil::Unquote(value_begin_, value_end_); | 137 return HttpUtil::Unquote(value_begin_, value_end_); |
| 121 } | 138 } |
| 122 | 139 |
| 123 // static | 140 // static |
| 124 std::string HttpAuth::GetChallengeHeaderName(Target target) { | 141 std::string HttpAuth::GetChallengeHeaderName(Target target) { |
| 125 switch(target) { | 142 switch (target) { |
| 126 case AUTH_PROXY: | 143 case AUTH_PROXY: |
| 127 return "Proxy-Authenticate"; | 144 return "Proxy-Authenticate"; |
| 128 case AUTH_SERVER: | 145 case AUTH_SERVER: |
| 129 return "WWW-Authenticate"; | 146 return "WWW-Authenticate"; |
| 130 default: | 147 default: |
| 131 NOTREACHED(); | 148 NOTREACHED(); |
| 132 return ""; | 149 return ""; |
| 133 } | 150 } |
| 134 } | 151 } |
| 135 | 152 |
| 136 // static | 153 // static |
| 137 std::string HttpAuth::GetAuthorizationHeaderName(Target target) { | 154 std::string HttpAuth::GetAuthorizationHeaderName(Target target) { |
| 138 switch(target) { | 155 switch (target) { |
| 139 case AUTH_PROXY: | 156 case AUTH_PROXY: |
| 140 return "Proxy-Authorization"; | 157 return "Proxy-Authorization"; |
| 141 case AUTH_SERVER: | 158 case AUTH_SERVER: |
| 142 return "Authorization"; | 159 return "Authorization"; |
| 143 default: | 160 default: |
| 144 NOTREACHED(); | 161 NOTREACHED(); |
| 145 return ""; | 162 return ""; |
| 146 } | 163 } |
| 147 } | 164 } |
| 148 | 165 |
| 149 } // namespace net | 166 } // namespace net |
| OLD | NEW |