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