Home | History | Annotate | Download | only in http
      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 
     20 namespace net {
     21 
     22 HttpAuth::Identity::Identity() : source(IDENT_SRC_NONE), invalid(true) {}
     23 
     24 // static
     25 void 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
     58 HttpAuth::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
     92 std::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
    105 std::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
    118 std::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
    131 const 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