http_auth_sspi_win_unittest.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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"
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_auth_sspi_win.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/mock_sspi_library_win.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MatchDomainUserAfterSplit(const std::wstring& combined,
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const std::wstring& expected_domain,
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const std::wstring& expected_user) {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring actual_domain;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring actual_user;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SplitDomainAndUser(combined, &actual_domain, &actual_user);
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(expected_domain, actual_domain);
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(expected_user, actual_user);
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const ULONG kMaxTokenLength = 100;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(HttpAuthSSPITest, SplitUserAndDomain) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MatchDomainUserAfterSplit(L"foobar", L"", L"foobar");
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MatchDomainUserAfterSplit(L"FOO\\bar", L"FOO", L"bar");
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(HttpAuthSSPITest, DetermineMaxTokenLength_Normal) {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecPkgInfoW package_info;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&package_info, 0x0, sizeof(package_info));
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  package_info.cbMaxToken = 1337;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MockSSPILibrary mock_library;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mock_library.ExpectQuerySecurityPackageInfo(L"NTLM", SEC_E_OK, &package_info);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULONG max_token_length = kMaxTokenLength;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rv = DetermineMaxTokenLength(&mock_library, L"NTLM", &max_token_length);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(OK, rv);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1337, max_token_length);
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(HttpAuthSSPITest, DetermineMaxTokenLength_InvalidPackage) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MockSSPILibrary mock_library;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mock_library.ExpectQuerySecurityPackageInfo(L"Foo", SEC_E_SECPKG_NOT_FOUND,
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              NULL);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULONG max_token_length = kMaxTokenLength;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rv = DetermineMaxTokenLength(&mock_library, L"Foo", &max_token_length);
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, rv);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |DetermineMaxTokenLength()| interface states that |max_token_length| should
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // not change on failure.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(100, max_token_length);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(HttpAuthSSPITest, ParseChallenge_FirstRound) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The first round should just consist of an unadorned "Negotiate" header.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MockSSPILibrary mock_library;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpAuthSSPI auth_sspi(&mock_library, "Negotiate",
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         NEGOSSP_NAME, kMaxTokenLength);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string challenge_text = "Negotiate";
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpAuth::ChallengeTokenizer challenge(challenge_text.begin(),
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         challenge_text.end());
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            auth_sspi.ParseChallenge(&challenge));
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(HttpAuthSSPITest, ParseChallenge_TwoRounds) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The first round should just have "Negotiate", and the second round should
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // have a valid base64 token associated with it.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MockSSPILibrary mock_library;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpAuthSSPI auth_sspi(&mock_library, "Negotiate",
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         NEGOSSP_NAME, kMaxTokenLength);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string first_challenge_text = "Negotiate";
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpAuth::ChallengeTokenizer first_challenge(first_challenge_text.begin(),
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               first_challenge_text.end());
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            auth_sspi.ParseChallenge(&first_challenge));
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Generate an auth token and create another thing.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string auth_token;
85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_EQ(OK, auth_sspi.GenerateAuthToken(NULL, "HTTP/intranet.google.com",
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            &auth_token));
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string second_challenge_text = "Negotiate Zm9vYmFy";
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpAuth::ChallengeTokenizer second_challenge(second_challenge_text.begin(),
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                second_challenge_text.end());
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            auth_sspi.ParseChallenge(&second_challenge));
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(HttpAuthSSPITest, ParseChallenge_UnexpectedTokenFirstRound) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the first round challenge has an additional authentication token, it
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // should be treated as an invalid challenge from the server.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MockSSPILibrary mock_library;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpAuthSSPI auth_sspi(&mock_library, "Negotiate",
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         NEGOSSP_NAME, kMaxTokenLength);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string challenge_text = "Negotiate Zm9vYmFy";
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpAuth::ChallengeTokenizer challenge(challenge_text.begin(),
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         challenge_text.end());
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            auth_sspi.ParseChallenge(&challenge));
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(HttpAuthSSPITest, ParseChallenge_MissingTokenSecondRound) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If a later-round challenge is simply "Negotiate", it should be treated as
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // an authentication challenge rejection from the server or proxy.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MockSSPILibrary mock_library;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpAuthSSPI auth_sspi(&mock_library, "Negotiate",
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         NEGOSSP_NAME, kMaxTokenLength);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string first_challenge_text = "Negotiate";
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpAuth::ChallengeTokenizer first_challenge(first_challenge_text.begin(),
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               first_challenge_text.end());
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            auth_sspi.ParseChallenge(&first_challenge));
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string auth_token;
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_EQ(OK, auth_sspi.GenerateAuthToken(NULL, "HTTP/intranet.google.com",
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            &auth_token));
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string second_challenge_text = "Negotiate";
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpAuth::ChallengeTokenizer second_challenge(second_challenge_text.begin(),
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                second_challenge_text.end());
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            auth_sspi.ParseChallenge(&second_challenge));
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(HttpAuthSSPITest, ParseChallenge_NonBase64EncodedToken) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If a later-round challenge has an invalid base64 encoded token, it should
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be treated as an invalid challenge.
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MockSSPILibrary mock_library;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpAuthSSPI auth_sspi(&mock_library, "Negotiate",
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         NEGOSSP_NAME, kMaxTokenLength);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string first_challenge_text = "Negotiate";
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpAuth::ChallengeTokenizer first_challenge(first_challenge_text.begin(),
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               first_challenge_text.end());
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            auth_sspi.ParseChallenge(&first_challenge));
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string auth_token;
143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_EQ(OK, auth_sspi.GenerateAuthToken(NULL, "HTTP/intranet.google.com",
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            &auth_token));
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string second_challenge_text = "Negotiate =happyjoy=";
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpAuth::ChallengeTokenizer second_challenge(second_challenge_text.begin(),
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                second_challenge_text.end());
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            auth_sspi.ParseChallenge(&second_challenge));
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
153