Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / http / http_auth_gssapi_posix_unittest.cc
blob79a248f893dcf8bc720edc759008674d8df53870
1 // Copyright (c) 2012 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.
5 #include "net/http/http_auth_gssapi_posix.h"
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/native_library.h"
11 #include "net/base/net_errors.h"
12 #include "net/http/http_auth_challenge_tokenizer.h"
13 #include "net/http/mock_gssapi_library_posix.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 namespace net {
18 namespace {
20 // gss_buffer_t helpers.
21 void ClearBuffer(gss_buffer_t dest) {
22 if (!dest)
23 return;
24 dest->length = 0;
25 delete [] reinterpret_cast<char*>(dest->value);
26 dest->value = NULL;
29 void SetBuffer(gss_buffer_t dest, const void* src, size_t length) {
30 if (!dest)
31 return;
32 ClearBuffer(dest);
33 if (!src)
34 return;
35 dest->length = length;
36 if (length) {
37 dest->value = new char[length];
38 memcpy(dest->value, src, length);
42 void CopyBuffer(gss_buffer_t dest, const gss_buffer_t src) {
43 if (!dest)
44 return;
45 ClearBuffer(dest);
46 if (!src)
47 return;
48 SetBuffer(dest, src->value, src->length);
51 const char kInitialAuthResponse[] = "Mary had a little lamb";
53 void EstablishInitialContext(test::MockGSSAPILibrary* library) {
54 test::GssContextMockImpl context_info(
55 "localhost", // Source name
56 "example.com", // Target name
57 23, // Lifetime
58 *CHROME_GSS_SPNEGO_MECH_OID_DESC, // Mechanism
59 0, // Context flags
60 1, // Locally initiated
61 0); // Open
62 gss_buffer_desc in_buffer = {0, NULL};
63 gss_buffer_desc out_buffer = {arraysize(kInitialAuthResponse),
64 const_cast<char*>(kInitialAuthResponse)};
65 library->ExpectSecurityContext(
66 "Negotiate",
67 GSS_S_CONTINUE_NEEDED,
69 context_info,
70 in_buffer,
71 out_buffer);
74 void UnexpectedCallback(int result) {
75 // At present getting tokens from gssapi is fully synchronous, so the callback
76 // should never be called.
77 ADD_FAILURE();
80 } // namespace
82 TEST(HttpAuthGSSAPIPOSIXTest, GSSAPIStartup) {
83 // TODO(ahendrickson): Manipulate the libraries and paths to test each of the
84 // libraries we expect, and also whether or not they have the interface
85 // functions we want.
86 scoped_ptr<GSSAPILibrary> gssapi(new GSSAPISharedLibrary(std::string()));
87 DCHECK(gssapi.get());
88 EXPECT_TRUE(gssapi.get()->Init());
91 #if defined(DLOPEN_KERBEROS)
92 TEST(HttpAuthGSSAPIPOSIXTest, GSSAPILoadCustomLibrary) {
93 scoped_ptr<GSSAPILibrary> gssapi(
94 new GSSAPISharedLibrary("/this/library/does/not/exist"));
95 EXPECT_FALSE(gssapi.get()->Init());
97 #endif // defined(DLOPEN_KERBEROS)
99 TEST(HttpAuthGSSAPIPOSIXTest, GSSAPICycle) {
100 scoped_ptr<test::MockGSSAPILibrary> mock_library(new test::MockGSSAPILibrary);
101 DCHECK(mock_library.get());
102 mock_library->Init();
103 const char kAuthResponse[] = "Mary had a little lamb";
104 test::GssContextMockImpl context1(
105 "localhost", // Source name
106 "example.com", // Target name
107 23, // Lifetime
108 *CHROME_GSS_SPNEGO_MECH_OID_DESC, // Mechanism
109 0, // Context flags
110 1, // Locally initiated
111 0); // Open
112 test::GssContextMockImpl context2(
113 "localhost", // Source name
114 "example.com", // Target name
115 23, // Lifetime
116 *CHROME_GSS_SPNEGO_MECH_OID_DESC, // Mechanism
117 0, // Context flags
118 1, // Locally initiated
119 1); // Open
120 test::MockGSSAPILibrary::SecurityContextQuery queries[] = {
121 test::MockGSSAPILibrary::SecurityContextQuery(
122 "Negotiate", // Package name
123 GSS_S_CONTINUE_NEEDED, // Major response code
124 0, // Minor response code
125 context1, // Context
126 NULL, // Expected input token
127 kAuthResponse), // Output token
128 test::MockGSSAPILibrary::SecurityContextQuery(
129 "Negotiate", // Package name
130 GSS_S_COMPLETE, // Major response code
131 0, // Minor response code
132 context2, // Context
133 kAuthResponse, // Expected input token
134 kAuthResponse) // Output token
137 for (size_t i = 0; i < arraysize(queries); ++i) {
138 mock_library->ExpectSecurityContext(queries[i].expected_package,
139 queries[i].response_code,
140 queries[i].minor_response_code,
141 queries[i].context_info,
142 queries[i].expected_input_token,
143 queries[i].output_token);
146 OM_uint32 major_status = 0;
147 OM_uint32 minor_status = 0;
148 gss_cred_id_t initiator_cred_handle = NULL;
149 gss_ctx_id_t context_handle = NULL;
150 gss_name_t target_name = NULL;
151 gss_OID mech_type = NULL;
152 OM_uint32 req_flags = 0;
153 OM_uint32 time_req = 25;
154 gss_channel_bindings_t input_chan_bindings = NULL;
155 gss_buffer_desc input_token = { 0, NULL };
156 gss_OID actual_mech_type= NULL;
157 gss_buffer_desc output_token = { 0, NULL };
158 OM_uint32 ret_flags = 0;
159 OM_uint32 time_rec = 0;
160 for (size_t i = 0; i < arraysize(queries); ++i) {
161 major_status = mock_library->init_sec_context(&minor_status,
162 initiator_cred_handle,
163 &context_handle,
164 target_name,
165 mech_type,
166 req_flags,
167 time_req,
168 input_chan_bindings,
169 &input_token,
170 &actual_mech_type,
171 &output_token,
172 &ret_flags,
173 &time_rec);
174 EXPECT_EQ(queries[i].response_code, major_status);
175 CopyBuffer(&input_token, &output_token);
176 ClearBuffer(&output_token);
178 ClearBuffer(&input_token);
179 major_status = mock_library->delete_sec_context(&minor_status,
180 &context_handle,
181 GSS_C_NO_BUFFER);
182 EXPECT_EQ(static_cast<OM_uint32>(GSS_S_COMPLETE), major_status);
185 TEST(HttpAuthGSSAPITest, ParseChallenge_FirstRound) {
186 // The first round should just consist of an unadorned "Negotiate" header.
187 test::MockGSSAPILibrary mock_library;
188 HttpAuthGSSAPI auth_gssapi(&mock_library, "Negotiate",
189 CHROME_GSS_SPNEGO_MECH_OID_DESC);
190 std::string challenge_text = "Negotiate";
191 HttpAuthChallengeTokenizer challenge(challenge_text.begin(),
192 challenge_text.end());
193 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
194 auth_gssapi.ParseChallenge(&challenge));
197 TEST(HttpAuthGSSAPITest, ParseChallenge_TwoRounds) {
198 // The first round should just have "Negotiate", and the second round should
199 // have a valid base64 token associated with it.
200 test::MockGSSAPILibrary mock_library;
201 HttpAuthGSSAPI auth_gssapi(&mock_library, "Negotiate",
202 CHROME_GSS_SPNEGO_MECH_OID_DESC);
203 std::string first_challenge_text = "Negotiate";
204 HttpAuthChallengeTokenizer first_challenge(first_challenge_text.begin(),
205 first_challenge_text.end());
206 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
207 auth_gssapi.ParseChallenge(&first_challenge));
209 // Generate an auth token and create another thing.
210 EstablishInitialContext(&mock_library);
211 std::string auth_token;
212 EXPECT_EQ(OK, auth_gssapi.GenerateAuthToken(NULL, "HTTP/intranet.google.com",
213 &auth_token,
214 base::Bind(&UnexpectedCallback)));
216 std::string second_challenge_text = "Negotiate Zm9vYmFy";
217 HttpAuthChallengeTokenizer second_challenge(second_challenge_text.begin(),
218 second_challenge_text.end());
219 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
220 auth_gssapi.ParseChallenge(&second_challenge));
223 TEST(HttpAuthGSSAPITest, ParseChallenge_UnexpectedTokenFirstRound) {
224 // If the first round challenge has an additional authentication token, it
225 // should be treated as an invalid challenge from the server.
226 test::MockGSSAPILibrary mock_library;
227 HttpAuthGSSAPI auth_gssapi(&mock_library, "Negotiate",
228 CHROME_GSS_SPNEGO_MECH_OID_DESC);
229 std::string challenge_text = "Negotiate Zm9vYmFy";
230 HttpAuthChallengeTokenizer challenge(challenge_text.begin(),
231 challenge_text.end());
232 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
233 auth_gssapi.ParseChallenge(&challenge));
236 TEST(HttpAuthGSSAPITest, ParseChallenge_MissingTokenSecondRound) {
237 // If a later-round challenge is simply "Negotiate", it should be treated as
238 // an authentication challenge rejection from the server or proxy.
239 test::MockGSSAPILibrary mock_library;
240 HttpAuthGSSAPI auth_gssapi(&mock_library, "Negotiate",
241 CHROME_GSS_SPNEGO_MECH_OID_DESC);
242 std::string first_challenge_text = "Negotiate";
243 HttpAuthChallengeTokenizer first_challenge(first_challenge_text.begin(),
244 first_challenge_text.end());
245 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
246 auth_gssapi.ParseChallenge(&first_challenge));
248 EstablishInitialContext(&mock_library);
249 std::string auth_token;
250 EXPECT_EQ(OK, auth_gssapi.GenerateAuthToken(NULL, "HTTP/intranet.google.com",
251 &auth_token,
252 base::Bind(&UnexpectedCallback)));
253 std::string second_challenge_text = "Negotiate";
254 HttpAuthChallengeTokenizer second_challenge(second_challenge_text.begin(),
255 second_challenge_text.end());
256 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
257 auth_gssapi.ParseChallenge(&second_challenge));
260 TEST(HttpAuthGSSAPITest, ParseChallenge_NonBase64EncodedToken) {
261 // If a later-round challenge has an invalid base64 encoded token, it should
262 // be treated as an invalid challenge.
263 test::MockGSSAPILibrary mock_library;
264 HttpAuthGSSAPI auth_gssapi(&mock_library, "Negotiate",
265 CHROME_GSS_SPNEGO_MECH_OID_DESC);
266 std::string first_challenge_text = "Negotiate";
267 HttpAuthChallengeTokenizer first_challenge(first_challenge_text.begin(),
268 first_challenge_text.end());
269 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
270 auth_gssapi.ParseChallenge(&first_challenge));
272 EstablishInitialContext(&mock_library);
273 std::string auth_token;
274 EXPECT_EQ(OK, auth_gssapi.GenerateAuthToken(NULL, "HTTP/intranet.google.com",
275 &auth_token,
276 base::Bind(&UnexpectedCallback)));
277 std::string second_challenge_text = "Negotiate =happyjoy=";
278 HttpAuthChallengeTokenizer second_challenge(second_challenge_text.begin(),
279 second_challenge_text.end());
280 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
281 auth_gssapi.ParseChallenge(&second_challenge));
284 } // namespace net