• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.h"
6 
7 #include <algorithm>
8 
9 #include "base/basictypes.h"
10 #include "base/string_util.h"
11 #include "net/base/net_errors.h"
12 #include "net/http/http_auth_handler_basic.h"
13 #include "net/http/http_auth_handler_digest.h"
14 #include "net/http/http_auth_handler_negotiate.h"
15 #include "net/http/http_auth_handler_ntlm.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/http/http_util.h"
18 
19 namespace net {
20 
Identity()21 HttpAuth::Identity::Identity() : source(IDENT_SRC_NONE), invalid(true) {}
22 
23 // static
ChooseBestChallenge(HttpAuthHandlerFactory * http_auth_handler_factory,const HttpResponseHeaders * headers,Target target,const GURL & origin,const std::set<Scheme> & disabled_schemes,const BoundNetLog & net_log,scoped_ptr<HttpAuthHandler> * handler)24 void HttpAuth::ChooseBestChallenge(
25     HttpAuthHandlerFactory* http_auth_handler_factory,
26     const HttpResponseHeaders* headers,
27     Target target,
28     const GURL& origin,
29     const std::set<Scheme>& disabled_schemes,
30     const BoundNetLog& net_log,
31     scoped_ptr<HttpAuthHandler>* handler) {
32   DCHECK(http_auth_handler_factory);
33   DCHECK(handler->get() == NULL);
34 
35   // Choose the challenge whose authentication handler gives the maximum score.
36   scoped_ptr<HttpAuthHandler> best;
37   const std::string header_name = GetChallengeHeaderName(target);
38   std::string cur_challenge;
39   void* iter = NULL;
40   while (headers->EnumerateHeader(&iter, header_name, &cur_challenge)) {
41     scoped_ptr<HttpAuthHandler> cur;
42     int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
43         cur_challenge, target, origin, net_log, &cur);
44     if (rv != OK) {
45       VLOG(1) << "Unable to create AuthHandler. Status: "
46               << ErrorToString(rv) << " Challenge: " << cur_challenge;
47       continue;
48     }
49     if (cur.get() && (!best.get() || best->score() < cur->score()) &&
50         (disabled_schemes.find(cur->auth_scheme()) == disabled_schemes.end()))
51       best.swap(cur);
52   }
53   handler->swap(best);
54 }
55 
56 // static
HandleChallengeResponse(HttpAuthHandler * handler,const HttpResponseHeaders * headers,Target target,const std::set<Scheme> & disabled_schemes,std::string * challenge_used)57 HttpAuth::AuthorizationResult HttpAuth::HandleChallengeResponse(
58     HttpAuthHandler* handler,
59     const HttpResponseHeaders* headers,
60     Target target,
61     const std::set<Scheme>& disabled_schemes,
62     std::string* challenge_used) {
63   DCHECK(handler);
64   DCHECK(headers);
65   DCHECK(challenge_used);
66   challenge_used->clear();
67   HttpAuth::Scheme current_scheme = handler->auth_scheme();
68   if (disabled_schemes.find(current_scheme) != disabled_schemes.end())
69     return HttpAuth::AUTHORIZATION_RESULT_REJECT;
70   std::string current_scheme_name = SchemeToString(current_scheme);
71   const std::string header_name = GetChallengeHeaderName(target);
72   void* iter = NULL;
73   std::string challenge;
74   HttpAuth::AuthorizationResult authorization_result =
75       HttpAuth::AUTHORIZATION_RESULT_INVALID;
76   while (headers->EnumerateHeader(&iter, header_name, &challenge)) {
77     HttpAuth::ChallengeTokenizer props(challenge.begin(), challenge.end());
78     if (!LowerCaseEqualsASCII(props.scheme(), current_scheme_name.c_str()))
79       continue;
80     authorization_result = handler->HandleAnotherChallenge(&props);
81     if (authorization_result != HttpAuth::AUTHORIZATION_RESULT_INVALID) {
82       *challenge_used = challenge;
83       return authorization_result;
84     }
85   }
86   // Finding no matches is equivalent to rejection.
87   return HttpAuth::AUTHORIZATION_RESULT_REJECT;
88 }
89 
param_pairs() const90 HttpUtil::NameValuePairsIterator HttpAuth::ChallengeTokenizer::param_pairs()
91     const {
92   return HttpUtil::NameValuePairsIterator(params_begin_, params_end_, ',');
93 }
94 
base64_param() const95 std::string HttpAuth::ChallengeTokenizer::base64_param() const {
96   // Strip off any padding.
97   // (See https://bugzilla.mozilla.org/show_bug.cgi?id=230351.)
98   //
99   // Our base64 decoder requires that the length be a multiple of 4.
100   int encoded_length = params_end_ - params_begin_;
101   while (encoded_length > 0 && encoded_length % 4 != 0 &&
102          params_begin_[encoded_length - 1] == '=') {
103     --encoded_length;
104   }
105   return std::string(params_begin_, params_begin_ + encoded_length);
106 }
107 
Init(std::string::const_iterator begin,std::string::const_iterator end)108 void HttpAuth::ChallengeTokenizer::Init(std::string::const_iterator begin,
109                                         std::string::const_iterator end) {
110   // The first space-separated token is the auth-scheme.
111   // NOTE: we are more permissive than RFC 2617 which says auth-scheme
112   // is separated by 1*SP.
113   StringTokenizer tok(begin, end, HTTP_LWS);
114   if (!tok.GetNext()) {
115     // Default param and scheme iterators provide empty strings
116     return;
117   }
118 
119   // Save the scheme's position.
120   scheme_begin_ = tok.token_begin();
121   scheme_end_ = tok.token_end();
122 
123   params_begin_ = scheme_end_;
124   params_end_ = end;
125   HttpUtil::TrimLWS(&params_begin_, &params_end_);
126 }
127 
128 // static
GetChallengeHeaderName(Target target)129 std::string HttpAuth::GetChallengeHeaderName(Target target) {
130   switch (target) {
131     case AUTH_PROXY:
132       return "Proxy-Authenticate";
133     case AUTH_SERVER:
134       return "WWW-Authenticate";
135     default:
136       NOTREACHED();
137       return "";
138   }
139 }
140 
141 // static
GetAuthorizationHeaderName(Target target)142 std::string HttpAuth::GetAuthorizationHeaderName(Target target) {
143   switch (target) {
144     case AUTH_PROXY:
145       return "Proxy-Authorization";
146     case AUTH_SERVER:
147       return "Authorization";
148     default:
149       NOTREACHED();
150       return "";
151   }
152 }
153 
154 // static
GetAuthTargetString(Target target)155 std::string HttpAuth::GetAuthTargetString(Target target) {
156   switch (target) {
157     case AUTH_PROXY:
158       return "proxy";
159     case AUTH_SERVER:
160       return "server";
161     default:
162       NOTREACHED();
163       return "";
164   }
165 }
166 
167 // static
SchemeToString(Scheme scheme)168 const char* HttpAuth::SchemeToString(Scheme scheme) {
169   static const char* const kSchemeNames[] = {
170     "basic",
171     "digest",
172     "ntlm",
173     "negotiate",
174     "mock",
175   };
176   COMPILE_ASSERT(arraysize(kSchemeNames) == AUTH_SCHEME_MAX,
177                  http_auth_scheme_names_incorrect_size);
178   if (scheme < AUTH_SCHEME_BASIC || scheme >= AUTH_SCHEME_MAX) {
179     NOTREACHED();
180     return "invalid_scheme";
181   }
182   return kSchemeNames[scheme];
183 }
184 
185 }  // namespace net
186