1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// found in the LICENSE file.
4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "remoting/host/token_validator_base.h"
6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/base64.h"
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/bind.h"
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/callback.h"
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/json/json_reader.h"
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/logging.h"
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/memory/weak_ptr.h"
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/single_thread_task_runner.h"
14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/strings/string_util.h"
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/values.h"
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/base/escape.h"
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/base/io_buffer.h"
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/base/request_priority.h"
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/base/upload_bytes_element_reader.h"
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/base/upload_data_stream.h"
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/ssl/client_cert_store.h"
22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if defined(USE_NSS)
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/ssl/client_cert_store_nss.h"
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#elif defined(OS_WIN)
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/ssl/client_cert_store_win.h"
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#elif defined(OS_MACOSX)
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/ssl/client_cert_store_mac.h"
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/ssl/ssl_cert_request_info.h"
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/url_request/url_request.h"
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/url_request/url_request_context.h"
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/url_request/url_request_status.h"
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "url/gurl.h"
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace {
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kBufferSize = 4096;
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const char kCertIssuerWildCard[] = "*";
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace remoting {
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TokenValidatorBase::TokenValidatorBase(
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const ThirdPartyAuthConfig& third_party_auth_config,
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& token_scope,
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_refptr<net::URLRequestContextGetter> request_context_getter)
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : third_party_auth_config_(third_party_auth_config),
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      token_scope_(token_scope),
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      request_context_getter_(request_context_getter),
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      buffer_(new net::IOBuffer(kBufferSize)),
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      weak_factory_(this) {
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(third_party_auth_config_.token_url.is_valid());
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(third_party_auth_config_.token_validation_url.is_valid());
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TokenValidatorBase::~TokenValidatorBase() {
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// TokenValidator interface.
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void TokenValidatorBase::ValidateThirdPartyToken(
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& token,
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const base::Callback<void(
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        const std::string& shared_secret)>& on_token_validated) {
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(!request_);
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(!on_token_validated.is_null());
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  on_token_validated_ = on_token_validated;
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  StartValidateRequest(token);
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const GURL& TokenValidatorBase::token_url() const {
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return third_party_auth_config_.token_url;
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const std::string& TokenValidatorBase::token_scope() const {
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return token_scope_;
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// URLFetcherDelegate interface.
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void TokenValidatorBase::OnResponseStarted(net::URLRequest* source) {
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK_EQ(request_.get(), source);
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int bytes_read = 0;
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request_->Read(buffer_.get(), kBufferSize, &bytes_read);
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  OnReadCompleted(request_.get(), bytes_read);
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void TokenValidatorBase::OnReadCompleted(net::URLRequest* source,
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                         int bytes_read) {
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK_EQ(request_.get(), source);
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  do {
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (!request_->status().is_success() || bytes_read <= 0)
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      break;
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    data_.append(buffer_->data(), bytes_read);
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } while (request_->Read(buffer_.get(), kBufferSize, &bytes_read));
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const net::URLRequestStatus status = request_->status();
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!status.is_io_pending()) {
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    std::string shared_token = ProcessResponse();
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    request_.reset();
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    on_token_validated_.Run(shared_token);
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void TokenValidatorBase::OnCertificateRequested(
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    net::URLRequest* source,
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    net::SSLCertRequestInfo* cert_request_info) {
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK_EQ(request_.get(), source);
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  net::ClientCertStore* client_cert_store;
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if defined(USE_NSS)
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  client_cert_store = new net::ClientCertStoreNSS(
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      net::ClientCertStoreNSS::PasswordDelegateFactory());
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#elif defined(OS_WIN)
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  client_cert_store = new net::ClientCertStoreWin();
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#elif defined(OS_MACOSX)
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  client_cert_store = new net::ClientCertStoreMac();
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#elif defined(USE_OPENSSL)
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // OpenSSL does not use the ClientCertStore infrastructure.
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  client_cert_store = NULL;
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#else
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#error Unknown platform.
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif
129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // The callback is uncancellable, and GetClientCert requires selected_certs
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // and client_cert_store to stay alive until the callback is called. So we
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // must give it a WeakPtr for |this|, and ownership of the other parameters.
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  net::CertificateList* selected_certs(new net::CertificateList());
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  client_cert_store->GetClientCerts(
134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      *cert_request_info, selected_certs,
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&TokenValidatorBase::OnCertificatesSelected,
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 weak_factory_.GetWeakPtr(), base::Owned(selected_certs),
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 base::Owned(client_cert_store)));
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void TokenValidatorBase::OnCertificatesSelected(
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    net::CertificateList* selected_certs,
142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    net::ClientCertStore* unused) {
143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const std::string& issuer =
144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      third_party_auth_config_.token_validation_cert_issuer;
145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (request_) {
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for (size_t i = 0; i < selected_certs->size(); ++i) {
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (issuer == kCertIssuerWildCard ||
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          issuer == (*selected_certs)[i]->issuer().common_name) {
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        request_->ContinueWithCertificate((*selected_certs)[i].get());
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        return;
151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    request_->ContinueWithCertificate(NULL);
154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool TokenValidatorBase::IsValidScope(const std::string& token_scope) {
158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // TODO(rmsousa): Deal with reordering/subsets/supersets/aliases/etc.
159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return token_scope == token_scope_;
160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)std::string TokenValidatorBase::ProcessResponse() {
163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Verify that we got a successful response.
164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  net::URLRequestStatus status = request_->status();
165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!status.is_success()) {
166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LOG(ERROR) << "Error validating token, status=" << status.status()
167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)               << " err=" << status.error();
168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return std::string();
169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int response = request_->GetResponseCode();
172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (response != 200) {
173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LOG(ERROR)
174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        << "Error " << response << " validating token: '" << data_ << "'";
175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return std::string();
176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Decode the JSON data from the response.
179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<base::Value> value(base::JSONReader::Read(data_));
180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::DictionaryValue* dict;
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY ||
182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      !value->GetAsDictionary(&dict)) {
183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LOG(ERROR) << "Invalid token validation response: '" << data_ << "'";
184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return std::string();
185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string token_scope;
188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  dict->GetStringWithoutPathExpansion("scope", &token_scope);
189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!IsValidScope(token_scope)) {
190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LOG(ERROR) << "Invalid scope: '" << token_scope
191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)               << "', expected: '" << token_scope_ <<"'.";
192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return std::string();
193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string shared_secret;
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Everything is valid, so return the shared secret to the caller.
197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  dict->GetStringWithoutPathExpansion("access_token", &shared_secret);
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return shared_secret;
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace remoting
202