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

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

Issue 193022: Use SSPI for NTLM authentication on Windows. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Upload before checkin Created 11 years, 3 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 | Annotate | Revision Log
« no previous file with comments | « net/http/http_network_transaction.h ('k') | net/http/http_network_transaction_unittest.cc » ('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) 2006-2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2009 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_network_transaction.h" 5 #include "net/http/http_network_transaction.h"
6 6
7 #include "base/scoped_ptr.h" 7 #include "base/scoped_ptr.h"
8 #include "base/compiler_specific.h" 8 #include "base/compiler_specific.h"
9 #include "base/field_trial.h" 9 #include "base/field_trial.h"
10 #include "base/histogram.h" 10 #include "base/histogram.h"
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
137 user_callback_(NULL), 137 user_callback_(NULL),
138 session_(session), 138 session_(session),
139 request_(NULL), 139 request_(NULL),
140 pac_request_(NULL), 140 pac_request_(NULL),
141 socket_factory_(csf), 141 socket_factory_(csf),
142 reused_socket_(false), 142 reused_socket_(false),
143 using_ssl_(false), 143 using_ssl_(false),
144 proxy_mode_(kDirectConnection), 144 proxy_mode_(kDirectConnection),
145 establishing_tunnel_(false), 145 establishing_tunnel_(false),
146 reading_body_from_socket_(false), 146 reading_body_from_socket_(false),
147 embedded_identity_used_(false),
147 request_headers_(new RequestHeaders()), 148 request_headers_(new RequestHeaders()),
148 request_headers_bytes_sent_(0), 149 request_headers_bytes_sent_(0),
149 header_buf_(new ResponseHeaders()), 150 header_buf_(new ResponseHeaders()),
150 header_buf_capacity_(0), 151 header_buf_capacity_(0),
151 header_buf_len_(0), 152 header_buf_len_(0),
152 header_buf_body_offset_(-1), 153 header_buf_body_offset_(-1),
153 header_buf_http_offset_(-1), 154 header_buf_http_offset_(-1),
154 response_body_length_(-1), // -1 means unspecified. 155 response_body_length_(-1), // -1 means unspecified.
155 response_body_read_(0), 156 response_body_read_(0),
156 read_buf_len_(0), 157 read_buf_len_(0),
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP); 247 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP);
247 248
248 // Add the auth entry to the cache before restarting. We don't know whether 249 // Add the auth entry to the cache before restarting. We don't know whether
249 // the identity is valid yet, but if it is valid we want other transactions 250 // the identity is valid yet, but if it is valid we want other transactions
250 // to know about it. If an entry for (origin, handler->realm()) already 251 // to know about it. If an entry for (origin, handler->realm()) already
251 // exists, we update it. 252 // exists, we update it.
252 // 253 //
253 // If auth_identity_[target].source is HttpAuth::IDENT_SRC_NONE, 254 // If auth_identity_[target].source is HttpAuth::IDENT_SRC_NONE,
254 // auth_identity_[target] contains no identity because identity is not 255 // auth_identity_[target] contains no identity because identity is not
255 // required yet. 256 // required yet.
257 //
258 // TODO(wtc): For NTLM_SSPI, we add the same auth entry to the cache in
259 // round 1 and round 2, which is redundant but correct. It would be nice
260 // to add an auth entry to the cache only once, preferrably in round 1.
261 // See http://crbug.com/21015.
256 bool has_auth_identity = 262 bool has_auth_identity =
257 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE; 263 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE;
258 if (has_auth_identity) { 264 if (has_auth_identity) {
259 session_->auth_cache()->Add(AuthOrigin(target), auth_handler_[target], 265 session_->auth_cache()->Add(AuthOrigin(target), auth_handler_[target],
260 auth_identity_[target].username, auth_identity_[target].password, 266 auth_identity_[target].username, auth_identity_[target].password,
261 AuthPath(target)); 267 AuthPath(target));
262 } 268 }
263 269
264 bool keep_alive = false; 270 bool keep_alive = false;
265 if (response_.headers->IsKeepAlive()) { 271 if (response_.headers->IsKeepAlive()) {
266 // If there is a response body of known length, we need to drain it first. 272 // If there is a response body of known length, we need to drain it first.
267 if (response_body_length_ > 0 || chunked_decoder_.get()) { 273 if (response_body_length_ > 0 || chunked_decoder_.get()) {
268 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART; 274 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
269 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket 275 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket
270 read_buf_len_ = kDrainBodyBufferSize; 276 read_buf_len_ = kDrainBodyBufferSize;
271 return; 277 return;
272 } 278 }
273 if (response_body_length_ == 0) // No response body to drain. 279 if (response_body_length_ == 0) // No response body to drain.
274 keep_alive = true; 280 keep_alive = true;
275 // response_body_length_ is -1 and we're not using chunked encoding. We 281 // response_body_length_ is -1 and we're not using chunked encoding. We
276 // don't know the length of the response body, so we can't reuse this 282 // don't know the length of the response body, so we can't reuse this
277 // connection even though the server says it's keep-alive. 283 // connection even though the server says it's keep-alive.
278 } 284 }
279 285
280 // If the auth scheme is connection-based but the proxy/server mistakenly 286 // If the auth scheme is connection-based but the proxy/server mistakenly
281 // marks the connection as non-keep-alive, the auth is going to fail, so log 287 // marks the connection as non-keep-alive, the auth is going to fail, so log
282 // an error message. 288 // an error message.
289 //
290 // TODO(wtc): has_auth_identity is not the right condition. We should
291 // be testing for "not round 1" here. See http://crbug.com/21015.
283 if (!keep_alive && auth_handler_[target]->is_connection_based() && 292 if (!keep_alive && auth_handler_[target]->is_connection_based() &&
284 has_auth_identity) { 293 has_auth_identity) {
285 LOG(ERROR) << "Can't perform " << auth_handler_[target]->scheme() 294 LOG(ERROR) << "Can't perform " << auth_handler_[target]->scheme()
286 << " auth to the " << AuthTargetString(target) << " " 295 << " auth to the " << AuthTargetString(target) << " "
287 << AuthOrigin(target) << " over a non-keep-alive connection"; 296 << AuthOrigin(target) << " over a non-keep-alive connection";
288 297
289 HttpVersion http_version = response_.headers->GetHttpVersion(); 298 HttpVersion http_version = response_.headers->GetHttpVersion();
290 LOG(ERROR) << " HTTP version is " << http_version.major_value() << "." 299 LOG(ERROR) << " HTTP version is " << http_version.major_value() << "."
291 << http_version.minor_value(); 300 << http_version.minor_value();
292 301
(...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after
735 ShouldApplyProxyAuth() && 744 ShouldApplyProxyAuth() &&
736 (HaveAuth(HttpAuth::AUTH_PROXY) || 745 (HaveAuth(HttpAuth::AUTH_PROXY) ||
737 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY)); 746 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY));
738 bool have_server_auth = 747 bool have_server_auth =
739 ShouldApplyServerAuth() && 748 ShouldApplyServerAuth() &&
740 (HaveAuth(HttpAuth::AUTH_SERVER) || 749 (HaveAuth(HttpAuth::AUTH_SERVER) ||
741 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER)); 750 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER));
742 751
743 std::string authorization_headers; 752 std::string authorization_headers;
744 753
754 // TODO(wtc): If BuildAuthorizationHeader fails (returns an authorization
755 // header with no credentials), we should return an error to prevent
756 // entering an infinite auth restart loop. See http://crbug.com/21050.
745 if (have_proxy_auth) 757 if (have_proxy_auth)
746 authorization_headers.append( 758 authorization_headers.append(
747 BuildAuthorizationHeader(HttpAuth::AUTH_PROXY)); 759 BuildAuthorizationHeader(HttpAuth::AUTH_PROXY));
748 if (have_server_auth) 760 if (have_server_auth)
749 authorization_headers.append( 761 authorization_headers.append(
750 BuildAuthorizationHeader(HttpAuth::AUTH_SERVER)); 762 BuildAuthorizationHeader(HttpAuth::AUTH_SERVER));
751 763
752 if (establishing_tunnel_) { 764 if (establishing_tunnel_) {
753 BuildTunnelRequest(request_, authorization_headers, 765 BuildTunnelRequest(request_, authorization_headers,
754 &request_headers_->headers_); 766 &request_headers_->headers_);
(...skipping 1017 matching lines...) Expand 10 before | Expand all | Expand 10 after
1772 } 1784 }
1773 return false; 1785 return false;
1774 } 1786 }
1775 1787
1776 bool HttpNetworkTransaction::SelectNextAuthIdentityToTry( 1788 bool HttpNetworkTransaction::SelectNextAuthIdentityToTry(
1777 HttpAuth::Target target) { 1789 HttpAuth::Target target) {
1778 DCHECK(auth_handler_[target]); 1790 DCHECK(auth_handler_[target]);
1779 DCHECK(auth_identity_[target].invalid); 1791 DCHECK(auth_identity_[target].invalid);
1780 1792
1781 // Try to use the username/password encoded into the URL first. 1793 // Try to use the username/password encoded into the URL first.
1782 // (By checking source == IDENT_SRC_NONE, we make sure that this
1783 // is only done once for the transaction.)
1784 if (target == HttpAuth::AUTH_SERVER && request_->url.has_username() && 1794 if (target == HttpAuth::AUTH_SERVER && request_->url.has_username() &&
1785 auth_identity_[target].source == HttpAuth::IDENT_SRC_NONE) { 1795 !embedded_identity_used_) {
1786 auth_identity_[target].source = HttpAuth::IDENT_SRC_URL; 1796 auth_identity_[target].source = HttpAuth::IDENT_SRC_URL;
1787 auth_identity_[target].invalid = false; 1797 auth_identity_[target].invalid = false;
1788 // Extract the username:password from the URL. 1798 // Extract the username:password from the URL.
1789 GetIdentifyFromUrl(request_->url, 1799 GetIdentifyFromUrl(request_->url,
1790 &auth_identity_[target].username, 1800 &auth_identity_[target].username,
1791 &auth_identity_[target].password); 1801 &auth_identity_[target].password);
1802 embedded_identity_used_ = true;
1792 // TODO(eroman): If the password is blank, should we also try combining 1803 // TODO(eroman): If the password is blank, should we also try combining
1793 // with a password from the cache? 1804 // with a password from the cache?
1794 return true; 1805 return true;
1795 } 1806 }
1796 1807
1797 // Check the auth cache for a realm entry. 1808 // Check the auth cache for a realm entry.
1798 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByRealm( 1809 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByRealm(
1799 AuthOrigin(target), auth_handler_[target]->realm()); 1810 AuthOrigin(target), auth_handler_[target]->realm());
1800 1811
1801 if (entry) { 1812 if (entry) {
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
1874 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER; 1885 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
1875 1886
1876 LOG(INFO) << "The " << AuthTargetString(target) << " " 1887 LOG(INFO) << "The " << AuthTargetString(target) << " "
1877 << AuthOrigin(target) << " requested auth" 1888 << AuthOrigin(target) << " requested auth"
1878 << AuthChallengeLogMessage(); 1889 << AuthChallengeLogMessage();
1879 1890
1880 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct()) 1891 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct())
1881 return ERR_UNEXPECTED_PROXY_AUTH; 1892 return ERR_UNEXPECTED_PROXY_AUTH;
1882 1893
1883 // The auth we tried just failed, hence it can't be valid. Remove it from 1894 // The auth we tried just failed, hence it can't be valid. Remove it from
1884 // the cache so it won't be used again, unless it's a null identity. 1895 // the cache so it won't be used again.
1885 if (HaveAuth(target) && 1896 // TODO(wtc): IsFinalRound is not the right condition. In a multi-round
1886 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE) 1897 // auth sequence, the server may fail the auth in round 1 if our first
1898 // authorization header is broken. We should inspect response_.headers to
1899 // determine if the server already failed the auth or wants us to continue.
1900 // See http://crbug.com/21015.
1901 if (HaveAuth(target) && auth_handler_[target]->IsFinalRound()) {
1887 InvalidateRejectedAuthFromCache(target); 1902 InvalidateRejectedAuthFromCache(target);
1903 auth_handler_[target] = NULL;
1904 auth_identity_[target] = HttpAuth::Identity();
1905 }
1888 1906
1889 auth_identity_[target].invalid = true; 1907 auth_identity_[target].invalid = true;
1890 1908
1891 if (target != HttpAuth::AUTH_SERVER || 1909 if (target != HttpAuth::AUTH_SERVER ||
1892 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA)) { 1910 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA)) {
1893 // Find the best authentication challenge that we support. 1911 // Find the best authentication challenge that we support.
1894 HttpAuth::ChooseBestChallenge(response_.headers.get(), 1912 HttpAuth::ChooseBestChallenge(response_.headers.get(),
1895 target, 1913 target,
1896 &auth_handler_[target]); 1914 &auth_handler_[target]);
1897 } 1915 }
(...skipping 14 matching lines...) Expand all
1912 // We found no supported challenge -- let the transaction continue 1930 // We found no supported challenge -- let the transaction continue
1913 // so we end up displaying the error page. 1931 // so we end up displaying the error page.
1914 return OK; 1932 return OK;
1915 } 1933 }
1916 1934
1917 if (auth_handler_[target]->NeedsIdentity()) { 1935 if (auth_handler_[target]->NeedsIdentity()) {
1918 // Pick a new auth identity to try, by looking to the URL and auth cache. 1936 // Pick a new auth identity to try, by looking to the URL and auth cache.
1919 // If an identity to try is found, it is saved to auth_identity_[target]. 1937 // If an identity to try is found, it is saved to auth_identity_[target].
1920 SelectNextAuthIdentityToTry(target); 1938 SelectNextAuthIdentityToTry(target);
1921 } else { 1939 } else {
1922 // Proceed with a null identity. 1940 // Proceed with the existing identity or a null identity.
1923 // 1941 //
1924 // TODO(wtc): Add a safeguard against infinite transaction restarts, if 1942 // TODO(wtc): Add a safeguard against infinite transaction restarts, if
1925 // the server keeps returning "NTLM". 1943 // the server keeps returning "NTLM".
1926 auth_identity_[target].source = HttpAuth::IDENT_SRC_NONE;
1927 auth_identity_[target].invalid = false; 1944 auth_identity_[target].invalid = false;
1928 auth_identity_[target].username.clear();
1929 auth_identity_[target].password.clear();
1930 } 1945 }
1931 1946
1932 // Make a note that we are waiting for auth. This variable is inspected 1947 // Make a note that we are waiting for auth. This variable is inspected
1933 // when the client calls RestartWithAuth() to pick up where we left off. 1948 // when the client calls RestartWithAuth() to pick up where we left off.
1934 pending_auth_target_ = target; 1949 pending_auth_target_ = target;
1935 1950
1936 if (auth_identity_[target].invalid) { 1951 if (auth_identity_[target].invalid) {
1937 // We have exhausted all identity possibilities, all we can do now is 1952 // We have exhausted all identity possibilities, all we can do now is
1938 // pass the challenge information back to the client. 1953 // pass the challenge information back to the client.
1939 PopulateAuthChallenge(target); 1954 PopulateAuthChallenge(target);
(...skipping 16 matching lines...) Expand all
1956 host_and_port = proxy_info_.proxy_server().host_and_port(); 1971 host_and_port = proxy_info_.proxy_server().host_and_port();
1957 } else { 1972 } else {
1958 DCHECK(target == HttpAuth::AUTH_SERVER); 1973 DCHECK(target == HttpAuth::AUTH_SERVER);
1959 host_and_port = GetHostAndPort(request_->url); 1974 host_and_port = GetHostAndPort(request_->url);
1960 } 1975 }
1961 auth_info->host_and_port = ASCIIToWide(host_and_port); 1976 auth_info->host_and_port = ASCIIToWide(host_and_port);
1962 response_.auth_challenge = auth_info; 1977 response_.auth_challenge = auth_info;
1963 } 1978 }
1964 1979
1965 } // namespace net 1980 } // namespace net
OLDNEW
« no previous file with comments | « net/http/http_network_transaction.h ('k') | net/http/http_network_transaction_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698