Home | History | Annotate | Download | only in http
      1 // Copyright (c) 2010 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 "base/basictypes.h"
      6 #include "net/base/net_errors.h"
      7 #include "net/http/http_auth_sspi_win.h"
      8 #include "net/http/mock_sspi_library_win.h"
      9 #include "testing/gtest/include/gtest/gtest.h"
     10 
     11 namespace net {
     12 
     13 namespace {
     14 
     15 void MatchDomainUserAfterSplit(const std::wstring& combined,
     16                                const std::wstring& expected_domain,
     17                                const std::wstring& expected_user) {
     18   std::wstring actual_domain;
     19   std::wstring actual_user;
     20   SplitDomainAndUser(combined, &actual_domain, &actual_user);
     21   EXPECT_EQ(expected_domain, actual_domain);
     22   EXPECT_EQ(expected_user, actual_user);
     23 }
     24 
     25 const ULONG kMaxTokenLength = 100;
     26 
     27 }  // namespace
     28 
     29 TEST(HttpAuthSSPITest, SplitUserAndDomain) {
     30   MatchDomainUserAfterSplit(L"foobar", L"", L"foobar");
     31   MatchDomainUserAfterSplit(L"FOO\\bar", L"FOO", L"bar");
     32 }
     33 
     34 TEST(HttpAuthSSPITest, DetermineMaxTokenLength_Normal) {
     35   SecPkgInfoW package_info;
     36   memset(&package_info, 0x0, sizeof(package_info));
     37   package_info.cbMaxToken = 1337;
     38 
     39   MockSSPILibrary mock_library;
     40   mock_library.ExpectQuerySecurityPackageInfo(L"NTLM", SEC_E_OK, &package_info);
     41   ULONG max_token_length = kMaxTokenLength;
     42   int rv = DetermineMaxTokenLength(&mock_library, L"NTLM", &max_token_length);
     43   EXPECT_EQ(OK, rv);
     44   EXPECT_EQ(1337, max_token_length);
     45 }
     46 
     47 TEST(HttpAuthSSPITest, DetermineMaxTokenLength_InvalidPackage) {
     48   MockSSPILibrary mock_library;
     49   mock_library.ExpectQuerySecurityPackageInfo(L"Foo", SEC_E_SECPKG_NOT_FOUND,
     50                                               NULL);
     51   ULONG max_token_length = kMaxTokenLength;
     52   int rv = DetermineMaxTokenLength(&mock_library, L"Foo", &max_token_length);
     53   EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, rv);
     54   // |DetermineMaxTokenLength()| interface states that |max_token_length| should
     55   // not change on failure.
     56   EXPECT_EQ(100, max_token_length);
     57 }
     58 
     59 TEST(HttpAuthSSPITest, ParseChallenge_FirstRound) {
     60   // The first round should just consist of an unadorned "Negotiate" header.
     61   MockSSPILibrary mock_library;
     62   HttpAuthSSPI auth_sspi(&mock_library, "Negotiate",
     63                          NEGOSSP_NAME, kMaxTokenLength);
     64   std::string challenge_text = "Negotiate";
     65   HttpAuth::ChallengeTokenizer challenge(challenge_text.begin(),
     66                                          challenge_text.end());
     67   EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
     68             auth_sspi.ParseChallenge(&challenge));
     69 }
     70 
     71 TEST(HttpAuthSSPITest, ParseChallenge_TwoRounds) {
     72   // The first round should just have "Negotiate", and the second round should
     73   // have a valid base64 token associated with it.
     74   MockSSPILibrary mock_library;
     75   HttpAuthSSPI auth_sspi(&mock_library, "Negotiate",
     76                          NEGOSSP_NAME, kMaxTokenLength);
     77   std::string first_challenge_text = "Negotiate";
     78   HttpAuth::ChallengeTokenizer first_challenge(first_challenge_text.begin(),
     79                                                first_challenge_text.end());
     80   EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
     81             auth_sspi.ParseChallenge(&first_challenge));
     82 
     83   // Generate an auth token and create another thing.
     84   std::string auth_token;
     85   EXPECT_EQ(OK, auth_sspi.GenerateAuthToken(NULL, NULL,
     86                                             L"HTTP/intranet.google.com",
     87                                             &auth_token));
     88 
     89   std::string second_challenge_text = "Negotiate Zm9vYmFy";
     90   HttpAuth::ChallengeTokenizer second_challenge(second_challenge_text.begin(),
     91                                                 second_challenge_text.end());
     92   EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
     93             auth_sspi.ParseChallenge(&second_challenge));
     94 }
     95 
     96 TEST(HttpAuthSSPITest, ParseChallenge_UnexpectedTokenFirstRound) {
     97   // If the first round challenge has an additional authentication token, it
     98   // should be treated as an invalid challenge from the server.
     99   MockSSPILibrary mock_library;
    100   HttpAuthSSPI auth_sspi(&mock_library, "Negotiate",
    101                          NEGOSSP_NAME, kMaxTokenLength);
    102   std::string challenge_text = "Negotiate Zm9vYmFy";
    103   HttpAuth::ChallengeTokenizer challenge(challenge_text.begin(),
    104                                          challenge_text.end());
    105   EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
    106             auth_sspi.ParseChallenge(&challenge));
    107 }
    108 
    109 TEST(HttpAuthSSPITest, ParseChallenge_MissingTokenSecondRound) {
    110   // If a later-round challenge is simply "Negotiate", it should be treated as
    111   // an authentication challenge rejection from the server or proxy.
    112   MockSSPILibrary mock_library;
    113   HttpAuthSSPI auth_sspi(&mock_library, "Negotiate",
    114                          NEGOSSP_NAME, kMaxTokenLength);
    115   std::string first_challenge_text = "Negotiate";
    116   HttpAuth::ChallengeTokenizer first_challenge(first_challenge_text.begin(),
    117                                                first_challenge_text.end());
    118   EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
    119             auth_sspi.ParseChallenge(&first_challenge));
    120 
    121   std::string auth_token;
    122   EXPECT_EQ(OK, auth_sspi.GenerateAuthToken(NULL, NULL,
    123                                             L"HTTP/intranet.google.com",
    124                                             &auth_token));
    125   std::string second_challenge_text = "Negotiate";
    126   HttpAuth::ChallengeTokenizer second_challenge(second_challenge_text.begin(),
    127                                                 second_challenge_text.end());
    128   EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
    129             auth_sspi.ParseChallenge(&second_challenge));
    130 }
    131 
    132 TEST(HttpAuthSSPITest, ParseChallenge_NonBase64EncodedToken) {
    133   // If a later-round challenge has an invalid base64 encoded token, it should
    134   // be treated as an invalid challenge.
    135   MockSSPILibrary mock_library;
    136   HttpAuthSSPI auth_sspi(&mock_library, "Negotiate",
    137                          NEGOSSP_NAME, kMaxTokenLength);
    138   std::string first_challenge_text = "Negotiate";
    139   HttpAuth::ChallengeTokenizer first_challenge(first_challenge_text.begin(),
    140                                                first_challenge_text.end());
    141   EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
    142             auth_sspi.ParseChallenge(&first_challenge));
    143 
    144   std::string auth_token;
    145   EXPECT_EQ(OK, auth_sspi.GenerateAuthToken(NULL, NULL,
    146                                             L"HTTP/intranet.google.com",
    147                                             &auth_token));
    148   std::string second_challenge_text = "Negotiate =happyjoy=";
    149   HttpAuth::ChallengeTokenizer second_challenge(second_challenge_text.begin(),
    150                                                 second_challenge_text.end());
    151   EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
    152             auth_sspi.ParseChallenge(&second_challenge));
    153 }
    154 
    155 }  // namespace net
    156