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.h"
6
7#include <algorithm>
8
9#include "base/basictypes.h"
10#include "base/strings/string_tokenizer.h"
11#include "base/strings/string_util.h"
12#include "net/base/net_errors.h"
13#include "net/http/http_auth_challenge_tokenizer.h"
14#include "net/http/http_auth_handler.h"
15#include "net/http/http_auth_handler_factory.h"
16#include "net/http/http_request_headers.h"
17#include "net/http/http_response_headers.h"
18#include "net/http/http_util.h"
19
20namespace net {
21
22HttpAuth::Identity::Identity() : source(IDENT_SRC_NONE), invalid(true) {}
23
24// static
25void HttpAuth::ChooseBestChallenge(
26    HttpAuthHandlerFactory* http_auth_handler_factory,
27    const HttpResponseHeaders* headers,
28    Target target,
29    const GURL& origin,
30    const std::set<Scheme>& disabled_schemes,
31    const BoundNetLog& net_log,
32    scoped_ptr<HttpAuthHandler>* handler) {
33  DCHECK(http_auth_handler_factory);
34  DCHECK(handler->get() == NULL);
35
36  // Choose the challenge whose authentication handler gives the maximum score.
37  scoped_ptr<HttpAuthHandler> best;
38  const std::string header_name = GetChallengeHeaderName(target);
39  std::string cur_challenge;
40  void* iter = NULL;
41  while (headers->EnumerateHeader(&iter, header_name, &cur_challenge)) {
42    scoped_ptr<HttpAuthHandler> cur;
43    int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
44        cur_challenge, target, origin, net_log, &cur);
45    if (rv != OK) {
46      VLOG(1) << "Unable to create AuthHandler. Status: "
47              << ErrorToString(rv) << " Challenge: " << cur_challenge;
48      continue;
49    }
50    if (cur.get() && (!best.get() || best->score() < cur->score()) &&
51        (disabled_schemes.find(cur->auth_scheme()) == disabled_schemes.end()))
52      best.swap(cur);
53  }
54  handler->swap(best);
55}
56
57// static
58HttpAuth::AuthorizationResult HttpAuth::HandleChallengeResponse(
59    HttpAuthHandler* handler,
60    const HttpResponseHeaders* headers,
61    Target target,
62    const std::set<Scheme>& disabled_schemes,
63    std::string* challenge_used) {
64  DCHECK(handler);
65  DCHECK(headers);
66  DCHECK(challenge_used);
67  challenge_used->clear();
68  HttpAuth::Scheme current_scheme = handler->auth_scheme();
69  if (disabled_schemes.find(current_scheme) != disabled_schemes.end())
70    return HttpAuth::AUTHORIZATION_RESULT_REJECT;
71  std::string current_scheme_name = SchemeToString(current_scheme);
72  const std::string header_name = GetChallengeHeaderName(target);
73  void* iter = NULL;
74  std::string challenge;
75  HttpAuth::AuthorizationResult authorization_result =
76      HttpAuth::AUTHORIZATION_RESULT_INVALID;
77  while (headers->EnumerateHeader(&iter, header_name, &challenge)) {
78    HttpAuthChallengeTokenizer props(challenge.begin(), challenge.end());
79    if (!LowerCaseEqualsASCII(props.scheme(), current_scheme_name.c_str()))
80      continue;
81    authorization_result = handler->HandleAnotherChallenge(&props);
82    if (authorization_result != HttpAuth::AUTHORIZATION_RESULT_INVALID) {
83      *challenge_used = challenge;
84      return authorization_result;
85    }
86  }
87  // Finding no matches is equivalent to rejection.
88  return HttpAuth::AUTHORIZATION_RESULT_REJECT;
89}
90
91// static
92std::string HttpAuth::GetChallengeHeaderName(Target target) {
93  switch (target) {
94    case AUTH_PROXY:
95      return "Proxy-Authenticate";
96    case AUTH_SERVER:
97      return "WWW-Authenticate";
98    default:
99      NOTREACHED();
100      return std::string();
101  }
102}
103
104// static
105std::string HttpAuth::GetAuthorizationHeaderName(Target target) {
106  switch (target) {
107    case AUTH_PROXY:
108      return HttpRequestHeaders::kProxyAuthorization;
109    case AUTH_SERVER:
110      return HttpRequestHeaders::kAuthorization;
111    default:
112      NOTREACHED();
113      return std::string();
114  }
115}
116
117// static
118std::string HttpAuth::GetAuthTargetString(Target target) {
119  switch (target) {
120    case AUTH_PROXY:
121      return "proxy";
122    case AUTH_SERVER:
123      return "server";
124    default:
125      NOTREACHED();
126      return std::string();
127  }
128}
129
130// static
131const char* HttpAuth::SchemeToString(Scheme scheme) {
132  static const char* const kSchemeNames[] = {
133    "basic",
134    "digest",
135    "ntlm",
136    "negotiate",
137    "spdyproxy",
138    "mock",
139  };
140  COMPILE_ASSERT(arraysize(kSchemeNames) == AUTH_SCHEME_MAX,
141                 http_auth_scheme_names_incorrect_size);
142  if (scheme < AUTH_SCHEME_BASIC || scheme >= AUTH_SCHEME_MAX) {
143    NOTREACHED();
144    return "invalid_scheme";
145  }
146  return kSchemeNames[scheme];
147}
148
149}  // namespace net
150