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