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

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

Issue 2873673002: Add unit tests for NTLMv1 portable implementation (Closed)
Patch Set: Merge build config back to net Created 3 years, 5 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
OLDNEW
(Empty)
1 // Copyright 2017 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 <string>
6
7 #include "base/base64.h"
8 #include "base/memory/ptr_util.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "net/base/test_completion_callback.h"
12 #include "net/dns/mock_host_resolver.h"
13 #include "net/http/http_auth_challenge_tokenizer.h"
14 #include "net/http/http_auth_handler_ntlm.h"
15 #include "net/http/http_request_info.h"
16 #include "net/http/mock_allow_http_auth_preferences.h"
17 #include "net/log/net_log_with_source.h"
18 #include "net/ntlm/ntlm.h"
19 #include "net/ntlm/ntlm_buffer_reader.h"
20 #include "net/ntlm/ntlm_buffer_writer.h"
21 #include "net/ntlm/ntlm_test_data.h"
22 #include "net/ssl/ssl_info.h"
23 #include "net/test/gtest_util.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "testing/platform_test.h"
27
28 namespace net {
29
30 class HttpAuthHandlerNtlmPortableTest : public PlatformTest {
31 public:
32 // Test input value defined in [MS-NLMP] Section 4.2.1.
33 HttpAuthHandlerNtlmPortableTest() {
34 http_auth_preferences_.reset(new MockAllowHttpAuthPreferences());
35 factory_.reset(new HttpAuthHandlerNTLM::Factory());
36 factory_->set_http_auth_preferences(http_auth_preferences_.get());
37 creds_ = AuthCredentials(
38 ntlm::NTLM_DOMAIN + base::ASCIIToUTF16("\\") + ntlm::NTLM_USER,
39 ntlm::NTLM_PASSWORD);
40 }
41
42 int CreateHandler() {
43 GURL gurl("https://foo.com");
44 SSLInfo null_ssl_info;
45
46 return factory_->CreateAuthHandlerFromString(
47 "NTLM", HttpAuth::AUTH_SERVER, null_ssl_info, gurl, NetLogWithSource(),
48 &auth_handler_);
49 }
50
51 std::string CreateNtlmAuthHeader(base::StringPiece message) {
52 std::string output;
53 base::Base64Encode(message, &output);
54
55 return "NTLM " + output;
56 }
57
58 HttpAuth::AuthorizationResult HandleAnotherChallenge(
59 const std::string& challenge) {
60 HttpAuthChallengeTokenizer tokenizer(challenge.begin(), challenge.end());
61 return GetAuthHandler()->HandleAnotherChallenge(&tokenizer);
62 }
63
64 bool DecodeChallenge(const std::string& challenge, std::string* decoded) {
65 HttpAuthChallengeTokenizer tokenizer(challenge.begin(), challenge.end());
66 return base::Base64Decode(tokenizer.base64_param(), decoded);
67 }
68
69 int GenerateAuthToken(std::string* token) {
70 TestCompletionCallback callback;
71 HttpRequestInfo request_info;
72 return callback.GetResult(GetAuthHandler()->GenerateAuthToken(
73 GetCreds(), &request_info, callback.callback(), token));
74 }
75
76 void ReadBytesPayload(ntlm::NtlmBufferReader* reader,
77 uint8_t* buffer,
78 size_t len) {
79 // First read the security buffer.
80 ntlm::SecurityBuffer sec_buf;
81 EXPECT_TRUE(reader->ReadSecurityBuffer(&sec_buf));
82 EXPECT_EQ(sec_buf.length, len);
83 EXPECT_TRUE(reader->ReadBytesFrom(sec_buf, buffer));
84 }
85
86 // Reads bytes from a payload and assigns them to a string. This makes
87 // no assumptions about the underlying encoding.
88 void ReadStringPayload(ntlm::NtlmBufferReader* reader, std::string* str) {
89 ntlm::SecurityBuffer sec_buf;
90 EXPECT_TRUE(reader->ReadSecurityBuffer(&sec_buf));
91
92 uint8_t raw[sec_buf.length];
93 EXPECT_TRUE(reader->ReadBytesFrom(sec_buf, raw));
94
95 str->assign(reinterpret_cast<const char*>(raw), sec_buf.length);
96 }
97
98 // Reads bytes from a payload and assigns them to a string16. This makes
99 // no assumptions about the underlying encoding. This will fail if there
100 // are an odd number of bytes in the payload.
101 void ReadString16Payload(ntlm::NtlmBufferReader* reader,
102 base::string16* str) {
103 ntlm::SecurityBuffer sec_buf;
104 EXPECT_TRUE(reader->ReadSecurityBuffer(&sec_buf));
105 EXPECT_EQ(0, sec_buf.length % 2);
106
107 uint8_t raw[sec_buf.length];
108 EXPECT_TRUE(reader->ReadBytesFrom(sec_buf, raw));
109
110 #if IS_BIG_ENDIAN
111 for (size_t i = 0; i < sec_buf.length; i += 2) {
112 std::swap(raw[i], raw[i + 1]);
113 }
114 #endif
115
116 str->assign(reinterpret_cast<const base::char16*>(raw), sec_buf.length / 2);
117 }
118
119 int GetGenerateAuthTokenResult() {
120 std::string token;
121 return GenerateAuthToken(&token);
122 }
123
124 AuthCredentials* GetCreds() { return &creds_; }
125
126 HttpAuthHandlerNTLM* GetAuthHandler() {
127 return static_cast<HttpAuthHandlerNTLM*>(auth_handler_.get());
128 }
129
130 static void MockRandom(uint8_t* output, size_t n) {
131 // This is set to 0xaa because the client challenge for testing in
132 // [MS-NLMP] Section 4.2.1 is 8 bytes of 0xaa.
133 memset(output, 0xaa, n);
134 }
135
136 static std::string MockGetHostName() { return ntlm::NTLM_HOSTNAME_ASCII; }
137
138 protected:
139 // A minimal challenge message header for tests. The target name security
140 // buffer is zero length and pointing to the end of the header. The
141 // server challenge is set as in [MS-NLMP] Section 4.2.1.
142 // NOTE: The flag field is |NEGOTIATE_MESSAGE_FLAGS| which is different to
143 // the suggested test inputs in [MS-NLMP] Section 4.2.1 because the current
144 // implementation does not support all those flags.
145 const uint8_t challenge_header_[ntlm::CHALLENGE_HEADER_LEN] = {
asanka 2017/07/12 19:53:16 Let's call this challenge_message_ or something li
asanka 2017/07/12 19:53:16 Also, 'static const'. Otherwise this would be equi
zentaro 2017/07/13 17:10:19 This get's added to ntlm_test_data in the next CL
zentaro 2017/07/13 17:10:19 Done.
146 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0', 0x02, 0x00, 0x00,
147 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x07, 0x82,
148 0x08, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
149
150 private:
151 AuthCredentials creds_;
152 std::unique_ptr<HttpAuthHandler> auth_handler_;
153 std::unique_ptr<MockAllowHttpAuthPreferences> http_auth_preferences_;
154 std::unique_ptr<HttpAuthHandlerNTLM::Factory> factory_;
155 };
156
157 TEST_F(HttpAuthHandlerNtlmPortableTest, SimpleConstruction) {
158 ASSERT_EQ(OK, CreateHandler());
159 ASSERT_TRUE(GetAuthHandler() != nullptr);
160 }
161
162 TEST_F(HttpAuthHandlerNtlmPortableTest, DoNotAllowDefaultCreds) {
163 ASSERT_EQ(OK, CreateHandler());
164 ASSERT_FALSE(GetAuthHandler()->AllowsDefaultCredentials());
165 }
166
167 TEST_F(HttpAuthHandlerNtlmPortableTest, AllowsExplicitCredentials) {
168 ASSERT_EQ(OK, CreateHandler());
169 ASSERT_TRUE(GetAuthHandler()->AllowsExplicitCredentials());
170 }
171
172 TEST_F(HttpAuthHandlerNtlmPortableTest, VerifyType1Message) {
173 ASSERT_EQ(OK, CreateHandler());
174
175 std::string token;
176 ASSERT_EQ(OK, GenerateAuthToken(&token));
177 // The type 1 message generated is always the same. The only variable
178 // part of the message is the flags and Chrome always offers the same
Ryan Sleevi 2017/07/12 17:56:38 s/chrome/this implementation/? (We're in //net, i
zentaro 2017/07/13 17:10:19 Done.
179 // set of flags.
180 ASSERT_EQ("NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=", token);
181 }
182
183 TEST_F(HttpAuthHandlerNtlmPortableTest, EmptyTokenFails) {
184 ASSERT_EQ(OK, CreateHandler());
185
asanka 2017/07/12 19:53:15 For consistency with usage, there would be a Gener
zentaro 2017/07/13 17:10:19 Done.
186 // The encoded token for a type 2 message can't be empty.
187 ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
188 HandleAnotherChallenge("NTLM"));
189 }
190
191 TEST_F(HttpAuthHandlerNtlmPortableTest, InvalidBase64Encoding) {
192 ASSERT_EQ(OK, CreateHandler());
193
194 // Token isn't valid base64.
195 ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
196 HandleAnotherChallenge("NTLM !!!!!!!!!!!!!"));
197 ASSERT_EQ(ERR_UNEXPECTED, GetGenerateAuthTokenResult());
198 }
199
200 TEST_F(HttpAuthHandlerNtlmPortableTest, CantChangeSchemeMidway) {
201 ASSERT_EQ(OK, CreateHandler());
202
203 // Can't switch to a different auth scheme in the middle of the process.
204 ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
205 HandleAnotherChallenge("Negotiate SSdtIG5vdCBhIHJlYWwgdG9rZW4h"));
206 }
207
208 TEST_F(HttpAuthHandlerNtlmPortableTest, MinimalStructurallyValidType2) {
209 ASSERT_EQ(OK, CreateHandler());
210 ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
211 HandleAnotherChallenge(CreateNtlmAuthHeader(base::StringPiece(
212 reinterpret_cast<const char*>(challenge_header_),
213 ntlm::CHALLENGE_HEADER_LEN))));
214 ASSERT_EQ(OK, GetGenerateAuthTokenResult());
215 }
216
217 TEST_F(HttpAuthHandlerNtlmPortableTest, Type2MessageTooShort) {
218 ASSERT_EQ(OK, CreateHandler());
219
220 char raw[31];
221 memcpy(raw, challenge_header_, 31);
222
223 // Fail because the minimum size valid message is 32 bytes.
224 ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
225 HandleAnotherChallenge(
226 CreateNtlmAuthHeader(base::StringPiece(raw, sizeof(raw)))));
227 ASSERT_EQ(ERR_UNEXPECTED, GetGenerateAuthTokenResult());
228 }
229
230 TEST_F(HttpAuthHandlerNtlmPortableTest, Type2MessageNoSig) {
asanka 2017/07/12 19:53:16 Type2MessageWrongSignature
zentaro 2017/07/13 17:10:19 Done.
231 ASSERT_EQ(OK, CreateHandler());
232
233 char raw[32];
234 memcpy(raw, challenge_header_, 32);
235 // Modify the default valid message to overwrite the last byte of the
236 // signature.
237 raw[7] = 0xff;
238
239 // Fail because the first 8 bytes don't match "NTLMSSP\0"
240 ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
241 HandleAnotherChallenge(
242 CreateNtlmAuthHeader(base::StringPiece(raw, sizeof(raw)))));
243 ASSERT_EQ(ERR_UNEXPECTED, GetGenerateAuthTokenResult());
244 }
245
246 TEST_F(HttpAuthHandlerNtlmPortableTest, Type2WrongMessageType) {
247 ASSERT_EQ(OK, CreateHandler());
248
249 char raw[32];
250 memcpy(raw, challenge_header_, 32);
251 // Modify the message type so it is not 0x00000002
252 raw[8] = 0x03;
253
254 // Fail because the message type should be MessageType::CHALLENGE (0x00000002)
255 ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
256 HandleAnotherChallenge(CreateNtlmAuthHeader(raw)));
257 ASSERT_EQ(ERR_UNEXPECTED, GetGenerateAuthTokenResult());
258 }
259
260 TEST_F(HttpAuthHandlerNtlmPortableTest, Type2MessageWithNoTargetName) {
261 ASSERT_EQ(OK, CreateHandler());
262
263 // The spec (2.2.1.2) states that the length SHOULD be 0 and the offset
264 // SHOULD be where the payload would be if it was present. This is the
265 // expected response from a compliant server when no target name is sent.
266 // In reality the offset should always be ignored if the length is zero.
267 // Also implementations often just write zeros.
268 char raw[32];
269 memcpy(raw, challenge_header_, 32);
270 // Modify the default valid message to overwrite the offset to zero.
271 raw[16] = 0x00;
272
273 ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
274 HandleAnotherChallenge(
275 CreateNtlmAuthHeader(base::StringPiece(raw, sizeof(raw)))));
276 ASSERT_EQ(OK, GetGenerateAuthTokenResult());
277 }
278
279 TEST_F(HttpAuthHandlerNtlmPortableTest, Type2MessageWithTargetName) {
280 ASSERT_EQ(OK, CreateHandler());
281
282 // One extra byte is provided for target name.
283 char raw[33];
284 memcpy(raw, challenge_header_, 32);
285 // Modify the default valid message to indicate 1 byte is present in the
286 // target name payload.
287 raw[12] = 0x01;
288 raw[14] = 0x01;
289 // Put something in the target name.
290 raw[32] = 'Z';
291
292 ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
293 HandleAnotherChallenge(
294 CreateNtlmAuthHeader(base::StringPiece(raw, sizeof(raw)))));
295 ASSERT_EQ(OK, GetGenerateAuthTokenResult());
296 }
297
298 TEST_F(HttpAuthHandlerNtlmPortableTest, NoTargetNameOverflowFromOffset) {
299 ASSERT_EQ(OK, CreateHandler());
300
301 char raw[32];
302 memcpy(raw, challenge_header_, 32);
303 // Modify the default valid message to claim that the target name field is 1
304 // byte long overrunning the end of the message message.
305 raw[12] = 0x01;
306 raw[14] = 0x01;
307
308 // The above malformed message could cause an implementation to read outside
309 // the message buffer because the offset is past the end of the message.
310 // Verify it gets rejected.
311 ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
312 HandleAnotherChallenge(
313 CreateNtlmAuthHeader(base::StringPiece(raw, sizeof(raw)))));
314 ASSERT_EQ(ERR_UNEXPECTED, GetGenerateAuthTokenResult());
315 }
316
317 TEST_F(HttpAuthHandlerNtlmPortableTest, NoTargetNameOverflowFromLength) {
318 ASSERT_EQ(OK, CreateHandler());
319
320 // Message has 1 extra byte of space after the header for the target name.
321 // One extra byte is provided for target name.
322 char raw[33];
323 memcpy(raw, challenge_header_, 32);
324 // Modify the default valid message to indicate 2 bytes are present in the
325 // target name payload (however there is only space for 1).
326 raw[12] = 0x02;
327 raw[14] = 0x02;
328 // Put something in the target name.
329 raw[32] = 'Z';
330
331 // The above malformed message could cause an implementation to read outside
332 // the message buffer because the length is longer than available space.
333 // Verify it gets rejected.
334 ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
335 HandleAnotherChallenge(
336 CreateNtlmAuthHeader(base::StringPiece(raw, sizeof(raw)))));
337 ASSERT_EQ(ERR_UNEXPECTED, GetGenerateAuthTokenResult());
338 }
339
340 TEST_F(HttpAuthHandlerNtlmPortableTest, Type3RespectsUnicode) {
341 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockRandom,
342 MockGetHostName);
343 ASSERT_EQ(OK, CreateHandler());
344
345 // Generate the type 2 message from the server.
346 ntlm::NtlmBufferWriter writer(ntlm::CHALLENGE_HEADER_LEN);
347 ASSERT_TRUE(writer.WriteMessageHeader(ntlm::MessageType::CHALLENGE));
348 // No target name. Chrome doesn't use it anyway.
349 ASSERT_TRUE(writer.WriteSecurityBuffer(
350 ntlm::SecurityBuffer(ntlm::CHALLENGE_HEADER_LEN, 0)));
351 // Set the unicode flag.
352 ASSERT_TRUE(writer.WriteFlags(ntlm::NegotiateFlags::UNICODE));
353
354 std::string token;
355 ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
356 HandleAnotherChallenge(CreateNtlmAuthHeader(writer.GetBuffer())));
357 ASSERT_EQ(OK, GenerateAuthToken(&token));
358
359 // Validate the type 3 message
360 std::string decoded;
361 ASSERT_TRUE(DecodeChallenge(token, &decoded));
362 ntlm::NtlmBufferReader reader(decoded);
363 ASSERT_TRUE(reader.MatchMessageHeader(ntlm::MessageType::AUTHENTICATE));
364
365 // Skip the LM and NTLM Hash fields. This test isn't testing that.
366 ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
367 ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
368 base::string16 domain;
369 base::string16 username;
370 base::string16 hostname;
371 ReadString16Payload(&reader, &domain);
372 ASSERT_EQ(ntlm::NTLM_DOMAIN, domain);
373 ReadString16Payload(&reader, &username);
374 ASSERT_EQ(ntlm::NTLM_USER, username);
375 ReadString16Payload(&reader, &hostname);
376 ASSERT_EQ(ntlm::NTLM_HOSTNAME, hostname);
377
378 // The session key is not used for the NTLM scheme in HTTP. Since
379 // NTLMSSP_NEGOTIATE_KEY_EXCH was not sent this is empty.
380 ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
381
382 // Verify the unicode flag is set.
383 ntlm::NegotiateFlags flags;
384 ASSERT_TRUE(reader.ReadFlags(&flags));
385 ASSERT_EQ(ntlm::NegotiateFlags::UNICODE,
386 flags & ntlm::NegotiateFlags::UNICODE);
387 }
388
389 TEST_F(HttpAuthHandlerNtlmPortableTest, Type3WithoutUnicode) {
390 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockRandom,
391 MockGetHostName);
392 ASSERT_EQ(OK, CreateHandler());
393
394 // Generate the type 2 message from the server.
395 ntlm::NtlmBufferWriter writer(ntlm::CHALLENGE_HEADER_LEN);
396 ASSERT_TRUE(writer.WriteMessageHeader(ntlm::MessageType::CHALLENGE));
397 // No target name. Chrome doesn't use it anyway.
398 ASSERT_TRUE(writer.WriteSecurityBuffer(
399 ntlm::SecurityBuffer(ntlm::CHALLENGE_HEADER_LEN, 0)));
400 // Set the OEM flag.
401 ASSERT_TRUE(writer.WriteFlags(ntlm::NegotiateFlags::OEM));
402
403 std::string token;
404 ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
405 HandleAnotherChallenge(CreateNtlmAuthHeader(writer.GetBuffer())));
406 ASSERT_EQ(OK, GenerateAuthToken(&token));
407
408 // Validate the type 3 message
409 std::string decoded;
410 ASSERT_TRUE(DecodeChallenge(token, &decoded));
411 ntlm::NtlmBufferReader reader(decoded);
412 ASSERT_TRUE(reader.MatchMessageHeader(ntlm::MessageType::AUTHENTICATE));
413
414 // Skip the 2 hash fields. This test isn't testing that.
415 ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
416 ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
417 std::string domain;
418 std::string username;
419 std::string hostname;
420 ReadStringPayload(&reader, &domain);
421 ASSERT_EQ(ntlm::NTLM_DOMAIN_ASCII, domain);
422 ReadStringPayload(&reader, &username);
423 ASSERT_EQ(ntlm::NTLM_USER_ASCII, username);
424 ReadStringPayload(&reader, &hostname);
425 ASSERT_EQ(ntlm::NTLM_HOSTNAME_ASCII, hostname);
426
427 // The session key is not used for the NTLM scheme in HTTP. Since
428 // NTLMSSP_NEGOTIATE_KEY_EXCH was not sent this is empty.
429 ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
430
431 // Verify the unicode flag is not set and OEM flag is.
432 ntlm::NegotiateFlags flags;
433 ASSERT_TRUE(reader.ReadFlags(&flags));
434 ASSERT_EQ(ntlm::NegotiateFlags::NONE, flags & ntlm::NegotiateFlags::UNICODE);
435 ASSERT_EQ(ntlm::NegotiateFlags::OEM, flags & ntlm::NegotiateFlags::OEM);
436 }
437
438 TEST_F(HttpAuthHandlerNtlmPortableTest, Type3UnicodeNoSessionSecurity) {
439 // Verify that the client won't be downgraded if the server clears
440 // the session security flag.
441 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockRandom,
442 MockGetHostName);
443 ASSERT_EQ(OK, CreateHandler());
444
445 // Generate the type 2 message from the server.
446 ntlm::NtlmBufferWriter writer(ntlm::CHALLENGE_HEADER_LEN);
447 ASSERT_TRUE(writer.WriteMessageHeader(ntlm::MessageType::CHALLENGE));
448 // No target name. Chrome doesn't use it anyway.
449 ASSERT_TRUE(writer.WriteSecurityBuffer(
450 ntlm::SecurityBuffer(ntlm::CHALLENGE_HEADER_LEN, 0)));
451 // Set the unicode but not the session security flag.
452 ASSERT_TRUE(writer.WriteFlags(ntlm::NegotiateFlags::UNICODE));
453
454 ASSERT_TRUE(writer.WriteBytes(ntlm::SERVER_CHALLENGE, ntlm::CHALLENGE_LEN));
455 ASSERT_TRUE(writer.IsEndOfBuffer());
456
457 std::string token;
458 ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
459 HandleAnotherChallenge(CreateNtlmAuthHeader(writer.GetBuffer())));
460 ASSERT_EQ(OK, GenerateAuthToken(&token));
461
462 // Validate the type 3 message
463 std::string decoded;
464 ASSERT_TRUE(DecodeChallenge(token, &decoded));
465 ntlm::NtlmBufferReader reader(decoded);
466 ASSERT_TRUE(reader.MatchMessageHeader(ntlm::MessageType::AUTHENTICATE));
467
468 // Read the LM and NTLM Response Payloads.
469 uint8_t actual_lm_response[ntlm::RESPONSE_V1_LEN];
470 uint8_t actual_ntlm_response[ntlm::RESPONSE_V1_LEN];
471 ReadBytesPayload(&reader, actual_lm_response, ntlm::RESPONSE_V1_LEN);
472 ReadBytesPayload(&reader, actual_ntlm_response, ntlm::RESPONSE_V1_LEN);
473
474 // Verify that the client still generated a response that uses
475 // session security.
476 ASSERT_EQ(0, memcmp(ntlm::EXPECTED_V1_WITH_SS_LM_RESPONSE, actual_lm_response,
477 ntlm::RESPONSE_V1_LEN));
478 ASSERT_EQ(0, memcmp(ntlm::EXPECTED_V1_WITH_SS_NTLM_RESPONSE,
479 actual_ntlm_response, ntlm::RESPONSE_V1_LEN));
480
481 base::string16 domain;
482 base::string16 username;
483 base::string16 hostname;
484 ReadString16Payload(&reader, &domain);
485 ASSERT_EQ(ntlm::NTLM_DOMAIN, domain);
486 ReadString16Payload(&reader, &username);
487 ASSERT_EQ(ntlm::NTLM_USER, username);
488 ReadString16Payload(&reader, &hostname);
489 ASSERT_EQ(ntlm::NTLM_HOSTNAME, hostname);
490
491 // The session key is not used for the NTLM scheme in HTTP. Since
492 // NTLMSSP_NEGOTIATE_KEY_EXCH was not sent this is empty.
493 ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
494
495 // Verify the unicode flag is set.
496 ntlm::NegotiateFlags flags;
497 ASSERT_TRUE(reader.ReadFlags(&flags));
498 ASSERT_EQ(ntlm::NegotiateFlags::UNICODE,
499 flags & ntlm::NegotiateFlags::UNICODE);
500 }
501
502 TEST_F(HttpAuthHandlerNtlmPortableTest, Type3UnicodeWithSessionSecurity) {
503 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockRandom,
504 MockGetHostName);
505 ASSERT_EQ(OK, CreateHandler());
506
507 // Generate the type 2 message from the server.
508 ntlm::NtlmBufferWriter writer(ntlm::CHALLENGE_HEADER_LEN);
509 ASSERT_TRUE(writer.WriteMessageHeader(ntlm::MessageType::CHALLENGE));
510 // No target name. Chrome doesn't use it anyway.
511 ASSERT_TRUE(writer.WriteSecurityBuffer(
512 ntlm::SecurityBuffer(ntlm::CHALLENGE_HEADER_LEN, 0)));
513 // Set the unicode and session security flag.
514 ASSERT_TRUE(
515 writer.WriteFlags((ntlm::NegotiateFlags::UNICODE |
516 ntlm::NegotiateFlags::EXTENDED_SESSIONSECURITY)));
517
518 ASSERT_TRUE(writer.WriteBytes(ntlm::SERVER_CHALLENGE, ntlm::CHALLENGE_LEN));
519 ASSERT_TRUE(writer.IsEndOfBuffer());
520
521 std::string token;
522 ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
523 HandleAnotherChallenge(CreateNtlmAuthHeader(writer.GetBuffer())));
524 ASSERT_EQ(OK, GenerateAuthToken(&token));
525
526 // Validate the type 3 message
527 std::string decoded;
528 ASSERT_TRUE(DecodeChallenge(token, &decoded));
529 ntlm::NtlmBufferReader reader(decoded);
530 ASSERT_TRUE(reader.MatchMessageHeader(ntlm::MessageType::AUTHENTICATE));
531
532 // Read the LM and NTLM Response Payloads.
533 uint8_t actual_lm_response[ntlm::RESPONSE_V1_LEN];
534 uint8_t actual_ntlm_response[ntlm::RESPONSE_V1_LEN];
535 ReadBytesPayload(&reader, actual_lm_response, ntlm::RESPONSE_V1_LEN);
536 ReadBytesPayload(&reader, actual_ntlm_response, ntlm::RESPONSE_V1_LEN);
537
538 ASSERT_EQ(0, memcmp(ntlm::EXPECTED_V1_WITH_SS_LM_RESPONSE, actual_lm_response,
539 ntlm::RESPONSE_V1_LEN));
540 ASSERT_EQ(0, memcmp(ntlm::EXPECTED_V1_WITH_SS_NTLM_RESPONSE,
541 actual_ntlm_response, ntlm::RESPONSE_V1_LEN));
542
543 base::string16 domain;
544 base::string16 username;
545 base::string16 hostname;
546 ReadString16Payload(&reader, &domain);
547 ASSERT_EQ(ntlm::NTLM_DOMAIN, domain);
548 ReadString16Payload(&reader, &username);
549 ASSERT_EQ(ntlm::NTLM_USER, username);
550 ReadString16Payload(&reader, &hostname);
551 ASSERT_EQ(ntlm::NTLM_HOSTNAME, hostname);
552
553 // The session key is not used for the NTLM scheme in HTTP. Since
554 // NTLMSSP_NEGOTIATE_KEY_EXCH was not sent this is empty.
555 ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
556
557 // Verify the unicode flag is set.
558 ntlm::NegotiateFlags flags;
559 ASSERT_TRUE(reader.ReadFlags(&flags));
560 ASSERT_EQ(ntlm::NegotiateFlags::UNICODE,
561 flags & ntlm::NegotiateFlags::UNICODE);
562 }
asanka 2017/07/12 19:53:16 These are pretty neat tests!
563
564 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698