summaryrefslogtreecommitdiff
path: root/chromium/net/http/http_auth_handler_basic.cc
blob: 9b4eec2bd5fddcad9a471d614335cca53a993ffb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/http/http_auth_handler_basic.h"

#include <string>

#include "base/base64.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "net/base/net_errors.h"
#include "net/base/net_string_util.h"
#include "net/dns/host_resolver.h"
#include "net/http/http_auth.h"
#include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/http_auth_preferences.h"
#include "net/http/http_auth_scheme.h"
#include "url/scheme_host_port.h"
#include "url/url_constants.h"

namespace net {

namespace {

// Parses a realm from an auth challenge, and converts to UTF8-encoding.
// Returns whether the realm is invalid or the parameters are invalid.
//
// Note that if a realm was not specified, we will default it to "";
// so specifying 'Basic realm=""' is equivalent to 'Basic'.
//
// This is more generous than RFC 2617, which is pretty clear in the
// production of challenge that realm is required.
//
// We allow it to be compatibility with certain embedded webservers that don't
// include a realm (see http://crbug.com/20984.)
//
// The over-the-wire realm is encoded as ISO-8859-1 (aka Latin-1).
//
// TODO(cbentzel): Realm may need to be decoded using RFC 2047 rules as
// well, see http://crbug.com/25790.
bool ParseRealm(const HttpAuthChallengeTokenizer& tokenizer,
                std::string* realm) {
  CHECK(realm);
  realm->clear();
  HttpUtil::NameValuePairsIterator parameters = tokenizer.param_pairs();
  while (parameters.GetNext()) {
    if (!base::EqualsCaseInsensitiveASCII(parameters.name_piece(), "realm"))
      continue;

    if (!ConvertToUtf8AndNormalize(parameters.value_piece(), kCharsetLatin1,
                                   realm)) {
      return false;
    }
  }
  return parameters.valid();
}

}  // namespace

bool HttpAuthHandlerBasic::Init(
    HttpAuthChallengeTokenizer* challenge,
    const SSLInfo& ssl_info,
    const NetworkAnonymizationKey& network_anonymization_key) {
  auth_scheme_ = HttpAuth::AUTH_SCHEME_BASIC;
  score_ = 1;
  properties_ = 0;
  return ParseChallenge(challenge);
}

bool HttpAuthHandlerBasic::ParseChallenge(
    HttpAuthChallengeTokenizer* challenge) {
  if (challenge->auth_scheme() != kBasicAuthScheme)
    return false;

  std::string realm;
  if (!ParseRealm(*challenge, &realm))
    return false;

  realm_ = realm;
  return true;
}

int HttpAuthHandlerBasic::GenerateAuthTokenImpl(
    const AuthCredentials* credentials,
    const HttpRequestInfo*,
    CompletionOnceCallback callback,
    std::string* auth_token) {
  DCHECK(credentials);
  // Firefox, Safari and Chromium all use UTF-8 encoding; IE uses iso-8859-1.
  // RFC7617 does not specify a default encoding, but UTF-8 is the only allowed
  // value for the optional charset parameter on the challenge.
  std::string base64_username_password;
  base::Base64Encode(base::UTF16ToUTF8(credentials->username()) + ":" +
                         base::UTF16ToUTF8(credentials->password()),
                     &base64_username_password);
  *auth_token = "Basic " + base64_username_password;
  return OK;
}

HttpAuth::AuthorizationResult HttpAuthHandlerBasic::HandleAnotherChallengeImpl(
    HttpAuthChallengeTokenizer* challenge) {
  // Basic authentication is always a single round, so any responses
  // should be treated as a rejection.  However, if the new challenge
  // is for a different realm, then indicate the realm change.
  std::string realm;
  if (!ParseRealm(*challenge, &realm))
    return HttpAuth::AUTHORIZATION_RESULT_INVALID;
  return (realm_ != realm) ? HttpAuth::AUTHORIZATION_RESULT_DIFFERENT_REALM
                           : HttpAuth::AUTHORIZATION_RESULT_REJECT;
}

HttpAuthHandlerBasic::Factory::Factory() = default;

HttpAuthHandlerBasic::Factory::~Factory() = default;

int HttpAuthHandlerBasic::Factory::CreateAuthHandler(
    HttpAuthChallengeTokenizer* challenge,
    HttpAuth::Target target,
    const SSLInfo& ssl_info,
    const NetworkAnonymizationKey& network_anonymization_key,
    const url::SchemeHostPort& scheme_host_port,
    CreateReason reason,
    int digest_nonce_count,
    const NetLogWithSource& net_log,
    HostResolver* host_resolver,
    std::unique_ptr<HttpAuthHandler>* handler) {
  if (http_auth_preferences() &&
      !http_auth_preferences()->basic_over_http_enabled() &&
      scheme_host_port.scheme() == url::kHttpScheme) {
    return ERR_UNSUPPORTED_AUTH_SCHEME;
  }
  // TODO(cbentzel): Move towards model of parsing in the factory
  //                 method and only constructing when valid.
  auto tmp_handler = std::make_unique<HttpAuthHandlerBasic>();
  if (!tmp_handler->InitFromChallenge(challenge, target, ssl_info,
                                      network_anonymization_key,
                                      scheme_host_port, net_log)) {
    return ERR_INVALID_RESPONSE;
  }
  *handler = std::move(tmp_handler);
  return OK;
}

}  // namespace net