15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_auth_handler_basic.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base64.h" 107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_util.h" 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h" 135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "net/base/net_string_util.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_auth.h" 15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/http/http_auth_challenge_tokenizer.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Parses a realm from an auth challenge, and converts to UTF8-encoding. 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns whether the realm is invalid or the parameters are invalid. 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that if a realm was not specified, we will default it to ""; 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// so specifying 'Basic realm=""' is equivalent to 'Basic'. 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is more generous than RFC 2617, which is pretty clear in the 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// production of challenge that realm is required. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We allow it to be compatibility with certain embedded webservers that don't 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// include a realm (see http://crbug.com/20984.) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The over-the-wire realm is encoded as ISO-8859-1 (aka Latin-1). 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(cbentzel): Realm may need to be decoded using RFC 2047 rules as 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// well, see http://crbug.com/25790. 37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ParseRealm(const HttpAuthChallengeTokenizer& tokenizer, 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* realm) { 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(realm); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) realm->clear(); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpUtil::NameValuePairsIterator parameters = tokenizer.param_pairs(); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (parameters.GetNext()) { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!LowerCaseEqualsASCII(parameters.name(), "realm")) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!net::ConvertToUtf8AndNormalize(parameters.value(), kCharsetLatin1, 47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) realm)) { 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return parameters.valid(); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool HttpAuthHandlerBasic::Init(HttpAuthChallengeTokenizer* challenge) { 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_scheme_ = HttpAuth::AUTH_SCHEME_BASIC; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) score_ = 1; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) properties_ = 0; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ParseChallenge(challenge); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpAuthHandlerBasic::ParseChallenge( 64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HttpAuthChallengeTokenizer* challenge) { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Verify the challenge's auth-scheme. 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!LowerCaseEqualsASCII(challenge->scheme(), "basic")) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string realm; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ParseRealm(*challenge, &realm)) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) realm_ = realm; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpAuth::AuthorizationResult HttpAuthHandlerBasic::HandleAnotherChallenge( 78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HttpAuthChallengeTokenizer* challenge) { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Basic authentication is always a single round, so any responses 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // should be treated as a rejection. However, if the new challenge 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is for a different realm, then indicate the realm change. 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string realm; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ParseRealm(*challenge, &realm)) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return HttpAuth::AUTHORIZATION_RESULT_INVALID; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (realm_ != realm)? 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuth::AUTHORIZATION_RESULT_DIFFERENT_REALM: 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuth::AUTHORIZATION_RESULT_REJECT; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpAuthHandlerBasic::GenerateAuthTokenImpl( 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AuthCredentials* credentials, const HttpRequestInfo*, 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CompletionCallback&, std::string* auth_token) { 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(credentials); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(eroman): is this the right encoding of username/password? 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string base64_username_password; 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Base64Encode(base::UTF16ToUTF8(credentials->username()) + ":" + 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::UTF16ToUTF8(credentials->password()), 98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) &base64_username_password); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *auth_token = "Basic " + base64_username_password; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpAuthHandlerBasic::Factory::Factory() { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpAuthHandlerBasic::Factory::~Factory() { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpAuthHandlerBasic::Factory::CreateAuthHandler( 110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HttpAuthChallengeTokenizer* challenge, 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuth::Target target, 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& origin, 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreateReason reason, 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int digest_nonce_count, 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BoundNetLog& net_log, 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<HttpAuthHandler>* handler) { 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(cbentzel): Move towards model of parsing in the factory 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // method and only constructing when valid. 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<HttpAuthHandler> tmp_handler(new HttpAuthHandlerBasic()); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log)) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_INVALID_RESPONSE; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handler->swap(tmp_handler); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 127