Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(377)

Side by Side Diff: net/http/http_auth_handler_negotiate_win.cc

Issue 1535019: Kerberos SPN generation for Negotiate challenges (Closed)
Patch Set: Fix to GetCanonicalName that is another CL. Created 10 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/http/http_auth_handler_negotiate_posix.cc ('k') | net/http/http_auth_handler_ntlm.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/http/http_auth_handler_negotiate.h" 5 #include "net/http/http_auth_handler_negotiate.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "net/base/address_family.h"
9 #include "net/base/host_resolver.h"
8 #include "net/base/net_errors.h" 10 #include "net/base/net_errors.h"
9 #include "net/http/http_auth_filter.h" 11 #include "net/http/http_auth_filter.h"
10 12
11 namespace net { 13 namespace net {
12 14
13 HttpAuthHandlerNegotiate::HttpAuthHandlerNegotiate(SSPILibrary* library, 15 HttpAuthHandlerNegotiate::HttpAuthHandlerNegotiate(SSPILibrary* library,
14 ULONG max_token_length) 16 ULONG max_token_length,
15 : auth_sspi_(library, "Negotiate", NEGOSSP_NAME, max_token_length) { 17 bool disable_cname_lookup,
18 bool use_port)
19 : auth_sspi_(library, "Negotiate", NEGOSSP_NAME, max_token_length),
20 user_callback_(NULL),
21 ALLOW_THIS_IN_INITIALIZER_LIST(resolve_cname_callback_(
22 this, &HttpAuthHandlerNegotiate::OnResolveCanonicalName)),
23 disable_cname_lookup_(disable_cname_lookup),
24 use_port_(use_port) {
16 } 25 }
17 26
18 HttpAuthHandlerNegotiate::~HttpAuthHandlerNegotiate() { 27 HttpAuthHandlerNegotiate::~HttpAuthHandlerNegotiate() {
19 } 28 }
20 29
21 int HttpAuthHandlerNegotiate::GenerateAuthToken( 30 int HttpAuthHandlerNegotiate::GenerateAuthToken(
22 const std::wstring& username, 31 const std::wstring& username,
23 const std::wstring& password, 32 const std::wstring& password,
24 const HttpRequestInfo* request, 33 const HttpRequestInfo* request,
25 const ProxyInfo* proxy, 34 const ProxyInfo* proxy,
26 std::string* auth_token) { 35 std::string* auth_token) {
27 return auth_sspi_.GenerateAuthToken( 36 return auth_sspi_.GenerateAuthToken(
28 &username, 37 &username,
29 &password, 38 &password,
30 origin_, 39 spn_,
31 request, 40 request,
32 proxy, 41 proxy,
33 auth_token); 42 auth_token);
34 } 43 }
35 44
36 // The Negotiate challenge header looks like: 45 // The Negotiate challenge header looks like:
37 // WWW-Authenticate: NEGOTIATE auth-data 46 // WWW-Authenticate: NEGOTIATE auth-data
38 bool HttpAuthHandlerNegotiate::Init(HttpAuth::ChallengeTokenizer* challenge) { 47 bool HttpAuthHandlerNegotiate::Init(HttpAuth::ChallengeTokenizer* challenge) {
39 scheme_ = "negotiate"; 48 scheme_ = "negotiate";
40 score_ = 4; 49 score_ = 4;
41 properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED; 50 properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED;
42 return auth_sspi_.ParseChallenge(challenge); 51 return auth_sspi_.ParseChallenge(challenge);
43 } 52 }
44 53
45 // Require identity on first pass instead of second. 54 // Require identity on first pass instead of second.
46 bool HttpAuthHandlerNegotiate::NeedsIdentity() { 55 bool HttpAuthHandlerNegotiate::NeedsIdentity() {
47 return auth_sspi_.NeedsIdentity(); 56 return auth_sspi_.NeedsIdentity();
48 } 57 }
49 58
50 bool HttpAuthHandlerNegotiate::IsFinalRound() { 59 bool HttpAuthHandlerNegotiate::IsFinalRound() {
51 return auth_sspi_.IsFinalRound(); 60 return auth_sspi_.IsFinalRound();
52 } 61 }
53 62
54 bool HttpAuthHandlerNegotiate::SupportsDefaultCredentials() { 63 bool HttpAuthHandlerNegotiate::SupportsDefaultCredentials() {
55 return true; 64 return true;
56 } 65 }
57 66
67 bool HttpAuthHandlerNegotiate::NeedsCanonicalName() {
68 if (!spn_.empty())
69 return false;
70 if (disable_cname_lookup_) {
71 spn_ = CreateSPN(address_list_, origin_);
72 address_list_.Reset();
73 return false;
74 }
75 return true;
76 }
77
78 int HttpAuthHandlerNegotiate::ResolveCanonicalName(HostResolver* resolver,
79 CompletionCallback* callback,
80 const BoundNetLog& net_log) {
81 // TODO(cbentzel): Add reverse DNS lookup for numeric addresses.
82 DCHECK(!single_resolve_.get());
83 DCHECK(!disable_cname_lookup_);
84 DCHECK(callback);
85
86 HostResolver::RequestInfo info(origin_.host(), 0);
87 info.set_host_resolver_flags(HOST_RESOLVER_CANONNAME);
88 single_resolve_.reset(new SingleRequestHostResolver(resolver));
89 int rv = single_resolve_->Resolve(info, &address_list_,
90 &resolve_cname_callback_,
91 net_log);
92 if (rv == ERR_IO_PENDING) {
93 user_callback_ = callback;
94 return rv;
95 }
96 OnResolveCanonicalName(rv);
97 // Always return OK. OnResolveCanonicalName logs the error code if not
98 // OK and attempts to use the original origin_ hostname rather than failing
99 // the auth attempt completely.
100 return OK;
101 }
102
103 void HttpAuthHandlerNegotiate::OnResolveCanonicalName(int result) {
104 if (result != OK) {
105 // Even in the error case, try to use origin_.host instead of
106 // passing the failure on to the caller.
107 LOG(INFO) << "Problem finding canonical name for SPN for host "
108 << origin_.host() << ": " << ErrorToString(result);
109 result = OK;
110 }
111 spn_ = CreateSPN(address_list_, origin_);
112 address_list_.Reset();
113 if (user_callback_) {
114 CompletionCallback* callback = user_callback_;
115 user_callback_ = NULL;
116 callback->Run(result);
117 }
118 }
119
120 std::wstring HttpAuthHandlerNegotiate::CreateSPN(
121 const AddressList& address_list, const GURL& origin) {
122 // Kerberos SPNs are in the form HTTP/<host>:<port>
123 // http://msdn.microsoft.com/en-us/library/ms677601%28VS.85%29.aspx
124 //
125 // However, reality differs from the specification. A good description of
126 // the problems can be found here:
127 // http://blog.michelbarneveld.nl/michel/archive/2009/11/14/the-reason-why-k b911149-and-kb908209-are-not-the-soluton.aspx
128 //
129 // Typically the <host> portion should be the canonical FQDN for the service.
130 // If this could not be resolved, the original hostname in the URL will be
131 // attempted instead. However, some intranets register SPNs using aliases
132 // for the same canonical DNS name to allow multiple web services to reside
133 // on the same host machine without requiring different ports. IE6 and IE7
134 // have hotpatches that allow the default behavior to be overridden.
135 // http://support.microsoft.com/kb/911149
136 // http://support.microsoft.com/kb/938305
137 //
138 // According to the spec, the <port> option should be included if it is a
139 // non-standard port (i.e. not 80 or 443 in the HTTP case). However,
140 // historically browsers have not included the port, even on non-standard
141 // ports. IE6 required a hotpatch and a registry setting to enable
142 // including non-standard ports, and IE7 and IE8 also require the same
143 // registry setting, but no hotpatch. Firefox does not appear to have an
144 // option to include non-standard ports as of 3.6.
145 // http://support.microsoft.com/kb/908209
146 //
147 // Without any command-line flags, Chrome matches the behavior of Firefox
148 // and IE. Users can override the behavior so aliases are allowed and
149 // non-standard ports are included.
150 int port = origin.EffectiveIntPort();
151 std::string server;
152 if (!address_list.GetCanonicalName(&server))
153 server = origin.host();
154 if (port != 80 && port != 443 && use_port_) {
155 return ASCIIToWide(StringPrintf("HTTP/%s:%d", server.c_str(), port));
156 } else {
157 return ASCIIToWide(StringPrintf("HTTP/%s", server.c_str()));
158 }
159 }
160
58 int HttpAuthHandlerNegotiate::GenerateDefaultAuthToken( 161 int HttpAuthHandlerNegotiate::GenerateDefaultAuthToken(
59 const HttpRequestInfo* request, 162 const HttpRequestInfo* request,
60 const ProxyInfo* proxy, 163 const ProxyInfo* proxy,
61 std::string* auth_token) { 164 std::string* auth_token) {
62 return auth_sspi_.GenerateAuthToken( 165 return auth_sspi_.GenerateAuthToken(
63 NULL, // username 166 NULL, // username
64 NULL, // password 167 NULL, // password
65 origin_, 168 spn_,
66 request, 169 request,
67 proxy, 170 proxy,
68 auth_token); 171 auth_token);
69 } 172 }
70 173
71 HttpAuthHandlerNegotiate::Factory::Factory() 174 HttpAuthHandlerNegotiate::Factory::Factory()
72 : max_token_length_(0), 175 : disable_cname_lookup_(false),
176 use_port_(false),
177 max_token_length_(0),
73 first_creation_(true), 178 first_creation_(true),
74 is_unsupported_(false), 179 is_unsupported_(false),
75 sspi_library_(SSPILibrary::GetDefault()) { 180 sspi_library_(SSPILibrary::GetDefault()) {
76 } 181 }
77 182
78 HttpAuthHandlerNegotiate::Factory::~Factory() { 183 HttpAuthHandlerNegotiate::Factory::~Factory() {
79 } 184 }
80 185
81 int HttpAuthHandlerNegotiate::Factory::CreateAuthHandler( 186 int HttpAuthHandlerNegotiate::Factory::CreateAuthHandler(
82 HttpAuth::ChallengeTokenizer* challenge, 187 HttpAuth::ChallengeTokenizer* challenge,
83 HttpAuth::Target target, 188 HttpAuth::Target target,
84 const GURL& origin, 189 const GURL& origin,
85 scoped_refptr<HttpAuthHandler>* handler) { 190 scoped_refptr<HttpAuthHandler>* handler) {
86 if (is_unsupported_) 191 if (is_unsupported_)
87 return ERR_UNSUPPORTED_AUTH_SCHEME; 192 return ERR_UNSUPPORTED_AUTH_SCHEME;
88 if (max_token_length_ == 0) { 193 if (max_token_length_ == 0) {
89 int rv = DetermineMaxTokenLength(sspi_library_, NEGOSSP_NAME, 194 int rv = DetermineMaxTokenLength(sspi_library_, NEGOSSP_NAME,
90 &max_token_length_); 195 &max_token_length_);
91 if (rv == ERR_UNSUPPORTED_AUTH_SCHEME) 196 if (rv == ERR_UNSUPPORTED_AUTH_SCHEME)
92 is_unsupported_ = true; 197 is_unsupported_ = true;
93 if (rv != OK) 198 if (rv != OK)
94 return rv; 199 return rv;
95 } 200 }
96 // TODO(cbentzel): Move towards model of parsing in the factory 201 // TODO(cbentzel): Move towards model of parsing in the factory
97 // method and only constructing when valid. 202 // method and only constructing when valid.
98 scoped_refptr<HttpAuthHandler> tmp_handler( 203 scoped_refptr<HttpAuthHandler> tmp_handler(
99 new HttpAuthHandlerNegotiate(sspi_library_, max_token_length_)); 204 new HttpAuthHandlerNegotiate(sspi_library_, max_token_length_,
205 disable_cname_lookup_, use_port_));
100 if (!tmp_handler->InitFromChallenge(challenge, target, origin)) 206 if (!tmp_handler->InitFromChallenge(challenge, target, origin))
101 return ERR_INVALID_RESPONSE; 207 return ERR_INVALID_RESPONSE;
102 handler->swap(tmp_handler); 208 handler->swap(tmp_handler);
103 return OK; 209 return OK;
104 } 210 }
105 211
106 } // namespace net 212 } // namespace net
OLDNEW
« no previous file with comments | « net/http/http_auth_handler_negotiate_posix.cc ('k') | net/http/http_auth_handler_ntlm.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698