Home | History | Annotate | Download | only in http
      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 
     21 HttpAuth::Identity::Identity() : source(IDENT_SRC_NONE), invalid(true) {}
     22 
     23 // static
     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
     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 
     90 HttpUtil::NameValuePairsIterator HttpAuth::ChallengeTokenizer::param_pairs()
     91     const {
     92   return HttpUtil::NameValuePairsIterator(params_begin_, params_end_, ',');
     93 }
     94 
     95 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 
    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
    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
    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
    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
    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