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

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: Cleanup Created 3 years, 6 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 (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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698