15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h" 7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/http/http_auth_challenge_tokenizer.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_auth_sspi_win.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/mock_sspi_library_win.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MatchDomainUserAfterSplit(const std::wstring& combined, 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring& expected_domain, 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring& expected_user) { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::wstring actual_domain; 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::wstring actual_user; 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SplitDomainAndUser(combined, &actual_domain, &actual_user); 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(expected_domain, actual_domain); 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(expected_user, actual_user); 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const ULONG kMaxTokenLength = 100; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(HttpAuthSSPITest, SplitUserAndDomain) { 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MatchDomainUserAfterSplit(L"foobar", L"", L"foobar"); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MatchDomainUserAfterSplit(L"FOO\\bar", L"FOO", L"bar"); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(HttpAuthSSPITest, DetermineMaxTokenLength_Normal) { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SecPkgInfoW package_info; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&package_info, 0x0, sizeof(package_info)); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) package_info.cbMaxToken = 1337; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MockSSPILibrary mock_library; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_library.ExpectQuerySecurityPackageInfo(L"NTLM", SEC_E_OK, &package_info); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ULONG max_token_length = kMaxTokenLength; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = DetermineMaxTokenLength(&mock_library, L"NTLM", &max_token_length); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(OK, rv); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(1337, max_token_length); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(HttpAuthSSPITest, DetermineMaxTokenLength_InvalidPackage) { 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MockSSPILibrary mock_library; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_library.ExpectQuerySecurityPackageInfo(L"Foo", SEC_E_SECPKG_NOT_FOUND, 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ULONG max_token_length = kMaxTokenLength; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = DetermineMaxTokenLength(&mock_library, L"Foo", &max_token_length); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, rv); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |DetermineMaxTokenLength()| interface states that |max_token_length| should 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // not change on failure. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(100, max_token_length); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(HttpAuthSSPITest, ParseChallenge_FirstRound) { 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The first round should just consist of an unadorned "Negotiate" header. 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MockSSPILibrary mock_library; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuthSSPI auth_sspi(&mock_library, "Negotiate", 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NEGOSSP_NAME, kMaxTokenLength); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string challenge_text = "Negotiate"; 66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HttpAuthChallengeTokenizer challenge(challenge_text.begin(), 67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) challenge_text.end()); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT, 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_sspi.ParseChallenge(&challenge)); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(HttpAuthSSPITest, ParseChallenge_TwoRounds) { 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The first round should just have "Negotiate", and the second round should 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // have a valid base64 token associated with it. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MockSSPILibrary mock_library; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuthSSPI auth_sspi(&mock_library, "Negotiate", 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NEGOSSP_NAME, kMaxTokenLength); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string first_challenge_text = "Negotiate"; 79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HttpAuthChallengeTokenizer first_challenge(first_challenge_text.begin(), 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) first_challenge_text.end()); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT, 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_sspi.ParseChallenge(&first_challenge)); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Generate an auth token and create another thing. 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string auth_token; 86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ(OK, auth_sspi.GenerateAuthToken(NULL, "HTTP/intranet.google.com", 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &auth_token)); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string second_challenge_text = "Negotiate Zm9vYmFy"; 90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HttpAuthChallengeTokenizer second_challenge(second_challenge_text.begin(), 91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) second_challenge_text.end()); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT, 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_sspi.ParseChallenge(&second_challenge)); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(HttpAuthSSPITest, ParseChallenge_UnexpectedTokenFirstRound) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the first round challenge has an additional authentication token, it 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // should be treated as an invalid challenge from the server. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MockSSPILibrary mock_library; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuthSSPI auth_sspi(&mock_library, "Negotiate", 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NEGOSSP_NAME, kMaxTokenLength); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string challenge_text = "Negotiate Zm9vYmFy"; 103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HttpAuthChallengeTokenizer challenge(challenge_text.begin(), 104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) challenge_text.end()); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID, 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_sspi.ParseChallenge(&challenge)); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(HttpAuthSSPITest, ParseChallenge_MissingTokenSecondRound) { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If a later-round challenge is simply "Negotiate", it should be treated as 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // an authentication challenge rejection from the server or proxy. 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MockSSPILibrary mock_library; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuthSSPI auth_sspi(&mock_library, "Negotiate", 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NEGOSSP_NAME, kMaxTokenLength); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string first_challenge_text = "Negotiate"; 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HttpAuthChallengeTokenizer first_challenge(first_challenge_text.begin(), 117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) first_challenge_text.end()); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT, 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_sspi.ParseChallenge(&first_challenge)); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string auth_token; 122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ(OK, auth_sspi.GenerateAuthToken(NULL, "HTTP/intranet.google.com", 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &auth_token)); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string second_challenge_text = "Negotiate"; 125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HttpAuthChallengeTokenizer second_challenge(second_challenge_text.begin(), 126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) second_challenge_text.end()); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT, 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_sspi.ParseChallenge(&second_challenge)); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(HttpAuthSSPITest, ParseChallenge_NonBase64EncodedToken) { 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If a later-round challenge has an invalid base64 encoded token, it should 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // be treated as an invalid challenge. 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MockSSPILibrary mock_library; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuthSSPI auth_sspi(&mock_library, "Negotiate", 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NEGOSSP_NAME, kMaxTokenLength); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string first_challenge_text = "Negotiate"; 138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HttpAuthChallengeTokenizer first_challenge(first_challenge_text.begin(), 139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) first_challenge_text.end()); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT, 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_sspi.ParseChallenge(&first_challenge)); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string auth_token; 144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ(OK, auth_sspi.GenerateAuthToken(NULL, "HTTP/intranet.google.com", 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &auth_token)); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string second_challenge_text = "Negotiate =happyjoy="; 147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HttpAuthChallengeTokenizer second_challenge(second_challenge_text.begin(), 148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) second_challenge_text.end()); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID, 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_sspi.ParseChallenge(&second_challenge)); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 154