OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include <set> | |
6 #include <string> | |
7 | |
8 #include "base/memory/ref_counted.h" | |
9 #include "base/memory/scoped_ptr.h" | |
10 #include "base/strings/string_util.h" | |
11 #include "net/base/net_errors.h" | |
12 #include "net/dns/mock_host_resolver.h" | |
13 #include "net/http/http_auth.h" | |
14 #include "net/http/http_auth_challenge_tokenizer.h" | |
15 #include "net/http/http_auth_filter.h" | |
16 #include "net/http/http_auth_handler.h" | |
17 #include "net/http/http_auth_handler_factory.h" | |
18 #include "net/http/http_auth_handler_mock.h" | |
19 #include "net/http/http_response_headers.h" | |
20 #include "net/http/http_util.h" | |
21 #include "net/http/mock_allow_url_security_manager.h" | |
22 #include "testing/gtest/include/gtest/gtest.h" | |
23 | |
24 namespace net { | |
25 | |
26 namespace { | |
27 | |
28 HttpAuthHandlerMock* CreateMockHandler(bool connection_based) { | |
29 HttpAuthHandlerMock* auth_handler = new HttpAuthHandlerMock(); | |
30 auth_handler->set_connection_based(connection_based); | |
31 std::string challenge_text = "Basic"; | |
32 HttpAuthChallengeTokenizer challenge(challenge_text.begin(), | |
33 challenge_text.end()); | |
34 GURL origin("www.example.com"); | |
35 EXPECT_TRUE(auth_handler->InitFromChallenge(&challenge, | |
36 HttpAuth::AUTH_SERVER, | |
37 origin, | |
38 BoundNetLog())); | |
39 return auth_handler; | |
40 } | |
41 | |
42 HttpResponseHeaders* HeadersFromResponseText(const std::string& response) { | |
43 return new HttpResponseHeaders( | |
44 HttpUtil::AssembleRawHeaders(response.c_str(), response.length())); | |
45 } | |
46 | |
47 HttpAuth::AuthorizationResult HandleChallengeResponse( | |
48 bool connection_based, | |
49 const std::string& headers_text, | |
50 std::string* challenge_used) { | |
51 scoped_ptr<HttpAuthHandlerMock> mock_handler( | |
52 CreateMockHandler(connection_based)); | |
53 std::set<HttpAuth::Scheme> disabled_schemes; | |
54 scoped_refptr<HttpResponseHeaders> headers( | |
55 HeadersFromResponseText(headers_text)); | |
56 return HttpAuth::HandleChallengeResponse( | |
57 mock_handler.get(), | |
58 headers.get(), | |
59 HttpAuth::AUTH_SERVER, | |
60 disabled_schemes, | |
61 challenge_used); | |
62 } | |
63 | |
64 } // namespace | |
65 | |
66 TEST(HttpAuthTest, ChooseBestChallenge) { | |
67 static const struct { | |
68 const char* headers; | |
69 HttpAuth::Scheme challenge_scheme; | |
70 const char* challenge_realm; | |
71 } tests[] = { | |
72 { | |
73 // Basic is the only challenge type, pick it. | |
74 "Y: Digest realm=\"X\", nonce=\"aaaaaaaaaa\"\n" | |
75 "www-authenticate: Basic realm=\"BasicRealm\"\n", | |
76 | |
77 HttpAuth::AUTH_SCHEME_BASIC, | |
78 "BasicRealm", | |
79 }, | |
80 { | |
81 // Fake is the only challenge type, but it is unsupported. | |
82 "Y: Digest realm=\"FooBar\", nonce=\"aaaaaaaaaa\"\n" | |
83 "www-authenticate: Fake realm=\"FooBar\"\n", | |
84 | |
85 HttpAuth::AUTH_SCHEME_MAX, | |
86 "", | |
87 }, | |
88 { | |
89 // Pick Digest over Basic. | |
90 "www-authenticate: Basic realm=\"FooBar\"\n" | |
91 "www-authenticate: Fake realm=\"FooBar\"\n" | |
92 "www-authenticate: nonce=\"aaaaaaaaaa\"\n" | |
93 "www-authenticate: Digest realm=\"DigestRealm\", nonce=\"aaaaaaaaaa\"\n", | |
94 | |
95 HttpAuth::AUTH_SCHEME_DIGEST, | |
96 "DigestRealm", | |
97 }, | |
98 { | |
99 // Handle an empty header correctly. | |
100 "Y: Digest realm=\"X\", nonce=\"aaaaaaaaaa\"\n" | |
101 "www-authenticate:\n", | |
102 | |
103 HttpAuth::AUTH_SCHEME_MAX, | |
104 "", | |
105 }, | |
106 { | |
107 "WWW-Authenticate: Negotiate\n" | |
108 "WWW-Authenticate: NTLM\n", | |
109 | |
110 #if defined(USE_KERBEROS) | |
111 // Choose Negotiate over NTLM on all platforms. | |
112 // TODO(ahendrickson): This may be flaky on Linux and OSX as it | |
113 // relies on being able to load one of the known .so files | |
114 // for gssapi. | |
115 HttpAuth::AUTH_SCHEME_NEGOTIATE, | |
116 #else | |
117 // On systems that don't use Kerberos fall back to NTLM. | |
118 HttpAuth::AUTH_SCHEME_NTLM, | |
119 #endif // defined(USE_KERBEROS) | |
120 "", | |
121 } | |
122 }; | |
123 GURL origin("http://www.example.com"); | |
124 std::set<HttpAuth::Scheme> disabled_schemes; | |
125 MockAllowURLSecurityManager url_security_manager; | |
126 scoped_ptr<HostResolver> host_resolver(new MockHostResolver()); | |
127 scoped_ptr<HttpAuthHandlerRegistryFactory> http_auth_handler_factory( | |
128 HttpAuthHandlerFactory::CreateDefault(host_resolver.get())); | |
129 http_auth_handler_factory->SetURLSecurityManager( | |
130 "negotiate", &url_security_manager); | |
131 | |
132 for (size_t i = 0; i < arraysize(tests); ++i) { | |
133 // Make a HttpResponseHeaders object. | |
134 std::string headers_with_status_line("HTTP/1.1 401 Unauthorized\n"); | |
135 headers_with_status_line += tests[i].headers; | |
136 scoped_refptr<HttpResponseHeaders> headers( | |
137 HeadersFromResponseText(headers_with_status_line)); | |
138 | |
139 scoped_ptr<HttpAuthHandler> handler; | |
140 HttpAuth::ChooseBestChallenge(http_auth_handler_factory.get(), | |
141 headers.get(), | |
142 HttpAuth::AUTH_SERVER, | |
143 origin, | |
144 disabled_schemes, | |
145 BoundNetLog(), | |
146 &handler); | |
147 | |
148 if (handler.get()) { | |
149 EXPECT_EQ(tests[i].challenge_scheme, handler->auth_scheme()); | |
150 EXPECT_STREQ(tests[i].challenge_realm, handler->realm().c_str()); | |
151 } else { | |
152 EXPECT_EQ(HttpAuth::AUTH_SCHEME_MAX, tests[i].challenge_scheme); | |
153 EXPECT_STREQ("", tests[i].challenge_realm); | |
154 } | |
155 } | |
156 } | |
157 | |
158 TEST(HttpAuthTest, HandleChallengeResponse) { | |
159 std::string challenge_used; | |
160 const char* const kMockChallenge = | |
161 "HTTP/1.1 401 Unauthorized\n" | |
162 "WWW-Authenticate: Mock token_here\n"; | |
163 const char* const kBasicChallenge = | |
164 "HTTP/1.1 401 Unauthorized\n" | |
165 "WWW-Authenticate: Basic realm=\"happy\"\n"; | |
166 const char* const kMissingChallenge = | |
167 "HTTP/1.1 401 Unauthorized\n"; | |
168 const char* const kEmptyChallenge = | |
169 "HTTP/1.1 401 Unauthorized\n" | |
170 "WWW-Authenticate: \n"; | |
171 const char* const kBasicAndMockChallenges = | |
172 "HTTP/1.1 401 Unauthorized\n" | |
173 "WWW-Authenticate: Basic realm=\"happy\"\n" | |
174 "WWW-Authenticate: Mock token_here\n"; | |
175 const char* const kTwoMockChallenges = | |
176 "HTTP/1.1 401 Unauthorized\n" | |
177 "WWW-Authenticate: Mock token_a\n" | |
178 "WWW-Authenticate: Mock token_b\n"; | |
179 | |
180 // Request based schemes should treat any new challenges as rejections of the | |
181 // previous authentication attempt. (There is a slight exception for digest | |
182 // authentication and the stale parameter, but that is covered in the | |
183 // http_auth_handler_digest_unittests). | |
184 EXPECT_EQ( | |
185 HttpAuth::AUTHORIZATION_RESULT_REJECT, | |
186 HandleChallengeResponse(false, kMockChallenge, &challenge_used)); | |
187 EXPECT_EQ("Mock token_here", challenge_used); | |
188 | |
189 EXPECT_EQ( | |
190 HttpAuth::AUTHORIZATION_RESULT_REJECT, | |
191 HandleChallengeResponse(false, kBasicChallenge, &challenge_used)); | |
192 EXPECT_EQ("", challenge_used); | |
193 | |
194 EXPECT_EQ( | |
195 HttpAuth::AUTHORIZATION_RESULT_REJECT, | |
196 HandleChallengeResponse(false, kMissingChallenge, &challenge_used)); | |
197 EXPECT_EQ("", challenge_used); | |
198 | |
199 EXPECT_EQ( | |
200 HttpAuth::AUTHORIZATION_RESULT_REJECT, | |
201 HandleChallengeResponse(false, kEmptyChallenge, &challenge_used)); | |
202 EXPECT_EQ("", challenge_used); | |
203 | |
204 EXPECT_EQ( | |
205 HttpAuth::AUTHORIZATION_RESULT_REJECT, | |
206 HandleChallengeResponse(false, kBasicAndMockChallenges, &challenge_used)); | |
207 EXPECT_EQ("Mock token_here", challenge_used); | |
208 | |
209 EXPECT_EQ( | |
210 HttpAuth::AUTHORIZATION_RESULT_REJECT, | |
211 HandleChallengeResponse(false, kTwoMockChallenges, &challenge_used)); | |
212 EXPECT_EQ("Mock token_a", challenge_used); | |
213 | |
214 // Connection based schemes will treat new auth challenges for the same scheme | |
215 // as acceptance (and continuance) of the current approach. If there are | |
216 // no auth challenges for the same scheme, the response will be treated as | |
217 // a rejection. | |
218 EXPECT_EQ( | |
219 HttpAuth::AUTHORIZATION_RESULT_ACCEPT, | |
220 HandleChallengeResponse(true, kMockChallenge, &challenge_used)); | |
221 EXPECT_EQ("Mock token_here", challenge_used); | |
222 | |
223 EXPECT_EQ( | |
224 HttpAuth::AUTHORIZATION_RESULT_REJECT, | |
225 HandleChallengeResponse(true, kBasicChallenge, &challenge_used)); | |
226 EXPECT_EQ("", challenge_used); | |
227 | |
228 EXPECT_EQ( | |
229 HttpAuth::AUTHORIZATION_RESULT_REJECT, | |
230 HandleChallengeResponse(true, kMissingChallenge, &challenge_used)); | |
231 EXPECT_EQ("", challenge_used); | |
232 | |
233 EXPECT_EQ( | |
234 HttpAuth::AUTHORIZATION_RESULT_REJECT, | |
235 HandleChallengeResponse(true, kEmptyChallenge, &challenge_used)); | |
236 EXPECT_EQ("", challenge_used); | |
237 | |
238 EXPECT_EQ( | |
239 HttpAuth::AUTHORIZATION_RESULT_ACCEPT, | |
240 HandleChallengeResponse(true, kBasicAndMockChallenges, &challenge_used)); | |
241 EXPECT_EQ("Mock token_here", challenge_used); | |
242 | |
243 EXPECT_EQ( | |
244 HttpAuth::AUTHORIZATION_RESULT_ACCEPT, | |
245 HandleChallengeResponse(true, kTwoMockChallenges, &challenge_used)); | |
246 EXPECT_EQ("Mock token_a", challenge_used); | |
247 } | |
248 | |
249 TEST(HttpAuthTest, GetChallengeHeaderName) { | |
250 std::string name; | |
251 | |
252 name = HttpAuth::GetChallengeHeaderName(HttpAuth::AUTH_SERVER); | |
253 EXPECT_STREQ("WWW-Authenticate", name.c_str()); | |
254 | |
255 name = HttpAuth::GetChallengeHeaderName(HttpAuth::AUTH_PROXY); | |
256 EXPECT_STREQ("Proxy-Authenticate", name.c_str()); | |
257 } | |
258 | |
259 TEST(HttpAuthTest, GetAuthorizationHeaderName) { | |
260 std::string name; | |
261 | |
262 name = HttpAuth::GetAuthorizationHeaderName(HttpAuth::AUTH_SERVER); | |
263 EXPECT_STREQ("Authorization", name.c_str()); | |
264 | |
265 name = HttpAuth::GetAuthorizationHeaderName(HttpAuth::AUTH_PROXY); | |
266 EXPECT_STREQ("Proxy-Authorization", name.c_str()); | |
267 } | |
268 | |
269 } // namespace net | |
OLD | NEW |