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