summaryrefslogtreecommitdiffstats
path: root/net/http/http_auth_gssapi_posix_unittest.cc
diff options
context:
space:
mode:
authorcbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-11 14:03:30 +0000
committercbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-11 14:03:30 +0000
commiteca50e128ff1bc41bc0cc1d3fdf2e015ba459d4c (patch)
treeae0368388f38766781c5ddff86c9e0e2c0c9c362 /net/http/http_auth_gssapi_posix_unittest.cc
parent4630db4630bc415cc3b7be70bce87160559810df (diff)
downloadchromium_src-eca50e128ff1bc41bc0cc1d3fdf2e015ba459d4c.zip
chromium_src-eca50e128ff1bc41bc0cc1d3fdf2e015ba459d4c.tar.gz
chromium_src-eca50e128ff1bc41bc0cc1d3fdf2e015ba459d4c.tar.bz2
Fix multi-round authentication.
In the case of Negotiate, authentication can look like C: GET S: 401, WWW-Authenticate: Negotiate C: GET, WWW-Authorization: Negotiate <client_token_1> S: 401, WWW-Authenticate: Negotiate <server_token_1> C: GET, WWW-Authorization: Negotiate <client_token_2> S: 401, WWW-Authenticate: Negotiate <server_token_2> on that third challenge, the handler was reported as being in "the final round" and this was treated as a rejection of the authentication attempt. After that, the new challenge token was used by a new auth handler that hadn't established a security context, and an ERR_INVALID_HANDLE would be returned. This CL also does some prep work to correctly handle the "stale=true" value for Digest authentication, but I decided to defer the HttpAuthCache changes needed for that to a separate CL since this was large enough. BUG=53282 TEST=net_unittests. Unfortunately, I haven't been able to set up a proxy/server to do more than two auth challenges, but this does happen in the wild. Review URL: http://codereview.chromium.org/3360017 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@59188 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/http/http_auth_gssapi_posix_unittest.cc')
-rw-r--r--net/http/http_auth_gssapi_posix_unittest.cc123
1 files changed, 123 insertions, 0 deletions
diff --git a/net/http/http_auth_gssapi_posix_unittest.cc b/net/http/http_auth_gssapi_posix_unittest.cc
index e66bf85..62bae71 100644
--- a/net/http/http_auth_gssapi_posix_unittest.cc
+++ b/net/http/http_auth_gssapi_posix_unittest.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/native_library.h"
#include "base/scoped_ptr.h"
+#include "net/base/net_errors.h"
#include "net/http/mock_gssapi_library_posix.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -46,6 +47,29 @@ void CopyBuffer(gss_buffer_t dest, const gss_buffer_t src) {
SetBuffer(dest, src->value, src->length);
}
+const char kInitialAuthResponse[] = "Mary had a little lamb";
+
+void EstablishInitialContext(test::MockGSSAPILibrary* library) {
+ test::GssContextMockImpl context_info(
+ "localhost", // Source name
+ "example.com", // Target name
+ 23, // Lifetime
+ *GSS_C_NT_HOSTBASED_SERVICE, // Mechanism
+ 0, // Context flags
+ 1, // Locally initiated
+ 0); // Open
+ gss_buffer_desc in_buffer = {0, NULL};
+ gss_buffer_desc out_buffer = {arraysize(kInitialAuthResponse),
+ const_cast<char*>(kInitialAuthResponse)};
+ library->ExpectSecurityContext(
+ "Negotiate",
+ GSS_S_CONTINUE_NEEDED,
+ 0,
+ context_info,
+ in_buffer,
+ out_buffer);
+}
+
} // namespace
TEST(HttpAuthGSSAPIPOSIXTest, GSSAPIStartup) {
@@ -144,4 +168,103 @@ TEST(HttpAuthGSSAPIPOSIXTest, GSSAPICycle) {
GSS_C_NO_BUFFER);
}
+TEST(HttpAuthGSSAPITest, ParseChallenge_FirstRound) {
+ // The first round should just consist of an unadorned "Negotiate" header.
+ test::MockGSSAPILibrary mock_library;
+ HttpAuthGSSAPI auth_gssapi(&mock_library, "Negotiate",
+ CHROME_GSS_KRB5_MECH_OID_DESC);
+ std::string challenge_text = "Negotiate";
+ HttpAuth::ChallengeTokenizer challenge(challenge_text.begin(),
+ challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+ auth_gssapi.ParseChallenge(&challenge));
+}
+
+TEST(HttpAuthGSSAPITest, ParseChallenge_TwoRounds) {
+ // The first round should just have "Negotiate", and the second round should
+ // have a valid base64 token associated with it.
+ test::MockGSSAPILibrary mock_library;
+ HttpAuthGSSAPI auth_gssapi(&mock_library, "Negotiate",
+ CHROME_GSS_KRB5_MECH_OID_DESC);
+ std::string first_challenge_text = "Negotiate";
+ HttpAuth::ChallengeTokenizer first_challenge(first_challenge_text.begin(),
+ first_challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+ auth_gssapi.ParseChallenge(&first_challenge));
+
+ // Generate an auth token and create another thing.
+ EstablishInitialContext(&mock_library);
+ std::string auth_token;
+ EXPECT_EQ(OK, auth_gssapi.GenerateAuthToken(NULL, NULL,
+ L"HTTP/intranet.google.com",
+ &auth_token));
+
+ std::string second_challenge_text = "Negotiate Zm9vYmFy";
+ HttpAuth::ChallengeTokenizer second_challenge(second_challenge_text.begin(),
+ second_challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+ auth_gssapi.ParseChallenge(&second_challenge));
+}
+
+TEST(HttpAuthGSSAPITest, ParseChallenge_UnexpectedTokenFirstRound) {
+ // If the first round challenge has an additional authentication token, it
+ // should be treated as an invalid challenge from the server.
+ test::MockGSSAPILibrary mock_library;
+ HttpAuthGSSAPI auth_gssapi(&mock_library, "Negotiate",
+ CHROME_GSS_KRB5_MECH_OID_DESC);
+ std::string challenge_text = "Negotiate Zm9vYmFy";
+ HttpAuth::ChallengeTokenizer challenge(challenge_text.begin(),
+ challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
+ auth_gssapi.ParseChallenge(&challenge));
+}
+
+TEST(HttpAuthGSSAPITest, ParseChallenge_MissingTokenSecondRound) {
+ // If a later-round challenge is simply "Negotiate", it should be treated as
+ // an authentication challenge rejection from the server or proxy.
+ test::MockGSSAPILibrary mock_library;
+ HttpAuthGSSAPI auth_gssapi(&mock_library, "Negotiate",
+ CHROME_GSS_KRB5_MECH_OID_DESC);
+ std::string first_challenge_text = "Negotiate";
+ HttpAuth::ChallengeTokenizer first_challenge(first_challenge_text.begin(),
+ first_challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+ auth_gssapi.ParseChallenge(&first_challenge));
+
+ EstablishInitialContext(&mock_library);
+ std::string auth_token;
+ EXPECT_EQ(OK, auth_gssapi.GenerateAuthToken(NULL, NULL,
+ L"HTTP/intranet.google.com",
+ &auth_token));
+ std::string second_challenge_text = "Negotiate";
+ HttpAuth::ChallengeTokenizer second_challenge(second_challenge_text.begin(),
+ second_challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
+ auth_gssapi.ParseChallenge(&second_challenge));
+}
+
+TEST(HttpAuthGSSAPITest, ParseChallenge_NonBase64EncodedToken) {
+ // If a later-round challenge has an invalid base64 encoded token, it should
+ // be treated as an invalid challenge.
+ test::MockGSSAPILibrary mock_library;
+ HttpAuthGSSAPI auth_gssapi(&mock_library, "Negotiate",
+ CHROME_GSS_KRB5_MECH_OID_DESC);
+ std::string first_challenge_text = "Negotiate";
+ HttpAuth::ChallengeTokenizer first_challenge(first_challenge_text.begin(),
+ first_challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+ auth_gssapi.ParseChallenge(&first_challenge));
+
+ EstablishInitialContext(&mock_library);
+ std::string auth_token;
+ EXPECT_EQ(OK, auth_gssapi.GenerateAuthToken(NULL, NULL,
+ L"HTTP/intranet.google.com",
+ &auth_token));
+ std::string second_challenge_text = "Negotiate =happyjoy=";
+ HttpAuth::ChallengeTokenizer second_challenge(second_challenge_text.begin(),
+ second_challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
+ auth_gssapi.ParseChallenge(&second_challenge));
+}
+
} // namespace net