| 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 "net/http/http_auth_handler_basic.h" | |
| 6 | |
| 7 #include <string> | |
| 8 | |
| 9 #include "base/base64.h" | |
| 10 #include "base/strings/string_util.h" | |
| 11 #include "base/strings/utf_string_conversions.h" | |
| 12 #include "net/base/net_errors.h" | |
| 13 #include "net/base/net_string_util.h" | |
| 14 #include "net/http/http_auth.h" | |
| 15 #include "net/http/http_auth_challenge_tokenizer.h" | |
| 16 | |
| 17 namespace net { | |
| 18 | |
| 19 namespace { | |
| 20 | |
| 21 // Parses a realm from an auth challenge, and converts to UTF8-encoding. | |
| 22 // Returns whether the realm is invalid or the parameters are invalid. | |
| 23 // | |
| 24 // Note that if a realm was not specified, we will default it to ""; | |
| 25 // so specifying 'Basic realm=""' is equivalent to 'Basic'. | |
| 26 // | |
| 27 // This is more generous than RFC 2617, which is pretty clear in the | |
| 28 // production of challenge that realm is required. | |
| 29 // | |
| 30 // We allow it to be compatibility with certain embedded webservers that don't | |
| 31 // include a realm (see http://crbug.com/20984.) | |
| 32 // | |
| 33 // The over-the-wire realm is encoded as ISO-8859-1 (aka Latin-1). | |
| 34 // | |
| 35 // TODO(cbentzel): Realm may need to be decoded using RFC 2047 rules as | |
| 36 // well, see http://crbug.com/25790. | |
| 37 bool ParseRealm(const HttpAuthChallengeTokenizer& tokenizer, | |
| 38 std::string* realm) { | |
| 39 CHECK(realm); | |
| 40 realm->clear(); | |
| 41 HttpUtil::NameValuePairsIterator parameters = tokenizer.param_pairs(); | |
| 42 while (parameters.GetNext()) { | |
| 43 if (!LowerCaseEqualsASCII(parameters.name(), "realm")) | |
| 44 continue; | |
| 45 | |
| 46 if (!net::ConvertToUtf8AndNormalize(parameters.value(), kCharsetLatin1, | |
| 47 realm)) { | |
| 48 return false; | |
| 49 } | |
| 50 } | |
| 51 return parameters.valid(); | |
| 52 } | |
| 53 | |
| 54 } // namespace | |
| 55 | |
| 56 bool HttpAuthHandlerBasic::Init(HttpAuthChallengeTokenizer* challenge) { | |
| 57 auth_scheme_ = HttpAuth::AUTH_SCHEME_BASIC; | |
| 58 score_ = 1; | |
| 59 properties_ = 0; | |
| 60 return ParseChallenge(challenge); | |
| 61 } | |
| 62 | |
| 63 bool HttpAuthHandlerBasic::ParseChallenge( | |
| 64 HttpAuthChallengeTokenizer* challenge) { | |
| 65 // Verify the challenge's auth-scheme. | |
| 66 if (!LowerCaseEqualsASCII(challenge->scheme(), "basic")) | |
| 67 return false; | |
| 68 | |
| 69 std::string realm; | |
| 70 if (!ParseRealm(*challenge, &realm)) | |
| 71 return false; | |
| 72 | |
| 73 realm_ = realm; | |
| 74 return true; | |
| 75 } | |
| 76 | |
| 77 HttpAuth::AuthorizationResult HttpAuthHandlerBasic::HandleAnotherChallenge( | |
| 78 HttpAuthChallengeTokenizer* challenge) { | |
| 79 // Basic authentication is always a single round, so any responses | |
| 80 // should be treated as a rejection. However, if the new challenge | |
| 81 // is for a different realm, then indicate the realm change. | |
| 82 std::string realm; | |
| 83 if (!ParseRealm(*challenge, &realm)) | |
| 84 return HttpAuth::AUTHORIZATION_RESULT_INVALID; | |
| 85 return (realm_ != realm)? | |
| 86 HttpAuth::AUTHORIZATION_RESULT_DIFFERENT_REALM: | |
| 87 HttpAuth::AUTHORIZATION_RESULT_REJECT; | |
| 88 } | |
| 89 | |
| 90 int HttpAuthHandlerBasic::GenerateAuthTokenImpl( | |
| 91 const AuthCredentials* credentials, const HttpRequestInfo*, | |
| 92 const CompletionCallback&, std::string* auth_token) { | |
| 93 DCHECK(credentials); | |
| 94 // TODO(eroman): is this the right encoding of username/password? | |
| 95 std::string base64_username_password; | |
| 96 base::Base64Encode(base::UTF16ToUTF8(credentials->username()) + ":" + | |
| 97 base::UTF16ToUTF8(credentials->password()), | |
| 98 &base64_username_password); | |
| 99 *auth_token = "Basic " + base64_username_password; | |
| 100 return OK; | |
| 101 } | |
| 102 | |
| 103 HttpAuthHandlerBasic::Factory::Factory() { | |
| 104 } | |
| 105 | |
| 106 HttpAuthHandlerBasic::Factory::~Factory() { | |
| 107 } | |
| 108 | |
| 109 int HttpAuthHandlerBasic::Factory::CreateAuthHandler( | |
| 110 HttpAuthChallengeTokenizer* challenge, | |
| 111 HttpAuth::Target target, | |
| 112 const GURL& origin, | |
| 113 CreateReason reason, | |
| 114 int digest_nonce_count, | |
| 115 const BoundNetLog& net_log, | |
| 116 scoped_ptr<HttpAuthHandler>* handler) { | |
| 117 // TODO(cbentzel): Move towards model of parsing in the factory | |
| 118 // method and only constructing when valid. | |
| 119 scoped_ptr<HttpAuthHandler> tmp_handler(new HttpAuthHandlerBasic()); | |
| 120 if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log)) | |
| 121 return ERR_INVALID_RESPONSE; | |
| 122 handler->swap(tmp_handler); | |
| 123 return OK; | |
| 124 } | |
| 125 | |
| 126 } // namespace net | |
| OLD | NEW |