Commit d95ee260 authored by rmsousa@chromium.org's avatar rmsousa@chromium.org

Refactor TokenValidatorImpl into a base class + implementation.

Most of the common logic and response handling code are moved into a base class, and the implementation contains just the logic to prepare the validation request (which is where the actual keypair-based authentication happens). This makes it easier to implement different, non-keypair-based host authentication mechanisms.

BUG=

Review URL: https://codereview.chromium.org/165293004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@253378 0039d316-1c4b-4281-b951-d872f2087c98
parent 37ea9a6d
......@@ -71,6 +71,7 @@
#include "remoting/jingle_glue/xmpp_signal_strategy.h"
#include "remoting/protocol/me2me_host_authenticator_factory.h"
#include "remoting/protocol/pairing_registry.h"
#include "remoting/protocol/token_validator.h"
#if defined(OS_POSIX)
#include <signal.h>
......@@ -550,8 +551,8 @@ void HostProcess::CreateAuthenticatorFactory() {
host_secret_hash_, pairing_registry);
} else if (third_party_auth_config_.is_valid()) {
scoped_ptr<protocol::ThirdPartyHostAuthenticator::TokenValidatorFactory>
token_validator_factory(new TokenValidatorFactoryImpl(
scoped_ptr<protocol::TokenValidatorFactory> token_validator_factory(
new TokenValidatorFactoryImpl(
third_party_auth_config_,
key_pair_, context_->url_request_context_getter()));
factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth(
......
// Copyright 2014 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 "remoting/host/token_validator_base.h"
#include "base/base64.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/values.h"
#include "net/base/escape.h"
#include "net/base/io_buffer.h"
#include "net/base/request_priority.h"
#include "net/base/upload_bytes_element_reader.h"
#include "net/base/upload_data_stream.h"
#include "net/ssl/client_cert_store.h"
#if defined(USE_NSS)
#include "net/ssl/client_cert_store_nss.h"
#elif defined(OS_WIN)
#include "net/ssl/client_cert_store_win.h"
#elif defined(OS_MACOSX)
#include "net/ssl/client_cert_store_mac.h"
#endif
#include "net/ssl/ssl_cert_request_info.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_status.h"
#include "url/gurl.h"
namespace {
const int kBufferSize = 4096;
const char kCertIssuerWildCard[] = "*";
} // namespace
namespace remoting {
TokenValidatorBase::TokenValidatorBase(
const ThirdPartyAuthConfig& third_party_auth_config,
const std::string& token_scope,
scoped_refptr<net::URLRequestContextGetter> request_context_getter)
: third_party_auth_config_(third_party_auth_config),
token_scope_(token_scope),
request_context_getter_(request_context_getter),
buffer_(new net::IOBuffer(kBufferSize)),
weak_factory_(this) {
DCHECK(third_party_auth_config_.token_url.is_valid());
DCHECK(third_party_auth_config_.token_validation_url.is_valid());
}
TokenValidatorBase::~TokenValidatorBase() {
}
// TokenValidator interface.
void TokenValidatorBase::ValidateThirdPartyToken(
const std::string& token,
const base::Callback<void(
const std::string& shared_secret)>& on_token_validated) {
DCHECK(!request_);
DCHECK(!on_token_validated.is_null());
on_token_validated_ = on_token_validated;
StartValidateRequest(token);
}
const GURL& TokenValidatorBase::token_url() const {
return third_party_auth_config_.token_url;
}
const std::string& TokenValidatorBase::token_scope() const {
return token_scope_;
}
// URLFetcherDelegate interface.
void TokenValidatorBase::OnResponseStarted(net::URLRequest* source) {
DCHECK_EQ(request_.get(), source);
int bytes_read = 0;
request_->Read(buffer_.get(), kBufferSize, &bytes_read);
OnReadCompleted(request_.get(), bytes_read);
}
void TokenValidatorBase::OnReadCompleted(net::URLRequest* source,
int bytes_read) {
DCHECK_EQ(request_.get(), source);
do {
if (!request_->status().is_success() || bytes_read <= 0)
break;
data_.append(buffer_->data(), bytes_read);
} while (request_->Read(buffer_.get(), kBufferSize, &bytes_read));
const net::URLRequestStatus status = request_->status();
if (!status.is_io_pending()) {
std::string shared_token = ProcessResponse();
request_.reset();
on_token_validated_.Run(shared_token);
}
}
void TokenValidatorBase::OnCertificateRequested(
net::URLRequest* source,
net::SSLCertRequestInfo* cert_request_info) {
DCHECK_EQ(request_.get(), source);
net::ClientCertStore* client_cert_store;
#if defined(USE_NSS)
client_cert_store = new net::ClientCertStoreNSS(
net::ClientCertStoreNSS::PasswordDelegateFactory());
#elif defined(OS_WIN)
client_cert_store = new net::ClientCertStoreWin();
#elif defined(OS_MACOSX)
client_cert_store = new net::ClientCertStoreMac();
#else
#error Unknown platform.
#endif
// The callback is uncancellable, and GetClientCert requires selected_certs
// and client_cert_store to stay alive until the callback is called. So we
// must give it a WeakPtr for |this|, and ownership of the other parameters.
net::CertificateList* selected_certs(new net::CertificateList());
client_cert_store->GetClientCerts(
*cert_request_info, selected_certs,
base::Bind(&TokenValidatorBase::OnCertificatesSelected,
weak_factory_.GetWeakPtr(), base::Owned(selected_certs),
base::Owned(client_cert_store)));
}
void TokenValidatorBase::OnCertificatesSelected(
net::CertificateList* selected_certs,
net::ClientCertStore* unused) {
const std::string& issuer =
third_party_auth_config_.token_validation_cert_issuer;
if (request_) {
for (size_t i = 0; i < selected_certs->size(); ++i) {
if (issuer == kCertIssuerWildCard ||
issuer == (*selected_certs)[i]->issuer().common_name) {
request_->ContinueWithCertificate((*selected_certs)[i]);
return;
}
}
request_->ContinueWithCertificate(NULL);
}
}
bool TokenValidatorBase::IsValidScope(const std::string& token_scope) {
// TODO(rmsousa): Deal with reordering/subsets/supersets/aliases/etc.
return token_scope == token_scope_;
}
std::string TokenValidatorBase::ProcessResponse() {
// Verify that we got a successful response.
net::URLRequestStatus status = request_->status();
if (!status.is_success()) {
LOG(ERROR) << "Error validating token, status=" << status.status()
<< " err=" << status.error();
return std::string();
}
int response = request_->GetResponseCode();
if (response != 200) {
LOG(ERROR)
<< "Error " << response << " validating token: '" << data_ << "'";
return std::string();
}
// Decode the JSON data from the response.
scoped_ptr<base::Value> value(base::JSONReader::Read(data_));
base::DictionaryValue* dict;
if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY ||
!value->GetAsDictionary(&dict)) {
LOG(ERROR) << "Invalid token validation response: '" << data_ << "'";
return std::string();
}
std::string token_scope;
dict->GetStringWithoutPathExpansion("scope", &token_scope);
if (!IsValidScope(token_scope)) {
LOG(ERROR) << "Invalid scope: '" << token_scope
<< "', expected: '" << token_scope_ <<"'.";
return std::string();
}
std::string shared_secret;
// Everything is valid, so return the shared secret to the caller.
dict->GetStringWithoutPathExpansion("access_token", &shared_secret);
return shared_secret;
}
} // namespace remoting
// Copyright 2014 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 REMOTING_HOST_TOKEN_VALIDATOR_BASE_H_
#define REMOTING_HOST_TOKEN_VALIDATOR_BASE_H_
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context_getter.h"
#include "remoting/protocol/token_validator.h"
#include "url/gurl.h"
namespace net {
class ClientCertStore;
typedef std::vector<scoped_refptr<X509Certificate> > CertificateList;
}
namespace remoting {
struct ThirdPartyAuthConfig {
inline bool is_empty() const {
return token_url.is_empty() && token_validation_url.is_empty();
}
inline bool is_valid() const {
return token_url.is_valid() && token_validation_url.is_valid();
}
GURL token_url;
GURL token_validation_url;
std::string token_validation_cert_issuer;
};
class TokenValidatorBase
: public net::URLRequest::Delegate,
public protocol::TokenValidator {
public:
TokenValidatorBase(
const ThirdPartyAuthConfig& third_party_auth_config,
const std::string& token_scope,
scoped_refptr<net::URLRequestContextGetter> request_context_getter);
virtual ~TokenValidatorBase();
// TokenValidator interface.
virtual void ValidateThirdPartyToken(
const std::string& token,
const base::Callback<void(
const std::string& shared_secret)>& on_token_validated) OVERRIDE;
virtual const GURL& token_url() const OVERRIDE;
virtual const std::string& token_scope() const OVERRIDE;
// URLRequest::Delegate interface.
virtual void OnResponseStarted(net::URLRequest* source) OVERRIDE;
virtual void OnReadCompleted(net::URLRequest* source,
int bytes_read) OVERRIDE;
virtual void OnCertificateRequested(
net::URLRequest* source,
net::SSLCertRequestInfo* cert_request_info) OVERRIDE;
protected:
void OnCertificatesSelected(net::CertificateList* selected_certs,
net::ClientCertStore* unused);
virtual void StartValidateRequest(const std::string& token) = 0;
virtual bool IsValidScope(const std::string& token_scope);
std::string ProcessResponse();
// Constructor parameters.
ThirdPartyAuthConfig third_party_auth_config_;
std::string token_scope_;
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
// URLRequest related fields.
scoped_ptr<net::URLRequest> request_;
scoped_refptr<net::IOBuffer> buffer_;
std::string data_;
base::Callback<void(const std::string& shared_secret)> on_token_validated_;
base::WeakPtrFactory<TokenValidatorBase> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(TokenValidatorBase);
};
} // namespace remoting
#endif // REMOTING_HOST_TOKEN_VALIDATOR_BASE_H
......@@ -10,29 +10,15 @@
#include "base/basictypes.h"
#include "net/url_request/url_request_context_getter.h"
#include "remoting/protocol/third_party_host_authenticator.h"
#include "remoting/host/token_validator_base.h"
#include "remoting/protocol/token_validator.h"
namespace remoting {
struct ThirdPartyAuthConfig {
inline bool is_empty() const {
return token_url.is_empty() && token_validation_url.is_empty();
}
inline bool is_valid() const {
return token_url.is_valid() && token_validation_url.is_valid();
}
GURL token_url;
GURL token_validation_url;
std::string token_validation_cert_issuer;
};
// This class dispenses |TokenValidator| implementations that use a UrlFetcher
// to contact a |token_validation_url| and exchange the |token| for a
// |shared_secret|.
class TokenValidatorFactoryImpl
: public protocol::ThirdPartyHostAuthenticator::TokenValidatorFactory {
class TokenValidatorFactoryImpl : public protocol::TokenValidatorFactory {
public:
// Creates a new factory. |token_url| and |token_validation_url| are the
// third party authentication service URLs, obtained via policy. |key_pair_|
......@@ -45,9 +31,9 @@ class TokenValidatorFactoryImpl
virtual ~TokenValidatorFactoryImpl();
// TokenValidatorFactory interface.
virtual scoped_ptr<protocol::ThirdPartyHostAuthenticator::TokenValidator>
CreateTokenValidator(const std::string& local_jid,
const std::string& remote_jid) OVERRIDE;
virtual scoped_ptr<protocol::TokenValidator> CreateTokenValidator(
const std::string& local_jid,
const std::string& remote_jid) OVERRIDE;
private:
ThirdPartyAuthConfig third_party_auth_config_;
......
......@@ -132,8 +132,7 @@ class TokenValidatorFactoryImplTest : public testing::Test {
scoped_refptr<RsaKeyPair> key_pair_;
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
scoped_ptr<TokenValidatorFactoryImpl> token_validator_factory_;
scoped_ptr<protocol::ThirdPartyHostAuthenticator::TokenValidator>
token_validator_;
scoped_ptr<protocol::TokenValidator> token_validator_;
};
TEST_F(TokenValidatorFactoryImplTest, Success) {
......
......@@ -9,6 +9,7 @@
#include "remoting/base/rsa_key_pair.h"
#include "remoting/protocol/channel_authenticator.h"
#include "remoting/protocol/negotiating_host_authenticator.h"
#include "remoting/protocol/token_validator.h"
#include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
namespace remoting {
......@@ -86,7 +87,7 @@ Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth(
const std::string& host_owner,
const std::string& local_cert,
scoped_refptr<RsaKeyPair> key_pair,
scoped_ptr<ThirdPartyHostAuthenticator::TokenValidatorFactory>
scoped_ptr<TokenValidatorFactory>
token_validator_factory) {
scoped_ptr<Me2MeHostAuthenticatorFactory> result(
new Me2MeHostAuthenticatorFactory());
......
......@@ -14,6 +14,7 @@
#include "remoting/protocol/authentication_method.h"
#include "remoting/protocol/authenticator.h"
#include "remoting/protocol/third_party_host_authenticator.h"
#include "remoting/protocol/token_validator.h"
namespace remoting {
......@@ -40,8 +41,7 @@ class Me2MeHostAuthenticatorFactory : public AuthenticatorFactory {
const std::string& host_owner,
const std::string& local_cert,
scoped_refptr<RsaKeyPair> key_pair,
scoped_ptr<ThirdPartyHostAuthenticator::TokenValidatorFactory>
token_validator_factory);
scoped_ptr<TokenValidatorFactory> token_validator_factory);
// Create a factory that dispenses rejecting authenticators (used when the
// host config/policy is inconsistent)
......@@ -67,8 +67,7 @@ class Me2MeHostAuthenticatorFactory : public AuthenticatorFactory {
SharedSecretHash shared_secret_hash_;
// Used only for third party host authenticators.
scoped_ptr<ThirdPartyHostAuthenticator::TokenValidatorFactory>
token_validator_factory_;
scoped_ptr<TokenValidatorFactory> token_validator_factory_;
// Used only for pairing host authenticators.
scoped_refptr<PairingRegistry> pairing_registry_;
......
......@@ -15,6 +15,7 @@
#include "remoting/protocol/channel_authenticator.h"
#include "remoting/protocol/pairing_host_authenticator.h"
#include "remoting/protocol/pairing_registry.h"
#include "remoting/protocol/token_validator.h"
#include "remoting/protocol/v2_authenticator.h"
#include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
......@@ -52,7 +53,7 @@ scoped_ptr<Authenticator>
NegotiatingHostAuthenticator::CreateWithThirdPartyAuth(
const std::string& local_cert,
scoped_refptr<RsaKeyPair> key_pair,
scoped_ptr<ThirdPartyHostAuthenticator::TokenValidator> token_validator) {
scoped_ptr<TokenValidator> token_validator) {
scoped_ptr<NegotiatingHostAuthenticator> result(
new NegotiatingHostAuthenticator(local_cert, key_pair));
result->token_validator_ = token_validator.Pass();
......
......@@ -43,7 +43,7 @@ class NegotiatingHostAuthenticator : public NegotiatingAuthenticatorBase {
static scoped_ptr<Authenticator> CreateWithThirdPartyAuth(
const std::string& local_cert,
scoped_refptr<RsaKeyPair> key_pair,
scoped_ptr<ThirdPartyHostAuthenticator::TokenValidator> token_validator);
scoped_ptr<TokenValidator> token_validator);
// Overriden from Authenticator.
virtual void ProcessMessage(const buzz::XmlElement* message,
......@@ -69,7 +69,7 @@ class NegotiatingHostAuthenticator : public NegotiatingAuthenticatorBase {
std::string shared_secret_hash_;
// Used only for third party host authenticators.
scoped_ptr<ThirdPartyHostAuthenticator::TokenValidator> token_validator_;
scoped_ptr<TokenValidator> token_validator_;
// Used only for pairing authenticators.
scoped_refptr<PairingRegistry> pairing_registry_;
......
......@@ -12,6 +12,7 @@
#include "remoting/protocol/third_party_authenticator_base.h"
#include "remoting/protocol/third_party_client_authenticator.h"
#include "remoting/protocol/third_party_host_authenticator.h"
#include "remoting/protocol/token_validator.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
......@@ -61,8 +62,7 @@ class ThirdPartyAuthenticatorTest : public AuthenticatorTestBase {
TokenFetchedCallback on_token_fetched_;
};
class FakeTokenValidator
: public ThirdPartyHostAuthenticator::TokenValidator {
class FakeTokenValidator : public TokenValidator {
public:
FakeTokenValidator()
: token_url_(kTokenUrl),
......@@ -104,8 +104,7 @@ class ThirdPartyAuthenticatorTest : public AuthenticatorTestBase {
protected:
void InitAuthenticators() {
scoped_ptr<ThirdPartyHostAuthenticator::TokenValidator>
token_validator(new FakeTokenValidator());
scoped_ptr<TokenValidator> token_validator(new FakeTokenValidator());
token_validator_ = static_cast<FakeTokenValidator*>(token_validator.get());
host_.reset(new ThirdPartyHostAuthenticator(
host_cert_, key_pair_, token_validator.Pass()));
......
......@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "remoting/base/constants.h"
#include "remoting/base/rsa_key_pair.h"
#include "remoting/protocol/token_validator.h"
#include "remoting/protocol/v2_authenticator.h"
#include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
......
......@@ -10,7 +10,6 @@
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "remoting/protocol/third_party_authenticator_base.h"
#include "url/gurl.h"
namespace remoting {
......@@ -18,6 +17,8 @@ class RsaKeyPair;
namespace protocol {
class TokenValidator;
// Implements the host side of the third party authentication mechanism.
// The host authenticator sends the |token_url| and |scope| obtained from the
// |TokenValidator| to the client, and expects a |token| in response.
......@@ -27,44 +28,6 @@ namespace protocol {
// |V2Authenticator|, which is used to establish the encrypted connection.
class ThirdPartyHostAuthenticator : public ThirdPartyAuthenticatorBase {
public:
class TokenValidator {
public:
// Callback passed to |ValidateThirdPartyToken|, and called once the host
// authentication finishes. |shared_secret| should be used by the host to
// create a V2Authenticator. In case of failure, the callback is called with
// an empty |shared_secret|.
typedef base::Callback<void(
const std::string& shared_secret)> TokenValidatedCallback;
virtual ~TokenValidator() {}
// Validates |token| with the server and exchanges it for a |shared_secret|.
// |token_validated_callback| is called when the host authentication ends,
// in the same thread |ValidateThirdPartyToken| was originally called.
// The request is canceled if this object is destroyed.
virtual void ValidateThirdPartyToken(
const std::string& token,
const TokenValidatedCallback& token_validated_callback) = 0;
// URL sent to the client, to be used by its |TokenFetcher| to get a token.
virtual const GURL& token_url() const = 0;
// Space-separated list of connection attributes the host must send to the
// client, and require the token received in response to match.
virtual const std::string& token_scope() const = 0;
};
class TokenValidatorFactory {
public:
virtual ~TokenValidatorFactory() {}
// Creates a TokenValidator. |local_jid| and |remote_jid| are used to create
// a token scope that is restricted to the current connection's JIDs.
virtual scoped_ptr<TokenValidator> CreateTokenValidator(
const std::string& local_jid,
const std::string& remote_jid) = 0;
};
// Creates a third-party host authenticator. |local_cert| and |key_pair| are
// used by the underlying V2Authenticator to create the SSL channels.
// |token_validator| contains the token parameters to be sent to the client
......
// Copyright 2014 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 REMOTING_PROTOCOL_TOKEN_VALIDATOR_H_
#define REMOTING_PROTOCOL_TOKEN_VALIDATOR_H_
#include <string>
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "url/gurl.h"
namespace remoting {
class RsaKeyPair;
namespace protocol {
// The |TokenValidator| encapsulates the parameters to be sent to the client
// to obtain a token, and the method to validate that token and obtain the
// shared secret for the connection.
class TokenValidator {
public:
// Callback passed to |ValidateThirdPartyToken|, and called once the host
// authentication finishes. |shared_secret| should be used by the host to
// create a V2Authenticator. In case of failure, the callback is called with
// an empty |shared_secret|.
typedef base::Callback<void(
const std::string& shared_secret)> TokenValidatedCallback;
virtual ~TokenValidator() {}
// Validates |token| with the server and exchanges it for a |shared_secret|.
// |token_validated_callback| is called when the host authentication ends,
// in the same thread |ValidateThirdPartyToken| was originally called.
// The request is canceled if this object is destroyed.
virtual void ValidateThirdPartyToken(
const std::string& token,
const TokenValidatedCallback& token_validated_callback) = 0;
// URL sent to the client, to be used by its |TokenFetcher| to get a token.
virtual const GURL& token_url() const = 0;
// Space-separated list of connection attributes the host must send to the
// client, and require the token received in response to match.
virtual const std::string& token_scope() const = 0;
};
// Factory for |TokenValidator|.
class TokenValidatorFactory {
public:
virtual ~TokenValidatorFactory() {}
// Creates a TokenValidator. |local_jid| and |remote_jid| are used to create
// a token scope that is restricted to the current connection's JIDs.
virtual scoped_ptr<TokenValidator> CreateTokenValidator(
const std::string& local_jid,
const std::string& remote_jid) = 0;
};
} // namespace protocol
} // namespace remoting
#endif // REMOTING_PROTOCOL_TOKEN_VALIDATOR_H_
......@@ -224,6 +224,8 @@
'host/shaped_screen_capturer.h',
'host/signaling_connector.cc',
'host/signaling_connector.h',
'host/token_validator_base.cc',
'host/token_validator_base.h',
'host/token_validator_factory_impl.cc',
'host/token_validator_factory_impl.h',
'host/usage_stats_consent.h',
......
......@@ -177,6 +177,7 @@
'protocol/third_party_client_authenticator.h',
'protocol/third_party_host_authenticator.cc',
'protocol/third_party_host_authenticator.h',
'protocol/token_validator.h',
'protocol/v2_authenticator.cc',
'protocol/v2_authenticator.h',
'protocol/video_reader.cc',
......
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