1 // Copyright (c) 2009 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_ntlm.h" 6 7 #include "base/base64.h" 8 #include "base/string_util.h" 9 #include "net/base/net_errors.h" 10 11 namespace net { 12 13 std::string HttpAuthHandlerNTLM::GenerateCredentials( 14 const std::wstring& username, 15 const std::wstring& password, 16 const HttpRequestInfo* request, 17 const ProxyInfo* proxy) { 18 #if defined(NTLM_SSPI) 19 std::string auth_credentials; 20 21 int rv = auth_sspi_.GenerateCredentials( 22 username, 23 password, 24 origin_, 25 request, 26 proxy, 27 &auth_credentials); 28 if (rv == OK) 29 return auth_credentials; 30 return std::string(); 31 #else // !defined(NTLM_SSPI) 32 // TODO(wtc): See if we can use char* instead of void* for in_buf and 33 // out_buf. This change will need to propagate to GetNextToken, 34 // GenerateType1Msg, and GenerateType3Msg, and perhaps further. 35 const void* in_buf; 36 void* out_buf; 37 uint32 in_buf_len, out_buf_len; 38 std::string decoded_auth_data; 39 40 // |username| may be in the form "DOMAIN\user". Parse it into the two 41 // components. 42 std::wstring domain; 43 std::wstring user; 44 size_t backslash_idx = username.find(L'\\'); 45 if (backslash_idx == std::wstring::npos) { 46 user = username; 47 } else { 48 domain = username.substr(0, backslash_idx); 49 user = username.substr(backslash_idx + 1); 50 } 51 domain_ = WideToUTF16(domain); 52 username_ = WideToUTF16(user); 53 password_ = WideToUTF16(password); 54 55 // Initial challenge. 56 if (auth_data_.empty()) { 57 in_buf_len = 0; 58 in_buf = NULL; 59 int rv = InitializeBeforeFirstChallenge(); 60 if (rv != OK) 61 return std::string(); 62 } else { 63 // Decode |auth_data_| into the input buffer. 64 int len = auth_data_.length(); 65 66 // Strip off any padding. 67 // (See https://bugzilla.mozilla.org/show_bug.cgi?id=230351.) 68 // 69 // Our base64 decoder requires that the length be a multiple of 4. 70 while (len > 0 && len % 4 != 0 && auth_data_[len - 1] == '=') 71 len--; 72 auth_data_.erase(len); 73 74 if (!base::Base64Decode(auth_data_, &decoded_auth_data)) 75 return std::string(); // Improper base64 encoding 76 in_buf_len = decoded_auth_data.length(); 77 in_buf = decoded_auth_data.data(); 78 } 79 80 int rv = GetNextToken(in_buf, in_buf_len, &out_buf, &out_buf_len); 81 if (rv != OK) 82 return std::string(); 83 84 // Base64 encode data in output buffer and prepend "NTLM ". 85 std::string encode_input(static_cast<char*>(out_buf), out_buf_len); 86 std::string encode_output; 87 bool ok = base::Base64Encode(encode_input, &encode_output); 88 // OK, we are done with |out_buf| 89 free(out_buf); 90 if (!ok) 91 return std::string(); 92 return std::string("NTLM ") + encode_output; 93 #endif 94 } 95 96 // The NTLM challenge header looks like: 97 // WWW-Authenticate: NTLM auth-data 98 bool HttpAuthHandlerNTLM::ParseChallenge( 99 std::string::const_iterator challenge_begin, 100 std::string::const_iterator challenge_end) { 101 scheme_ = "ntlm"; 102 score_ = 3; 103 properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED; 104 105 #if defined(NTLM_SSPI) 106 return auth_sspi_.ParseChallenge(challenge_begin, challenge_end); 107 #else 108 auth_data_.clear(); 109 110 // Verify the challenge's auth-scheme. 111 HttpAuth::ChallengeTokenizer challenge_tok(challenge_begin, challenge_end); 112 if (!challenge_tok.valid() || 113 !LowerCaseEqualsASCII(challenge_tok.scheme(), "ntlm")) 114 return false; 115 116 // Extract the auth-data. We can't use challenge_tok.GetNext() because 117 // auth-data is base64-encoded and may contain '=' padding at the end, 118 // which would be mistaken for a name=value pair. 119 challenge_begin += 4; // Skip over "NTLM". 120 HttpUtil::TrimLWS(&challenge_begin, &challenge_end); 121 122 auth_data_.assign(challenge_begin, challenge_end); 123 124 return true; 125 #endif 126 } 127 128 } // namespace net 129