15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_auth_handler_ntlm.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(NTLM_SSPI) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base64.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_util.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h" 15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/http/http_auth_challenge_tokenizer.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpAuth::AuthorizationResult HttpAuthHandlerNTLM::HandleAnotherChallenge( 20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HttpAuthChallengeTokenizer* challenge) { 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ParseChallenge(challenge, false); 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool HttpAuthHandlerNTLM::Init(HttpAuthChallengeTokenizer* tok) { 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_scheme_ = HttpAuth::AUTH_SCHEME_NTLM; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) score_ = 3; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ParseChallenge(tok, true) == HttpAuth::AUTHORIZATION_RESULT_ACCEPT; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpAuthHandlerNTLM::GenerateAuthTokenImpl( 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AuthCredentials* credentials, const HttpRequestInfo* request, 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CompletionCallback& callback, std::string* auth_token) { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(NTLM_SSPI) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return auth_sspi_.GenerateAuthToken( 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) credentials, 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreateSPN(origin_), 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_token); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else // !defined(NTLM_SSPI) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(cbentzel): Shouldn't be hitting this case. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!credentials) { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Username and password are expected to be non-NULL."; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_MISSING_AUTH_CREDENTIALS; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(wtc): See if we can use char* instead of void* for in_buf and 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // out_buf. This change will need to propagate to GetNextToken, 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GenerateType1Msg, and GenerateType3Msg, and perhaps further. 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* in_buf; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* out_buf; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 in_buf_len, out_buf_len; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string decoded_auth_data; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The username may be in the form "DOMAIN\user". Parse it into the two 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // components. 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::string16 domain; 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::string16 user; 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::string16& username = credentials->username(); 597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const base::char16 backslash_character = '\\'; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t backslash_idx = username.find(backslash_character); 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (backslash_idx == base::string16::npos) { 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user = username; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) domain = username.substr(0, backslash_idx); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user = username.substr(backslash_idx + 1); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) domain_ = domain; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) credentials_.Set(user, credentials->password()); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initial challenge. 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (auth_data_.empty()) { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_buf_len = 0; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_buf = NULL; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = InitializeBeforeFirstChallenge(); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv != OK) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::Base64Decode(auth_data_, &decoded_auth_data)) { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Unexpected problem Base64 decoding."; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_UNEXPECTED; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_buf_len = decoded_auth_data.length(); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_buf = decoded_auth_data.data(); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = GetNextToken(in_buf, in_buf_len, &out_buf, &out_buf_len); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv != OK) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Base64 encode data in output buffer and prepend "NTLM ". 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string encode_input(static_cast<char*>(out_buf), out_buf_len); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string encode_output; 93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::Base64Encode(encode_input, &encode_output); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // OK, we are done with |out_buf| 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(out_buf); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *auth_token = std::string("NTLM ") + encode_output; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The NTLM challenge header looks like: 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WWW-Authenticate: NTLM auth-data 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpAuth::AuthorizationResult HttpAuthHandlerNTLM::ParseChallenge( 104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HttpAuthChallengeTokenizer* tok, bool initial_challenge) { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(NTLM_SSPI) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // auth_sspi_ contains state for whether or not this is the initial challenge. 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return auth_sspi_.ParseChallenge(tok); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(cbentzel): Most of the logic between SSPI, GSSAPI, and portable NTLM 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // authentication parsing could probably be shared - just need to know if 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // there was previously a challenge round. 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(cbentzel): Write a test case to validate that auth_data_ is left empty 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in all failure conditions. 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_data_.clear(); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Verify the challenge's auth-scheme. 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!LowerCaseEqualsASCII(tok->scheme(), "ntlm")) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return HttpAuth::AUTHORIZATION_RESULT_INVALID; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string base64_param = tok->base64_param(); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base64_param.empty()) { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!initial_challenge) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return HttpAuth::AUTHORIZATION_RESULT_REJECT; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return HttpAuth::AUTHORIZATION_RESULT_ACCEPT; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (initial_challenge) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return HttpAuth::AUTHORIZATION_RESULT_INVALID; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_data_ = base64_param; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return HttpAuth::AUTHORIZATION_RESULT_ACCEPT; 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(NTLM_SSPI) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)std::string HttpAuthHandlerNTLM::CreateSPN(const GURL& origin) { 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The service principal name of the destination server. See 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // http://msdn.microsoft.com/en-us/library/ms677949%28VS.85%29.aspx 139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::string target("HTTP/"); 140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) target.append(GetHostAndPort(origin)); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return target; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 145