| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/host/token_validator_factory_impl.h" | 5 #include "remoting/host/token_validator_factory_impl.h" |
| 6 | 6 |
| 7 #include <set> | |
| 8 | |
| 9 #include "base/base64.h" | 7 #include "base/base64.h" |
| 10 #include "base/bind.h" | 8 #include "base/bind.h" |
| 11 #include "base/callback.h" | 9 #include "base/callback.h" |
| 12 #include "base/json/json_reader.h" | 10 #include "base/json/json_reader.h" |
| 13 #include "base/location.h" | |
| 14 #include "base/logging.h" | 11 #include "base/logging.h" |
| 15 #include "base/memory/weak_ptr.h" | |
| 16 #include "base/single_thread_task_runner.h" | 12 #include "base/single_thread_task_runner.h" |
| 17 #include "base/strings/string_util.h" | 13 #include "base/strings/string_util.h" |
| 18 #include "base/values.h" | 14 #include "base/values.h" |
| 19 #include "crypto/random.h" | 15 #include "crypto/random.h" |
| 20 #include "net/base/escape.h" | 16 #include "net/base/escape.h" |
| 21 #include "net/base/io_buffer.h" | 17 #include "net/base/io_buffer.h" |
| 22 #include "net/base/request_priority.h" | 18 #include "net/base/request_priority.h" |
| 23 #include "net/base/upload_bytes_element_reader.h" | 19 #include "net/base/upload_bytes_element_reader.h" |
| 24 #include "net/base/upload_data_stream.h" | 20 #include "net/base/upload_data_stream.h" |
| 25 #include "net/ssl/client_cert_store.h" | |
| 26 #if defined(USE_NSS) | |
| 27 #include "net/ssl/client_cert_store_nss.h" | |
| 28 #elif defined(OS_WIN) | |
| 29 #include "net/ssl/client_cert_store_win.h" | |
| 30 #elif defined(OS_MACOSX) | |
| 31 #include "net/ssl/client_cert_store_mac.h" | |
| 32 #endif | |
| 33 #include "net/ssl/ssl_cert_request_info.h" | |
| 34 #include "net/url_request/url_request.h" | 21 #include "net/url_request/url_request.h" |
| 35 #include "net/url_request/url_request_context.h" | 22 #include "net/url_request/url_request_context.h" |
| 36 #include "net/url_request/url_request_status.h" | 23 #include "net/url_request/url_request_status.h" |
| 37 #include "remoting/base/rsa_key_pair.h" | 24 #include "remoting/base/rsa_key_pair.h" |
| 25 #include "remoting/host/token_validator_base.h" |
| 38 #include "url/gurl.h" | 26 #include "url/gurl.h" |
| 39 | 27 |
| 40 namespace { | 28 namespace { |
| 41 | 29 |
| 42 // Length in bytes of the cryptographic nonce used to salt the token scope. | 30 // Length in bytes of the cryptographic nonce used to salt the token scope. |
| 43 const size_t kNonceLength = 16; // 128 bits. | 31 const size_t kNonceLength = 16; // 128 bits. |
| 44 const int kBufferSize = 4096; | |
| 45 const char kCertIssuerWildCard[] = "*"; | |
| 46 | 32 |
| 47 } // namespace | 33 } // namespace |
| 48 | 34 |
| 49 namespace remoting { | 35 namespace remoting { |
| 50 | 36 |
| 51 class TokenValidatorImpl | 37 |
| 52 : public net::URLRequest::Delegate, | 38 class TokenValidatorImpl : public TokenValidatorBase { |
| 53 public protocol::ThirdPartyHostAuthenticator::TokenValidator { | |
| 54 public: | 39 public: |
| 55 TokenValidatorImpl( | 40 TokenValidatorImpl( |
| 56 const ThirdPartyAuthConfig& third_party_auth_config, | 41 const ThirdPartyAuthConfig& third_party_auth_config, |
| 57 scoped_refptr<RsaKeyPair> key_pair, | 42 scoped_refptr<RsaKeyPair> key_pair, |
| 58 const std::string& local_jid, | 43 const std::string& local_jid, |
| 59 const std::string& remote_jid, | 44 const std::string& remote_jid, |
| 60 scoped_refptr<net::URLRequestContextGetter> request_context_getter); | 45 scoped_refptr<net::URLRequestContextGetter> request_context_getter); |
| 61 virtual ~TokenValidatorImpl(); | |
| 62 | 46 |
| 63 // TokenValidator interface. | 47 protected: |
| 64 virtual const GURL& token_url() const OVERRIDE; | 48 virtual void StartValidateRequest(const std::string& token) OVERRIDE; |
| 65 virtual const std::string& token_scope() const OVERRIDE; | |
| 66 virtual void ValidateThirdPartyToken( | |
| 67 const std::string& token, | |
| 68 const base::Callback<void( | |
| 69 const std::string& shared_secret)>& on_token_validated) OVERRIDE; | |
| 70 | |
| 71 // URLFetcherDelegate interface. | |
| 72 virtual void OnResponseStarted(net::URLRequest* source) OVERRIDE; | |
| 73 virtual void OnReadCompleted(net::URLRequest* source, | |
| 74 int bytes_read) OVERRIDE; | |
| 75 virtual void OnCertificateRequested( | |
| 76 net::URLRequest* source, | |
| 77 net::SSLCertRequestInfo* cert_request_info) OVERRIDE; | |
| 78 | 49 |
| 79 private: | 50 private: |
| 80 static std::string CreateScope(const std::string& local_jid, | 51 static std::string CreateScope(const std::string& local_jid, |
| 81 const std::string& remote_jid); | 52 const std::string& remote_jid); |
| 82 | 53 |
| 83 void OnCertificatesSelected(net::CertificateList* selected_certs, | |
| 84 net::ClientCertStore* unused); | |
| 85 bool IsValidScope(const std::string& token_scope); | |
| 86 std::string ProcessResponse(); | |
| 87 | |
| 88 std::string post_body_; | 54 std::string post_body_; |
| 89 scoped_ptr<net::URLRequest> request_; | |
| 90 scoped_refptr<net::IOBuffer> buffer_; | |
| 91 std::string data_; | |
| 92 ThirdPartyAuthConfig third_party_auth_config_; | |
| 93 scoped_refptr<RsaKeyPair> key_pair_; | 55 scoped_refptr<RsaKeyPair> key_pair_; |
| 94 std::string token_scope_; | |
| 95 scoped_refptr<net::URLRequestContextGetter> request_context_getter_; | |
| 96 base::Callback<void(const std::string& shared_secret)> on_token_validated_; | |
| 97 | |
| 98 base::WeakPtrFactory<TokenValidatorImpl> weak_factory_; | |
| 99 | 56 |
| 100 DISALLOW_COPY_AND_ASSIGN(TokenValidatorImpl); | 57 DISALLOW_COPY_AND_ASSIGN(TokenValidatorImpl); |
| 101 }; | 58 }; |
| 102 | 59 |
| 103 TokenValidatorImpl::TokenValidatorImpl( | 60 TokenValidatorImpl::TokenValidatorImpl( |
| 104 const ThirdPartyAuthConfig& third_party_auth_config, | 61 const ThirdPartyAuthConfig& third_party_auth_config, |
| 105 scoped_refptr<RsaKeyPair> key_pair, | 62 scoped_refptr<RsaKeyPair> key_pair, |
| 106 const std::string& local_jid, | 63 const std::string& local_jid, |
| 107 const std::string& remote_jid, | 64 const std::string& remote_jid, |
| 108 scoped_refptr<net::URLRequestContextGetter> request_context_getter) | 65 scoped_refptr<net::URLRequestContextGetter> request_context_getter) |
| 109 : buffer_(new net::IOBuffer(kBufferSize)), | 66 : TokenValidatorBase(third_party_auth_config, |
| 110 third_party_auth_config_(third_party_auth_config), | 67 CreateScope(local_jid, remote_jid), |
| 111 key_pair_(key_pair), | 68 request_context_getter), |
| 112 request_context_getter_(request_context_getter), | 69 key_pair_(key_pair) { |
| 113 weak_factory_(this) { | |
| 114 DCHECK(third_party_auth_config_.token_url.is_valid()); | |
| 115 DCHECK(third_party_auth_config_.token_validation_url.is_valid()); | |
| 116 DCHECK(key_pair_.get()); | 70 DCHECK(key_pair_.get()); |
| 117 token_scope_ = CreateScope(local_jid, remote_jid); | 71 token_scope_ = CreateScope(local_jid, remote_jid); |
| 118 } | 72 } |
| 119 | 73 |
| 120 TokenValidatorImpl::~TokenValidatorImpl() { | |
| 121 } | |
| 122 | |
| 123 // TokenValidator interface. | 74 // TokenValidator interface. |
| 124 void TokenValidatorImpl::ValidateThirdPartyToken( | 75 void TokenValidatorImpl::StartValidateRequest(const std::string& token) { |
| 125 const std::string& token, | |
| 126 const base::Callback<void( | |
| 127 const std::string& shared_secret)>& on_token_validated) { | |
| 128 DCHECK(!request_); | |
| 129 DCHECK(!on_token_validated.is_null()); | |
| 130 | |
| 131 on_token_validated_ = on_token_validated; | |
| 132 | |
| 133 post_body_ = "code=" + net::EscapeUrlEncodedData(token, true) + | 76 post_body_ = "code=" + net::EscapeUrlEncodedData(token, true) + |
| 134 "&client_id=" + net::EscapeUrlEncodedData( | 77 "&client_id=" + net::EscapeUrlEncodedData( |
| 135 key_pair_->GetPublicKey(), true) + | 78 key_pair_->GetPublicKey(), true) + |
| 136 "&client_secret=" + net::EscapeUrlEncodedData( | 79 "&client_secret=" + net::EscapeUrlEncodedData( |
| 137 key_pair_->SignMessage(token), true) + | 80 key_pair_->SignMessage(token), true) + |
| 138 "&grant_type=authorization_code"; | 81 "&grant_type=authorization_code"; |
| 139 | 82 |
| 140 request_ = request_context_getter_->GetURLRequestContext()->CreateRequest( | 83 request_ = request_context_getter_->GetURLRequestContext()->CreateRequest( |
| 141 third_party_auth_config_.token_validation_url, net::DEFAULT_PRIORITY, | 84 third_party_auth_config_.token_validation_url, net::DEFAULT_PRIORITY, |
| 142 this); | 85 this); |
| 143 request_->SetExtraRequestHeaderByName( | 86 request_->SetExtraRequestHeaderByName( |
| 144 net::HttpRequestHeaders::kContentType, | 87 net::HttpRequestHeaders::kContentType, |
| 145 "application/x-www-form-urlencoded", true); | 88 "application/x-www-form-urlencoded", true); |
| 146 request_->set_method("POST"); | 89 request_->set_method("POST"); |
| 147 scoped_ptr<net::UploadElementReader> reader( | 90 scoped_ptr<net::UploadElementReader> reader( |
| 148 new net::UploadBytesElementReader( | 91 new net::UploadBytesElementReader( |
| 149 post_body_.data(), post_body_.size())); | 92 post_body_.data(), post_body_.size())); |
| 150 request_->set_upload(make_scoped_ptr( | 93 request_->set_upload(make_scoped_ptr( |
| 151 net::UploadDataStream::CreateWithReader(reader.Pass(), 0))); | 94 net::UploadDataStream::CreateWithReader(reader.Pass(), 0))); |
| 152 request_->Start(); | 95 request_->Start(); |
| 153 } | 96 } |
| 154 | 97 |
| 155 const GURL& TokenValidatorImpl::token_url() const { | |
| 156 return third_party_auth_config_.token_url; | |
| 157 } | |
| 158 | |
| 159 const std::string& TokenValidatorImpl::token_scope() const { | |
| 160 return token_scope_; | |
| 161 } | |
| 162 | |
| 163 // URLFetcherDelegate interface. | |
| 164 void TokenValidatorImpl::OnResponseStarted(net::URLRequest* source) { | |
| 165 DCHECK_EQ(request_.get(), source); | |
| 166 | |
| 167 int bytes_read = 0; | |
| 168 request_->Read(buffer_.get(), kBufferSize, &bytes_read); | |
| 169 OnReadCompleted(request_.get(), bytes_read); | |
| 170 } | |
| 171 | |
| 172 void TokenValidatorImpl::OnReadCompleted(net::URLRequest* source, | |
| 173 int bytes_read) { | |
| 174 DCHECK_EQ(request_.get(), source); | |
| 175 | |
| 176 do { | |
| 177 if (!request_->status().is_success() || bytes_read <= 0) | |
| 178 break; | |
| 179 | |
| 180 data_.append(buffer_->data(), bytes_read); | |
| 181 } while (request_->Read(buffer_.get(), kBufferSize, &bytes_read)); | |
| 182 | |
| 183 const net::URLRequestStatus status = request_->status(); | |
| 184 | |
| 185 if (!status.is_io_pending()) { | |
| 186 std::string shared_token = ProcessResponse(); | |
| 187 request_.reset(); | |
| 188 on_token_validated_.Run(shared_token); | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 void TokenValidatorImpl::OnCertificateRequested( | |
| 193 net::URLRequest* source, | |
| 194 net::SSLCertRequestInfo* cert_request_info) { | |
| 195 DCHECK_EQ(request_.get(), source); | |
| 196 | |
| 197 net::ClientCertStore* client_cert_store; | |
| 198 #if defined(USE_NSS) | |
| 199 client_cert_store = new net::ClientCertStoreNSS( | |
| 200 net::ClientCertStoreNSS::PasswordDelegateFactory()); | |
| 201 #elif defined(OS_WIN) | |
| 202 client_cert_store = new net::ClientCertStoreWin(); | |
| 203 #elif defined(OS_MACOSX) | |
| 204 client_cert_store = new net::ClientCertStoreMac(); | |
| 205 #else | |
| 206 #error Unknown platform. | |
| 207 #endif | |
| 208 // The callback is uncancellable, and GetClientCert requires selected_certs | |
| 209 // and client_cert_store to stay alive until the callback is called. So we | |
| 210 // must give it a WeakPtr for |this|, and ownership of the other parameters. | |
| 211 net::CertificateList* selected_certs(new net::CertificateList()); | |
| 212 client_cert_store->GetClientCerts( | |
| 213 *cert_request_info, selected_certs, | |
| 214 base::Bind(&TokenValidatorImpl::OnCertificatesSelected, | |
| 215 weak_factory_.GetWeakPtr(), base::Owned(selected_certs), | |
| 216 base::Owned(client_cert_store))); | |
| 217 } | |
| 218 | |
| 219 void TokenValidatorImpl::OnCertificatesSelected( | |
| 220 net::CertificateList* selected_certs, | |
| 221 net::ClientCertStore* unused) { | |
| 222 const std::string& issuer = | |
| 223 third_party_auth_config_.token_validation_cert_issuer; | |
| 224 if (request_) { | |
| 225 for (size_t i = 0; i < selected_certs->size(); ++i) { | |
| 226 if (issuer == kCertIssuerWildCard || | |
| 227 issuer == (*selected_certs)[i]->issuer().common_name) { | |
| 228 request_->ContinueWithCertificate((*selected_certs)[i]); | |
| 229 return; | |
| 230 } | |
| 231 } | |
| 232 request_->ContinueWithCertificate(NULL); | |
| 233 } | |
| 234 } | |
| 235 | |
| 236 bool TokenValidatorImpl::IsValidScope(const std::string& token_scope) { | |
| 237 // TODO(rmsousa): Deal with reordering/subsets/supersets/aliases/etc. | |
| 238 return token_scope == token_scope_; | |
| 239 } | |
| 240 | |
| 241 std::string TokenValidatorImpl::CreateScope( | 98 std::string TokenValidatorImpl::CreateScope( |
| 242 const std::string& local_jid, | 99 const std::string& local_jid, |
| 243 const std::string& remote_jid) { | 100 const std::string& remote_jid) { |
| 244 std::string nonce_bytes; | 101 std::string nonce_bytes; |
| 245 crypto::RandBytes(WriteInto(&nonce_bytes, kNonceLength + 1), kNonceLength); | 102 crypto::RandBytes(WriteInto(&nonce_bytes, kNonceLength + 1), kNonceLength); |
| 246 std::string nonce; | 103 std::string nonce; |
| 247 base::Base64Encode(nonce_bytes, &nonce); | 104 base::Base64Encode(nonce_bytes, &nonce); |
| 248 return "client:" + remote_jid + " host:" + local_jid + " nonce:" + nonce; | 105 return "client:" + remote_jid + " host:" + local_jid + " nonce:" + nonce; |
| 249 } | 106 } |
| 250 | 107 |
| 251 std::string TokenValidatorImpl::ProcessResponse() { | |
| 252 // Verify that we got a successful response. | |
| 253 net::URLRequestStatus status = request_->status(); | |
| 254 if (!status.is_success()) { | |
| 255 LOG(ERROR) << "Error validating token, status=" << status.status() | |
| 256 << " err=" << status.error(); | |
| 257 return std::string(); | |
| 258 } | |
| 259 | |
| 260 int response = request_->GetResponseCode(); | |
| 261 if (response != 200) { | |
| 262 LOG(ERROR) | |
| 263 << "Error " << response << " validating token: '" << data_ << "'"; | |
| 264 return std::string(); | |
| 265 } | |
| 266 | |
| 267 // Decode the JSON data from the response. | |
| 268 scoped_ptr<base::Value> value(base::JSONReader::Read(data_)); | |
| 269 base::DictionaryValue* dict; | |
| 270 if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY || | |
| 271 !value->GetAsDictionary(&dict)) { | |
| 272 LOG(ERROR) << "Invalid token validation response: '" << data_ << "'"; | |
| 273 return std::string(); | |
| 274 } | |
| 275 | |
| 276 std::string token_scope; | |
| 277 dict->GetStringWithoutPathExpansion("scope", &token_scope); | |
| 278 if (!IsValidScope(token_scope)) { | |
| 279 LOG(ERROR) << "Invalid scope: '" << token_scope | |
| 280 << "', expected: '" << token_scope_ <<"'."; | |
| 281 return std::string(); | |
| 282 } | |
| 283 | |
| 284 std::string shared_secret; | |
| 285 // Everything is valid, so return the shared secret to the caller. | |
| 286 dict->GetStringWithoutPathExpansion("access_token", &shared_secret); | |
| 287 return shared_secret; | |
| 288 } | |
| 289 | |
| 290 TokenValidatorFactoryImpl::TokenValidatorFactoryImpl( | 108 TokenValidatorFactoryImpl::TokenValidatorFactoryImpl( |
| 291 const ThirdPartyAuthConfig& third_party_auth_config, | 109 const ThirdPartyAuthConfig& third_party_auth_config, |
| 292 scoped_refptr<RsaKeyPair> key_pair, | 110 scoped_refptr<RsaKeyPair> key_pair, |
| 293 scoped_refptr<net::URLRequestContextGetter> request_context_getter) | 111 scoped_refptr<net::URLRequestContextGetter> request_context_getter) |
| 294 : third_party_auth_config_(third_party_auth_config), | 112 : third_party_auth_config_(third_party_auth_config), |
| 295 key_pair_(key_pair), | 113 key_pair_(key_pair), |
| 296 request_context_getter_(request_context_getter) { | 114 request_context_getter_(request_context_getter) { |
| 297 } | 115 } |
| 298 | 116 |
| 299 TokenValidatorFactoryImpl::~TokenValidatorFactoryImpl() { | 117 TokenValidatorFactoryImpl::~TokenValidatorFactoryImpl() { |
| 300 } | 118 } |
| 301 | 119 |
| 302 scoped_ptr<protocol::ThirdPartyHostAuthenticator::TokenValidator> | 120 scoped_ptr<protocol::TokenValidator> |
| 303 TokenValidatorFactoryImpl::CreateTokenValidator( | 121 TokenValidatorFactoryImpl::CreateTokenValidator( |
| 304 const std::string& local_jid, | 122 const std::string& local_jid, |
| 305 const std::string& remote_jid) { | 123 const std::string& remote_jid) { |
| 306 return scoped_ptr<protocol::ThirdPartyHostAuthenticator::TokenValidator>( | 124 return scoped_ptr<protocol::TokenValidator>( |
| 307 new TokenValidatorImpl(third_party_auth_config_, | 125 new TokenValidatorImpl(third_party_auth_config_, |
| 308 key_pair_, local_jid, remote_jid, | 126 key_pair_, local_jid, remote_jid, |
| 309 request_context_getter_)); | 127 request_context_getter_)); |
| 310 } | 128 } |
| 311 | 129 |
| 312 } // namespace remoting | 130 } // namespace remoting |
| OLD | NEW |