http_auth_handler_basic_unittest.cc 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  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. #include "net/http/http_auth_handler_basic.h"
  5. #include <memory>
  6. #include <string>
  7. #include "base/strings/string_util.h"
  8. #include "base/strings/utf_string_conversions.h"
  9. #include "net/base/net_errors.h"
  10. #include "net/base/network_isolation_key.h"
  11. #include "net/base/test_completion_callback.h"
  12. #include "net/dns/mock_host_resolver.h"
  13. #include "net/http/http_auth_challenge_tokenizer.h"
  14. #include "net/http/http_auth_preferences.h"
  15. #include "net/http/http_request_info.h"
  16. #include "net/log/net_log_with_source.h"
  17. #include "net/ssl/ssl_info.h"
  18. #include "net/test/gtest_util.h"
  19. #include "testing/gmock/include/gmock/gmock.h"
  20. #include "testing/gtest/include/gtest/gtest.h"
  21. #include "url/scheme_host_port.h"
  22. using net::test::IsError;
  23. using net::test::IsOk;
  24. namespace net {
  25. TEST(HttpAuthHandlerBasicTest, GenerateAuthToken) {
  26. static const struct {
  27. const char* username;
  28. const char* password;
  29. const char* expected_credentials;
  30. } tests[] = {
  31. { "foo", "bar", "Basic Zm9vOmJhcg==" },
  32. // Empty username
  33. { "", "foobar", "Basic OmZvb2Jhcg==" },
  34. // Empty password
  35. { "anon", "", "Basic YW5vbjo=" },
  36. // Empty username and empty password.
  37. { "", "", "Basic Og==" },
  38. };
  39. url::SchemeHostPort scheme_host_port(GURL("http://www.example.com"));
  40. HttpAuthHandlerBasic::Factory factory;
  41. for (const auto& test : tests) {
  42. std::string challenge = "Basic realm=\"Atlantis\"";
  43. SSLInfo null_ssl_info;
  44. auto host_resolver = std::make_unique<MockHostResolver>();
  45. std::unique_ptr<HttpAuthHandler> basic;
  46. EXPECT_EQ(OK, factory.CreateAuthHandlerFromString(
  47. challenge, HttpAuth::AUTH_SERVER, null_ssl_info,
  48. NetworkIsolationKey(), scheme_host_port,
  49. NetLogWithSource(), host_resolver.get(), &basic));
  50. AuthCredentials credentials(base::ASCIIToUTF16(test.username),
  51. base::ASCIIToUTF16(test.password));
  52. HttpRequestInfo request_info;
  53. std::string auth_token;
  54. TestCompletionCallback callback;
  55. int rv = basic->GenerateAuthToken(&credentials, &request_info,
  56. callback.callback(), &auth_token);
  57. EXPECT_THAT(rv, IsOk());
  58. EXPECT_STREQ(test.expected_credentials, auth_token.c_str());
  59. }
  60. }
  61. TEST(HttpAuthHandlerBasicTest, HandleAnotherChallenge) {
  62. static const struct {
  63. const char* challenge;
  64. HttpAuth::AuthorizationResult expected_rv;
  65. } tests[] = {
  66. // The handler is initialized using this challenge. The first
  67. // time HandleAnotherChallenge is called with it should cause it
  68. // to treat the second challenge as a rejection since it is for
  69. // the same realm.
  70. {
  71. "Basic realm=\"First\"",
  72. HttpAuth::AUTHORIZATION_RESULT_REJECT
  73. },
  74. // A challenge for a different realm.
  75. {
  76. "Basic realm=\"Second\"",
  77. HttpAuth::AUTHORIZATION_RESULT_DIFFERENT_REALM
  78. },
  79. // Although RFC 2617 isn't explicit about this case, if there is
  80. // more than one realm directive, we pick the last one. So this
  81. // challenge should be treated as being for "First" realm.
  82. {
  83. "Basic realm=\"Second\",realm=\"First\"",
  84. HttpAuth::AUTHORIZATION_RESULT_REJECT
  85. },
  86. // And this one should be treated as if it was for "Second."
  87. {
  88. "basic realm=\"First\",realm=\"Second\"",
  89. HttpAuth::AUTHORIZATION_RESULT_DIFFERENT_REALM
  90. }
  91. };
  92. url::SchemeHostPort scheme_host_port(GURL("http://www.example.com"));
  93. HttpAuthHandlerBasic::Factory factory;
  94. SSLInfo null_ssl_info;
  95. auto host_resolver = std::make_unique<MockHostResolver>();
  96. std::unique_ptr<HttpAuthHandler> basic;
  97. EXPECT_EQ(OK, factory.CreateAuthHandlerFromString(
  98. tests[0].challenge, HttpAuth::AUTH_SERVER, null_ssl_info,
  99. NetworkIsolationKey(), scheme_host_port, NetLogWithSource(),
  100. host_resolver.get(), &basic));
  101. for (const auto& test : tests) {
  102. std::string challenge(test.challenge);
  103. HttpAuthChallengeTokenizer tok(challenge.begin(),
  104. challenge.end());
  105. EXPECT_EQ(test.expected_rv, basic->HandleAnotherChallenge(&tok));
  106. }
  107. }
  108. TEST(HttpAuthHandlerBasicTest, InitFromChallenge) {
  109. static const struct {
  110. const char* challenge;
  111. int expected_rv;
  112. const char* expected_realm;
  113. } tests[] = {
  114. // No realm (we allow this even though realm is supposed to be required
  115. // according to RFC 2617.)
  116. {
  117. "Basic",
  118. OK,
  119. "",
  120. },
  121. // Realm is empty string.
  122. {
  123. "Basic realm=\"\"",
  124. OK,
  125. "",
  126. },
  127. // Realm is valid.
  128. {
  129. "Basic realm=\"test_realm\"",
  130. OK,
  131. "test_realm",
  132. },
  133. // The parser ignores tokens which aren't known.
  134. {
  135. "Basic realm=\"test_realm\",unknown_token=foobar",
  136. OK,
  137. "test_realm",
  138. },
  139. // The parser skips over tokens which aren't known.
  140. {
  141. "Basic unknown_token=foobar,realm=\"test_realm\"",
  142. OK,
  143. "test_realm",
  144. },
  145. #if 0
  146. // TODO(cbentzel): It's unclear what the parser should do in these cases.
  147. // It seems like this should either be treated as invalid,
  148. // or the spaces should be used as a separator.
  149. {
  150. "Basic realm=\"test_realm\" unknown_token=foobar",
  151. OK,
  152. "test_realm",
  153. },
  154. // The parser skips over tokens which aren't known.
  155. {
  156. "Basic unknown_token=foobar realm=\"test_realm\"",
  157. OK,
  158. "test_realm",
  159. },
  160. #endif
  161. // The parser fails when the first token is not "Basic".
  162. {
  163. "Negotiate",
  164. ERR_INVALID_RESPONSE,
  165. ""
  166. },
  167. // Although RFC 2617 isn't explicit about this case, if there is
  168. // more than one realm directive, we pick the last one.
  169. {
  170. "Basic realm=\"foo\",realm=\"bar\"",
  171. OK,
  172. "bar",
  173. },
  174. // Handle ISO-8859-1 character as part of the realm. The realm is converted
  175. // to UTF-8.
  176. {
  177. "Basic realm=\"foo-\xE5\"",
  178. OK,
  179. "foo-\xC3\xA5",
  180. },
  181. };
  182. HttpAuthHandlerBasic::Factory factory;
  183. url::SchemeHostPort scheme_host_port(GURL("http://www.example.com"));
  184. for (const auto& test : tests) {
  185. std::string challenge = test.challenge;
  186. SSLInfo null_ssl_info;
  187. auto host_resolver = std::make_unique<MockHostResolver>();
  188. std::unique_ptr<HttpAuthHandler> basic;
  189. int rv = factory.CreateAuthHandlerFromString(
  190. challenge, HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(),
  191. scheme_host_port, NetLogWithSource(), host_resolver.get(), &basic);
  192. EXPECT_EQ(test.expected_rv, rv);
  193. if (rv == OK)
  194. EXPECT_EQ(test.expected_realm, basic->realm());
  195. }
  196. }
  197. // Test that when Basic is configured to forbid HTTP, attempting to create a
  198. // Basic auth handler for a HTTP context is rejected.
  199. TEST(HttpAuthHandlerBasicTest, BasicAuthRequiresHTTPS) {
  200. url::SchemeHostPort nonsecure_scheme_host_port(
  201. GURL("http://www.example.com"));
  202. HttpAuthHandlerBasic::Factory factory;
  203. HttpAuthPreferences http_auth_preferences;
  204. http_auth_preferences.set_basic_over_http_enabled(false);
  205. factory.set_http_auth_preferences(&http_auth_preferences);
  206. std::string challenge = "Basic realm=\"Atlantis\"";
  207. SSLInfo null_ssl_info;
  208. auto host_resolver = std::make_unique<MockHostResolver>();
  209. std::unique_ptr<HttpAuthHandler> basic;
  210. // Ensure that HTTP is disallowed.
  211. EXPECT_THAT(factory.CreateAuthHandlerFromString(
  212. challenge, HttpAuth::AUTH_SERVER, null_ssl_info,
  213. NetworkIsolationKey(), nonsecure_scheme_host_port,
  214. NetLogWithSource(), host_resolver.get(), &basic),
  215. IsError(ERR_UNSUPPORTED_AUTH_SCHEME));
  216. // Ensure that HTTPS is allowed.
  217. url::SchemeHostPort secure_scheme_host_port(GURL("https://www.example.com"));
  218. EXPECT_THAT(factory.CreateAuthHandlerFromString(
  219. challenge, HttpAuth::AUTH_SERVER, null_ssl_info,
  220. NetworkIsolationKey(), secure_scheme_host_port,
  221. NetLogWithSource(), host_resolver.get(), &basic),
  222. IsOk());
  223. }
  224. } // namespace net