Introduced IDR_SIGNIN_INTERNALS_INDEX_* strings to grit_whitelist.txt
[chromium-blink-merge.git] / remoting / host / token_validator_factory_impl.cc
blob3dd92456546b0875109b32e72f5a330566478575
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "remoting/host/token_validator_factory_impl.h"
7 #include <set>
9 #include "base/base64.h"
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/json/json_reader.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/strings/string_util.h"
17 #include "base/values.h"
18 #include "crypto/random.h"
19 #include "net/base/escape.h"
20 #include "net/url_request/url_fetcher.h"
21 #include "net/url_request/url_fetcher_delegate.h"
22 #include "net/url_request/url_request_status.h"
23 #include "remoting/base/rsa_key_pair.h"
24 #include "url/gurl.h"
26 namespace {
28 // Length in bytes of the cryptographic nonce used to salt the token scope.
29 const size_t kNonceLength = 16; // 128 bits.
33 namespace remoting {
35 class TokenValidatorImpl
36 : public net::URLFetcherDelegate,
37 public protocol::ThirdPartyHostAuthenticator::TokenValidator {
38 public:
39 TokenValidatorImpl(
40 const GURL& token_url,
41 const GURL& token_validation_url,
42 scoped_refptr<RsaKeyPair> key_pair,
43 const std::string& local_jid,
44 const std::string& remote_jid,
45 scoped_refptr<net::URLRequestContextGetter> request_context_getter)
46 : token_url_(token_url),
47 token_validation_url_(token_validation_url),
48 key_pair_(key_pair),
49 request_context_getter_(request_context_getter) {
50 DCHECK(token_url_.is_valid());
51 DCHECK(token_validation_url_.is_valid());
52 DCHECK(key_pair_.get());
53 token_scope_ = CreateScope(local_jid, remote_jid);
56 virtual ~TokenValidatorImpl() {
59 // TokenValidator interface.
60 virtual void ValidateThirdPartyToken(
61 const std::string& token,
62 const base::Callback<void(
63 const std::string& shared_secret)>& on_token_validated) OVERRIDE {
64 DCHECK(!request_);
65 DCHECK(!on_token_validated.is_null());
67 on_token_validated_ = on_token_validated;
69 std::string post_body =
70 "code=" + net::EscapeUrlEncodedData(token, true) +
71 "&client_id=" + net::EscapeUrlEncodedData(
72 key_pair_->GetPublicKey(), true) +
73 "&client_secret=" + net::EscapeUrlEncodedData(
74 key_pair_->SignMessage(token), true) +
75 "&grant_type=authorization_code";
76 request_.reset(net::URLFetcher::Create(
77 0, token_validation_url_, net::URLFetcher::POST, this));
78 request_->SetUploadData("application/x-www-form-urlencoded", post_body);
79 request_->SetRequestContext(request_context_getter_.get());
80 request_->Start();
83 virtual const GURL& token_url() const OVERRIDE {
84 return token_url_;
87 virtual const std::string& token_scope() const OVERRIDE {
88 return token_scope_;
91 // URLFetcherDelegate interface.
92 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
93 DCHECK_EQ(request_.get(), source);
94 std::string shared_token = ProcessResponse();
95 request_.reset();
96 on_token_validated_.Run(shared_token);
99 private:
100 bool IsValidScope(const std::string& token_scope) {
101 // TODO(rmsousa): Deal with reordering/subsets/supersets/aliases/etc.
102 return token_scope == token_scope_;
105 static std::string CreateScope(const std::string& local_jid,
106 const std::string& remote_jid) {
107 std::string nonce_bytes;
108 crypto::RandBytes(WriteInto(&nonce_bytes, kNonceLength + 1), kNonceLength);
109 std::string nonce;
110 bool success = base::Base64Encode(nonce_bytes, &nonce);
111 DCHECK(success);
112 return "client:" + remote_jid + " host:" + local_jid + " nonce:" + nonce;
115 std::string ProcessResponse() {
116 // Verify that we got a successful response.
117 net::URLRequestStatus status = request_->GetStatus();
118 if (!status.is_success()) {
119 LOG(ERROR) << "Error validating token, status=" << status.status()
120 << " err=" << status.error();
121 return std::string();
124 int response = request_->GetResponseCode();
125 std::string data;
126 request_->GetResponseAsString(&data);
127 if (response != 200) {
128 LOG(ERROR)
129 << "Error " << response << " validating token: '" << data << "'";
130 return std::string();
133 // Decode the JSON data from the response.
134 scoped_ptr<base::Value> value(base::JSONReader::Read(data));
135 DictionaryValue* dict;
136 if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY ||
137 !value->GetAsDictionary(&dict)) {
138 LOG(ERROR) << "Invalid token validation response: '" << data << "'";
139 return std::string();
142 std::string token_scope;
143 dict->GetStringWithoutPathExpansion("scope", &token_scope);
144 if (!IsValidScope(token_scope)) {
145 LOG(ERROR) << "Invalid scope: '" << token_scope
146 << "', expected: '" << token_scope_ <<"'.";
147 return std::string();
150 std::string shared_secret;
151 // Everything is valid, so return the shared secret to the caller.
152 dict->GetStringWithoutPathExpansion("access_token", &shared_secret);
153 return shared_secret;
156 scoped_ptr<net::URLFetcher> request_;
157 GURL token_url_;
158 GURL token_validation_url_;
159 scoped_refptr<RsaKeyPair> key_pair_;
160 std::string token_scope_;
161 scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
162 base::Callback<void(const std::string& shared_secret)> on_token_validated_;
164 DISALLOW_COPY_AND_ASSIGN(TokenValidatorImpl);
167 TokenValidatorFactoryImpl::TokenValidatorFactoryImpl(
168 const GURL& token_url,
169 const GURL& token_validation_url,
170 scoped_refptr<RsaKeyPair> key_pair,
171 scoped_refptr<net::URLRequestContextGetter> request_context_getter)
172 : token_url_(token_url),
173 token_validation_url_(token_validation_url),
174 key_pair_(key_pair),
175 request_context_getter_(request_context_getter) {
178 TokenValidatorFactoryImpl::~TokenValidatorFactoryImpl() {
181 scoped_ptr<protocol::ThirdPartyHostAuthenticator::TokenValidator>
182 TokenValidatorFactoryImpl::CreateTokenValidator(
183 const std::string& local_jid,
184 const std::string& remote_jid) {
185 return scoped_ptr<protocol::ThirdPartyHostAuthenticator::TokenValidator>(
186 new TokenValidatorImpl(token_url_, token_validation_url_, key_pair_,
187 local_jid, remote_jid,
188 request_context_getter_));
191 } // namespace remoting