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_handler_factory.h"
6
7#include "base/stl_util.h"
8#include "base/strings/string_util.h"
9#include "net/base/net_errors.h"
10#include "net/http/http_auth_challenge_tokenizer.h"
11#include "net/http/http_auth_filter.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_ntlm.h"
15
16#if defined(USE_KERBEROS)
17#include "net/http/http_auth_handler_negotiate.h"
18#endif
19
20namespace net {
21
22int HttpAuthHandlerFactory::CreateAuthHandlerFromString(
23    const std::string& challenge,
24    HttpAuth::Target target,
25    const GURL& origin,
26    const BoundNetLog& net_log,
27    scoped_ptr<HttpAuthHandler>* handler) {
28  HttpAuthChallengeTokenizer props(challenge.begin(), challenge.end());
29  return CreateAuthHandler(&props, target, origin, CREATE_CHALLENGE, 1,
30                           net_log, handler);
31}
32
33int HttpAuthHandlerFactory::CreatePreemptiveAuthHandlerFromString(
34    const std::string& challenge,
35    HttpAuth::Target target,
36    const GURL& origin,
37    int digest_nonce_count,
38    const BoundNetLog& net_log,
39    scoped_ptr<HttpAuthHandler>* handler) {
40  HttpAuthChallengeTokenizer props(challenge.begin(), challenge.end());
41  return CreateAuthHandler(&props, target, origin, CREATE_PREEMPTIVE,
42                           digest_nonce_count, net_log, handler);
43}
44
45// static
46HttpAuthHandlerRegistryFactory* HttpAuthHandlerFactory::CreateDefault(
47    HostResolver* host_resolver) {
48  DCHECK(host_resolver);
49  HttpAuthHandlerRegistryFactory* registry_factory =
50      new HttpAuthHandlerRegistryFactory();
51  registry_factory->RegisterSchemeFactory(
52      "basic", new HttpAuthHandlerBasic::Factory());
53  registry_factory->RegisterSchemeFactory(
54      "digest", new HttpAuthHandlerDigest::Factory());
55
56#if defined(USE_KERBEROS)
57  HttpAuthHandlerNegotiate::Factory* negotiate_factory =
58      new HttpAuthHandlerNegotiate::Factory();
59#if defined(OS_POSIX)
60  negotiate_factory->set_library(new GSSAPISharedLibrary(std::string()));
61#elif defined(OS_WIN)
62  negotiate_factory->set_library(new SSPILibraryDefault());
63#endif
64  negotiate_factory->set_host_resolver(host_resolver);
65  registry_factory->RegisterSchemeFactory("negotiate", negotiate_factory);
66#endif  // defined(USE_KERBEROS)
67
68  HttpAuthHandlerNTLM::Factory* ntlm_factory =
69      new HttpAuthHandlerNTLM::Factory();
70#if defined(OS_WIN)
71  ntlm_factory->set_sspi_library(new SSPILibraryDefault());
72#endif
73  registry_factory->RegisterSchemeFactory("ntlm", ntlm_factory);
74  return registry_factory;
75}
76
77namespace {
78
79bool IsSupportedScheme(const std::vector<std::string>& supported_schemes,
80                       const std::string& scheme) {
81  std::vector<std::string>::const_iterator it = std::find(
82      supported_schemes.begin(), supported_schemes.end(), scheme);
83  return it != supported_schemes.end();
84}
85
86}  // namespace
87
88HttpAuthHandlerRegistryFactory::HttpAuthHandlerRegistryFactory() {
89}
90
91HttpAuthHandlerRegistryFactory::~HttpAuthHandlerRegistryFactory() {
92  STLDeleteContainerPairSecondPointers(factory_map_.begin(),
93                                       factory_map_.end());
94}
95
96void HttpAuthHandlerRegistryFactory::SetURLSecurityManager(
97    const std::string& scheme,
98    URLSecurityManager* security_manager) {
99  HttpAuthHandlerFactory* factory = GetSchemeFactory(scheme);
100  if (factory)
101    factory->set_url_security_manager(security_manager);
102}
103
104void HttpAuthHandlerRegistryFactory::RegisterSchemeFactory(
105    const std::string& scheme,
106    HttpAuthHandlerFactory* factory) {
107  std::string lower_scheme = base::StringToLowerASCII(scheme);
108  FactoryMap::iterator it = factory_map_.find(lower_scheme);
109  if (it != factory_map_.end()) {
110    delete it->second;
111  }
112  if (factory)
113    factory_map_[lower_scheme] = factory;
114  else
115    factory_map_.erase(it);
116}
117
118HttpAuthHandlerFactory* HttpAuthHandlerRegistryFactory::GetSchemeFactory(
119    const std::string& scheme) const {
120  std::string lower_scheme = base::StringToLowerASCII(scheme);
121  FactoryMap::const_iterator it = factory_map_.find(lower_scheme);
122  if (it == factory_map_.end()) {
123    return NULL;                  // |scheme| is not registered.
124  }
125  return it->second;
126}
127
128// static
129HttpAuthHandlerRegistryFactory* HttpAuthHandlerRegistryFactory::Create(
130    const std::vector<std::string>& supported_schemes,
131    URLSecurityManager* security_manager,
132    HostResolver* host_resolver,
133    const std::string& gssapi_library_name,
134    bool negotiate_disable_cname_lookup,
135    bool negotiate_enable_port) {
136  HttpAuthHandlerRegistryFactory* registry_factory =
137      new HttpAuthHandlerRegistryFactory();
138  if (IsSupportedScheme(supported_schemes, "basic"))
139    registry_factory->RegisterSchemeFactory(
140        "basic", new HttpAuthHandlerBasic::Factory());
141  if (IsSupportedScheme(supported_schemes, "digest"))
142    registry_factory->RegisterSchemeFactory(
143        "digest", new HttpAuthHandlerDigest::Factory());
144  if (IsSupportedScheme(supported_schemes, "ntlm")) {
145    HttpAuthHandlerNTLM::Factory* ntlm_factory =
146        new HttpAuthHandlerNTLM::Factory();
147    ntlm_factory->set_url_security_manager(security_manager);
148#if defined(OS_WIN)
149    ntlm_factory->set_sspi_library(new SSPILibraryDefault());
150#endif
151    registry_factory->RegisterSchemeFactory("ntlm", ntlm_factory);
152  }
153#if defined(USE_KERBEROS)
154  if (IsSupportedScheme(supported_schemes, "negotiate")) {
155    HttpAuthHandlerNegotiate::Factory* negotiate_factory =
156        new HttpAuthHandlerNegotiate::Factory();
157#if defined(OS_POSIX)
158    negotiate_factory->set_library(
159        new GSSAPISharedLibrary(gssapi_library_name));
160#elif defined(OS_WIN)
161    negotiate_factory->set_library(new SSPILibraryDefault());
162#endif
163    negotiate_factory->set_url_security_manager(security_manager);
164    DCHECK(host_resolver || negotiate_disable_cname_lookup);
165    negotiate_factory->set_host_resolver(host_resolver);
166    negotiate_factory->set_disable_cname_lookup(negotiate_disable_cname_lookup);
167    negotiate_factory->set_use_port(negotiate_enable_port);
168    registry_factory->RegisterSchemeFactory("negotiate", negotiate_factory);
169  }
170#endif  // defined(USE_KERBEROS)
171
172  return registry_factory;
173}
174
175int HttpAuthHandlerRegistryFactory::CreateAuthHandler(
176    HttpAuthChallengeTokenizer* challenge,
177    HttpAuth::Target target,
178    const GURL& origin,
179    CreateReason reason,
180    int digest_nonce_count,
181    const BoundNetLog& net_log,
182    scoped_ptr<HttpAuthHandler>* handler) {
183  std::string scheme = challenge->scheme();
184  if (scheme.empty()) {
185    handler->reset();
186    return ERR_INVALID_RESPONSE;
187  }
188  std::string lower_scheme = base::StringToLowerASCII(scheme);
189  FactoryMap::iterator it = factory_map_.find(lower_scheme);
190  if (it == factory_map_.end()) {
191    handler->reset();
192    return ERR_UNSUPPORTED_AUTH_SCHEME;
193  }
194  DCHECK(it->second);
195  return it->second->CreateAuthHandler(challenge, target, origin, reason,
196                                       digest_nonce_count, net_log, handler);
197}
198
199}  // namespace net
200