Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(29)

Side by Side Diff: remoting/host/url_fetcher_token_validator_factory.cc

Issue 12313085: Host-side third party token validation (Closed) Base URL: http://git.chromium.org/chromium/src.git@third_party_auth_protocol
Patch Set: Add missing parameters Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "remoting/host/url_fetcher_token_validator_factory.h"
6
7 #include <set>
8
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/values.h"
17 #include "crypto/random.h"
18 #include "googleurl/src/gurl.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
25 namespace {
26
27 // Length in bytes of the cryptographic nonce used to salt the token scope.
28 const size_t kNonceLength = 16; // 128 bits.
Sergey Ulanov 2013/03/28 22:34:54 indentation
rmsousa 2013/04/04 22:13:43 Done.
29
30 }
31
32 namespace remoting {
33
34 class UrlFetcherTokenValidator
35 : public net::URLFetcherDelegate,
36 public protocol::ThirdPartyHostAuthenticator::TokenValidator {
37 public:
38 UrlFetcherTokenValidator(
39 const GURL& token_url,
40 const GURL& token_validation_url,
41 scoped_refptr<RsaKeyPair> key_pair,
42 const std::string& local_jid,
43 const std::string& remote_jid,
44 scoped_refptr<net::URLRequestContextGetter> request_context_getter)
45 : token_url_(token_url),
46 token_validation_url_(token_validation_url),
47 key_pair_(key_pair),
48 request_context_getter_(request_context_getter) {
49 DCHECK(token_url_.is_valid());
50 DCHECK(token_validation_url_.is_valid());
51 DCHECK(key_pair_);
52 token_scope_ = CreateScope(local_jid, remote_jid);
53 }
54
55 virtual ~UrlFetcherTokenValidator() {
56 }
57
58 // TokenValidator interface.
59 virtual void ValidateThirdPartyToken(
60 const std::string& token,
61 const base::Callback<void(
62 const std::string& shared_secret)>& on_token_validated) OVERRIDE {
63 DCHECK(!request_);
64 DCHECK(!on_token_validated.is_null());
65
66 on_token_validated_ = on_token_validated;
67
68 std::string post_body =
69 "code=" + net::EscapeUrlEncodedData(token, true) +
70 "&client_id=" + net::EscapeUrlEncodedData(
71 key_pair_->GetPublicKey(), true) +
72 "&client_secret=" + net::EscapeUrlEncodedData(
73 key_pair_->SignMessage(token), true) +
74 "&grant_type=authorization_code";
75 request_.reset(net::URLFetcher::Create(
76 token_validation_url_, net::URLFetcher::POST, this));
77 request_->SetUploadData("application/x-www-form-urlencoded", post_body);
Sergey Ulanov 2013/03/28 22:34:54 Can we use json here instead of url-encoding the d
rmsousa 2013/03/28 23:12:49 I'm trying to follow the OAuth protocol, which use
Sergey Ulanov 2013/03/28 23:39:39 I'm not sure why we need to worry about OAuth here
rmsousa 2013/04/04 22:13:43 Yes, the protocol will be OAuth. It's possible to
78 request_->SetRequestContext(request_context_getter_);
79 request_->Start();
80 }
81
82 virtual const GURL& token_url() const OVERRIDE {
83 return token_url_;
84 }
85
86 virtual const std::string& token_scope() const OVERRIDE {
87 return token_scope_;
88 }
89
90 // URLFetcherDelegate interface.
91 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
92 DCHECK_EQ(request_.get(), source);
93 std::string shared_token = GetSharedSecretFromResponse(source);
94 on_token_validated_.Run(shared_token);
95 request_.reset();
96 }
97
98 private:
99 bool IsValidScope(const std::string& token_scope) {
100 // TODO(rmsousa): Deal with reordering/subsets/supersets/aliases/etc.
101 return token_scope == token_scope_;
102 }
103
104 static std::string CreateScope(const std::string& local_jid,
105 const std::string& remote_jid) {
106 char nonce_bytes[kNonceLength];
107 crypto::RandBytes(nonce_bytes, kNonceLength);
108 std::string nonce;
109 bool success = base::Base64Encode(nonce_bytes, &nonce);
110 DCHECK(success);
111 return "client:" + remote_jid + " host:" + local_jid + " nonce:" + nonce;
112 }
113
114 std::string GetSharedSecretFromResponse(const net::URLFetcher* source) {
Sergey Ulanov 2013/03/28 22:34:54 Maybe call it ProcessResponse?
Sergey Ulanov 2013/03/28 22:34:54 |source| is a meaningless name in this context, bu
rmsousa 2013/04/04 22:13:43 Done.
rmsousa 2013/04/04 22:13:43 Done.
115 std::string shared_secret;
116
117 // Verify that we got a successful response.
118 int response = source->GetResponseCode();
119 net::URLRequestStatus status = source->GetStatus();
120 std::string data;
121 if (!status.is_success() || response != 200) {
122 LOG(ERROR) <<
Sergey Ulanov 2013/03/28 22:34:54 nit: wrap << operator
rmsousa 2013/04/04 22:13:43 Done.
123 "Error " << response << " validating token: '" << data << "'";
124 return shared_secret;
Sergey Ulanov 2013/03/28 22:34:54 This is confusing. Maybe better to return std::str
rmsousa 2013/04/04 22:13:43 Done.
125 }
126
127 // Decode the JSON data from the response.
128 source->GetResponseAsString(&data);
129 scoped_ptr<base::Value> value(base::JSONReader::Read(data));
130 if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY) {
131 LOG(ERROR) << "Invalid token validation response: '" << data << "'";
132 return shared_secret;
133 }
134
135 // Get the scope from the response, and verify that it is valid.
136 DictionaryValue* dict = static_cast<DictionaryValue*>(value.get());
Sergey Ulanov 2013/03/28 22:34:54 Ouch. Instead of downcasting using static_cast<> u
rmsousa 2013/04/04 22:13:43 Done.
137 std::string token_scope;
138 dict->GetStringWithoutPathExpansion("scope", &token_scope);
139 if (!IsValidScope(token_scope)) {
140 LOG(ERROR) << "Invalid scope: '" << token_scope
141 << "', expected: '" << token_scope_ <<"'.";
142 return shared_secret;
143 }
144
145 // Everything is valid, so return the shared secret to the caller.
146 dict->GetStringWithoutPathExpansion("access_token", &shared_secret);
147 return shared_secret;
148 }
149
150 scoped_ptr<net::URLFetcher> request_;
151 GURL token_url_;
152 GURL token_validation_url_;
153 scoped_refptr<RsaKeyPair> key_pair_;
154 std::string token_scope_;
155 scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
156 base::Callback<void(const std::string& shared_secret)> on_token_validated_;
157
158 DISALLOW_COPY_AND_ASSIGN(UrlFetcherTokenValidator);
159 };
160
161 UrlFetcherTokenValidatorFactory::UrlFetcherTokenValidatorFactory(
162 scoped_refptr<net::URLRequestContextGetter> request_context_getter)
163 : request_context_getter_(request_context_getter) {
164 }
165
166 UrlFetcherTokenValidatorFactory::~UrlFetcherTokenValidatorFactory() {
167 }
168
169 scoped_ptr<protocol::ThirdPartyHostAuthenticator::TokenValidator>
170 UrlFetcherTokenValidatorFactory::CreateTokenValidator(
171 const GURL& token_url,
172 const GURL& token_validation_url,
173 scoped_refptr<RsaKeyPair> key_pair,
174 const std::string& local_jid,
175 const std::string& remote_jid) {
176 return scoped_ptr<protocol::ThirdPartyHostAuthenticator::TokenValidator>(
177 new UrlFetcherTokenValidator(token_url, token_validation_url, key_pair,
178 local_jid, remote_jid, request_context_getter_));
Sergey Ulanov 2013/03/28 22:34:54 indentation
rmsousa 2013/04/04 22:13:43 Done.
179 }
180
181 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698