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 |