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_controller.h" | 5 #include "net/http/http_auth_controller.h" |
6 | 6 |
| 7 #include "base/utf_string_conversions.h" |
7 #include "net/base/net_errors.h" | 8 #include "net/base/net_errors.h" |
8 #include "net/base/net_log.h" | 9 #include "net/base/net_log.h" |
9 #include "net/base/test_completion_callback.h" | 10 #include "net/base/test_completion_callback.h" |
10 #include "net/http/http_auth_cache.h" | 11 #include "net/http/http_auth_cache.h" |
11 #include "net/http/http_auth_handler_mock.h" | 12 #include "net/http/http_auth_handler_mock.h" |
12 #include "net/http/http_request_info.h" | 13 #include "net/http/http_request_info.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 #include "testing/gtest/include/gtest/gtest.h" | 16 #include "testing/gtest/include/gtest/gtest.h" |
16 | 17 |
17 namespace net { | 18 namespace net { |
18 | 19 |
19 namespace { | 20 namespace { |
20 | 21 |
21 enum HandlerRunMode { | 22 enum HandlerRunMode { |
22 RUN_HANDLER_SYNC, | 23 RUN_HANDLER_SYNC, |
23 RUN_HANDLER_ASYNC | 24 RUN_HANDLER_ASYNC |
24 }; | 25 }; |
25 | 26 |
26 enum SchemeState { | 27 enum SchemeState { |
27 SCHEME_IS_DISABLED, | 28 SCHEME_IS_DISABLED, |
28 SCHEME_IS_ENABLED | 29 SCHEME_IS_ENABLED |
29 }; | 30 }; |
30 | 31 |
| 32 scoped_refptr<HttpResponseHeaders> HeadersFromString(const char* string) { |
| 33 std::string raw_string(string); |
| 34 std::string headers_string = HttpUtil::AssembleRawHeaders( |
| 35 raw_string.c_str(), raw_string.length()); |
| 36 scoped_refptr<HttpResponseHeaders> headers( |
| 37 new HttpResponseHeaders(headers_string)); |
| 38 return headers; |
| 39 } |
| 40 |
31 // Runs an HttpAuthController with a single round mock auth handler | 41 // Runs an HttpAuthController with a single round mock auth handler |
32 // that returns |handler_rv| on token generation. The handler runs in | 42 // that returns |handler_rv| on token generation. The handler runs in |
33 // async if |run_mode| is RUN_HANDLER_ASYNC. Upon completion, the | 43 // async if |run_mode| is RUN_HANDLER_ASYNC. Upon completion, the |
34 // return value of the controller is tested against | 44 // return value of the controller is tested against |
35 // |expected_controller_rv|. |scheme_state| indicates whether the | 45 // |expected_controller_rv|. |scheme_state| indicates whether the |
36 // auth scheme used should be disabled after this run. | 46 // auth scheme used should be disabled after this run. |
37 void RunSingleRoundAuthTest(HandlerRunMode run_mode, | 47 void RunSingleRoundAuthTest(HandlerRunMode run_mode, |
38 int handler_rv, | 48 int handler_rv, |
39 int expected_controller_rv, | 49 int expected_controller_rv, |
40 SchemeState scheme_state) { | 50 SchemeState scheme_state) { |
41 BoundNetLog dummy_log; | 51 BoundNetLog dummy_log; |
42 HttpAuthCache dummy_auth_cache; | 52 HttpAuthCache dummy_auth_cache; |
43 | 53 |
44 HttpRequestInfo request; | 54 HttpRequestInfo request; |
45 request.method = "GET"; | 55 request.method = "GET"; |
46 request.url = GURL("http://example.com"); | 56 request.url = GURL("http://example.com"); |
47 | 57 |
48 const std::string headers_raw_string = | 58 scoped_refptr<HttpResponseHeaders> headers(HeadersFromString( |
49 "HTTP/1.1 407\r\n" | 59 "HTTP/1.1 407\r\n" |
50 "Proxy-Authenticate: MOCK foo\r\n" | 60 "Proxy-Authenticate: MOCK foo\r\n" |
51 "\r\n"; | 61 "\r\n")); |
52 std::string headers_string = HttpUtil::AssembleRawHeaders( | |
53 headers_raw_string.c_str(), headers_raw_string.length()); | |
54 scoped_refptr<HttpResponseHeaders> headers( | |
55 new HttpResponseHeaders(headers_string)); | |
56 | 62 |
57 HttpAuthHandlerMock::Factory auth_handler_factory; | 63 HttpAuthHandlerMock::Factory auth_handler_factory; |
58 HttpAuthHandlerMock* auth_handler = new HttpAuthHandlerMock(); | 64 HttpAuthHandlerMock* auth_handler = new HttpAuthHandlerMock(); |
59 auth_handler->SetGenerateExpectation((run_mode == RUN_HANDLER_ASYNC), | 65 auth_handler->SetGenerateExpectation((run_mode == RUN_HANDLER_ASYNC), |
60 handler_rv); | 66 handler_rv); |
61 auth_handler_factory.AddMockHandler(auth_handler, HttpAuth::AUTH_PROXY); | 67 auth_handler_factory.AddMockHandler(auth_handler, HttpAuth::AUTH_PROXY); |
62 auth_handler_factory.set_do_init_from_challenge(true); | 68 auth_handler_factory.set_do_init_from_challenge(true); |
63 | 69 |
64 scoped_refptr<HttpAuthController> controller( | 70 scoped_refptr<HttpAuthController> controller( |
65 new HttpAuthController(HttpAuth::AUTH_PROXY, | 71 new HttpAuthController(HttpAuth::AUTH_PROXY, |
66 GURL("http://example.com"), | 72 GURL("http://example.com"), |
67 &dummy_auth_cache, &auth_handler_factory)); | 73 &dummy_auth_cache, &auth_handler_factory)); |
68 ASSERT_EQ(OK, | 74 ASSERT_EQ(OK, |
69 controller->HandleAuthChallenge(headers, false, false, dummy_log)); | 75 controller->HandleAuthChallenge(headers, false, false, dummy_log)); |
70 EXPECT_TRUE(controller->HaveAuthHandler()); | 76 ASSERT_TRUE(controller->HaveAuthHandler()); |
71 controller->ResetAuth(string16(), string16()); | 77 controller->ResetAuth(string16(), string16()); |
72 EXPECT_TRUE(controller->HaveAuth()); | 78 EXPECT_TRUE(controller->HaveAuth()); |
73 | 79 |
74 TestCompletionCallback callback; | 80 TestCompletionCallback callback; |
75 EXPECT_EQ((run_mode == RUN_HANDLER_ASYNC)? ERR_IO_PENDING: | 81 EXPECT_EQ((run_mode == RUN_HANDLER_ASYNC)? ERR_IO_PENDING: |
76 expected_controller_rv, | 82 expected_controller_rv, |
77 controller->MaybeGenerateAuthToken(&request, &callback, | 83 controller->MaybeGenerateAuthToken(&request, &callback, |
78 dummy_log)); | 84 dummy_log)); |
79 if (run_mode == RUN_HANDLER_ASYNC) | 85 if (run_mode == RUN_HANDLER_ASYNC) |
80 EXPECT_EQ(expected_controller_rv, callback.WaitForResult()); | 86 EXPECT_EQ(expected_controller_rv, callback.WaitForResult()); |
(...skipping 21 matching lines...) Expand all Loading... |
102 // tokens. | 108 // tokens. |
103 RunSingleRoundAuthTest(RUN_HANDLER_ASYNC, ERR_MISSING_AUTH_CREDENTIALS, OK, | 109 RunSingleRoundAuthTest(RUN_HANDLER_ASYNC, ERR_MISSING_AUTH_CREDENTIALS, OK, |
104 SCHEME_IS_DISABLED); | 110 SCHEME_IS_DISABLED); |
105 | 111 |
106 // If a non-permanent error is returned by the handler, then the | 112 // If a non-permanent error is returned by the handler, then the |
107 // controller should report it unchanged. | 113 // controller should report it unchanged. |
108 RunSingleRoundAuthTest(RUN_HANDLER_ASYNC, ERR_INVALID_AUTH_CREDENTIALS, | 114 RunSingleRoundAuthTest(RUN_HANDLER_ASYNC, ERR_INVALID_AUTH_CREDENTIALS, |
109 ERR_INVALID_AUTH_CREDENTIALS, SCHEME_IS_ENABLED); | 115 ERR_INVALID_AUTH_CREDENTIALS, SCHEME_IS_ENABLED); |
110 } | 116 } |
111 | 117 |
| 118 // If an HttpAuthHandler indicates that it doesn't allow explicit |
| 119 // credentials, don't prompt for credentials. |
| 120 TEST(HttpAuthControllerTest, NoExplicitCredentialsAllowed) { |
| 121 // Modified mock HttpAuthHandler for this test. |
| 122 class MockHandler : public HttpAuthHandlerMock { |
| 123 public: |
| 124 MockHandler(int expected_rv, HttpAuth::Scheme scheme) |
| 125 : expected_scheme_(scheme) { |
| 126 SetGenerateExpectation(false, expected_rv); |
| 127 } |
| 128 |
| 129 protected: |
| 130 virtual bool Init(HttpAuth::ChallengeTokenizer* challenge) OVERRIDE { |
| 131 HttpAuthHandlerMock::Init(challenge); |
| 132 set_allows_default_credentials(true); |
| 133 set_allows_explicit_credentials(false); |
| 134 set_connection_based(true); |
| 135 // Pretend to be SCHEME_BASIC so we can test failover logic. |
| 136 if (challenge->scheme() == "Basic") { |
| 137 auth_scheme_ = HttpAuth::AUTH_SCHEME_BASIC; |
| 138 --score_; // Reduce score, so we rank below Mock. |
| 139 set_allows_explicit_credentials(true); |
| 140 } |
| 141 EXPECT_EQ(expected_scheme_, auth_scheme_); |
| 142 return true; |
| 143 } |
| 144 |
| 145 virtual int GenerateAuthTokenImpl(const string16* username, |
| 146 const string16* password, |
| 147 const HttpRequestInfo* request, |
| 148 CompletionCallback* callback, |
| 149 std::string* auth_token) OVERRIDE { |
| 150 int result = |
| 151 HttpAuthHandlerMock::GenerateAuthTokenImpl(username, password, |
| 152 request, callback, |
| 153 auth_token); |
| 154 EXPECT_TRUE(result != OK || |
| 155 !AllowsExplicitCredentials() || !username->empty()); |
| 156 return result; |
| 157 } |
| 158 |
| 159 private: |
| 160 HttpAuth::Scheme expected_scheme_; |
| 161 }; |
| 162 |
| 163 BoundNetLog dummy_log; |
| 164 HttpAuthCache dummy_auth_cache; |
| 165 HttpRequestInfo request; |
| 166 request.method = "GET"; |
| 167 request.url = GURL("http://example.com"); |
| 168 |
| 169 HttpRequestHeaders request_headers; |
| 170 scoped_refptr<HttpResponseHeaders> headers(HeadersFromString( |
| 171 "HTTP/1.1 401\r\n" |
| 172 "WWW-Authenticate: Mock\r\n" |
| 173 "WWW-Authenticate: Basic\r\n" |
| 174 "\r\n")); |
| 175 |
| 176 HttpAuthHandlerMock::Factory auth_handler_factory; |
| 177 |
| 178 // Handlers for the first attempt at authentication. AUTH_SCHEME_MOCK handler |
| 179 // accepts the default identity and successfully constructs a token. |
| 180 auth_handler_factory.AddMockHandler( |
| 181 new MockHandler(OK, HttpAuth::AUTH_SCHEME_MOCK), HttpAuth::AUTH_SERVER); |
| 182 auth_handler_factory.AddMockHandler( |
| 183 new MockHandler(ERR_UNEXPECTED, HttpAuth::AUTH_SCHEME_BASIC), |
| 184 HttpAuth::AUTH_SERVER); |
| 185 |
| 186 // Handlers for the second attempt. Neither should be used to generate a |
| 187 // token. Instead the controller should realize that there are no viable |
| 188 // identities to use with the AUTH_SCHEME_MOCK handler and fail. |
| 189 auth_handler_factory.AddMockHandler( |
| 190 new MockHandler(ERR_UNEXPECTED, HttpAuth::AUTH_SCHEME_MOCK), |
| 191 HttpAuth::AUTH_SERVER); |
| 192 auth_handler_factory.AddMockHandler( |
| 193 new MockHandler(ERR_UNEXPECTED, HttpAuth::AUTH_SCHEME_BASIC), |
| 194 HttpAuth::AUTH_SERVER); |
| 195 |
| 196 // Fallback handlers for the second attempt. The AUTH_SCHEME_MOCK handler |
| 197 // should be discarded due to the disabled scheme, and the AUTH_SCHEME_BASIC |
| 198 // handler should successfully be used to generate a token. |
| 199 auth_handler_factory.AddMockHandler( |
| 200 new MockHandler(ERR_UNEXPECTED, HttpAuth::AUTH_SCHEME_MOCK), |
| 201 HttpAuth::AUTH_SERVER); |
| 202 auth_handler_factory.AddMockHandler( |
| 203 new MockHandler(OK, HttpAuth::AUTH_SCHEME_BASIC), |
| 204 HttpAuth::AUTH_SERVER); |
| 205 auth_handler_factory.set_do_init_from_challenge(true); |
| 206 |
| 207 scoped_refptr<HttpAuthController> controller( |
| 208 new HttpAuthController(HttpAuth::AUTH_SERVER, |
| 209 GURL("http://example.com"), |
| 210 &dummy_auth_cache, &auth_handler_factory)); |
| 211 ASSERT_EQ(OK, |
| 212 controller->HandleAuthChallenge(headers, false, false, dummy_log)); |
| 213 ASSERT_TRUE(controller->HaveAuthHandler()); |
| 214 controller->ResetAuth(string16(), string16()); |
| 215 EXPECT_TRUE(controller->HaveAuth()); |
| 216 |
| 217 // Should only succeed if we are using the AUTH_SCHEME_MOCK MockHandler. |
| 218 EXPECT_EQ(OK, controller->MaybeGenerateAuthToken(&request, NULL, dummy_log)); |
| 219 controller->AddAuthorizationHeader(&request_headers); |
| 220 |
| 221 // Once a token is generated, simulate the receipt of a server response |
| 222 // indicating that the authentication attempt was rejected. |
| 223 ASSERT_EQ(OK, |
| 224 controller->HandleAuthChallenge(headers, false, false, dummy_log)); |
| 225 ASSERT_TRUE(controller->HaveAuthHandler()); |
| 226 controller->ResetAuth(ASCIIToUTF16("Hello"), string16()); |
| 227 EXPECT_TRUE(controller->HaveAuth()); |
| 228 EXPECT_TRUE(controller->IsAuthSchemeDisabled(HttpAuth::AUTH_SCHEME_MOCK)); |
| 229 EXPECT_FALSE(controller->IsAuthSchemeDisabled(HttpAuth::AUTH_SCHEME_BASIC)); |
| 230 |
| 231 // Should only succeed if we are using the AUTH_SCHEME_BASIC MockHandler. |
| 232 EXPECT_EQ(OK, controller->MaybeGenerateAuthToken(&request, NULL, dummy_log)); |
| 233 } |
| 234 |
112 } // namespace net | 235 } // namespace net |
OLD | NEW |