1 // Copyright 2012 The Chromium Authors
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_gssapi_posix.h"
6
7 #include <memory>
8 #include <string_view>
9
10 #include "base/base_paths.h"
11 #include "base/check.h"
12 #include "base/functional/bind.h"
13 #include "base/json/json_reader.h"
14 #include "base/native_library.h"
15 #include "base/path_service.h"
16 #include "net/base/net_errors.h"
17 #include "net/http/http_auth_challenge_tokenizer.h"
18 #include "net/http/mock_gssapi_library_posix.h"
19 #include "net/log/net_log_with_source.h"
20 #include "net/log/test_net_log.h"
21 #include "net/log/test_net_log_util.h"
22 #include "net/net_buildflags.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24
25 namespace net {
26
27 namespace {
28
29 // gss_buffer_t helpers.
ClearBuffer(gss_buffer_t dest)30 void ClearBuffer(gss_buffer_t dest) {
31 if (!dest)
32 return;
33 dest->length = 0;
34 delete [] reinterpret_cast<char*>(dest->value);
35 dest->value = nullptr;
36 }
37
SetBuffer(gss_buffer_t dest,const void * src,size_t length)38 void SetBuffer(gss_buffer_t dest, const void* src, size_t length) {
39 if (!dest)
40 return;
41 ClearBuffer(dest);
42 if (!src)
43 return;
44 dest->length = length;
45 if (length) {
46 dest->value = new char[length];
47 memcpy(dest->value, src, length);
48 }
49 }
50
CopyBuffer(gss_buffer_t dest,const gss_buffer_t src)51 void CopyBuffer(gss_buffer_t dest, const gss_buffer_t src) {
52 if (!dest)
53 return;
54 ClearBuffer(dest);
55 if (!src)
56 return;
57 SetBuffer(dest, src->value, src->length);
58 }
59
60 const char kInitialAuthResponse[] = "Mary had a little lamb";
61
EstablishInitialContext(test::MockGSSAPILibrary * library)62 void EstablishInitialContext(test::MockGSSAPILibrary* library) {
63 test::GssContextMockImpl context_info(
64 "localhost", // Source name
65 "example.com", // Target name
66 23, // Lifetime
67 *CHROME_GSS_SPNEGO_MECH_OID_DESC, // Mechanism
68 0, // Context flags
69 1, // Locally initiated
70 0); // Open
71 gss_buffer_desc in_buffer = {0, nullptr};
72 gss_buffer_desc out_buffer = {std::size(kInitialAuthResponse),
73 const_cast<char*>(kInitialAuthResponse)};
74 library->ExpectSecurityContext(
75 "Negotiate",
76 GSS_S_CONTINUE_NEEDED,
77 0,
78 context_info,
79 in_buffer,
80 out_buffer);
81 }
82
UnexpectedCallback(int result)83 void UnexpectedCallback(int result) {
84 // At present getting tokens from gssapi is fully synchronous, so the callback
85 // should never be called.
86 ADD_FAILURE();
87 }
88
89 } // namespace
90
TEST(HttpAuthGSSAPIPOSIXTest,GSSAPIStartup)91 TEST(HttpAuthGSSAPIPOSIXTest, GSSAPIStartup) {
92 RecordingNetLogObserver net_log_observer;
93 // TODO(ahendrickson): Manipulate the libraries and paths to test each of the
94 // libraries we expect, and also whether or not they have the interface
95 // functions we want.
96 auto gssapi = std::make_unique<GSSAPISharedLibrary>(std::string());
97 DCHECK(gssapi.get());
98 EXPECT_TRUE(
99 gssapi.get()->Init(NetLogWithSource::Make(NetLogSourceType::NONE)));
100
101 // Should've logged a AUTH_LIBRARY_LOAD event, but not
102 // AUTH_LIBRARY_BIND_FAILED.
103 auto entries = net_log_observer.GetEntries();
104 auto offset = ExpectLogContainsSomewhere(
105 entries, 0u, NetLogEventType::AUTH_LIBRARY_LOAD, NetLogEventPhase::BEGIN);
106 offset = ExpectLogContainsSomewhereAfter(entries, offset,
107 NetLogEventType::AUTH_LIBRARY_LOAD,
108 NetLogEventPhase::END);
109 ASSERT_LT(offset, entries.size());
110
111 const auto& entry = entries[offset];
112 EXPECT_NE("", GetStringValueFromParams(entry, "library_name"));
113
114 // No load_result since it succeeded.
115 EXPECT_FALSE(GetOptionalStringValueFromParams(entry, "load_result"));
116 }
117
TEST(HttpAuthGSSAPIPOSIXTest,CustomLibraryMissing)118 TEST(HttpAuthGSSAPIPOSIXTest, CustomLibraryMissing) {
119 RecordingNetLogObserver net_log_observer;
120
121 auto gssapi =
122 std::make_unique<GSSAPISharedLibrary>("/this/library/does/not/exist");
123 EXPECT_FALSE(
124 gssapi.get()->Init(NetLogWithSource::Make(NetLogSourceType::NONE)));
125
126 auto entries = net_log_observer.GetEntries();
127 auto offset = ExpectLogContainsSomewhere(
128 entries, 0, NetLogEventType::AUTH_LIBRARY_LOAD, NetLogEventPhase::END);
129 ASSERT_LT(offset, entries.size());
130
131 const auto& entry = entries[offset];
132 EXPECT_NE("", GetStringValueFromParams(entry, "load_result"));
133 }
134
TEST(HttpAuthGSSAPIPOSIXTest,CustomLibraryExists)135 TEST(HttpAuthGSSAPIPOSIXTest, CustomLibraryExists) {
136 RecordingNetLogObserver net_log_observer;
137 base::FilePath module;
138 ASSERT_TRUE(base::PathService::Get(base::DIR_MODULE, &module));
139 auto basename = base::GetNativeLibraryName("test_gssapi");
140 module = module.AppendASCII(basename);
141 auto gssapi = std::make_unique<GSSAPISharedLibrary>(module.value());
142 EXPECT_TRUE(
143 gssapi.get()->Init(NetLogWithSource::Make(NetLogSourceType::NONE)));
144
145 auto entries = net_log_observer.GetEntries();
146 auto offset = ExpectLogContainsSomewhere(
147 entries, 0, NetLogEventType::AUTH_LIBRARY_LOAD, NetLogEventPhase::END);
148 ASSERT_LT(offset, entries.size());
149
150 const auto& entry = entries[offset];
151 EXPECT_FALSE(GetOptionalStringValueFromParams(entry, "load_result"));
152 EXPECT_EQ(module.AsUTF8Unsafe(),
153 GetStringValueFromParams(entry, "library_name"));
154 }
155
TEST(HttpAuthGSSAPIPOSIXTest,CustomLibraryMethodsMissing)156 TEST(HttpAuthGSSAPIPOSIXTest, CustomLibraryMethodsMissing) {
157 RecordingNetLogObserver net_log_observer;
158 base::FilePath module;
159 ASSERT_TRUE(base::PathService::Get(base::DIR_MODULE, &module));
160 auto basename = base::GetNativeLibraryName("test_badgssapi");
161 module = module.AppendASCII(basename);
162 auto gssapi = std::make_unique<GSSAPISharedLibrary>(module.value());
163
164 // Are you here because this test mysteriously passed even though the library
165 // doesn't actually have all the methods we need? This could be because the
166 // test library (//net:test_badgssapi) inadvertently depends on a valid GSSAPI
167 // library. On macOS this can happen because it's pretty easy to end up
168 // depending on GSS.framework.
169 //
170 // To resolve this issue, make sure that //net:test_badgssapi target in
171 // //net/BUILD.gn should have an empty `deps` and an empty `libs`.
172 EXPECT_FALSE(
173 gssapi.get()->Init(NetLogWithSource::Make(NetLogSourceType::NONE)));
174
175 auto entries = net_log_observer.GetEntries();
176 auto offset = ExpectLogContainsSomewhere(
177 entries, 0, NetLogEventType::AUTH_LIBRARY_BIND_FAILED,
178 NetLogEventPhase::NONE);
179 ASSERT_LT(offset, entries.size());
180
181 const auto& entry = entries[offset];
182 EXPECT_EQ("gss_import_name", GetStringValueFromParams(entry, "method"));
183 }
184
TEST(HttpAuthGSSAPIPOSIXTest,GSSAPICycle)185 TEST(HttpAuthGSSAPIPOSIXTest, GSSAPICycle) {
186 auto mock_library = std::make_unique<test::MockGSSAPILibrary>();
187 DCHECK(mock_library.get());
188 mock_library->Init(NetLogWithSource());
189 const char kAuthResponse[] = "Mary had a little lamb";
190 test::GssContextMockImpl context1(
191 "localhost", // Source name
192 "example.com", // Target name
193 23, // Lifetime
194 *CHROME_GSS_SPNEGO_MECH_OID_DESC, // Mechanism
195 0, // Context flags
196 1, // Locally initiated
197 0); // Open
198 test::GssContextMockImpl context2(
199 "localhost", // Source name
200 "example.com", // Target name
201 23, // Lifetime
202 *CHROME_GSS_SPNEGO_MECH_OID_DESC, // Mechanism
203 0, // Context flags
204 1, // Locally initiated
205 1); // Open
206 test::MockGSSAPILibrary::SecurityContextQuery queries[] = {
207 test::MockGSSAPILibrary::SecurityContextQuery(
208 "Negotiate", // Package name
209 GSS_S_CONTINUE_NEEDED, // Major response code
210 0, // Minor response code
211 context1, // Context
212 nullptr, // Expected input token
213 kAuthResponse), // Output token
214 test::MockGSSAPILibrary::SecurityContextQuery(
215 "Negotiate", // Package name
216 GSS_S_COMPLETE, // Major response code
217 0, // Minor response code
218 context2, // Context
219 kAuthResponse, // Expected input token
220 kAuthResponse) // Output token
221 };
222
223 for (const auto& query : queries) {
224 mock_library->ExpectSecurityContext(
225 query.expected_package, query.response_code, query.minor_response_code,
226 query.context_info, query.expected_input_token, query.output_token);
227 }
228
229 OM_uint32 major_status = 0;
230 OM_uint32 minor_status = 0;
231 gss_cred_id_t initiator_cred_handle = nullptr;
232 gss_ctx_id_t context_handle = nullptr;
233 gss_name_t target_name = nullptr;
234 gss_OID mech_type = nullptr;
235 OM_uint32 req_flags = 0;
236 OM_uint32 time_req = 25;
237 gss_channel_bindings_t input_chan_bindings = nullptr;
238 gss_buffer_desc input_token = {0, nullptr};
239 gss_OID actual_mech_type = nullptr;
240 gss_buffer_desc output_token = {0, nullptr};
241 OM_uint32 ret_flags = 0;
242 OM_uint32 time_rec = 0;
243 for (const auto& query : queries) {
244 major_status = mock_library->init_sec_context(&minor_status,
245 initiator_cred_handle,
246 &context_handle,
247 target_name,
248 mech_type,
249 req_flags,
250 time_req,
251 input_chan_bindings,
252 &input_token,
253 &actual_mech_type,
254 &output_token,
255 &ret_flags,
256 &time_rec);
257 EXPECT_EQ(query.response_code, major_status);
258 CopyBuffer(&input_token, &output_token);
259 ClearBuffer(&output_token);
260 }
261 ClearBuffer(&input_token);
262 major_status = mock_library->delete_sec_context(&minor_status,
263 &context_handle,
264 GSS_C_NO_BUFFER);
265 EXPECT_EQ(static_cast<OM_uint32>(GSS_S_COMPLETE), major_status);
266 }
267
TEST(HttpAuthGSSAPITest,ParseChallenge_FirstRound)268 TEST(HttpAuthGSSAPITest, ParseChallenge_FirstRound) {
269 // The first round should just consist of an unadorned "Negotiate" header.
270 test::MockGSSAPILibrary mock_library;
271 HttpAuthGSSAPI auth_gssapi(&mock_library, CHROME_GSS_SPNEGO_MECH_OID_DESC);
272 HttpAuthChallengeTokenizer challenge("Negotiate");
273 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
274 auth_gssapi.ParseChallenge(&challenge));
275 }
276
TEST(HttpAuthGSSAPITest,ParseChallenge_TwoRounds)277 TEST(HttpAuthGSSAPITest, ParseChallenge_TwoRounds) {
278 RecordingNetLogObserver net_log_observer;
279 // The first round should just have "Negotiate", and the second round should
280 // have a valid base64 token associated with it.
281 test::MockGSSAPILibrary mock_library;
282 HttpAuthGSSAPI auth_gssapi(&mock_library, CHROME_GSS_SPNEGO_MECH_OID_DESC);
283 HttpAuthChallengeTokenizer first_challenge("Negotiate");
284 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
285 auth_gssapi.ParseChallenge(&first_challenge));
286
287 // Generate an auth token and create another thing.
288 EstablishInitialContext(&mock_library);
289 std::string auth_token;
290 EXPECT_EQ(OK, auth_gssapi.GenerateAuthToken(
291 nullptr, "HTTP/intranet.google.com", std::string(),
292 &auth_token, NetLogWithSource::Make(NetLogSourceType::NONE),
293 base::BindOnce(&UnexpectedCallback)));
294
295 HttpAuthChallengeTokenizer second_challenge("Negotiate Zm9vYmFy");
296 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
297 auth_gssapi.ParseChallenge(&second_challenge));
298
299 auto entries = net_log_observer.GetEntries();
300 auto offset = ExpectLogContainsSomewhere(
301 entries, 0, NetLogEventType::AUTH_LIBRARY_INIT_SEC_CTX,
302 NetLogEventPhase::END);
303 // There should be two of these.
304 offset = ExpectLogContainsSomewhere(
305 entries, offset, NetLogEventType::AUTH_LIBRARY_INIT_SEC_CTX,
306 NetLogEventPhase::END);
307 ASSERT_LT(offset, entries.size());
308 const std::string* source =
309 entries[offset].params.FindStringByDottedPath("context.source.name");
310 ASSERT_TRUE(source);
311 EXPECT_EQ("localhost", *source);
312 }
313
TEST(HttpAuthGSSAPITest,ParseChallenge_UnexpectedTokenFirstRound)314 TEST(HttpAuthGSSAPITest, ParseChallenge_UnexpectedTokenFirstRound) {
315 // If the first round challenge has an additional authentication token, it
316 // should be treated as an invalid challenge from the server.
317 test::MockGSSAPILibrary mock_library;
318 HttpAuthGSSAPI auth_gssapi(&mock_library, CHROME_GSS_SPNEGO_MECH_OID_DESC);
319 HttpAuthChallengeTokenizer challenge("Negotiate Zm9vYmFy");
320 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
321 auth_gssapi.ParseChallenge(&challenge));
322 }
323
TEST(HttpAuthGSSAPITest,ParseChallenge_MissingTokenSecondRound)324 TEST(HttpAuthGSSAPITest, ParseChallenge_MissingTokenSecondRound) {
325 // If a later-round challenge is simply "Negotiate", it should be treated as
326 // an authentication challenge rejection from the server or proxy.
327 test::MockGSSAPILibrary mock_library;
328 HttpAuthGSSAPI auth_gssapi(&mock_library, CHROME_GSS_SPNEGO_MECH_OID_DESC);
329 HttpAuthChallengeTokenizer first_challenge("Negotiate");
330 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
331 auth_gssapi.ParseChallenge(&first_challenge));
332
333 EstablishInitialContext(&mock_library);
334 std::string auth_token;
335 EXPECT_EQ(OK,
336 auth_gssapi.GenerateAuthToken(
337 nullptr, "HTTP/intranet.google.com", std::string(), &auth_token,
338 NetLogWithSource(), base::BindOnce(&UnexpectedCallback)));
339 HttpAuthChallengeTokenizer second_challenge("Negotiate");
340 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
341 auth_gssapi.ParseChallenge(&second_challenge));
342 }
343
TEST(HttpAuthGSSAPITest,ParseChallenge_NonBase64EncodedToken)344 TEST(HttpAuthGSSAPITest, ParseChallenge_NonBase64EncodedToken) {
345 // If a later-round challenge has an invalid base64 encoded token, it should
346 // be treated as an invalid challenge.
347 test::MockGSSAPILibrary mock_library;
348 HttpAuthGSSAPI auth_gssapi(&mock_library, CHROME_GSS_SPNEGO_MECH_OID_DESC);
349 HttpAuthChallengeTokenizer first_challenge("Negotiate");
350 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
351 auth_gssapi.ParseChallenge(&first_challenge));
352
353 EstablishInitialContext(&mock_library);
354 std::string auth_token;
355 EXPECT_EQ(OK,
356 auth_gssapi.GenerateAuthToken(
357 nullptr, "HTTP/intranet.google.com", std::string(), &auth_token,
358 NetLogWithSource(), base::BindOnce(&UnexpectedCallback)));
359 HttpAuthChallengeTokenizer second_challenge("Negotiate =happyjoy=");
360 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
361 auth_gssapi.ParseChallenge(&second_challenge));
362 }
363
TEST(HttpAuthGSSAPITest,OidToValue_NIL)364 TEST(HttpAuthGSSAPITest, OidToValue_NIL) {
365 auto actual = OidToValue(GSS_C_NO_OID);
366 auto expected = base::JSONReader::Read(R"({ "oid": "<Empty OID>" })");
367 ASSERT_TRUE(expected.has_value());
368 EXPECT_EQ(actual, expected);
369 }
370
TEST(HttpAuthGSSAPITest,OidToValue_Known)371 TEST(HttpAuthGSSAPITest, OidToValue_Known) {
372 gss_OID_desc known = {6, const_cast<char*>("\x2b\x06\01\x05\x06\x03")};
373
374 auto actual = OidToValue(const_cast<const gss_OID>(&known));
375 auto expected = base::JSONReader::Read(R"(
376 {
377 "oid" : "GSS_C_NT_ANONYMOUS",
378 "length": 6,
379 "bytes" : "KwYBBQYD"
380 }
381 )");
382 ASSERT_TRUE(expected.has_value());
383 EXPECT_EQ(actual, expected);
384 }
385
TEST(HttpAuthGSSAPITest,OidToValue_Unknown)386 TEST(HttpAuthGSSAPITest, OidToValue_Unknown) {
387 gss_OID_desc unknown = {6, const_cast<char*>("\x2b\x06\01\x05\x06\x05")};
388 auto actual = OidToValue(const_cast<const gss_OID>(&unknown));
389 auto expected = base::JSONReader::Read(R"(
390 {
391 "length": 6,
392 "bytes" : "KwYBBQYF"
393 }
394 )");
395 ASSERT_TRUE(expected.has_value());
396 EXPECT_EQ(actual, expected);
397 }
398
TEST(HttpAuthGSSAPITest,GetGssStatusValue_NoLibrary)399 TEST(HttpAuthGSSAPITest, GetGssStatusValue_NoLibrary) {
400 auto actual = GetGssStatusValue(nullptr, "my_method", GSS_S_BAD_NAME, 1);
401 auto expected = base::JSONReader::Read(R"(
402 {
403 "function": "my_method",
404 "major_status": {
405 "status": 131072
406 },
407 "minor_status": {
408 "status": 1
409 }
410 }
411 )");
412 ASSERT_TRUE(expected.has_value());
413 EXPECT_EQ(actual, expected);
414 }
415
TEST(HttpAuthGSSAPITest,GetGssStatusValue_WithLibrary)416 TEST(HttpAuthGSSAPITest, GetGssStatusValue_WithLibrary) {
417 test::MockGSSAPILibrary library;
418 auto actual = GetGssStatusValue(&library, "my_method", GSS_S_BAD_NAME, 1);
419 auto expected = base::JSONReader::Read(R"(
420 {
421 "function": "my_method",
422 "major_status": {
423 "status": 131072,
424 "message": [ "Value: 131072, Type 1" ]
425 },
426 "minor_status": {
427 "status": 1,
428 "message": [ "Value: 1, Type 2" ]
429 }
430 }
431 )");
432 ASSERT_TRUE(expected.has_value());
433 EXPECT_EQ(actual, expected);
434 }
435
TEST(HttpAuthGSSAPITest,GetGssStatusValue_Multiline)436 TEST(HttpAuthGSSAPITest, GetGssStatusValue_Multiline) {
437 test::MockGSSAPILibrary library;
438 auto actual = GetGssStatusValue(
439 &library, "my_method",
440 static_cast<OM_uint32>(
441 test::MockGSSAPILibrary::DisplayStatusSpecials::MultiLine),
442 0);
443 auto expected = base::JSONReader::Read(R"(
444 {
445 "function": "my_method",
446 "major_status": {
447 "status": 128,
448 "message": [
449 "Line 1 for status 128",
450 "Line 2 for status 128",
451 "Line 3 for status 128",
452 "Line 4 for status 128",
453 "Line 5 for status 128"
454 ]
455 },
456 "minor_status": {
457 "status": 0
458 }
459 }
460 )");
461 ASSERT_TRUE(expected.has_value());
462 EXPECT_EQ(actual, expected);
463 }
464
TEST(HttpAuthGSSAPITest,GetGssStatusValue_InfiniteLines)465 TEST(HttpAuthGSSAPITest, GetGssStatusValue_InfiniteLines) {
466 test::MockGSSAPILibrary library;
467 auto actual = GetGssStatusValue(
468 &library, "my_method",
469 static_cast<OM_uint32>(
470 test::MockGSSAPILibrary::DisplayStatusSpecials::InfiniteLines),
471 0);
472 auto expected = base::JSONReader::Read(R"(
473 {
474 "function": "my_method",
475 "major_status": {
476 "status": 129,
477 "message": [
478 "Line 1 for status 129",
479 "Line 2 for status 129",
480 "Line 3 for status 129",
481 "Line 4 for status 129",
482 "Line 5 for status 129",
483 "Line 6 for status 129",
484 "Line 7 for status 129",
485 "Line 8 for status 129"
486 ]
487 },
488 "minor_status": {
489 "status": 0
490 }
491 }
492 )");
493 ASSERT_TRUE(expected.has_value());
494 EXPECT_EQ(actual, expected);
495 }
496
TEST(HttpAuthGSSAPITest,GetGssStatusValue_Failure)497 TEST(HttpAuthGSSAPITest, GetGssStatusValue_Failure) {
498 test::MockGSSAPILibrary library;
499 auto actual = GetGssStatusValue(
500 &library, "my_method",
501 static_cast<OM_uint32>(
502 test::MockGSSAPILibrary::DisplayStatusSpecials::Fail),
503 0);
504 auto expected = base::JSONReader::Read(R"(
505 {
506 "function": "my_method",
507 "major_status": {
508 "status": 130
509 },
510 "minor_status": {
511 "status": 0
512 }
513 }
514 )");
515 ASSERT_TRUE(expected.has_value());
516 EXPECT_EQ(actual, expected);
517 }
518
TEST(HttpAuthGSSAPITest,GetGssStatusValue_EmptyMessage)519 TEST(HttpAuthGSSAPITest, GetGssStatusValue_EmptyMessage) {
520 test::MockGSSAPILibrary library;
521 auto actual = GetGssStatusValue(
522 &library, "my_method",
523 static_cast<OM_uint32>(
524 test::MockGSSAPILibrary::DisplayStatusSpecials::EmptyMessage),
525 0);
526 auto expected = base::JSONReader::Read(R"(
527 {
528 "function": "my_method",
529 "major_status": {
530 "status": 131
531 },
532 "minor_status": {
533 "status": 0
534 }
535 }
536 )");
537 ASSERT_TRUE(expected.has_value());
538 EXPECT_EQ(actual, expected);
539 }
540
TEST(HttpAuthGSSAPITest,GetGssStatusValue_Misbehave)541 TEST(HttpAuthGSSAPITest, GetGssStatusValue_Misbehave) {
542 test::MockGSSAPILibrary library;
543 auto actual = GetGssStatusValue(
544 &library, "my_method",
545 static_cast<OM_uint32>(
546 test::MockGSSAPILibrary::DisplayStatusSpecials::UninitalizedBuffer),
547 0);
548 auto expected = base::JSONReader::Read(R"(
549 {
550 "function": "my_method",
551 "major_status": {
552 "status": 132
553 },
554 "minor_status": {
555 "status": 0
556 }
557 }
558 )");
559 ASSERT_TRUE(expected.has_value());
560 EXPECT_EQ(actual, expected);
561 }
562
TEST(HttpAuthGSSAPITest,GetGssStatusValue_NotUtf8)563 TEST(HttpAuthGSSAPITest, GetGssStatusValue_NotUtf8) {
564 test::MockGSSAPILibrary library;
565 auto actual = GetGssStatusValue(
566 &library, "my_method",
567 static_cast<OM_uint32>(
568 test::MockGSSAPILibrary::DisplayStatusSpecials::InvalidUtf8),
569 0);
570 auto expected = base::JSONReader::Read(R"(
571 {
572 "function": "my_method",
573 "major_status": {
574 "status": 133
575 },
576 "minor_status": {
577 "status": 0
578 }
579 }
580 )");
581 ASSERT_TRUE(expected.has_value());
582 EXPECT_EQ(actual, expected);
583 }
584
TEST(HttpAuthGSSAPITest,GetContextStateAsValue_ValidContext)585 TEST(HttpAuthGSSAPITest, GetContextStateAsValue_ValidContext) {
586 test::GssContextMockImpl context{"source_spn@somewhere",
587 "target_spn@somewhere.else",
588 /* lifetime_rec= */ 100,
589 *CHROME_GSS_SPNEGO_MECH_OID_DESC,
590 /* ctx_flags= */ 0,
591 /* locally_initiated= */ 1,
592 /* open= */ 0};
593 test::MockGSSAPILibrary library;
594 auto actual = GetContextStateAsValue(
595 &library, reinterpret_cast<const gss_ctx_id_t>(&context));
596 auto expected = base::JSONReader::Read(R"(
597 {
598 "source": {
599 "name": "source_spn@somewhere",
600 "type": {
601 "oid" : "<Empty OID>"
602 }
603 },
604 "target": {
605 "name": "target_spn@somewhere.else",
606 "type": {
607 "oid" : "<Empty OID>"
608 }
609 },
610 "lifetime": "100",
611 "mechanism": {
612 "oid": "<Empty OID>"
613 },
614 "flags": {
615 "value": "0x00000000",
616 "delegated": false,
617 "mutual": false
618 },
619 "open": false
620 }
621 )");
622 ASSERT_TRUE(expected.has_value());
623 EXPECT_EQ(actual, expected);
624 }
625
TEST(HttpAuthGSSAPITest,GetContextStateAsValue_NoContext)626 TEST(HttpAuthGSSAPITest, GetContextStateAsValue_NoContext) {
627 test::MockGSSAPILibrary library;
628 auto actual = GetContextStateAsValue(&library, GSS_C_NO_CONTEXT);
629 auto expected = base::JSONReader::Read(R"(
630 {
631 "error": {
632 "function": "<none>",
633 "major_status": {
634 "status": 524288
635 },
636 "minor_status": {
637 "status": 0
638 }
639 }
640 }
641 )");
642 ASSERT_TRUE(expected.has_value());
643 EXPECT_EQ(actual, expected);
644 }
645
646 } // namespace net
647