summaryrefslogtreecommitdiffstats
path: root/remoting/host/token_validator_factory_impl.cc
diff options
context:
space:
mode:
authorrmsousa@chromium.org <rmsousa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-06 04:50:43 +0000
committerrmsousa@chromium.org <rmsousa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-06 04:50:43 +0000
commit4386f0a9e032a669a6e6c311965ff3a9903850b9 (patch)
treed98e16fb9510c3391b780459c7d0f4b864af02d7 /remoting/host/token_validator_factory_impl.cc
parent46ad339269e5805bb499ebb76ce1077ff8c8d5be (diff)
downloadchromium_src-4386f0a9e032a669a6e6c311965ff3a9903850b9.zip
chromium_src-4386f0a9e032a669a6e6c311965ff3a9903850b9.tar.gz
chromium_src-4386f0a9e032a669a6e6c311965ff3a9903850b9.tar.bz2
Host-side third party token validation
This creates a TokenValidator implementation on the host, that upon receiving a token: Signs the token with its private key. Uses URLFetcher to request the exchange of the token for a secret from the Token Validation URL. On receiving a reply, checks that the scope in the reply matches the one required for this connection. Uses the callback to send the shared_token back to the authentication layer. (The server will authenticate the host by checking that the token signature matches the host public key that the client included in the token request) BUG=115899 Review URL: https://chromiumcodereview.appspot.com/12313085 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@192701 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/host/token_validator_factory_impl.cc')
-rw-r--r--remoting/host/token_validator_factory_impl.cc184
1 files changed, 184 insertions, 0 deletions
diff --git a/remoting/host/token_validator_factory_impl.cc b/remoting/host/token_validator_factory_impl.cc
new file mode 100644
index 0000000..a61bfaa
--- /dev/null
+++ b/remoting/host/token_validator_factory_impl.cc
@@ -0,0 +1,184 @@
+// Copyright 2013 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_factory_impl.h"
+
+#include <set>
+
+#include "base/base64.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/json/json_reader.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/single_thread_task_runner.h"
+#include "base/values.h"
+#include "crypto/random.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/escape.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "net/url_request/url_request_status.h"
+#include "remoting/base/rsa_key_pair.h"
+
+namespace {
+
+// Length in bytes of the cryptographic nonce used to salt the token scope.
+const size_t kNonceLength = 16; // 128 bits.
+
+}
+
+namespace remoting {
+
+class TokenValidatorImpl
+ : public net::URLFetcherDelegate,
+ public protocol::ThirdPartyHostAuthenticator::TokenValidator {
+ public:
+ TokenValidatorImpl(
+ const GURL& token_url,
+ const GURL& token_validation_url,
+ scoped_refptr<RsaKeyPair> key_pair,
+ const std::string& local_jid,
+ const std::string& remote_jid,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter)
+ : token_url_(token_url),
+ token_validation_url_(token_validation_url),
+ key_pair_(key_pair),
+ request_context_getter_(request_context_getter) {
+ DCHECK(token_url_.is_valid());
+ DCHECK(token_validation_url_.is_valid());
+ DCHECK(key_pair_);
+ token_scope_ = CreateScope(local_jid, remote_jid);
+ }
+
+ virtual ~TokenValidatorImpl() {
+ }
+
+ // TokenValidator interface.
+ virtual void ValidateThirdPartyToken(
+ const std::string& token,
+ const base::Callback<void(
+ const std::string& shared_secret)>& on_token_validated) OVERRIDE {
+ DCHECK(!request_);
+ DCHECK(!on_token_validated.is_null());
+
+ on_token_validated_ = on_token_validated;
+
+ std::string post_body =
+ "code=" + net::EscapeUrlEncodedData(token, true) +
+ "&client_id=" + net::EscapeUrlEncodedData(
+ key_pair_->GetPublicKey(), true) +
+ "&client_secret=" + net::EscapeUrlEncodedData(
+ key_pair_->SignMessage(token), true) +
+ "&grant_type=authorization_code";
+ request_.reset(net::URLFetcher::Create(
+ token_validation_url_, net::URLFetcher::POST, this));
+ request_->SetUploadData("application/x-www-form-urlencoded", post_body);
+ request_->SetRequestContext(request_context_getter_);
+ request_->Start();
+ }
+
+ virtual const GURL& token_url() const OVERRIDE {
+ return token_url_;
+ }
+
+ virtual const std::string& token_scope() const OVERRIDE {
+ return token_scope_;
+ }
+
+ // URLFetcherDelegate interface.
+ virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
+ DCHECK_EQ(request_.get(), source);
+ std::string shared_token = ProcessResponse();
+ on_token_validated_.Run(shared_token);
+ request_.reset();
+ }
+
+ private:
+ bool IsValidScope(const std::string& token_scope) {
+ // TODO(rmsousa): Deal with reordering/subsets/supersets/aliases/etc.
+ return token_scope == token_scope_;
+ }
+
+ static std::string CreateScope(const std::string& local_jid,
+ const std::string& remote_jid) {
+ char nonce_bytes[kNonceLength];
+ crypto::RandBytes(nonce_bytes, kNonceLength);
+ std::string nonce;
+ bool success = base::Base64Encode(nonce_bytes, &nonce);
+ DCHECK(success);
+ return "client:" + remote_jid + " host:" + local_jid + " nonce:" + nonce;
+ }
+
+ std::string ProcessResponse() {
+ // Verify that we got a successful response.
+ int response = request_->GetResponseCode();
+ net::URLRequestStatus status = request_->GetStatus();
+ std::string data;
+ if (!status.is_success() || response != 200) {
+ LOG(ERROR)
+ << "Error " << response << " validating token: '" << data << "'";
+ return std::string();
+ }
+
+ // Decode the JSON data from the response.
+ request_->GetResponseAsString(&data);
+ scoped_ptr<base::Value> value(base::JSONReader::Read(data));
+ 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;
+ }
+
+ scoped_ptr<net::URLFetcher> request_;
+ GURL token_url_;
+ GURL token_validation_url_;
+ scoped_refptr<RsaKeyPair> key_pair_;
+ std::string token_scope_;
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+ base::Callback<void(const std::string& shared_secret)> on_token_validated_;
+
+ DISALLOW_COPY_AND_ASSIGN(TokenValidatorImpl);
+};
+
+TokenValidatorFactoryImpl::TokenValidatorFactoryImpl(
+ const GURL& token_url,
+ const GURL& token_validation_url,
+ scoped_refptr<RsaKeyPair> key_pair,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter)
+ : token_url_(token_url),
+ token_validation_url_(token_validation_url),
+ key_pair_(key_pair),
+ request_context_getter_(request_context_getter) {
+}
+
+TokenValidatorFactoryImpl::~TokenValidatorFactoryImpl() {
+}
+
+scoped_ptr<protocol::ThirdPartyHostAuthenticator::TokenValidator>
+TokenValidatorFactoryImpl::CreateTokenValidator(
+ const std::string& local_jid,
+ const std::string& remote_jid) {
+ return scoped_ptr<protocol::ThirdPartyHostAuthenticator::TokenValidator>(
+ new TokenValidatorImpl(token_url_, token_validation_url_, key_pair_,
+ local_jid, remote_jid,
+ request_context_getter_));
+}
+
+} // namespace remoting