Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. | |
|
asanka
2017/06/23 21:29:10
No "(c)"
zentaro
2017/07/05 17:57:42
Done.
| |
| 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" | |
|
asanka
2017/06/23 21:29:10
The primary include file should http_auth_handler_
zentaro
2017/07/05 17:57:41
There is no http_auth_handler_ntlm_portable.h so I
| |
| 6 | |
| 7 #include <string> | |
| 8 | |
| 9 #include "base/base64.h" | |
| 10 #include "base/memory/ptr_util.h" | |
| 11 #include "base/strings/string_util.h" | |
| 12 #include "base/strings/utf_string_conversions.h" | |
| 13 #include "net/base/test_completion_callback.h" | |
| 14 #include "net/dns/mock_host_resolver.h" | |
| 15 #include "net/http/http_auth_challenge_tokenizer.h" | |
| 16 #include "net/http/http_request_info.h" | |
| 17 #include "net/http/mock_allow_http_auth_preferences.h" | |
| 18 #include "net/http/ntlm.h" | |
| 19 #include "net/http/ntlm_buffer_reader.h" | |
| 20 #include "net/http/ntlm_buffer_writer.h" | |
| 21 #include "net/http/ntlm_client.h" | |
| 22 #include "net/log/net_log_with_source.h" | |
| 23 #include "net/ssl/ssl_info.h" | |
| 24 #include "net/test/gtest_util.h" | |
| 25 #include "testing/gmock/include/gmock/gmock.h" | |
| 26 #include "testing/gtest/include/gtest/gtest.h" | |
| 27 #include "testing/platform_test.h" | |
| 28 | |
| 29 namespace net { | |
| 30 | |
| 31 #if defined(NTLM_PORTABLE) | |
|
asanka
2017/06/23 21:29:10
This condition is not necessary and not correct.
zentaro
2017/07/05 17:57:42
Done.
| |
| 32 | |
| 33 class HttpAuthHandlerNtlmPortableTest : public PlatformTest { | |
| 34 public: | |
| 35 HttpAuthHandlerNtlmPortableTest() | |
| 36 : domain_ascii_("THEDOMAIN"), | |
| 37 user_ascii_("someuser"), | |
| 38 password_ascii_("password") { | |
| 39 http_auth_preferences_.reset(new MockAllowHttpAuthPreferences()); | |
| 40 factory_.reset(new HttpAuthHandlerNTLM::Factory()); | |
| 41 factory_->set_http_auth_preferences(http_auth_preferences_.get()); | |
| 42 creds_ = | |
| 43 AuthCredentials(base::ASCIIToUTF16(domain_ascii_ + "\\" + user_ascii_), | |
| 44 base::ASCIIToUTF16(password_ascii_)); | |
| 45 } | |
| 46 | |
| 47 int CreateHandler() { | |
| 48 GURL gurl("https://foo.com"); | |
| 49 SSLInfo null_ssl_info; | |
| 50 | |
| 51 return factory_->CreateAuthHandlerFromString( | |
| 52 "NTLM", HttpAuth::AUTH_SERVER, null_ssl_info, gurl, NetLogWithSource(), | |
| 53 &auth_handler_); | |
| 54 } | |
| 55 | |
| 56 std::string CreateType2Token(base::StringPiece message) { | |
|
asanka
2017/06/23 21:29:10
Nit: doesn't really create a type2 token. Probably
zentaro
2017/07/05 17:57:41
Done.
| |
| 57 std::string output; | |
| 58 base::Base64Encode(message, &output); | |
| 59 | |
| 60 return "NTLM " + output; | |
| 61 } | |
| 62 | |
| 63 void HandleAnotherChallenge(const std::string& challenge, | |
|
asanka
2017/06/23 21:29:10
It's easier to read, even though a bit verbose, if
zentaro
2017/07/05 17:57:42
Done.
| |
| 64 HttpAuth::AuthorizationResult expected_result) { | |
| 65 HttpAuthChallengeTokenizer tokenizer(challenge.begin(), challenge.end()); | |
| 66 EXPECT_EQ(expected_result, | |
| 67 GetAuthHandler()->HandleAnotherChallenge(&tokenizer)); | |
| 68 } | |
| 69 | |
| 70 void HandleAnotherChallenge(const std::string& challenge) { | |
| 71 HandleAnotherChallenge(challenge, HttpAuth::AUTHORIZATION_RESULT_ACCEPT); | |
| 72 } | |
| 73 | |
| 74 bool DecodeChallenge(const std::string& challenge, std::string* decoded) { | |
| 75 HttpAuthChallengeTokenizer tokenizer(challenge.begin(), challenge.end()); | |
| 76 return base::Base64Decode(tokenizer.base64_param(), decoded); | |
| 77 } | |
| 78 | |
| 79 int GenerateAuthToken(std::string* token) { | |
| 80 TestCompletionCallback callback; | |
| 81 HttpRequestInfo request_info; | |
| 82 return callback.GetResult(GetAuthHandler()->GenerateAuthToken( | |
| 83 GetCreds(), &request_info, callback.callback(), token)); | |
| 84 } | |
| 85 | |
| 86 void ReadBytesPayload(ntlm::NtlmBufferReader* reader, | |
| 87 uint8_t* buffer, | |
| 88 size_t len) { | |
| 89 // First read the security buffer. | |
| 90 ntlm::SecurityBuffer sec_buf; | |
| 91 EXPECT_TRUE(reader->ReadSecurityBuffer(&sec_buf)); | |
| 92 EXPECT_EQ(sec_buf.length, len); | |
|
asanka
2017/06/23 21:29:10
Should return early if this winds up not being the
zentaro
2017/07/05 17:57:41
When I wrote most of the tests I didn't realize th
| |
| 93 EXPECT_TRUE(reader->ReadBytesFrom(sec_buf, buffer)); | |
| 94 } | |
| 95 | |
| 96 // Reads bytes from a payload and assigns them to a string. This makes | |
| 97 // no assumptions about the underlying encoding. | |
| 98 void ReadStringPayload(ntlm::NtlmBufferReader* reader, std::string* str) { | |
| 99 ntlm::SecurityBuffer sec_buf; | |
| 100 EXPECT_TRUE(reader->ReadSecurityBuffer(&sec_buf)); | |
| 101 | |
| 102 uint8_t raw[sec_buf.length]; | |
| 103 EXPECT_TRUE(reader->ReadBytesFrom(sec_buf, raw)); | |
| 104 | |
| 105 str->assign(reinterpret_cast<const char*>(raw), sec_buf.length); | |
| 106 } | |
| 107 | |
| 108 // Reads bytes from a payload and assigns them to a string16. This makes | |
| 109 // no assumptions about the underlying encoding. This will fail if there | |
| 110 // are an odd number of bytes in the payload. | |
| 111 void ReadString16Payload(ntlm::NtlmBufferReader* reader, | |
| 112 base::string16* str) { | |
| 113 ntlm::SecurityBuffer sec_buf; | |
| 114 EXPECT_TRUE(reader->ReadSecurityBuffer(&sec_buf)); | |
| 115 EXPECT_EQ(0, sec_buf.length % 2); | |
| 116 | |
| 117 uint8_t raw[sec_buf.length]; | |
| 118 EXPECT_TRUE(reader->ReadBytesFrom(sec_buf, raw)); | |
| 119 | |
| 120 #if IS_BIG_ENDIAN | |
| 121 for (size_t i = 0; i < sec_buf.length; i += 2) { | |
| 122 std::swap(raw[i], raw[i + 1]); | |
| 123 } | |
| 124 #endif | |
| 125 | |
| 126 str->assign(reinterpret_cast<const base::char16*>(raw), sec_buf.length / 2); | |
| 127 } | |
| 128 | |
| 129 int GetGenerateAuthTokenResult() { | |
| 130 std::string token; | |
| 131 return GenerateAuthToken(&token); | |
| 132 } | |
| 133 | |
| 134 AuthCredentials* GetCreds() { return &creds_; } | |
| 135 | |
| 136 HttpAuthHandlerNTLM* GetAuthHandler() { | |
| 137 return static_cast<HttpAuthHandlerNTLM*>(auth_handler_.get()); | |
| 138 } | |
| 139 | |
| 140 static void MockRandom(uint8_t* output, size_t n) { | |
|
asanka
2017/06/23 21:29:10
Why not memset(output, 4, n) ? https://xkcd.com/22
zentaro
2017/07/05 17:57:41
Works for me. I copy/pasted it from net/http/http_
| |
| 141 static const uint8_t bytes[] = {0x55, 0x29, 0x66, 0x26, | |
| 142 0x6b, 0x9c, 0x73, 0x54}; | |
| 143 static size_t current_byte = 0; | |
| 144 for (size_t i = 0; i < n; ++i) { | |
| 145 output[i] = bytes[current_byte++]; | |
| 146 current_byte %= arraysize(bytes); | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 static std::string MockGetHostName() { return "MYHOSTNAME"; } | |
| 151 | |
| 152 protected: | |
| 153 const std::string domain_ascii_; | |
| 154 const std::string user_ascii_; | |
| 155 const std::string password_ascii_; | |
| 156 | |
| 157 private: | |
| 158 AuthCredentials creds_; | |
| 159 std::unique_ptr<HttpAuthHandler> auth_handler_; | |
| 160 std::unique_ptr<MockAllowHttpAuthPreferences> http_auth_preferences_; | |
| 161 std::unique_ptr<HttpAuthHandlerNTLM::Factory> factory_; | |
| 162 }; | |
| 163 | |
| 164 TEST_F(HttpAuthHandlerNtlmPortableTest, SimpleConstruction) { | |
| 165 EXPECT_EQ(OK, CreateHandler()); | |
| 166 ASSERT_TRUE(GetAuthHandler() != nullptr); | |
| 167 } | |
| 168 | |
| 169 TEST_F(HttpAuthHandlerNtlmPortableTest, DoNotAllowDefaultCreds) { | |
| 170 EXPECT_EQ(OK, CreateHandler()); | |
| 171 EXPECT_FALSE(GetAuthHandler()->AllowsDefaultCredentials()); | |
| 172 } | |
| 173 | |
| 174 TEST_F(HttpAuthHandlerNtlmPortableTest, AllowsExplicitCredentials) { | |
| 175 EXPECT_EQ(OK, CreateHandler()); | |
| 176 EXPECT_TRUE(GetAuthHandler()->AllowsExplicitCredentials()); | |
| 177 } | |
| 178 | |
| 179 TEST_F(HttpAuthHandlerNtlmPortableTest, VerifyType1Message) { | |
| 180 EXPECT_EQ(OK, CreateHandler()); | |
| 181 | |
| 182 std::string token; | |
| 183 EXPECT_EQ(OK, GenerateAuthToken(&token)); | |
| 184 // The type 1 message generated is always the same. The only variable | |
| 185 // part of the message is the flags and Chrome always offers the same | |
| 186 // set of flags. | |
| 187 EXPECT_EQ("NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=", token); | |
| 188 | |
|
asanka
2017/06/23 21:29:10
The remainder of the test is basically testing the
zentaro
2017/07/05 17:57:41
Done.
| |
| 189 // Poke into the message to verify the fields inside are expected. | |
| 190 std::string decoded; | |
| 191 EXPECT_TRUE(DecodeChallenge(token, &decoded)); | |
| 192 | |
| 193 ntlm::NtlmBufferReader reader(decoded); | |
| 194 EXPECT_TRUE(reader.MatchMessageHeader(ntlm::MessageType::NEGOTIATE)); | |
| 195 ntlm::NegotiateFlags flags; | |
| 196 EXPECT_TRUE(reader.ReadFlags(&flags)); | |
| 197 EXPECT_EQ(ntlm::NEGOTIATE_MESSAGE_FLAGS, flags); | |
| 198 EXPECT_TRUE(reader.MatchEmptySecurityBuffer()); | |
| 199 EXPECT_TRUE(reader.MatchEmptySecurityBuffer()); | |
| 200 EXPECT_TRUE(reader.IsEndOfBuffer()); | |
| 201 } | |
| 202 | |
| 203 TEST_F(HttpAuthHandlerNtlmPortableTest, EmptyTokenFails) { | |
| 204 EXPECT_EQ(OK, CreateHandler()); | |
| 205 | |
| 206 // The encoded token for a type 2 message can't be empty. | |
| 207 HandleAnotherChallenge("NTLM", HttpAuth::AUTHORIZATION_RESULT_REJECT); | |
| 208 } | |
| 209 | |
| 210 TEST_F(HttpAuthHandlerNtlmPortableTest, InvalidBase64Encoding) { | |
| 211 EXPECT_EQ(OK, CreateHandler()); | |
| 212 | |
| 213 // Token isn't valid base64. | |
| 214 HandleAnotherChallenge("NTLM !!!!!!!!!!!!!"); | |
| 215 EXPECT_EQ(ERR_UNEXPECTED, GetGenerateAuthTokenResult()); | |
| 216 } | |
| 217 | |
| 218 TEST_F(HttpAuthHandlerNtlmPortableTest, CantChangeSchemeMidway) { | |
| 219 EXPECT_EQ(OK, CreateHandler()); | |
| 220 | |
| 221 // Can't switch to a different auth scheme in the middle of the process. | |
| 222 HandleAnotherChallenge( | |
| 223 "Negotiate " | |
| 224 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCXziKeNIPIDYAAAAAAAAAAIYAhgBEAAAABgOAJQAA" | |
|
asanka
2017/06/23 21:29:10
The token is irrelevant. Let's go with something s
zentaro
2017/07/05 17:57:41
Done.
| |
| 225 "AA9aAEUATgBEAE8ATQACAAwAWgBFAE4ARABPAE0AAQAMAFoARQBOAEQAQwAxAAQAFAB6AGUA" | |
| 226 "bgBkAG8AbQAuAGwAbwBjAAMAIgBaAGUAbgBEAEMAMQAuAHoAZQBuAGQAbwBtAC4AbABvAGMA" | |
| 227 "BQAUAHoAZQBuAGQAbwBtAC4AbABvAGMABwAIAN6N+IxGwNIBAAAAAA==", | |
| 228 HttpAuth::AUTHORIZATION_RESULT_INVALID); | |
| 229 } | |
| 230 | |
| 231 TEST_F(HttpAuthHandlerNtlmPortableTest, Type2MessageTooShort) { | |
| 232 EXPECT_EQ(OK, CreateHandler()); | |
| 233 | |
| 234 // Fail because the minimum size valid message is 32 bytes. | |
| 235 char raw[31]; | |
| 236 HandleAnotherChallenge(CreateType2Token(base::StringPiece(raw, sizeof(raw)))); | |
|
asanka
2017/06/23 21:29:10
The memory bots may complain about this because th
zentaro
2017/07/05 17:57:41
Done.
| |
| 237 EXPECT_EQ(ERR_UNEXPECTED, GetGenerateAuthTokenResult()); | |
| 238 } | |
| 239 | |
| 240 TEST_F(HttpAuthHandlerNtlmPortableTest, Type2MessageNoSig) { | |
| 241 EXPECT_EQ(OK, CreateHandler()); | |
| 242 | |
| 243 // Fail because the first bytes don't match "NTLMSSP\0" | |
| 244 char raw[32]; | |
|
asanka
2017/06/23 21:29:11
Same as before. Use a known initialized buffer for
zentaro
2017/07/05 17:57:41
Done.
| |
| 245 memset(raw, 0, ntlm::SIGNATURE_LEN); | |
| 246 HandleAnotherChallenge(CreateType2Token(base::StringPiece(raw, sizeof(raw)))); | |
| 247 EXPECT_EQ(ERR_UNEXPECTED, GetGenerateAuthTokenResult()); | |
| 248 } | |
| 249 | |
| 250 TEST_F(HttpAuthHandlerNtlmPortableTest, Type2WrongMessageType) { | |
| 251 EXPECT_EQ(OK, CreateHandler()); | |
| 252 | |
| 253 // Fail because the message type should be MessageType::CHALLENGE (0x00000002) | |
| 254 ntlm::NtlmBufferWriter writer(32); | |
| 255 EXPECT_TRUE(writer.WriteMessageHeader(ntlm::MessageType::NEGOTIATE)); | |
| 256 | |
| 257 HandleAnotherChallenge(CreateType2Token(writer.GetBuffer())); | |
| 258 EXPECT_EQ(ERR_UNEXPECTED, GetGenerateAuthTokenResult()); | |
| 259 } | |
| 260 | |
| 261 TEST_F(HttpAuthHandlerNtlmPortableTest, MinimalStructurallyValidType2) { | |
| 262 EXPECT_EQ(OK, CreateHandler()); | |
| 263 | |
| 264 ntlm::NtlmBufferWriter writer(ntlm::CHALLENGE_HEADER_LEN); | |
| 265 EXPECT_TRUE(writer.WriteMessageHeader(ntlm::MessageType::CHALLENGE)); | |
| 266 | |
| 267 // A message with both length and offset equal zero is not forbidden | |
| 268 // by the spec (2.2.1.2) however it is not what is recommended. | |
| 269 // But test it anyway. | |
| 270 EXPECT_TRUE(writer.WriteSecurityBuffer(ntlm::SecurityBuffer())); | |
| 271 | |
| 272 HandleAnotherChallenge(CreateType2Token(writer.GetBuffer())); | |
| 273 EXPECT_EQ(OK, GetGenerateAuthTokenResult()); | |
| 274 } | |
| 275 | |
| 276 TEST_F(HttpAuthHandlerNtlmPortableTest, Type2MessageWithNoTargetName) { | |
| 277 EXPECT_EQ(OK, CreateHandler()); | |
| 278 | |
| 279 ntlm::NtlmBufferWriter writer(ntlm::CHALLENGE_HEADER_LEN); | |
| 280 EXPECT_TRUE(writer.WriteMessageHeader(ntlm::MessageType::CHALLENGE)); | |
| 281 | |
| 282 // The spec (2.2.1.2) states that the length SHOULD be 0 and the | |
| 283 // offset SHOULD be where the payload would be if it was present. | |
| 284 // This is the expected response from a compliant server when | |
| 285 // no target name is sent. In reality the offset should always | |
| 286 // be ignored if the length is zero. Also implementations often | |
| 287 // just write zeros. | |
| 288 EXPECT_TRUE(writer.WriteSecurityBuffer( | |
| 289 ntlm::SecurityBuffer(ntlm::CHALLENGE_HEADER_LEN, 0))); | |
| 290 | |
| 291 HandleAnotherChallenge(CreateType2Token(writer.GetBuffer())); | |
| 292 EXPECT_EQ(OK, GetGenerateAuthTokenResult()); | |
| 293 } | |
| 294 | |
| 295 TEST_F(HttpAuthHandlerNtlmPortableTest, Type2MessageWithTargetName) { | |
| 296 EXPECT_EQ(OK, CreateHandler()); | |
| 297 | |
| 298 // One extra byte is provided for target name. | |
| 299 ntlm::NtlmBufferWriter writer(ntlm::CHALLENGE_HEADER_LEN + 1); | |
| 300 EXPECT_TRUE(writer.WriteMessageHeader(ntlm::MessageType::CHALLENGE)); | |
| 301 | |
| 302 // The target name field is 1 byte long. | |
| 303 EXPECT_TRUE(writer.WriteSecurityBuffer( | |
| 304 ntlm::SecurityBuffer(ntlm::CHALLENGE_HEADER_LEN, 1))); | |
|
asanka
2017/06/23 21:29:11
Note that you are relying on NtlmBufferWriter init
zentaro
2017/07/05 17:57:41
N/A now.
| |
| 305 | |
| 306 HandleAnotherChallenge(CreateType2Token(writer.GetBuffer())); | |
| 307 EXPECT_EQ(OK, GetGenerateAuthTokenResult()); | |
| 308 } | |
| 309 | |
| 310 TEST_F(HttpAuthHandlerNtlmPortableTest, NoTargetNameOverflowFromOffset) { | |
| 311 EXPECT_EQ(OK, CreateHandler()); | |
| 312 | |
| 313 ntlm::NtlmBufferWriter writer(ntlm::CHALLENGE_HEADER_LEN); | |
| 314 EXPECT_TRUE(writer.WriteMessageHeader(ntlm::MessageType::CHALLENGE)); | |
| 315 | |
| 316 // Claim that the target name field is 1 byte long and outside | |
| 317 // the buffer. | |
| 318 EXPECT_TRUE(writer.WriteSecurityBuffer( | |
| 319 ntlm::SecurityBuffer(ntlm::CHALLENGE_HEADER_LEN, 1))); | |
| 320 | |
| 321 // The above malformed message could cause an implementation | |
| 322 // to read outside the message buffer because the offset is | |
| 323 // past the end of the message. Verify it gets rejected. | |
| 324 HandleAnotherChallenge(CreateType2Token(writer.GetBuffer())); | |
| 325 EXPECT_EQ(ERR_UNEXPECTED, GetGenerateAuthTokenResult()); | |
| 326 } | |
| 327 | |
| 328 TEST_F(HttpAuthHandlerNtlmPortableTest, NoTargetNameOverflowFromLength) { | |
| 329 EXPECT_EQ(OK, CreateHandler()); | |
| 330 | |
| 331 // Message has 1 extra byte of space after the header for the | |
| 332 // target name. | |
| 333 ntlm::NtlmBufferWriter writer(ntlm::CHALLENGE_HEADER_LEN + 1); | |
| 334 EXPECT_TRUE(writer.WriteMessageHeader(ntlm::MessageType::CHALLENGE)); | |
| 335 // Claim that the target name field is 2 bytes long but | |
| 336 // there is only 1 byte of space. | |
| 337 EXPECT_TRUE(writer.WriteSecurityBuffer( | |
| 338 ntlm::SecurityBuffer(ntlm::CHALLENGE_HEADER_LEN, 2))); | |
| 339 | |
| 340 // The above malformed message could cause an implementation | |
| 341 // to read outside the message buffer because the length is | |
| 342 // longer than available space. Verify it gets rejected. | |
| 343 HandleAnotherChallenge(CreateType2Token(writer.GetBuffer())); | |
| 344 EXPECT_EQ(ERR_UNEXPECTED, GetGenerateAuthTokenResult()); | |
| 345 } | |
| 346 | |
| 347 TEST_F(HttpAuthHandlerNtlmPortableTest, Type3RespectsUnicode) { | |
| 348 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockRandom, | |
| 349 MockGetHostName); | |
| 350 EXPECT_EQ(OK, CreateHandler()); | |
| 351 | |
| 352 // Generate the type 2 message from the server. | |
| 353 ntlm::NtlmBufferWriter writer(ntlm::CHALLENGE_HEADER_LEN); | |
| 354 EXPECT_TRUE(writer.WriteMessageHeader(ntlm::MessageType::CHALLENGE)); | |
| 355 // No target name. Chrome doesn't use it anyway. | |
| 356 EXPECT_TRUE(writer.WriteSecurityBuffer( | |
| 357 ntlm::SecurityBuffer(ntlm::CHALLENGE_HEADER_LEN, 0))); | |
| 358 // Set the unicode flag. | |
| 359 EXPECT_TRUE(writer.WriteFlags(ntlm::NegotiateFlags::UNICODE)); | |
| 360 | |
| 361 std::string token; | |
| 362 HandleAnotherChallenge(CreateType2Token(writer.GetBuffer())); | |
| 363 EXPECT_EQ(OK, GenerateAuthToken(&token)); | |
| 364 | |
| 365 // Validate the type 3 message | |
| 366 std::string decoded; | |
| 367 EXPECT_TRUE(DecodeChallenge(token, &decoded)); | |
| 368 ntlm::NtlmBufferReader reader(decoded); | |
| 369 EXPECT_TRUE(reader.MatchMessageHeader(ntlm::MessageType::AUTHENTICATE)); | |
| 370 | |
| 371 // Skip the LM and NTLM Hash fields. This test isn't testing that. | |
| 372 EXPECT_TRUE(reader.SkipSecurityBuffer()); | |
|
asanka
2017/06/23 21:29:10
SkipSecurityBufferWithValidation() ?
zentaro
2017/07/05 17:57:41
Done.
| |
| 373 EXPECT_TRUE(reader.SkipSecurityBuffer()); | |
| 374 base::string16 domain; | |
| 375 base::string16 username; | |
| 376 base::string16 hostname; | |
| 377 ReadString16Payload(&reader, &domain); | |
| 378 EXPECT_EQ(base::ASCIIToUTF16(domain_ascii_), domain); | |
| 379 ReadString16Payload(&reader, &username); | |
| 380 EXPECT_EQ(base::ASCIIToUTF16(user_ascii_), username); | |
| 381 ReadString16Payload(&reader, &hostname); | |
| 382 EXPECT_EQ(base::ASCIIToUTF16(MockGetHostName()), hostname); | |
| 383 | |
| 384 // Skip the session key which isn't used. | |
| 385 EXPECT_TRUE(reader.SkipSecurityBufferWithValidation()); | |
| 386 | |
| 387 // Verify the unicode flag is set. | |
| 388 ntlm::NegotiateFlags flags; | |
| 389 EXPECT_TRUE(reader.ReadFlags(&flags)); | |
| 390 EXPECT_EQ(ntlm::NegotiateFlags::UNICODE, | |
| 391 flags & ntlm::NegotiateFlags::UNICODE); | |
| 392 } | |
| 393 | |
| 394 TEST_F(HttpAuthHandlerNtlmPortableTest, Type3WithoutUnicode) { | |
| 395 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockRandom, | |
| 396 MockGetHostName); | |
| 397 EXPECT_EQ(OK, CreateHandler()); | |
| 398 | |
| 399 // Generate the type 2 message from the server. | |
| 400 ntlm::NtlmBufferWriter writer(ntlm::CHALLENGE_HEADER_LEN); | |
| 401 EXPECT_TRUE(writer.WriteMessageHeader(ntlm::MessageType::CHALLENGE)); | |
| 402 // No target name. Chrome doesn't use it anyway. | |
| 403 EXPECT_TRUE(writer.WriteSecurityBuffer( | |
| 404 ntlm::SecurityBuffer(ntlm::CHALLENGE_HEADER_LEN, 0))); | |
| 405 // Set the OEM flag. | |
| 406 EXPECT_TRUE(writer.WriteFlags(ntlm::NegotiateFlags::OEM)); | |
| 407 | |
| 408 std::string token; | |
| 409 HandleAnotherChallenge(CreateType2Token(writer.GetBuffer())); | |
| 410 EXPECT_EQ(OK, GenerateAuthToken(&token)); | |
| 411 | |
| 412 // Validate the type 3 message | |
| 413 std::string decoded; | |
| 414 EXPECT_TRUE(DecodeChallenge(token, &decoded)); | |
| 415 ntlm::NtlmBufferReader reader(decoded); | |
| 416 EXPECT_TRUE(reader.MatchMessageHeader(ntlm::MessageType::AUTHENTICATE)); | |
| 417 | |
| 418 // Skip the 2 hash fields. This test isn't testing that. | |
| 419 EXPECT_TRUE(reader.SkipSecurityBufferWithValidation()); | |
| 420 EXPECT_TRUE(reader.SkipSecurityBufferWithValidation()); | |
| 421 std::string domain; | |
| 422 std::string username; | |
| 423 std::string hostname; | |
| 424 ReadStringPayload(&reader, &domain); | |
| 425 EXPECT_EQ(domain_ascii_, domain); | |
| 426 ReadStringPayload(&reader, &username); | |
| 427 EXPECT_EQ(user_ascii_, username); | |
| 428 ReadStringPayload(&reader, &hostname); | |
| 429 EXPECT_EQ(MockGetHostName(), hostname); | |
| 430 | |
| 431 // Skip the session key which isn't used. | |
| 432 EXPECT_TRUE(reader.SkipSecurityBufferWithValidation()); | |
| 433 | |
| 434 // Verify the unicode flag is not set and OEM flag is. | |
| 435 ntlm::NegotiateFlags flags; | |
| 436 EXPECT_TRUE(reader.ReadFlags(&flags)); | |
| 437 EXPECT_EQ(ntlm::NegotiateFlags::NONE, flags & ntlm::NegotiateFlags::UNICODE); | |
| 438 EXPECT_EQ(ntlm::NegotiateFlags::OEM, flags & ntlm::NegotiateFlags::OEM); | |
| 439 } | |
| 440 | |
| 441 TEST_F(HttpAuthHandlerNtlmPortableTest, Type3UnicodeNoSessionSecurity) { | |
| 442 // Verify that the client won't be downgraded if the server clears | |
| 443 // the session security flag. | |
| 444 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockRandom, | |
| 445 MockGetHostName); | |
| 446 EXPECT_EQ(OK, CreateHandler()); | |
| 447 | |
| 448 // Generate the type 2 message from the server. | |
| 449 ntlm::NtlmBufferWriter writer(ntlm::CHALLENGE_HEADER_LEN); | |
| 450 EXPECT_TRUE(writer.WriteMessageHeader(ntlm::MessageType::CHALLENGE)); | |
| 451 // No target name. Chrome doesn't use it anyway. | |
| 452 EXPECT_TRUE(writer.WriteSecurityBuffer( | |
| 453 ntlm::SecurityBuffer(ntlm::CHALLENGE_HEADER_LEN, 0))); | |
| 454 // Set the unicode but not the session security flag. | |
| 455 EXPECT_TRUE(writer.WriteFlags(ntlm::NegotiateFlags::UNICODE)); | |
| 456 | |
| 457 uint8_t server_challenge[] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17}; | |
| 458 EXPECT_EQ(arraysize(server_challenge), ntlm::CHALLENGE_LEN); | |
| 459 EXPECT_TRUE(writer.WriteBytes(server_challenge, ntlm::CHALLENGE_LEN)); | |
| 460 EXPECT_TRUE(writer.IsEndOfBuffer()); | |
| 461 | |
| 462 std::string token; | |
| 463 HandleAnotherChallenge(CreateType2Token(writer.GetBuffer())); | |
| 464 EXPECT_EQ(OK, GenerateAuthToken(&token)); | |
| 465 | |
| 466 // Validate the type 3 message | |
| 467 std::string decoded; | |
| 468 EXPECT_TRUE(DecodeChallenge(token, &decoded)); | |
| 469 ntlm::NtlmBufferReader reader(decoded); | |
| 470 EXPECT_TRUE(reader.MatchMessageHeader(ntlm::MessageType::AUTHENTICATE)); | |
| 471 | |
| 472 // Read the LM and NTLM Response Payloads. | |
| 473 uint8_t expected_lm_response[ntlm::RESPONSE_V1_LEN]; | |
| 474 uint8_t expected_ntlm_response[ntlm::RESPONSE_V1_LEN]; | |
| 475 uint8_t actual_lm_response[ntlm::RESPONSE_V1_LEN]; | |
| 476 uint8_t actual_ntlm_response[ntlm::RESPONSE_V1_LEN]; | |
| 477 | |
| 478 ReadBytesPayload(&reader, actual_lm_response, ntlm::RESPONSE_V1_LEN); | |
| 479 ReadBytesPayload(&reader, actual_ntlm_response, ntlm::RESPONSE_V1_LEN); | |
| 480 | |
| 481 // Session security also uses a client generated challenge so | |
| 482 // use the mock to get the same value that the implementation | |
| 483 // would get. | |
| 484 uint8_t client_challenge[ntlm::CHALLENGE_LEN]; | |
| 485 MockRandom(client_challenge, ntlm::CHALLENGE_LEN); | |
| 486 | |
| 487 ntlm::GenerateResponsesV1WithSS(base::ASCIIToUTF16(password_ascii_), | |
|
asanka
2017/06/23 21:29:11
While this makes sense for now since the test is e
zentaro
2017/07/05 17:57:41
Are you OK leaving this for this CL?
We have val
| |
| 488 server_challenge, client_challenge, | |
| 489 expected_lm_response, expected_ntlm_response); | |
| 490 | |
| 491 // Verify that the client still generated a response that uses | |
| 492 // session security. | |
| 493 EXPECT_EQ(0, memcmp(expected_lm_response, actual_lm_response, | |
| 494 ntlm::RESPONSE_V1_LEN)); | |
| 495 EXPECT_EQ(0, memcmp(expected_ntlm_response, actual_ntlm_response, | |
| 496 ntlm::RESPONSE_V1_LEN)); | |
| 497 | |
| 498 base::string16 domain; | |
| 499 base::string16 username; | |
| 500 base::string16 hostname; | |
| 501 ReadString16Payload(&reader, &domain); | |
| 502 EXPECT_EQ(base::ASCIIToUTF16(domain_ascii_), domain); | |
| 503 ReadString16Payload(&reader, &username); | |
| 504 EXPECT_EQ(base::ASCIIToUTF16(user_ascii_), username); | |
| 505 ReadString16Payload(&reader, &hostname); | |
| 506 EXPECT_EQ(base::ASCIIToUTF16(MockGetHostName()), hostname); | |
| 507 | |
| 508 // Skip the session key which isn't used. | |
| 509 EXPECT_TRUE(reader.SkipSecurityBufferWithValidation()); | |
| 510 | |
| 511 // Verify the unicode flag is set. | |
| 512 ntlm::NegotiateFlags flags; | |
| 513 EXPECT_TRUE(reader.ReadFlags(&flags)); | |
| 514 EXPECT_EQ(ntlm::NegotiateFlags::UNICODE, | |
| 515 flags & ntlm::NegotiateFlags::UNICODE); | |
| 516 } | |
| 517 | |
| 518 TEST_F(HttpAuthHandlerNtlmPortableTest, Type3UnicodeWithSessionSecurity) { | |
| 519 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockRandom, | |
| 520 MockGetHostName); | |
| 521 EXPECT_EQ(OK, CreateHandler()); | |
| 522 | |
| 523 // Generate the type 2 message from the server. | |
| 524 ntlm::NtlmBufferWriter writer(ntlm::CHALLENGE_HEADER_LEN); | |
| 525 EXPECT_TRUE(writer.WriteMessageHeader(ntlm::MessageType::CHALLENGE)); | |
| 526 // No target name. Chrome doesn't use it anyway. | |
| 527 EXPECT_TRUE(writer.WriteSecurityBuffer( | |
| 528 ntlm::SecurityBuffer(ntlm::CHALLENGE_HEADER_LEN, 0))); | |
| 529 // Set the unicode and session security flag. | |
| 530 EXPECT_TRUE( | |
| 531 writer.WriteFlags((ntlm::NegotiateFlags::UNICODE | | |
| 532 ntlm::NegotiateFlags::EXTENDED_SESSIONSECURITY))); | |
| 533 | |
| 534 uint8_t server_challenge[] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17}; | |
| 535 EXPECT_EQ(arraysize(server_challenge), ntlm::CHALLENGE_LEN); | |
| 536 EXPECT_TRUE(writer.WriteBytes(server_challenge, ntlm::CHALLENGE_LEN)); | |
| 537 EXPECT_TRUE(writer.IsEndOfBuffer()); | |
| 538 | |
| 539 std::string token; | |
| 540 HandleAnotherChallenge(CreateType2Token(writer.GetBuffer())); | |
| 541 EXPECT_EQ(OK, GenerateAuthToken(&token)); | |
| 542 | |
| 543 // Validate the type 3 message | |
| 544 std::string decoded; | |
| 545 EXPECT_TRUE(DecodeChallenge(token, &decoded)); | |
| 546 ntlm::NtlmBufferReader reader(decoded); | |
| 547 EXPECT_TRUE(reader.MatchMessageHeader(ntlm::MessageType::AUTHENTICATE)); | |
| 548 | |
| 549 // Read the LM and NTLM Response Payloads. | |
| 550 uint8_t expected_lm_response[ntlm::RESPONSE_V1_LEN]; | |
| 551 uint8_t expected_ntlm_response[ntlm::RESPONSE_V1_LEN]; | |
| 552 uint8_t actual_lm_response[ntlm::RESPONSE_V1_LEN]; | |
| 553 uint8_t actual_ntlm_response[ntlm::RESPONSE_V1_LEN]; | |
| 554 | |
| 555 ReadBytesPayload(&reader, actual_lm_response, ntlm::RESPONSE_V1_LEN); | |
| 556 ReadBytesPayload(&reader, actual_ntlm_response, ntlm::RESPONSE_V1_LEN); | |
| 557 | |
| 558 // Session security also uses a client generated challenge so | |
| 559 // use the mock to get the same value that the implementation | |
| 560 // would get. | |
| 561 uint8_t client_challenge[ntlm::CHALLENGE_LEN]; | |
| 562 MockRandom(client_challenge, ntlm::CHALLENGE_LEN); | |
| 563 | |
| 564 ntlm::GenerateResponsesV1WithSS(base::ASCIIToUTF16(password_ascii_), | |
| 565 server_challenge, client_challenge, | |
| 566 expected_lm_response, expected_ntlm_response); | |
| 567 | |
| 568 EXPECT_EQ(0, memcmp(expected_lm_response, actual_lm_response, | |
| 569 ntlm::RESPONSE_V1_LEN)); | |
| 570 EXPECT_EQ(0, memcmp(expected_ntlm_response, actual_ntlm_response, | |
| 571 ntlm::RESPONSE_V1_LEN)); | |
| 572 | |
| 573 base::string16 domain; | |
| 574 base::string16 username; | |
| 575 base::string16 hostname; | |
| 576 ReadString16Payload(&reader, &domain); | |
| 577 EXPECT_EQ(base::ASCIIToUTF16(domain_ascii_), domain); | |
| 578 ReadString16Payload(&reader, &username); | |
| 579 EXPECT_EQ(base::ASCIIToUTF16(user_ascii_), username); | |
| 580 ReadString16Payload(&reader, &hostname); | |
| 581 EXPECT_EQ(base::ASCIIToUTF16(MockGetHostName()), hostname); | |
| 582 | |
| 583 // Skip the session key which isn't used. | |
|
asanka
2017/06/23 21:29:10
?
zentaro
2017/07/05 17:57:42
Clarified the comment a bit. AFAIK it's only for t
| |
| 584 EXPECT_TRUE(reader.SkipSecurityBufferWithValidation()); | |
| 585 | |
| 586 // Verify the unicode flag is set. | |
| 587 ntlm::NegotiateFlags flags; | |
| 588 EXPECT_TRUE(reader.ReadFlags(&flags)); | |
| 589 EXPECT_EQ(ntlm::NegotiateFlags::UNICODE, | |
| 590 flags & ntlm::NegotiateFlags::UNICODE); | |
| 591 } | |
| 592 | |
| 593 #endif // defined(NTLM_PORTABLE) | |
| 594 | |
| 595 } // namespace net | |
| OLD | NEW |