1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "remoting/host/token_validator_factory_impl.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/base64.h"
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/bind.h"
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/callback.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/json/json_reader.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/logging.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/single_thread_task_runner.h"
135e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/values.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "crypto/random.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/base/escape.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/base/io_buffer.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/base/request_priority.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/base/upload_bytes_element_reader.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/base/upload_data_stream.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/url_request/url_request.h"
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/url_request/url_request_context.h"
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/url_request/url_request_status.h"
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "remoting/base/rsa_key_pair.h"
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "remoting/host/token_validator_base.h"
267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Length in bytes of the cryptographic nonce used to salt the token scope.
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const size_t kNonceLength = 16;  // 128 bits.
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace remoting {
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class TokenValidatorImpl : public TokenValidatorBase {
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public:
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  TokenValidatorImpl(
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const ThirdPartyAuthConfig& third_party_auth_config,
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      scoped_refptr<RsaKeyPair> key_pair,
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const std::string& local_jid,
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const std::string& remote_jid,
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scoped_refptr<net::URLRequestContextGetter> request_context_getter);
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) protected:
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual void StartValidateRequest(const std::string& token) OVERRIDE;
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static std::string CreateScope(const std::string& local_jid,
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 const std::string& remote_jid);
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string post_body_;
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<RsaKeyPair> key_pair_;
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(TokenValidatorImpl);
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TokenValidatorImpl::TokenValidatorImpl(
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ThirdPartyAuthConfig& third_party_auth_config,
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<RsaKeyPair> key_pair,
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& local_jid,
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& remote_jid,
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<net::URLRequestContextGetter> request_context_getter)
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : TokenValidatorBase(third_party_auth_config,
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         CreateScope(local_jid, remote_jid),
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         request_context_getter),
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      key_pair_(key_pair) {
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(key_pair_.get());
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  token_scope_ = CreateScope(local_jid, remote_jid);
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// TokenValidator interface.
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void TokenValidatorImpl::StartValidateRequest(const std::string& token) {
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  post_body_ = "code=" + net::EscapeUrlEncodedData(token, true) +
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "&client_id=" + net::EscapeUrlEncodedData(
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          key_pair_->GetPublicKey(), true) +
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "&client_secret=" + net::EscapeUrlEncodedData(
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          key_pair_->SignMessage(token), true) +
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "&grant_type=authorization_code";
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  request_ = request_context_getter_->GetURLRequestContext()->CreateRequest(
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      third_party_auth_config_.token_validation_url, net::DEFAULT_PRIORITY,
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      this, NULL);
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  request_->SetExtraRequestHeaderByName(
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      net::HttpRequestHeaders::kContentType,
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "application/x-www-form-urlencoded", true);
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  request_->set_method("POST");
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<net::UploadElementReader> reader(
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new net::UploadBytesElementReader(
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          post_body_.data(), post_body_.size()));
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  request_->set_upload(make_scoped_ptr(
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      net::UploadDataStream::CreateWithReader(reader.Pass(), 0)));
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  request_->Start();
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string TokenValidatorImpl::CreateScope(
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& local_jid,
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& remote_jid) {
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string nonce_bytes;
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  crypto::RandBytes(WriteInto(&nonce_bytes, kNonceLength + 1), kNonceLength);
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string nonce;
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::Base64Encode(nonce_bytes, &nonce);
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return "client:" + remote_jid + " host:" + local_jid + " nonce:" + nonce;
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TokenValidatorFactoryImpl::TokenValidatorFactoryImpl(
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ThirdPartyAuthConfig& third_party_auth_config,
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_refptr<RsaKeyPair> key_pair,
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_refptr<net::URLRequestContextGetter> request_context_getter)
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : third_party_auth_config_(third_party_auth_config),
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      key_pair_(key_pair),
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      request_context_getter_(request_context_getter) {
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TokenValidatorFactoryImpl::~TokenValidatorFactoryImpl() {
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)scoped_ptr<protocol::TokenValidator>
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TokenValidatorFactoryImpl::CreateTokenValidator(
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& local_jid,
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& remote_jid) {
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return scoped_ptr<protocol::TokenValidator>(
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new TokenValidatorImpl(third_party_auth_config_,
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             key_pair_, local_jid, remote_jid,
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             request_context_getter_));
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace remoting
131