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.
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"
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
,
42 HttpResponseHeaders
* HeadersFromResponseText(const std::string
& response
) {
43 return new HttpResponseHeaders(
44 HttpUtil::AssembleRawHeaders(response
.c_str(), response
.length()));
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(
59 HttpAuth::AUTH_SERVER
,
66 TEST(HttpAuthTest
, ChooseBestChallenge
) {
69 HttpAuth::Scheme challenge_scheme
;
70 const char* challenge_realm
;
73 // Basic is the only challenge type, pick it.
74 "Y: Digest realm=\"X\", nonce=\"aaaaaaaaaa\"\n"
75 "www-authenticate: Basic realm=\"BasicRealm\"\n",
77 HttpAuth::AUTH_SCHEME_BASIC
,
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",
85 HttpAuth::AUTH_SCHEME_MAX
,
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",
95 HttpAuth::AUTH_SCHEME_DIGEST
,
99 // Handle an empty header correctly.
100 "Y: Digest realm=\"X\", nonce=\"aaaaaaaaaa\"\n"
101 "www-authenticate:\n",
103 HttpAuth::AUTH_SCHEME_MAX
,
107 "WWW-Authenticate: Negotiate\n"
108 "WWW-Authenticate: NTLM\n",
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
115 HttpAuth::AUTH_SCHEME_NEGOTIATE
,
117 // On systems that don't use Kerberos fall back to NTLM.
118 HttpAuth::AUTH_SCHEME_NTLM
,
119 #endif // defined(USE_KERBEROS)
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
);
132 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(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
));
139 scoped_ptr
<HttpAuthHandler
> handler
;
140 HttpAuth::ChooseBestChallenge(http_auth_handler_factory
.get(),
142 HttpAuth::AUTH_SERVER
,
149 EXPECT_EQ(tests
[i
].challenge_scheme
, handler
->auth_scheme());
150 EXPECT_STREQ(tests
[i
].challenge_realm
, handler
->realm().c_str());
152 EXPECT_EQ(HttpAuth::AUTH_SCHEME_MAX
, tests
[i
].challenge_scheme
);
153 EXPECT_STREQ("", tests
[i
].challenge_realm
);
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";
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).
185 HttpAuth::AUTHORIZATION_RESULT_REJECT
,
186 HandleChallengeResponse(false, kMockChallenge
, &challenge_used
));
187 EXPECT_EQ("Mock token_here", challenge_used
);
190 HttpAuth::AUTHORIZATION_RESULT_REJECT
,
191 HandleChallengeResponse(false, kBasicChallenge
, &challenge_used
));
192 EXPECT_EQ("", challenge_used
);
195 HttpAuth::AUTHORIZATION_RESULT_REJECT
,
196 HandleChallengeResponse(false, kMissingChallenge
, &challenge_used
));
197 EXPECT_EQ("", challenge_used
);
200 HttpAuth::AUTHORIZATION_RESULT_REJECT
,
201 HandleChallengeResponse(false, kEmptyChallenge
, &challenge_used
));
202 EXPECT_EQ("", challenge_used
);
205 HttpAuth::AUTHORIZATION_RESULT_REJECT
,
206 HandleChallengeResponse(false, kBasicAndMockChallenges
, &challenge_used
));
207 EXPECT_EQ("Mock token_here", challenge_used
);
210 HttpAuth::AUTHORIZATION_RESULT_REJECT
,
211 HandleChallengeResponse(false, kTwoMockChallenges
, &challenge_used
));
212 EXPECT_EQ("Mock token_a", challenge_used
);
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
219 HttpAuth::AUTHORIZATION_RESULT_ACCEPT
,
220 HandleChallengeResponse(true, kMockChallenge
, &challenge_used
));
221 EXPECT_EQ("Mock token_here", challenge_used
);
224 HttpAuth::AUTHORIZATION_RESULT_REJECT
,
225 HandleChallengeResponse(true, kBasicChallenge
, &challenge_used
));
226 EXPECT_EQ("", challenge_used
);
229 HttpAuth::AUTHORIZATION_RESULT_REJECT
,
230 HandleChallengeResponse(true, kMissingChallenge
, &challenge_used
));
231 EXPECT_EQ("", challenge_used
);
234 HttpAuth::AUTHORIZATION_RESULT_REJECT
,
235 HandleChallengeResponse(true, kEmptyChallenge
, &challenge_used
));
236 EXPECT_EQ("", challenge_used
);
239 HttpAuth::AUTHORIZATION_RESULT_ACCEPT
,
240 HandleChallengeResponse(true, kBasicAndMockChallenges
, &challenge_used
));
241 EXPECT_EQ("Mock token_here", challenge_used
);
244 HttpAuth::AUTHORIZATION_RESULT_ACCEPT
,
245 HandleChallengeResponse(true, kTwoMockChallenges
, &challenge_used
));
246 EXPECT_EQ("Mock token_a", challenge_used
);
249 TEST(HttpAuthTest
, GetChallengeHeaderName
) {
252 name
= HttpAuth::GetChallengeHeaderName(HttpAuth::AUTH_SERVER
);
253 EXPECT_STREQ("WWW-Authenticate", name
.c_str());
255 name
= HttpAuth::GetChallengeHeaderName(HttpAuth::AUTH_PROXY
);
256 EXPECT_STREQ("Proxy-Authenticate", name
.c_str());
259 TEST(HttpAuthTest
, GetAuthorizationHeaderName
) {
262 name
= HttpAuth::GetAuthorizationHeaderName(HttpAuth::AUTH_SERVER
);
263 EXPECT_STREQ("Authorization", name
.c_str());
265 name
= HttpAuth::GetAuthorizationHeaderName(HttpAuth::AUTH_PROXY
);
266 EXPECT_STREQ("Proxy-Authorization", name
.c_str());