Commit 890d67c0 authored by Asanka Herath's avatar Asanka Herath Committed by Commit Bot

[net/auth] Reduce use of raw scheme names in the authentication stack.

Shuttling around authentication scheme names as strings carries with it
the overhead of canonicalization everywhere they are used. Scheme names
are considered to be case-insensitive, so this means a lot of
invocations of base::ToLowerASCII() and others.

Instead, this CL introduces two changes:

  1. HttpAuthChallengeTokenizer::scheme() is renamed to auth_scheme() to
     visually disambiguate it from URL schemes.

  2. auth_scheme() always returns the lowercase string.

  3. Multi-round authentication header parse uses HttpAuth::Scheme
     enumeration instead of a string.

  4. HttpAuthGSSAPI doesn't take an authentication scheme as a string
     anymore.  It doesn't make sense to use any scheme other than
     "negotiate" with this class

Bug: 927182
Change-Id: I501af8e978857302d3893f1b7fb2dcd23d2b7e36
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1907418
Commit-Queue: Asanka Herath <asanka@chromium.org>
Reviewed-by: default avatarMatt Menke <mmenke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#715196}
parent 5b86f1f4
......@@ -13,6 +13,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/auth.h"
#include "net/base/net_errors.h"
#include "net/http/http_auth.h"
#include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/http_auth_multi_round_parse.h"
#include "net/http/http_auth_preferences.h"
......@@ -86,10 +87,11 @@ HttpAuth::AuthorizationResult HttpAuthNegotiateAndroid::ParseChallenge(
net::HttpAuthChallengeTokenizer* tok) {
if (first_challenge_) {
first_challenge_ = false;
return net::ParseFirstRoundChallenge("negotiate", tok);
return net::ParseFirstRoundChallenge(HttpAuth::AUTH_SCHEME_NEGOTIATE, tok);
}
std::string decoded_auth_token;
return net::ParseLaterRoundChallenge("negotiate", tok, &server_auth_token_,
return net::ParseLaterRoundChallenge(HttpAuth::AUTH_SCHEME_NEGOTIATE, tok,
&server_auth_token_,
&decoded_auth_token);
}
......
......@@ -81,7 +81,7 @@ HttpAuth::AuthorizationResult HttpAuth::HandleChallengeResponse(
HttpAuth::Scheme current_scheme = handler->auth_scheme();
if (disabled_schemes.find(current_scheme) != disabled_schemes.end())
return HttpAuth::AUTHORIZATION_RESULT_REJECT;
std::string current_scheme_name = SchemeToString(current_scheme);
const char* current_scheme_name = SchemeToString(current_scheme);
const std::string header_name = GetChallengeHeaderName(target);
size_t iter = 0;
std::string challenge;
......@@ -90,8 +90,7 @@ HttpAuth::AuthorizationResult HttpAuth::HandleChallengeResponse(
while (response_headers.EnumerateHeader(&iter, header_name, &challenge)) {
HttpAuthChallengeTokenizer challenge_tokens(challenge.begin(),
challenge.end());
if (!base::LowerCaseEqualsASCII(challenge_tokens.scheme(),
current_scheme_name))
if (challenge_tokens.auth_scheme() != current_scheme_name)
continue;
authorization_result = handler->HandleAnotherChallenge(&challenge_tokens);
if (authorization_result != HttpAuth::AUTHORIZATION_RESULT_INVALID) {
......
......@@ -4,6 +4,7 @@
#include "net/http/http_auth_challenge_tokenizer.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_tokenizer.h"
namespace net {
......@@ -13,8 +14,6 @@ HttpAuthChallengeTokenizer::HttpAuthChallengeTokenizer(
std::string::const_iterator end)
: begin_(begin),
end_(end),
scheme_begin_(begin),
scheme_end_(begin),
params_begin_(end),
params_end_(end) {
Init(begin, end);
......@@ -52,10 +51,10 @@ void HttpAuthChallengeTokenizer::Init(std::string::const_iterator begin,
}
// Save the scheme's position.
scheme_begin_ = tok.token_begin();
scheme_end_ = tok.token_end();
lower_case_scheme_ =
base::ToLowerASCII(base::StringPiece(tok.token_begin(), tok.token_end()));
params_begin_ = scheme_end_;
params_begin_ = tok.token_end();
params_end_ = end;
HttpUtil::TrimLWS(&params_begin_, &params_end_);
}
......
......@@ -32,10 +32,9 @@ class NET_EXPORT_PRIVATE HttpAuthChallengeTokenizer {
return std::string(begin_, end_);
}
// Get the auth scheme of the challenge.
base::StringPiece scheme() const {
return base::StringPiece(scheme_begin_, scheme_end_);
}
// Get the authenthication scheme of the challenge. The returned scheme is
// always lowercase.
const std::string& auth_scheme() const { return lower_case_scheme_; }
std::string::const_iterator params_begin() const { return params_begin_; }
std::string::const_iterator params_end() const { return params_end_; }
......@@ -49,11 +48,10 @@ class NET_EXPORT_PRIVATE HttpAuthChallengeTokenizer {
std::string::const_iterator begin_;
std::string::const_iterator end_;
std::string::const_iterator scheme_begin_;
std::string::const_iterator scheme_end_;
std::string::const_iterator params_begin_;
std::string::const_iterator params_end_;
std::string lower_case_scheme_;
};
} // namespace net
......
......@@ -14,7 +14,7 @@ TEST(HttpAuthChallengeTokenizerTest, Basic) {
HttpUtil::NameValuePairsIterator parameters = challenge.param_pairs();
EXPECT_TRUE(parameters.valid());
EXPECT_EQ(std::string("Basic"), challenge.scheme());
EXPECT_EQ(std::string("basic"), challenge.auth_scheme());
EXPECT_TRUE(parameters.GetNext());
EXPECT_TRUE(parameters.valid());
EXPECT_EQ(std::string("realm"), parameters.name());
......@@ -30,7 +30,7 @@ TEST(HttpAuthChallengeTokenizerTest, NoQuotes) {
HttpUtil::NameValuePairsIterator parameters = challenge.param_pairs();
EXPECT_TRUE(parameters.valid());
EXPECT_EQ(std::string("Basic"), challenge.scheme());
EXPECT_EQ(std::string("basic"), challenge.auth_scheme());
EXPECT_TRUE(parameters.GetNext());
EXPECT_TRUE(parameters.valid());
EXPECT_EQ(std::string("realm"), parameters.name());
......@@ -46,7 +46,7 @@ TEST(HttpAuthChallengeTokenizerTest, MismatchedQuotes) {
HttpUtil::NameValuePairsIterator parameters = challenge.param_pairs();
EXPECT_TRUE(parameters.valid());
EXPECT_EQ(std::string("Basic"), challenge.scheme());
EXPECT_EQ(std::string("basic"), challenge.auth_scheme());
EXPECT_TRUE(parameters.GetNext());
EXPECT_TRUE(parameters.valid());
EXPECT_EQ(std::string("realm"), parameters.name());
......@@ -62,7 +62,7 @@ TEST(HttpAuthChallengeTokenizerTest, MismatchedQuotesNoValue) {
HttpUtil::NameValuePairsIterator parameters = challenge.param_pairs();
EXPECT_TRUE(parameters.valid());
EXPECT_EQ(std::string("Basic"), challenge.scheme());
EXPECT_EQ(std::string("basic"), challenge.auth_scheme());
EXPECT_TRUE(parameters.GetNext());
EXPECT_TRUE(parameters.valid());
EXPECT_EQ(std::string("realm"), parameters.name());
......@@ -79,7 +79,7 @@ TEST(HttpAuthChallengeTokenizerTest, MismatchedQuotesSpaces) {
HttpUtil::NameValuePairsIterator parameters = challenge.param_pairs();
EXPECT_TRUE(parameters.valid());
EXPECT_EQ(std::string("Basic"), challenge.scheme());
EXPECT_EQ(std::string("basic"), challenge.auth_scheme());
EXPECT_TRUE(parameters.GetNext());
EXPECT_TRUE(parameters.valid());
EXPECT_EQ(std::string("realm"), parameters.name());
......@@ -96,7 +96,7 @@ TEST(HttpAuthChallengeTokenizerTest, MismatchedQuotesMultiple) {
HttpUtil::NameValuePairsIterator parameters = challenge.param_pairs();
EXPECT_TRUE(parameters.valid());
EXPECT_EQ(std::string("Digest"), challenge.scheme());
EXPECT_EQ(std::string("digest"), challenge.auth_scheme());
EXPECT_TRUE(parameters.GetNext());
EXPECT_TRUE(parameters.valid());
EXPECT_EQ(std::string("qop"), parameters.name());
......@@ -120,7 +120,7 @@ TEST(HttpAuthChallengeTokenizerTest, NoValue) {
HttpUtil::NameValuePairsIterator parameters = challenge.param_pairs();
EXPECT_TRUE(parameters.valid());
EXPECT_EQ(std::string("Digest"), challenge.scheme());
EXPECT_EQ(std::string("digest"), challenge.auth_scheme());
EXPECT_FALSE(parameters.GetNext());
EXPECT_FALSE(parameters.valid());
}
......@@ -134,7 +134,7 @@ TEST(HttpAuthChallengeTokenizerTest, Multiple) {
HttpUtil::NameValuePairsIterator parameters = challenge.param_pairs();
EXPECT_TRUE(parameters.valid());
EXPECT_EQ(std::string("Digest"), challenge.scheme());
EXPECT_EQ(std::string("digest"), challenge.auth_scheme());
EXPECT_TRUE(parameters.GetNext());
EXPECT_TRUE(parameters.valid());
EXPECT_EQ(std::string("algorithm"), parameters.name());
......@@ -159,7 +159,7 @@ TEST(HttpAuthChallengeTokenizerTest, NoProperty) {
HttpUtil::NameValuePairsIterator parameters = challenge.param_pairs();
EXPECT_TRUE(parameters.valid());
EXPECT_EQ(std::string("NTLM"), challenge.scheme());
EXPECT_EQ(std::string("ntlm"), challenge.auth_scheme());
EXPECT_FALSE(parameters.GetNext());
}
......@@ -169,7 +169,7 @@ TEST(HttpAuthChallengeTokenizerTest, Base64) {
HttpAuthChallengeTokenizer challenge(challenge_str.begin(),
challenge_str.end());
EXPECT_EQ(std::string("NTLM"), challenge.scheme());
EXPECT_EQ(std::string("ntlm"), challenge.auth_scheme());
// Notice the two equal statements below due to padding removal.
EXPECT_EQ(std::string("SGVsbG8sIFdvcmxkCg=="), challenge.base64_param());
}
......
......@@ -189,7 +189,7 @@ TEST(HttpAuthControllerTest, NoExplicitCredentialsAllowed) {
set_allows_explicit_credentials(false);
set_connection_based(true);
// Pretend to be SCHEME_BASIC so we can test failover logic.
if (challenge->scheme() == "Basic") {
if (challenge->auth_scheme() == "basic") {
auth_scheme_ = HttpAuth::AUTH_SCHEME_BASIC;
--score_; // Reduce score, so we rank below Mock.
set_allows_explicit_credentials(true);
......
......@@ -20,6 +20,7 @@
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "net/base/net_errors.h"
#include "net/http/http_auth.h"
#include "net/http/http_auth_gssapi_posix.h"
#include "net/http/http_auth_multi_round_parse.h"
#include "net/log/net_log_event_type.h"
......@@ -645,13 +646,8 @@ ScopedSecurityContext::~ScopedSecurityContext() {
}
}
HttpAuthGSSAPI::HttpAuthGSSAPI(GSSAPILibrary* library,
const std::string& scheme,
gss_OID gss_oid)
: scheme_(scheme),
gss_oid_(gss_oid),
library_(library),
scoped_sec_context_(library) {
HttpAuthGSSAPI::HttpAuthGSSAPI(GSSAPILibrary* library, gss_OID gss_oid)
: gss_oid_(gss_oid), library_(library), scoped_sec_context_(library) {
DCHECK(library_);
}
......@@ -678,10 +674,11 @@ void HttpAuthGSSAPI::SetDelegation(DelegationType delegation_type) {
HttpAuth::AuthorizationResult HttpAuthGSSAPI::ParseChallenge(
HttpAuthChallengeTokenizer* tok) {
if (scoped_sec_context_.get() == GSS_C_NO_CONTEXT) {
return net::ParseFirstRoundChallenge(scheme_, tok);
return net::ParseFirstRoundChallenge(HttpAuth::AUTH_SCHEME_NEGOTIATE, tok);
}
std::string encoded_auth_token;
return net::ParseLaterRoundChallenge(scheme_, tok, &encoded_auth_token,
return net::ParseLaterRoundChallenge(HttpAuth::AUTH_SCHEME_NEGOTIATE, tok,
&encoded_auth_token,
&decoded_server_auth_token_);
}
......@@ -710,7 +707,7 @@ int HttpAuthGSSAPI::GenerateAuthToken(const AuthCredentials* credentials,
output_token.length);
std::string encode_output;
base::Base64Encode(encode_input, &encode_output);
*auth_token = scheme_ + " " + encode_output;
*auth_token = "Negotiate " + encode_output;
return OK;
}
......
......@@ -220,7 +220,6 @@ class ScopedSecurityContext {
class NET_EXPORT_PRIVATE HttpAuthGSSAPI : public HttpNegotiateAuthSystem {
public:
HttpAuthGSSAPI(GSSAPILibrary* library,
const std::string& scheme,
const gss_OID gss_oid);
~HttpAuthGSSAPI() override;
......@@ -245,7 +244,6 @@ class NET_EXPORT_PRIVATE HttpAuthGSSAPI : public HttpNegotiateAuthSystem {
gss_buffer_t out_token,
const NetLogWithSource& net_log);
std::string scheme_;
gss_OID gss_oid_;
GSSAPILibrary* library_;
std::string decoded_server_auth_token_;
......
......@@ -268,8 +268,7 @@ TEST(HttpAuthGSSAPIPOSIXTest, GSSAPICycle) {
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_SPNEGO_MECH_OID_DESC);
HttpAuthGSSAPI auth_gssapi(&mock_library, CHROME_GSS_SPNEGO_MECH_OID_DESC);
std::string challenge_text = "Negotiate";
HttpAuthChallengeTokenizer challenge(challenge_text.begin(),
challenge_text.end());
......@@ -282,8 +281,7 @@ 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_SPNEGO_MECH_OID_DESC);
HttpAuthGSSAPI auth_gssapi(&mock_library, CHROME_GSS_SPNEGO_MECH_OID_DESC);
std::string first_challenge_text = "Negotiate";
HttpAuthChallengeTokenizer first_challenge(first_challenge_text.begin(),
first_challenge_text.end());
......@@ -323,8 +321,7 @@ 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_SPNEGO_MECH_OID_DESC);
HttpAuthGSSAPI auth_gssapi(&mock_library, CHROME_GSS_SPNEGO_MECH_OID_DESC);
std::string challenge_text = "Negotiate Zm9vYmFy";
HttpAuthChallengeTokenizer challenge(challenge_text.begin(),
challenge_text.end());
......@@ -336,8 +333,7 @@ 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_SPNEGO_MECH_OID_DESC);
HttpAuthGSSAPI auth_gssapi(&mock_library, CHROME_GSS_SPNEGO_MECH_OID_DESC);
std::string first_challenge_text = "Negotiate";
HttpAuthChallengeTokenizer first_challenge(first_challenge_text.begin(),
first_challenge_text.end());
......@@ -361,8 +357,7 @@ 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_SPNEGO_MECH_OID_DESC);
HttpAuthGSSAPI auth_gssapi(&mock_library, CHROME_GSS_SPNEGO_MECH_OID_DESC);
std::string first_challenge_text = "Negotiate";
HttpAuthChallengeTokenizer first_challenge(first_challenge_text.begin(),
first_challenge_text.end());
......
......@@ -65,8 +65,7 @@ bool HttpAuthHandlerBasic::Init(HttpAuthChallengeTokenizer* challenge,
bool HttpAuthHandlerBasic::ParseChallenge(
HttpAuthChallengeTokenizer* challenge) {
// Verify the challenge's auth-scheme.
if (!base::LowerCaseEqualsASCII(challenge->scheme(), kBasicAuthScheme))
if (challenge->auth_scheme() != kBasicAuthScheme)
return false;
std::string realm;
......
......@@ -139,7 +139,7 @@ HttpAuth::AuthorizationResult HttpAuthHandlerDigest::HandleAnotherChallengeImpl(
// to differentiate between stale and rejected responses.
// Note that the state of the current handler is not mutated - this way if
// there is a rejection the realm hasn't changed.
if (!base::LowerCaseEqualsASCII(challenge->scheme(), kDigestAuthScheme))
if (challenge->auth_scheme() != kDigestAuthScheme)
return HttpAuth::AUTHORIZATION_RESULT_INVALID;
HttpUtil::NameValuePairsIterator parameters = challenge->param_pairs();
......@@ -203,7 +203,7 @@ bool HttpAuthHandlerDigest::ParseChallenge(
realm_ = original_realm_ = nonce_ = domain_ = opaque_ = std::string();
// FAIL -- Couldn't match auth-scheme.
if (!base::LowerCaseEqualsASCII(challenge->scheme(), kDigestAuthScheme))
if (challenge->auth_scheme() != kDigestAuthScheme)
return false;
HttpUtil::NameValuePairsIterator parameters = challenge->param_pairs();
......
......@@ -200,13 +200,12 @@ int HttpAuthHandlerRegistryFactory::CreateAuthHandler(
const NetLogWithSource& net_log,
HostResolver* host_resolver,
std::unique_ptr<HttpAuthHandler>* handler) {
auto scheme = challenge->scheme();
auto scheme = challenge->auth_scheme();
if (scheme.empty()) {
handler->reset();
return ERR_INVALID_RESPONSE;
}
std::string lower_scheme = base::ToLowerASCII(scheme);
auto it = factory_map_.find(lower_scheme);
auto it = factory_map_.find(scheme);
if (it == factory_map_.end()) {
handler->reset();
return ERR_UNSUPPORTED_AUTH_SCHEME;
......
......@@ -121,7 +121,7 @@ HttpAuth::AuthorizationResult HttpAuthHandlerMock::HandleAnotherChallengeImpl(
return HttpAuth::AUTHORIZATION_RESULT_REJECT;
}
if (!base::LowerCaseEqualsASCII(challenge->scheme(), "mock")) {
if (challenge->auth_scheme() != "mock") {
state_ = State::DONE;
return HttpAuth::AUTHORIZATION_RESULT_INVALID;
}
......
......@@ -19,6 +19,7 @@
#include "net/base/net_errors.h"
#include "net/cert/x509_util.h"
#include "net/dns/host_resolver.h"
#include "net/http/http_auth.h"
#include "net/http/http_auth_filter.h"
#include "net/http/http_auth_preferences.h"
#include "net/log/net_log_capture_mode.h"
......@@ -59,9 +60,10 @@ std::unique_ptr<HttpNegotiateAuthSystem> CreateAuthSystem(
#if defined(OS_ANDROID)
return std::make_unique<net::android::HttpAuthNegotiateAndroid>(prefs);
#elif defined(OS_WIN)
return std::make_unique<HttpAuthSSPI>(auth_library, "Negotiate");
return std::make_unique<HttpAuthSSPI>(auth_library,
HttpAuth::AUTH_SCHEME_NEGOTIATE);
#elif defined(OS_POSIX)
return std::make_unique<HttpAuthGSSAPI>(auth_library, "Negotiate",
return std::make_unique<HttpAuthGSSAPI>(auth_library,
CHROME_GSS_SPNEGO_MECH_OID_DESC);
#endif
}
......
......@@ -202,7 +202,7 @@ HttpAuth::AuthorizationResult HttpAuthHandlerNTLM::ParseChallenge(
auth_data_.clear();
// Verify the challenge's auth-scheme.
if (!base::LowerCaseEqualsASCII(tok->scheme(), kNtlmAuthScheme))
if (tok->auth_scheme() != kNtlmAuthScheme)
return HttpAuth::AUTHORIZATION_RESULT_INVALID;
std::string base64_param = tok->base64_param();
......
......@@ -12,6 +12,7 @@
#include "base/strings/string_util.h"
#include "net/base/net_errors.h"
#include "net/dns/host_resolver.h"
#include "net/http/http_auth.h"
#include "net/http/http_auth_preferences.h"
#include "net/http/http_auth_sspi_win.h"
......@@ -43,7 +44,7 @@ int HttpAuthHandlerNTLM::Factory::CreateAuthHandler(
HttpAuthHandlerNTLM::HttpAuthHandlerNTLM(
SSPILibrary* sspi_library,
const HttpAuthPreferences* http_auth_preferences)
: auth_sspi_(sspi_library, "NTLM"),
: auth_sspi_(sspi_library, HttpAuth::AUTH_SCHEME_NTLM),
http_auth_preferences_(http_auth_preferences) {}
int HttpAuthHandlerNTLM::GenerateAuthTokenImpl(
......
......@@ -14,20 +14,16 @@ namespace net {
namespace {
// Check that the scheme in the challenge matches the expected scheme
bool SchemeIsValid(base::StringPiece scheme,
bool SchemeIsValid(HttpAuth::Scheme scheme,
HttpAuthChallengeTokenizer* challenge) {
// There is no guarantee that challenge->scheme() is valid ASCII, but
// LowerCaseEqualsASCII will do the right thing even if it isn't.
return base::LowerCaseEqualsASCII(challenge->scheme(),
base::ToLowerASCII(scheme));
return challenge->auth_scheme() == HttpAuth::SchemeToString(scheme);
}
} // namespace
HttpAuth::AuthorizationResult ParseFirstRoundChallenge(
base::StringPiece scheme,
HttpAuth::Scheme scheme,
HttpAuthChallengeTokenizer* challenge) {
// Verify the challenge's auth-scheme.
if (!SchemeIsValid(scheme, challenge))
return HttpAuth::AUTHORIZATION_RESULT_INVALID;
......@@ -39,11 +35,10 @@ HttpAuth::AuthorizationResult ParseFirstRoundChallenge(
}
HttpAuth::AuthorizationResult ParseLaterRoundChallenge(
base::StringPiece scheme,
HttpAuth::Scheme scheme,
HttpAuthChallengeTokenizer* challenge,
std::string* encoded_token,
std::string* decoded_token) {
// Verify the challenge's auth-scheme.
if (!SchemeIsValid(scheme, challenge))
return HttpAuth::AUTHORIZATION_RESULT_INVALID;
......@@ -51,7 +46,6 @@ HttpAuth::AuthorizationResult ParseLaterRoundChallenge(
if (encoded_token->empty())
return HttpAuth::AUTHORIZATION_RESULT_REJECT;
// Make sure the additional token is base64 encoded.
if (!base::Base64Decode(*encoded_token, decoded_token))
return HttpAuth::AUTHORIZATION_RESULT_INVALID;
return HttpAuth::AUTHORIZATION_RESULT_ACCEPT;
......
......@@ -16,11 +16,11 @@ namespace net {
class HttpAuthChallengeTokenizer;
NET_EXPORT_PRIVATE HttpAuth::AuthorizationResult ParseFirstRoundChallenge(
base::StringPiece scheme,
HttpAuth::Scheme scheme,
HttpAuthChallengeTokenizer* challenge);
NET_EXPORT_PRIVATE HttpAuth::AuthorizationResult ParseLaterRoundChallenge(
base::StringPiece scheme,
HttpAuth::Scheme scheme,
HttpAuthChallengeTokenizer* challenge,
std::string* encoded_token,
std::string* decoded_token);
......
......@@ -2,8 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/http_auth_multi_round_parse.h"
#include "base/strings/string_util.h"
#include "net/http/http_auth.h"
#include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/http_auth_scheme.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
......@@ -11,11 +15,12 @@ namespace net {
TEST(HttpAuthHandlerNegotiateParseTest, ParseFirstRoundChallenge) {
// The first round should just consist of an unadorned header with the scheme
// name.
std::string challenge_text = "DummyScheme";
std::string challenge_text = "Negotiate";
HttpAuthChallengeTokenizer challenge(challenge_text.begin(),
challenge_text.end());
EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
ParseFirstRoundChallenge("dummyscheme", &challenge));
EXPECT_EQ(
HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
ParseFirstRoundChallenge(HttpAuth::AUTH_SCHEME_NEGOTIATE, &challenge));
}
TEST(HttpAuthHandlerNegotiateParseTest,
......@@ -25,8 +30,9 @@ TEST(HttpAuthHandlerNegotiateParseTest,
std::string challenge_text = "Negotiate Zm9vYmFy";
HttpAuthChallengeTokenizer challenge(challenge_text.begin(),
challenge_text.end());
EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
ParseFirstRoundChallenge("negotiate", &challenge));
EXPECT_EQ(
HttpAuth::AUTHORIZATION_RESULT_INVALID,
ParseFirstRoundChallenge(HttpAuth::AUTH_SCHEME_NEGOTIATE, &challenge));
}
TEST(HttpAuthHandlerNegotiateParseTest,
......@@ -34,8 +40,9 @@ TEST(HttpAuthHandlerNegotiateParseTest,
std::string challenge_text = "DummyScheme";
HttpAuthChallengeTokenizer challenge(challenge_text.begin(),
challenge_text.end());
EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
ParseFirstRoundChallenge("negotiate", &challenge));
EXPECT_EQ(
HttpAuth::AUTHORIZATION_RESULT_INVALID,
ParseFirstRoundChallenge(HttpAuth::AUTH_SCHEME_NEGOTIATE, &challenge));
}
TEST(HttpAuthHandlerNegotiateParseTest, ParseLaterRoundChallenge) {
......@@ -45,9 +52,10 @@ TEST(HttpAuthHandlerNegotiateParseTest, ParseLaterRoundChallenge) {
challenge_text.end());
std::string encoded_token;
std::string decoded_token;
EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
ParseLaterRoundChallenge("negotiate", &challenge, &encoded_token,
&decoded_token));
EXPECT_EQ(
HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
ParseLaterRoundChallenge(HttpAuth::AUTH_SCHEME_NEGOTIATE, &challenge,
&encoded_token, &decoded_token));
EXPECT_EQ("Zm9vYmFy", encoded_token);
EXPECT_EQ("foobar", decoded_token);
}
......@@ -59,9 +67,10 @@ TEST(HttpAuthHandlerNegotiateParseTest,
challenge_text.end());
std::string encoded_token;
std::string decoded_token;
EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
ParseLaterRoundChallenge("negotiate", &challenge, &encoded_token,
&decoded_token));
EXPECT_EQ(
HttpAuth::AUTHORIZATION_RESULT_REJECT,
ParseLaterRoundChallenge(HttpAuth::AUTH_SCHEME_NEGOTIATE, &challenge,
&encoded_token, &decoded_token));
}
TEST(HttpAuthHandlerNegotiateParseTest,
......@@ -71,9 +80,19 @@ TEST(HttpAuthHandlerNegotiateParseTest,
challenge_text.end());
std::string encoded_token;
std::string decoded_token;
EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
ParseLaterRoundChallenge("negotiate", &challenge, &encoded_token,
&decoded_token));
EXPECT_EQ(
HttpAuth::AUTHORIZATION_RESULT_INVALID,
ParseLaterRoundChallenge(HttpAuth::AUTH_SCHEME_NEGOTIATE, &challenge,
&encoded_token, &decoded_token));
}
// The parser assumes that all authentication scheme names are lowercase.
TEST(HttpAuthHandlerNegotiateParseTest, AllSchemesAreCanonical) {
EXPECT_EQ(base::ToLowerASCII(kBasicAuthScheme), kBasicAuthScheme);
EXPECT_EQ(base::ToLowerASCII(kDigestAuthScheme), kDigestAuthScheme);
EXPECT_EQ(base::ToLowerASCII(kNtlmAuthScheme), kNtlmAuthScheme);
EXPECT_EQ(base::ToLowerASCII(kNegotiateAuthScheme), kNegotiateAuthScheme);
EXPECT_EQ(base::ToLowerASCII(kMockAuthScheme), kMockAuthScheme);
}
} // namespace net
......@@ -355,11 +355,13 @@ SECURITY_STATUS SSPILibraryDefault::FreeContextBuffer(PVOID pvContextBuffer) {
return ::FreeContextBuffer(pvContextBuffer);
}
HttpAuthSSPI::HttpAuthSSPI(SSPILibrary* library, const std::string& scheme)
HttpAuthSSPI::HttpAuthSSPI(SSPILibrary* library, HttpAuth::Scheme scheme)
: library_(library),
scheme_(scheme),
delegation_type_(DelegationType::kNone) {
DCHECK(library_);
DCHECK(scheme_ == HttpAuth::AUTH_SCHEME_NEGOTIATE ||
scheme_ == HttpAuth::AUTH_SCHEME_NTLM);
SecInvalidateHandle(&cred_);
SecInvalidateHandle(&ctxt_);
}
......@@ -437,7 +439,11 @@ int HttpAuthSSPI::GenerateAuthToken(const AuthCredentials* credentials,
base::Base64Encode(encode_input, &encode_output);
// OK, we are done with |out_buf|
free(out_buf);
*auth_token = scheme_ + " " + encode_output;
if (scheme_ == HttpAuth::AUTH_SCHEME_NEGOTIATE) {
*auth_token = "Negotiate " + encode_output;
} else {
*auth_token = "NTLM " + encode_output;
}
return OK;
}
......
......@@ -144,7 +144,7 @@ class SSPILibraryDefault : public SSPILibrary {
class NET_EXPORT_PRIVATE HttpAuthSSPI : public HttpNegotiateAuthSystem {
public:
HttpAuthSSPI(SSPILibrary* sspi_library, const std::string& scheme);
HttpAuthSSPI(SSPILibrary* sspi_library, HttpAuth::Scheme scheme);
~HttpAuthSSPI() override;
// HttpNegotiateAuthSystem implementation:
......@@ -176,7 +176,7 @@ class NET_EXPORT_PRIVATE HttpAuthSSPI : public HttpNegotiateAuthSystem {
void ResetSecurityContext();
SSPILibrary* library_;
std::string scheme_;
HttpAuth::Scheme scheme_;
std::string decoded_server_auth_token_;
CredHandle cred_;
CtxtHandle ctxt_;
......
......@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/json/json_reader.h"
#include "net/base/net_errors.h"
#include "net/http/http_auth.h"
#include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/mock_sspi_library_win.h"
#include "net/log/net_log_entry.h"
......@@ -81,7 +82,7 @@ TEST(HttpAuthSSPITest, DetermineMaxTokenLength_InvalidPackage) {
TEST(HttpAuthSSPITest, ParseChallenge_FirstRound) {
// The first round should just consist of an unadorned "Negotiate" header.
MockSSPILibrary mock_library{NEGOSSP_NAME};
HttpAuthSSPI auth_sspi(&mock_library, "Negotiate");
HttpAuthSSPI auth_sspi(&mock_library, HttpAuth::AUTH_SCHEME_NEGOTIATE);
std::string challenge_text = "Negotiate";
HttpAuthChallengeTokenizer challenge(challenge_text.begin(),
challenge_text.end());
......@@ -93,7 +94,7 @@ TEST(HttpAuthSSPITest, ParseChallenge_TwoRounds) {
// The first round should just have "Negotiate", and the second round should
// have a valid base64 token associated with it.
MockSSPILibrary mock_library{NEGOSSP_NAME};
HttpAuthSSPI auth_sspi(&mock_library, "Negotiate");
HttpAuthSSPI auth_sspi(&mock_library, HttpAuth::AUTH_SCHEME_NEGOTIATE);
std::string first_challenge_text = "Negotiate";
HttpAuthChallengeTokenizer first_challenge(first_challenge_text.begin(),
first_challenge_text.end());
......@@ -118,7 +119,7 @@ TEST(HttpAuthSSPITest, ParseChallenge_UnexpectedTokenFirstRound) {
// If the first round challenge has an additional authentication token, it
// should be treated as an invalid challenge from the server.
MockSSPILibrary mock_library{NEGOSSP_NAME};
HttpAuthSSPI auth_sspi(&mock_library, "Negotiate");
HttpAuthSSPI auth_sspi(&mock_library, HttpAuth::AUTH_SCHEME_NEGOTIATE);
std::string challenge_text = "Negotiate Zm9vYmFy";
HttpAuthChallengeTokenizer challenge(challenge_text.begin(),
challenge_text.end());
......@@ -130,7 +131,7 @@ TEST(HttpAuthSSPITest, ParseChallenge_MissingTokenSecondRound) {
// If a later-round challenge is simply "Negotiate", it should be treated as
// an authentication challenge rejection from the server or proxy.
MockSSPILibrary mock_library{NEGOSSP_NAME};
HttpAuthSSPI auth_sspi(&mock_library, "Negotiate");
HttpAuthSSPI auth_sspi(&mock_library, HttpAuth::AUTH_SCHEME_NEGOTIATE);
std::string first_challenge_text = "Negotiate";
HttpAuthChallengeTokenizer first_challenge(first_challenge_text.begin(),
first_challenge_text.end());
......@@ -153,7 +154,7 @@ TEST(HttpAuthSSPITest, ParseChallenge_NonBase64EncodedToken) {
// If a later-round challenge has an invalid base64 encoded token, it should
// be treated as an invalid challenge.
MockSSPILibrary mock_library{NEGOSSP_NAME};
HttpAuthSSPI auth_sspi(&mock_library, "Negotiate");
HttpAuthSSPI auth_sspi(&mock_library, HttpAuth::AUTH_SCHEME_NEGOTIATE);
std::string first_challenge_text = "Negotiate";
HttpAuthChallengeTokenizer first_challenge(first_challenge_text.begin(),
first_challenge_text.end());
......@@ -175,7 +176,7 @@ TEST(HttpAuthSSPITest, ParseChallenge_NonBase64EncodedToken) {
// Runs through a full handshake against the MockSSPILibrary.
TEST(HttpAuthSSPITest, GenerateAuthToken_FullHandshake_AmbientCreds) {
MockSSPILibrary mock_library{NEGOSSP_NAME};
HttpAuthSSPI auth_sspi(&mock_library, "Negotiate");
HttpAuthSSPI auth_sspi(&mock_library, HttpAuth::AUTH_SCHEME_NEGOTIATE);
std::string first_challenge_text = "Negotiate";
HttpAuthChallengeTokenizer first_challenge(first_challenge_text.begin(),
first_challenge_text.end());
......@@ -216,7 +217,7 @@ TEST(HttpAuthSSPITest, GenerateAuthToken_FullHandshake_AmbientCreds) {
TEST(HttpAuthSSPITest, GenerateAuthToken_FullHandshake_AmbientCreds_Logging) {
BoundTestNetLog net_log;
MockSSPILibrary mock_library{NEGOSSP_NAME};
HttpAuthSSPI auth_sspi(&mock_library, "Negotiate");
HttpAuthSSPI auth_sspi(&mock_library, HttpAuth::AUTH_SCHEME_NEGOTIATE);
std::string first_challenge_text = "Negotiate";
HttpAuthChallengeTokenizer first_challenge(first_challenge_text.begin(),
first_challenge_text.end());
......
......@@ -22,7 +22,7 @@ bool ShouldRedactChallenge(HttpAuthChallengeTokenizer* challenge) {
if (challenge->challenge_text().find(',') != std::string::npos)
return false;
std::string scheme = base::ToLowerASCII(challenge->scheme());
std::string scheme = challenge->auth_scheme();
// Invalid input.
if (scheme.empty())
return false;
......
......@@ -63,7 +63,7 @@ class MockHttpAuthHandlerFactory : public HttpAuthHandlerFactory {
std::unique_ptr<HttpAuthHandler>* handler) override {
handler->reset();
return challenge->scheme() == supported_scheme_
return challenge->auth_scheme() == supported_scheme_
? return_code_
: ERR_UNSUPPORTED_AUTH_SCHEME;
}
......@@ -139,7 +139,7 @@ TEST_F(URLRequestContextBuilderTest, CustomHttpAuthHandlerFactory) {
const int kBasicReturnCode = OK;
std::unique_ptr<HttpAuthHandler> handler;
builder_.SetHttpAuthHandlerFactory(
std::make_unique<MockHttpAuthHandlerFactory>("ExtraScheme",
std::make_unique<MockHttpAuthHandlerFactory>("extrascheme",
kBasicReturnCode));
std::unique_ptr<URLRequestContext> context(builder_.Build());
SSLInfo null_ssl_info;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment