http_auth.cc revision c7f5f8508d98d5952d42ed7648c2a8f30a4da156
1c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_auth.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <algorithm>
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/basictypes.h"
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h"
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_auth_handler_basic.h"
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_auth_handler_digest.h"
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_auth_handler_negotiate.h"
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_auth_handler_ntlm.h"
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_response_headers.h"
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_util.h"
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net {
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid HttpAuth::ChooseBestChallenge(const HttpResponseHeaders* headers,
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                   Target target,
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                   const GURL& origin,
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                   scoped_refptr<HttpAuthHandler>* handler) {
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // A connection-based authentication scheme must continue to use the
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // existing handler object in |*handler|.
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (*handler && (*handler)->is_connection_based()) {
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const std::string header_name = GetChallengeHeaderName(target);
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    std::string challenge;
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    void* iter = NULL;
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    while (headers->EnumerateHeader(&iter, header_name, &challenge)) {
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      ChallengeTokenizer props(challenge.begin(), challenge.end());
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (LowerCaseEqualsASCII(props.scheme(), (*handler)->scheme().c_str()) &&
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          (*handler)->InitFromChallenge(challenge.begin(), challenge.end(),
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                        target, origin))
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return;
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Choose the challenge whose authentication handler gives the maximum score.
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_refptr<HttpAuthHandler> best;
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const std::string header_name = GetChallengeHeaderName(target);
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  std::string cur_challenge;
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void* iter = NULL;
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  while (headers->EnumerateHeader(&iter, header_name, &cur_challenge)) {
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    scoped_refptr<HttpAuthHandler> cur;
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CreateAuthHandler(cur_challenge, target, origin, &cur);
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (cur && (!best || best->score() < cur->score()))
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      best.swap(cur);
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  handler->swap(best);
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid HttpAuth::CreateAuthHandler(const std::string& challenge,
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                 Target target,
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                 const GURL& origin,
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                 scoped_refptr<HttpAuthHandler>* handler) {
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Find the right auth handler for the challenge's scheme.
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ChallengeTokenizer props(challenge.begin(), challenge.end());
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!props.valid()) {
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    *handler = NULL;
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_refptr<HttpAuthHandler> tmp_handler;
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (LowerCaseEqualsASCII(props.scheme(), "basic")) {
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    tmp_handler = new HttpAuthHandlerBasic();
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else if (LowerCaseEqualsASCII(props.scheme(), "digest")) {
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    tmp_handler = new HttpAuthHandlerDigest();
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else if (LowerCaseEqualsASCII(props.scheme(), "negotiate")) {
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    tmp_handler = new HttpAuthHandlerNegotiate();
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else if (LowerCaseEqualsASCII(props.scheme(), "ntlm")) {
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    tmp_handler = new HttpAuthHandlerNTLM();
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (tmp_handler) {
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!tmp_handler->InitFromChallenge(challenge.begin(), challenge.end(),
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                        target, origin)) {
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // Invalid/unsupported challenge.
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      tmp_handler = NULL;
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  handler->swap(tmp_handler);
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid HttpAuth::ChallengeTokenizer::Init(std::string::const_iterator begin,
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                        std::string::const_iterator end) {
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // The first space-separated token is the auth-scheme.
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // NOTE: we are more permissive than RFC 2617 which says auth-scheme
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // is separated by 1*SP.
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  StringTokenizer tok(begin, end, HTTP_LWS);
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!tok.GetNext()) {
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    valid_ = false;
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Save the scheme's position.
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scheme_begin_ = tok.token_begin();
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scheme_end_ = tok.token_end();
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Everything past scheme_end_ is a (comma separated) value list.
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  props_ = HttpUtil::ValuesIterator(scheme_end_, end, ',');
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// We expect properties to be formatted as one of:
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   name="value"
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   name=value
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   name=
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool HttpAuth::ChallengeTokenizer::GetNext() {
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!props_.GetNext())
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Set the value as everything. Next we will split out the name.
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  value_begin_ = props_.value_begin();
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  value_end_ = props_.value_end();
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  name_begin_ = name_end_ = value_end_;
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Scan for the equals sign.
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  std::string::const_iterator equals = std::find(value_begin_, value_end_, '=');
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (equals == value_end_ || equals == value_begin_)
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return valid_ = false;  // Malformed
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Verify that the equals sign we found wasn't inside of quote marks.
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (std::string::const_iterator it = value_begin_; it != equals; ++it) {
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (HttpUtil::IsQuote(*it))
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return valid_ = false;  // Malformed
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  name_begin_ = value_begin_;
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  name_end_ = equals;
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  value_begin_ = equals + 1;
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (value_begin_ != value_end_ && HttpUtil::IsQuote(*value_begin_)) {
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Trim surrounding quotemarks off the value
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (*value_begin_ != *(value_end_ - 1))
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return valid_ = false;  // Malformed -- mismatching quotes.
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    value_is_quoted_ = true;
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    value_is_quoted_ = false;
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return true;
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// If value() has quotemarks, unquote it.
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstd::string HttpAuth::ChallengeTokenizer::unquoted_value() const {
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return HttpUtil::Unquote(value_begin_, value_end_);
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstd::string HttpAuth::GetChallengeHeaderName(Target target) {
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  switch (target) {
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case AUTH_PROXY:
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return "Proxy-Authenticate";
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case AUTH_SERVER:
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return "WWW-Authenticate";
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    default:
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      NOTREACHED();
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return "";
159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstd::string HttpAuth::GetAuthorizationHeaderName(Target target) {
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  switch (target) {
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case AUTH_PROXY:
166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return "Proxy-Authorization";
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case AUTH_SERVER:
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return "Authorization";
169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    default:
170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      NOTREACHED();
171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return "";
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace net
176