Skip to content

Commit

Permalink
SPDY proxy authentication support.
Browse files Browse the repository at this point in the history
BUG=147591


Review URL: https://chromiumcodereview.appspot.com/10913238

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@159342 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
piatek@google.com committed Sep 28, 2012
1 parent 08c8df6 commit ec44ee0
Show file tree
Hide file tree
Showing 14 changed files with 464 additions and 8 deletions.
36 changes: 28 additions & 8 deletions chrome/browser/io_thread.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "chrome/browser/net/pref_proxy_config_tracker.h"
#include "chrome/browser/net/proxy_service_factory.h"
#include "chrome/browser/net/sdch_dictionary_fetcher.h"
#include "chrome/browser/net/spdyproxy/http_auth_handler_spdyproxy.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
Expand Down Expand Up @@ -450,6 +451,10 @@ void IOThread::Init() {
globals_->cert_verifier.reset(net::CertVerifier::CreateDefault());
globals_->transport_security_state.reset(new net::TransportSecurityState());
globals_->ssl_config_service = GetSSLConfigService();
if (command_line.HasSwitch(switches::kSpdyProxyOrigin)) {
spdyproxy_origin_ =
command_line.GetSwitchValueASCII(switches::kSpdyProxyOrigin);
}
globals_->http_auth_handler_factory.reset(CreateDefaultAuthHandlerFactory(
globals_->host_resolver.get()));
globals_->http_server_properties.reset(new net::HttpServerPropertiesImpl);
Expand Down Expand Up @@ -591,13 +596,15 @@ void IOThread::CleanUp() {
// static
void IOThread::RegisterPrefs(PrefService* local_state) {
local_state->RegisterStringPref(prefs::kAuthSchemes,
"basic,digest,ntlm,negotiate");
"basic,digest,ntlm,negotiate,"
"spdyproxy");
local_state->RegisterBooleanPref(prefs::kDisableAuthNegotiateCnameLookup,
false);
local_state->RegisterBooleanPref(prefs::kEnableAuthNegotiatePort, false);
local_state->RegisterStringPref(prefs::kAuthServerWhitelist, "");
local_state->RegisterStringPref(prefs::kAuthNegotiateDelegateWhitelist, "");
local_state->RegisterStringPref(prefs::kGSSAPILibraryName, "");
local_state->RegisterStringPref(prefs::kSpdyProxyOrigin, "");
local_state->RegisterBooleanPref(prefs::kEnableReferrers, true);
}

Expand All @@ -619,13 +626,26 @@ net::HttpAuthHandlerFactory* IOThread::CreateDefaultAuthHandlerFactory(
std::vector<std::string> supported_schemes;
base::SplitString(auth_schemes_, ',', &supported_schemes);

return net::HttpAuthHandlerRegistryFactory::Create(
supported_schemes,
globals_->url_security_manager.get(),
resolver,
gssapi_library_name_,
negotiate_disable_cname_lookup_,
negotiate_enable_port_);
scoped_ptr<net::HttpAuthHandlerRegistryFactory> registry_factory(
net::HttpAuthHandlerRegistryFactory::Create(
supported_schemes, globals_->url_security_manager.get(),
resolver, gssapi_library_name_, negotiate_disable_cname_lookup_,
negotiate_enable_port_));

if (!spdyproxy_origin_.empty()) {
GURL origin_url(spdyproxy_origin_);
if (origin_url.is_valid()) {
registry_factory->RegisterSchemeFactory(
"spdyproxy",
new spdyproxy::HttpAuthHandlerSpdyProxy::Factory(origin_url));
} else {
LOG(WARNING) << "Skipping creation of SpdyProxy auth handler since "
<< "authorized origin is invalid: "
<< spdyproxy_origin_;
}
}

return registry_factory.release();
}

void IOThread::ClearHostCache() {
Expand Down
1 change: 1 addition & 0 deletions chrome/browser/io_thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ class IOThread : public content::BrowserThreadDelegate {
std::string auth_server_whitelist_;
std::string auth_delegate_whitelist_;
std::string gssapi_library_name_;
std::string spdyproxy_origin_;

// This is an instance of the default SSLConfigServiceManager for the current
// platform and it gets SSL preferences from local_state object.
Expand Down
168 changes: 168 additions & 0 deletions chrome/browser/net/spdyproxy/http_auth_handler_spdyproxy.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// Copyright (c) 2012 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 "chrome/browser/net/spdyproxy/http_auth_handler_spdyproxy.h"

#include <string>

#include "base/i18n/icu_string_conversions.h"
#include "base/metrics/histogram.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "net/base/net_errors.h"
#include "net/http/http_auth.h"
#include "net/http/http_request_info.h"

namespace spdyproxy {

using net::AuthCredentials;
using net::BoundNetLog;
using net::CompletionCallback;
using net::HttpAuth;
using net::HttpAuthHandler;
using net::HttpAuthHandlerFactory;
using net::HttpRequestInfo;
using net::HttpUtil;

HttpAuthHandlerSpdyProxy::Factory::Factory(
const GURL& authorized_spdyproxy_origin)
: authorized_spdyproxy_origin_(authorized_spdyproxy_origin) {
}

HttpAuthHandlerSpdyProxy::Factory::~Factory() {
}

int HttpAuthHandlerSpdyProxy::Factory::CreateAuthHandler(
HttpAuth::ChallengeTokenizer* challenge,
HttpAuth::Target target,
const GURL& origin,
CreateReason reason,
int digest_nonce_count,
const BoundNetLog& net_log,
scoped_ptr<HttpAuthHandler>* handler) {
// If a spdyproxy auth proxy has not been set, refuse all requests to use this
// auth handler.
if (authorized_spdyproxy_origin_.possibly_invalid_spec().empty()) {
VLOG(1) << "SpdyProxy auth without configuring authorized origin.";
return net::ERR_UNSUPPORTED_AUTH_SCHEME;
}

// We ensure that this authentication handler is used only with an authorized
// SPDY proxy, since otherwise a user's authentication token can be
// sniffed by a malicious proxy that presents an appropriate challenge.
const GURL origin_origin = origin.GetOrigin();
if (!(target == HttpAuth::AUTH_PROXY &&
origin_origin == authorized_spdyproxy_origin_)) {
UMA_HISTOGRAM_COUNTS("Net.UnexpectedSpdyProxyAuth", 1);
VLOG(1) << "SpdyProxy auth request with an unexpected config."
<< " origin: " << origin_origin.possibly_invalid_spec()
<< " authorized_origin: "
<< authorized_spdyproxy_origin_.possibly_invalid_spec();
return net::ERR_UNSUPPORTED_AUTH_SCHEME;
}

scoped_ptr<HttpAuthHandler> tmp_handler(
new HttpAuthHandlerSpdyProxy(authorized_spdyproxy_origin_));
if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log))
return net::ERR_INVALID_RESPONSE;
handler->swap(tmp_handler);
return net::OK;
}

HttpAuthHandlerSpdyProxy::HttpAuthHandlerSpdyProxy(
const GURL& authorized_spdyproxy_origin)
: HttpAuthHandler(),
authorized_spdyproxy_origin_(authorized_spdyproxy_origin) {
}

HttpAuth::AuthorizationResult
HttpAuthHandlerSpdyProxy::HandleAnotherChallenge(
HttpAuth::ChallengeTokenizer* challenge) {
// SpdyProxy authentication is always a single round, so any responses
// should be treated as a rejection.
return HttpAuth::AUTHORIZATION_RESULT_REJECT;
}

bool HttpAuthHandlerSpdyProxy::NeedsIdentity() {
return true;
}

bool HttpAuthHandlerSpdyProxy::AllowsDefaultCredentials() {
return false;
}

bool HttpAuthHandlerSpdyProxy::AllowsExplicitCredentials() {
return true;
}

bool HttpAuthHandlerSpdyProxy::Init(
HttpAuth::ChallengeTokenizer* challenge) {
auth_scheme_ = HttpAuth::AUTH_SCHEME_SPDYPROXY;
score_ = 5;
properties_ = ENCRYPTS_IDENTITY;
return ParseChallenge(challenge);
}

int HttpAuthHandlerSpdyProxy::GenerateAuthTokenImpl(
const AuthCredentials* credentials, const HttpRequestInfo* request,
const CompletionCallback&, std::string* auth_token) {
DCHECK(credentials);
if (credentials->password().length() == 0) {
DVLOG(1) << "Received a SpdyProxy auth token request without an "
<< "available token.";
return -1;
}
*auth_token = "SpdyProxy ps=\"" + ps_token_ + "\", sid=\"" +
UTF16ToUTF8(credentials->password()) + "\"";
return net::OK;
}

bool HttpAuthHandlerSpdyProxy::ParseChallenge(
HttpAuth::ChallengeTokenizer* challenge) {

// Verify the challenge's auth-scheme.
if (!LowerCaseEqualsASCII(challenge->scheme(), "spdyproxy")) {
VLOG(1) << "Parsed challenge without SpdyProxy type";
return false;
}

HttpUtil::NameValuePairsIterator parameters = challenge->param_pairs();

// Loop through all the properties.
while (parameters.GetNext()) {
// FAIL -- couldn't parse a property.
if (!ParseChallengeProperty(parameters.name(),
parameters.value()))
return false;
}
// Check if tokenizer failed.
if (!parameters.valid())
return false;

// Check that the required properties were provided.
if (realm_.empty())
return false;

if (ps_token_.empty())
return false;

return true;
}

bool HttpAuthHandlerSpdyProxy::ParseChallengeProperty(
const std::string& name, const std::string& value) {
if (LowerCaseEqualsASCII(name, "realm")) {
std::string realm;
if (!base::ConvertToUtf8AndNormalize(value, base::kCodepageLatin1, &realm))
return false;
realm_ = realm;
} else if (LowerCaseEqualsASCII(name, "ps")) {
ps_token_ = value;
} else {
VLOG(1) << "Skipping unrecognized SpdyProxy auth property, " << name;
}
return true;
}

} // namespace spdyproxy
80 changes: 80 additions & 0 deletions chrome/browser/net/spdyproxy/http_auth_handler_spdyproxy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright (c) 2012 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.

#ifndef CHROME_BROWSER_NET_SPDYPROXY_HTTP_AUTH_HANDLER_SPDYPROXY_H_
#define CHROME_BROWSER_NET_SPDYPROXY_HTTP_AUTH_HANDLER_SPDYPROXY_H_

#include <string>

#include "base/gtest_prod_util.h"
#include "net/http/http_auth_handler.h"
#include "net/http/http_auth_handler_factory.h"

namespace spdyproxy {

// Code for handling http SpdyProxy authentication.
class HttpAuthHandlerSpdyProxy : public net::HttpAuthHandler {
public:
class Factory : public net::HttpAuthHandlerFactory {
public:
// Constructs a new spdyproxy handler factory which mints handlers that
// respond to challenges only from the given |authorized_spdyproxy_origin|.
explicit Factory(const GURL& authorized_spdyproxy_origin);
virtual ~Factory();

virtual int CreateAuthHandler(
net::HttpAuth::ChallengeTokenizer* challenge,
net::HttpAuth::Target target,
const GURL& origin,
CreateReason reason,
int digest_nonce_count,
const net::BoundNetLog& net_log,
scoped_ptr<HttpAuthHandler>* handler) OVERRIDE;

private:
// The origin for which we will respond to SpdyProxy auth challenges.
GURL authorized_spdyproxy_origin_;
};

// Constructs a new spdyproxy handler which responds to challenges
// from the given |authorized_spdyproxy_origin|.
explicit HttpAuthHandlerSpdyProxy(
const GURL& authorized_spdyproxy_origin);

// Overrides from net::HttpAuthHandler.
virtual net::HttpAuth::AuthorizationResult HandleAnotherChallenge(
net::HttpAuth::ChallengeTokenizer* challenge) OVERRIDE;
virtual bool NeedsIdentity() OVERRIDE;
virtual bool AllowsDefaultCredentials() OVERRIDE;
virtual bool AllowsExplicitCredentials() OVERRIDE;

private:
FRIEND_TEST_ALL_PREFIXES(HttpAuthHandlerSpdyProxyTest, ParseChallenge);

virtual ~HttpAuthHandlerSpdyProxy() {}

virtual bool Init(net::HttpAuth::ChallengeTokenizer* challenge) OVERRIDE;

virtual int GenerateAuthTokenImpl(const net::AuthCredentials* credentials,
const net::HttpRequestInfo* request,
const net::CompletionCallback& callback,
std::string* auth_token) OVERRIDE;

bool ParseChallenge(net::HttpAuth::ChallengeTokenizer* challenge);

bool ParseChallengeProperty(const std::string& name,
const std::string& value);

// The origin for which we will respond to SpdyProxy auth challenges.
GURL authorized_spdyproxy_origin_;

// The ps token, encoded as UTF-8.
std::string ps_token_;

DISALLOW_COPY_AND_ASSIGN(HttpAuthHandlerSpdyProxy);
};

} // namespace spdyproxy

#endif // CHROME_BROWSER_NET_SPDYPROXY_HTTP_AUTH_HANDLER_SPDYPROXY_H_
Loading

0 comments on commit ec44ee0

Please sign in to comment.