Home | History | Annotate | Download | only in http
      1 // Copyright (c) 2011 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, L"HTTP/intranet.google.com",
     86                                             &auth_token));
     87 
     88   std::string second_challenge_text = "Negotiate Zm9vYmFy";
     89   HttpAuth::ChallengeTokenizer second_challenge(second_challenge_text.begin(),
     90                                                 second_challenge_text.end());
     91   EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
     92             auth_sspi.ParseChallenge(&second_challenge));
     93 }
     94 
     95 TEST(HttpAuthSSPITest, ParseChallenge_UnexpectedTokenFirstRound) {
     96   // If the first round challenge has an additional authentication token, it
     97   // should be treated as an invalid challenge from the server.
     98   MockSSPILibrary mock_library;
     99   HttpAuthSSPI auth_sspi(&mock_library, "Negotiate",
    100                          NEGOSSP_NAME, kMaxTokenLength);
    101   std::string challenge_text = "Negotiate Zm9vYmFy";
    102   HttpAuth::ChallengeTokenizer challenge(challenge_text.begin(),
    103                                          challenge_text.end());
    104   EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
    105             auth_sspi.ParseChallenge(&challenge));
    106 }
    107 
    108 TEST(HttpAuthSSPITest, ParseChallenge_MissingTokenSecondRound) {
    109   // If a later-round challenge is simply "Negotiate", it should be treated as
    110   // an authentication challenge rejection from the server or proxy.
    111   MockSSPILibrary mock_library;
    112   HttpAuthSSPI auth_sspi(&mock_library, "Negotiate",
    113                          NEGOSSP_NAME, kMaxTokenLength);
    114   std::string first_challenge_text = "Negotiate";
    115   HttpAuth::ChallengeTokenizer first_challenge(first_challenge_text.begin(),
    116                                                first_challenge_text.end());
    117   EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
    118             auth_sspi.ParseChallenge(&first_challenge));
    119 
    120   std::string auth_token;
    121   EXPECT_EQ(OK, auth_sspi.GenerateAuthToken(NULL, L"HTTP/intranet.google.com",
    122                                             &auth_token));
    123   std::string second_challenge_text = "Negotiate";
    124   HttpAuth::ChallengeTokenizer second_challenge(second_challenge_text.begin(),
    125                                                 second_challenge_text.end());
    126   EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
    127             auth_sspi.ParseChallenge(&second_challenge));
    128 }
    129 
    130 TEST(HttpAuthSSPITest, ParseChallenge_NonBase64EncodedToken) {
    131   // If a later-round challenge has an invalid base64 encoded token, it should
    132   // be treated as an invalid challenge.
    133   MockSSPILibrary mock_library;
    134   HttpAuthSSPI auth_sspi(&mock_library, "Negotiate",
    135                          NEGOSSP_NAME, kMaxTokenLength);
    136   std::string first_challenge_text = "Negotiate";
    137   HttpAuth::ChallengeTokenizer first_challenge(first_challenge_text.begin(),
    138                                                first_challenge_text.end());
    139   EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
    140             auth_sspi.ParseChallenge(&first_challenge));
    141 
    142   std::string auth_token;
    143   EXPECT_EQ(OK, auth_sspi.GenerateAuthToken(NULL, L"HTTP/intranet.google.com",
    144                                             &auth_token));
    145   std::string second_challenge_text = "Negotiate =happyjoy=";
    146   HttpAuth::ChallengeTokenizer second_challenge(second_challenge_text.begin(),
    147                                                 second_challenge_text.end());
    148   EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
    149             auth_sspi.ParseChallenge(&second_challenge));
    150 }
    151 
    152 }  // namespace net
    153