1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <list>
#include <set>
#include "base/basictypes.h"
#include "net/base/net_errors.h"
#include "net/http/http_auth_sspi_win.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
namespace {
void MatchDomainUserAfterSplit(const std::wstring& combined,
const std::wstring& expected_domain,
const std::wstring& expected_user) {
std::wstring actual_domain;
std::wstring actual_user;
SplitDomainAndUser(combined, &actual_domain, &actual_user);
EXPECT_EQ(expected_domain, actual_domain);
EXPECT_EQ(expected_user, actual_user);
}
class MockSSPILibrary : public SSPILibrary {
public:
MockSSPILibrary() {}
virtual ~MockSSPILibrary() {}
virtual SECURITY_STATUS AcquireCredentialsHandle(LPWSTR pszPrincipal,
LPWSTR pszPackage,
unsigned long fCredentialUse,
void* pvLogonId,
void* pvAuthData,
SEC_GET_KEY_FN pGetKeyFn,
void* pvGetKeyArgument,
PCredHandle phCredential,
PTimeStamp ptsExpiry) {
ADD_FAILURE();
return ERROR_CALL_NOT_IMPLEMENTED;
}
virtual SECURITY_STATUS InitializeSecurityContext(PCredHandle phCredential,
PCtxtHandle phContext,
SEC_WCHAR* pszTargetName,
unsigned long fContextReq,
unsigned long Reserved1,
unsigned long TargetDataRep,
PSecBufferDesc pInput,
unsigned long Reserved2,
PCtxtHandle phNewContext,
PSecBufferDesc pOutput,
unsigned long* contextAttr,
PTimeStamp ptsExpiry) {
ADD_FAILURE();
return ERROR_CALL_NOT_IMPLEMENTED;
}
virtual SECURITY_STATUS QuerySecurityPackageInfo(LPWSTR pszPackageName,
PSecPkgInfoW *pkgInfo) {
ADD_FAILURE();
return ERROR_CALL_NOT_IMPLEMENTED;
}
virtual SECURITY_STATUS FreeCredentialsHandle(PCredHandle phCredential) {
ADD_FAILURE();
return ERROR_CALL_NOT_IMPLEMENTED;
}
virtual SECURITY_STATUS DeleteSecurityContext(PCtxtHandle phContext) {
ADD_FAILURE();
return ERROR_CALL_NOT_IMPLEMENTED;
}
virtual SECURITY_STATUS FreeContextBuffer(PVOID pvContextBuffer) {
ADD_FAILURE();
return ERROR_CALL_NOT_IMPLEMENTED;
}
};
class ExpectedPackageQuerySSPILibrary : public MockSSPILibrary {
public:
ExpectedPackageQuerySSPILibrary() {}
virtual ~ExpectedPackageQuerySSPILibrary() {
EXPECT_TRUE(expected_package_queries_.empty());
EXPECT_TRUE(expected_freed_packages_.empty());
}
// Establishes an expectation for a |QuerySecurityPackageInfo()| call.
//
// Each expectation established by |ExpectSecurityQueryPackageInfo()| must be
// matched by a call to |QuerySecurityPackageInfo()| during the lifetime of
// the MockSSPILibrary. The |expected_package| argument must equal the
// |*pszPackageName| argument to |QuerySecurityPackageInfo()| for there to be
// a match. The expectations also establish an explicit ordering.
//
// For example, this sequence will be successful.
// ExpectedPackageQuerySSPILibrary lib;
// lib.ExpectQuerySecurityPackageInfo(L"NTLM", ...)
// lib.ExpectQuerySecurityPackageInfo(L"Negotiate", ...)
// lib.QuerySecurityPackageInfo(L"NTLM", ...)
// lib.QuerySecurityPackageInfo(L"Negotiate", ...)
//
// This sequence will fail since the queries do not occur in the order
// established by the expectations.
// ExpectedPackageQuerySSPILibrary lib;
// lib.ExpectQuerySecurityPackageInfo(L"NTLM", ...)
// lib.ExpectQuerySecurityPackageInfo(L"Negotiate", ...)
// lib.QuerySecurityPackageInfo(L"Negotiate", ...)
// lib.QuerySecurityPackageInfo(L"NTLM", ...)
//
// This sequence will fail because there were not enough queries.
// ExpectedPackageQuerySSPILibrary lib;
// lib.ExpectQuerySecurityPackageInfo(L"NTLM", ...)
// lib.ExpectQuerySecurityPackageInfo(L"Negotiate", ...)
// lib.QuerySecurityPackageInfo(L"NTLM", ...)
//
// |response_code| is used as the return value for
// |QuerySecurityPackageInfo()|. If |response_code| is SEC_E_OK,
// an expectation is also set for a call to |FreeContextBuffer()| after
// the matching |QuerySecurityPackageInfo()| is called.
//
// |package_info| is assigned to |*pkgInfo| in |QuerySecurityPackageInfo|.
// The lifetime of |*package_info| should last at least until the matching
// |QuerySecurityPackageInfo()| is called.
void ExpectQuerySecurityPackageInfo(const std::wstring& expected_package,
SECURITY_STATUS response_code,
PSecPkgInfoW package_info) {
PackageQuery package_query = {expected_package, response_code,
package_info};
expected_package_queries_.push_back(package_query);
}
// Queries security package information. This must be an expected call,
// see |ExpectQuerySecurityPackageInfo()| for more information.
virtual SECURITY_STATUS QuerySecurityPackageInfo(LPWSTR pszPackageName,
PSecPkgInfoW* pkgInfo) {
EXPECT_TRUE(!expected_package_queries_.empty());
PackageQuery package_query = expected_package_queries_.front();
expected_package_queries_.pop_front();
std::wstring actual_package(pszPackageName);
EXPECT_EQ(package_query.expected_package, actual_package);
*pkgInfo = package_query.package_info;
if (package_query.response_code == SEC_E_OK)
expected_freed_packages_.insert(package_query.package_info);
return package_query.response_code;
}
// Frees the context buffer. This should be called after a successful call
// of |QuerySecurityPackageInfo()|.
virtual SECURITY_STATUS FreeContextBuffer(PVOID pvContextBuffer) {
PSecPkgInfoW package_info = static_cast<PSecPkgInfoW>(pvContextBuffer);
std::set<PSecPkgInfoW>::iterator it = expected_freed_packages_.find(
package_info);
EXPECT_TRUE(it != expected_freed_packages_.end());
expected_freed_packages_.erase(it);
return SEC_E_OK;
}
private:
struct PackageQuery {
std::wstring expected_package;
SECURITY_STATUS response_code;
PSecPkgInfoW package_info;
};
// expected_package_queries contains an ordered list of expected
// |QuerySecurityPackageInfo()| calls and the return values for those
// calls.
std::list<PackageQuery> expected_package_queries_;
// Set of packages which should be freed.
std::set<PSecPkgInfoW> expected_freed_packages_;
};
} // namespace
TEST(HttpAuthSSPITest, SplitUserAndDomain) {
MatchDomainUserAfterSplit(L"foobar", L"", L"foobar");
MatchDomainUserAfterSplit(L"FOO\\bar", L"FOO", L"bar");
}
TEST(HttpAuthSSPITest, DetermineMaxTokenLength_Normal) {
SecPkgInfoW package_info;
memset(&package_info, 0x0, sizeof(package_info));
package_info.cbMaxToken = 1337;
ExpectedPackageQuerySSPILibrary mock_library;
mock_library.ExpectQuerySecurityPackageInfo(L"NTLM", SEC_E_OK, &package_info);
ULONG max_token_length = 100;
int rv = DetermineMaxTokenLength(&mock_library, L"NTLM", &max_token_length);
EXPECT_EQ(OK, rv);
EXPECT_EQ(1337, max_token_length);
}
TEST(HttpAuthSSPITest, DetermineMaxTokenLength_InvalidPackage) {
ExpectedPackageQuerySSPILibrary mock_library;
mock_library.ExpectQuerySecurityPackageInfo(L"Foo", SEC_E_SECPKG_NOT_FOUND,
NULL);
ULONG max_token_length = 100;
int rv = DetermineMaxTokenLength(&mock_library, L"Foo", &max_token_length);
EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, rv);
// |DetermineMaxTokenLength()| interface states that |max_token_length| should
// not change on failure.
EXPECT_EQ(100, max_token_length);
}
} // namespace net
|