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