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

Side by Side Diff: remoting/protocol/third_party_authenticator.cc

Issue 12326090: Third Party authentication protocol. (Closed) Base URL: http://git.chromium.org/chromium/src.git@host_key_pair
Patch Set: Add the missing new files Created 7 years, 10 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 (c) 2012 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/protocol/third_party_authenticator.h"
6
7 #include "base/base64.h"
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "base/logging.h"
11 #include "crypto/rsa_private_key.h"
12 #include "remoting/base/constants.h"
13 #include "remoting/protocol/channel_authenticator.h"
14 #include "remoting/protocol/v2_authenticator.h"
15 #include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
16
17 #if defined(_WIN32) && defined(GetMessage)
Sergey Ulanov 2013/02/26 01:14:50 Do you need this here?
rmsousa 2013/03/05 03:30:24 Done.
18 #undef GetMessage
19 #endif
20
21 namespace {
22
23 const buzz::StaticQName kTokenUrlTag = { remoting::kChromotingXmlNamespace,
24 "third-party-token-url" };
25 const buzz::StaticQName kTokenScopeTag = { remoting::kChromotingXmlNamespace,
26 "third-party-token-scope" };
27 const buzz::StaticQName kTokenTag = { remoting::kChromotingXmlNamespace,
28 "third-party-token" };
29 } // namespace
30
Sergey Ulanov 2013/02/26 01:14:50 remove extra empty line.
rmsousa 2013/03/05 03:30:24 Done.
31
32 namespace remoting {
33 namespace protocol {
34
35 // static
36 scoped_ptr<Authenticator> ThirdPartyAuthenticator::CreateForClient(
37 const std::string& host_public_key,
38 ThirdPartyAuthenticator::TokenFetcher* token_fetcher,
39 Authenticator::State initial_state) {
40 scoped_ptr<ThirdPartyAuthenticator> result(new ThirdPartyAuthenticator(
41 initial_state));
42 result->host_public_key_ = host_public_key;
43 result->token_fetcher_ = token_fetcher;
44 return scoped_ptr<Authenticator>(result.Pass());
45 }
46 // static
Wez 2013/02/27 07:05:30 nit: Blank line, plz
rmsousa 2013/03/05 03:30:24 Done.
47 scoped_ptr<Authenticator> ThirdPartyAuthenticator::CreateForHost(
48 const std::string& local_cert,
49 scoped_ptr<KeyPair> key_pair,
50 const std::string& token_url,
51 const std::string& token_validation_url,
52 const std::string& token_scope,
53 scoped_ptr<ThirdPartyAuthenticator::TokenValidator> token_validator,
54 Authenticator::State initial_state) {
55 scoped_ptr<ThirdPartyAuthenticator> result(new ThirdPartyAuthenticator(
56 initial_state));
57 result->local_cert_ = local_cert;
58 result->key_pair_ = key_pair.Pass();
59 result->host_public_key_ = result->key_pair_->GetPublicKey();
60 result->token_url_ = token_url;
61 result->token_validation_url_ = token_validation_url;
62 result->token_scope_ = token_scope;
63 result->token_validator_ = token_validator.Pass();
64 result->expecting_token_ = false;
Sergey Ulanov 2013/02/26 01:14:50 don't need this - it should be already initialized
rmsousa 2013/03/05 03:30:24 Done.
65 return scoped_ptr<Authenticator>(result.Pass());
66 }
67
68 ThirdPartyAuthenticator::ThirdPartyAuthenticator(
Sergey Ulanov 2013/02/26 01:14:50 Would it make sense two have separate classes - on
Wez 2013/02/27 07:05:30 Agreed. You don't really need a public class for
rmsousa 2013/03/05 03:30:24 Done.
rmsousa 2013/03/05 03:30:24 I separated in one public class plus two local sub
69 Authenticator::State initial_state)
70 : expecting_token_(false),
71 token_validator_(NULL),
72 token_fetcher_(NULL),
73 state_(initial_state),
74 rejection_reason_(INVALID_CREDENTIALS),
75 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
76 }
77
78 ThirdPartyAuthenticator::~ThirdPartyAuthenticator() {
79 }
80
81 Authenticator::State ThirdPartyAuthenticator::state() const {
82 if (state_ == ACCEPTED) {
Wez 2013/02/27 07:05:30 nit: No need for {} for simple single-line if.
83 return underlying_->state();
84 }
85 return state_;
86 }
87
88 Authenticator::RejectionReason ThirdPartyAuthenticator::rejection_reason()
89 const {
90 DCHECK_EQ(state(), REJECTED);
91 if (state_ == REJECTED) {
92 return rejection_reason_;
93 } else {
94 return underlying_->rejection_reason();
95 }
96 }
97
98 void ThirdPartyAuthenticator::ProcessMessage(const buzz::XmlElement* message) {
99 DCHECK_EQ(state(), WAITING_MESSAGE);
100
101 // The other side may have started the SPAKE negotiation.
102 // Keep a copy of the message until the V2 authenticator is ready.
103 const buzz::XmlElement* underlying_message =
104 Authenticator::FindAuthenticatorMessage(message);
105 if (underlying_message) {
106 if (underlying_) {
107 // Pass the message through the underlying authenticator.
108 DCHECK_EQ(underlying_->state(), WAITING_MESSAGE);
109 underlying_->ProcessMessage(underlying_message);
110 } else {
111 pending_message_.reset(new buzz::XmlElement(*underlying_message));
112 }
113 }
114
115 if (state_ == WAITING_MESSAGE) {
Sergey Ulanov 2013/02/26 01:14:50 there is a DCHECK for this condition at the top, s
Wez 2013/02/27 07:05:30 Is the caller responsible for never calling Proces
rmsousa 2013/03/05 03:30:24 the DCHECK is for state(), which is the authentica
rmsousa 2013/03/05 03:30:24 The caller is responsible for not calling if state
116 if (!is_host_side()) {
117 if (token_url_.empty()) {
118 // First message from the host, token URL and scope.
Wez 2013/02/27 07:05:30 nit: Make the above a sentence. Also, please move
119 DCHECK(token_scope_.empty());
120 token_url_ = message->TextNamed(kTokenUrlTag);
121 token_scope_ = message->TextNamed(kTokenScopeTag);
122 if (!token_url_.empty() && !token_scope_.empty()) {
123 state_ = WAITING_EXTERNAL;
124 return;
125 }
126 }
127 LOG(WARNING) << "Missing token issue URL/verification URL/scope.";
128 } else {
129 if (!expecting_token_) {
Wez 2013/02/27 07:05:30 Should this be |has_sent_urls| instead?
rmsousa 2013/03/05 03:30:24 Done.
130 // The host hasn't send the token URLs to the client yet, so ignore the
Wez 2013/02/27 07:05:30 typo: send -> sent
rmsousa 2013/03/05 03:30:24 Done.
131 // first message and send the URLs to the client.
132 state_ = MESSAGE_READY;
133 return;
134 }
135 DCHECK(token_.empty());
136 DCHECK(token_signature_.empty());
137 // Host has already sent the URL and expects a token from the client.
138 token_ = message->TextNamed(kTokenTag);
139 token_signature_ = key_pair_->GetSignature(token_);
140 if (!token_.empty() && !token_signature_.empty()) {
141 state_ = WAITING_EXTERNAL;
142 return;
143 }
144 LOG(WARNING) << "Missing token.";
145 }
146 state_ = REJECTED;
147 rejection_reason_ = PROTOCOL_ERROR;
148 return;
149 }
150 }
151
152 scoped_ptr<buzz::XmlElement> ThirdPartyAuthenticator::GetNextMessage() {
153 DCHECK_EQ(state(), MESSAGE_READY);
154
155 scoped_ptr<buzz::XmlElement> message = CreateEmptyAuthenticatorMessage();
156 if (state_ == MESSAGE_READY) {
Sergey Ulanov 2013/02/26 01:14:50 same here - there is a DCHECK for this condition.
157 if (!is_host_side()) {
158 if (!token_.empty()) {
159 buzz::XmlElement* token_tag = new buzz::XmlElement(kTokenTag);
160 token_tag->SetBodyText(token_);
161 message->AddElement(token_tag);
162 } else {
163 // The client doesn't really have anything to send yet, it's just
164 // waiting for the host to send the token_url.
Wez 2013/02/27 07:05:30 Surely the client should never be in the MESSAGE_R
rmsousa 2013/03/05 03:30:24 We expect an authentication message on the session
165 }
166 } else {
167 if (token_.empty()) {
168 DCHECK(!token_url_.empty());
169 DCHECK(!token_scope_.empty());
170 buzz::XmlElement* token_url_tag = new buzz::XmlElement(
171 kTokenUrlTag);
172 token_url_tag->SetBodyText(token_url_);
173 message->AddElement(token_url_tag);
174 buzz::XmlElement* token_scope_tag = new buzz::XmlElement(
175 kTokenScopeTag);
176 token_scope_tag->SetBodyText(token_scope_);
177 message->AddElement(token_scope_tag);
178 expecting_token_ = true;
179 }
180 }
181 }
182 if (underlying_ && underlying_->state() == MESSAGE_READY) {
Wez 2013/02/27 07:05:30 nit: Blank lines before & after this if...else...
rmsousa 2013/03/05 03:30:24 Done.
183 DCHECK(!shared_secret_.empty());
184 // This side already has the shared secret and can start the SPAKE
185 // negotiation in parallel with the remaining token messages.
186 message->AddElement(underlying_->GetNextMessage().release());
187 state_ = ACCEPTED;
188 } else {
189 state_ = WAITING_MESSAGE;
190 }
191 return message.Pass();
192 }
193
194 scoped_ptr<ChannelAuthenticator>
195 ThirdPartyAuthenticator::CreateChannelAuthenticator() const {
196 DCHECK_EQ(state(), ACCEPTED);
197 return underlying_->CreateChannelAuthenticator();
198 }
199
200 bool ThirdPartyAuthenticator::is_host_side() const {
201 return !token_fetcher_;
202 }
203
204 void ThirdPartyAuthenticator::PerformExternalAction(
205 const base::Closure& resume_callback) {
206 DCHECK_EQ(state(), WAITING_EXTERNAL);
207 if (is_host_side()) {
Sergey Ulanov 2013/02/26 01:14:50 Here the order of client and host parts is reverse
rmsousa 2013/03/05 03:30:24 Done.
208 DCHECK(!token_signature_.empty());
209 DCHECK(!token_validation_url_.empty());
210 DCHECK(!token_.empty());
211 DCHECK(!host_public_key_.empty());
212 DCHECK(!token_scope_.empty());
213 token_validator_->ValidateThirdPartyToken(
214 token_validation_url_, token_, host_public_key_, token_signature_,
215 token_scope_, base::Bind(
216 &ThirdPartyAuthenticator::OnThirdPartyTokenValidated,
217 weak_factory_.GetWeakPtr(),
218 resume_callback));
219 } else {
220 DCHECK(token_.empty());
221 token_fetcher_->FetchThirdPartyToken(
222 token_url_, host_public_key_, token_scope_, base::Bind(
223 &ThirdPartyAuthenticator::OnThirdPartyTokenFetched,
224 weak_factory_.GetWeakPtr(),
225 resume_callback));
226 }
227 }
228
229 void ThirdPartyAuthenticator::OnThirdPartyTokenFetched(
230 const base::Closure& resume_callback, const std::string& third_party_token,
Sergey Ulanov 2013/02/26 01:14:50 nit: one argument per line please when whole funct
rmsousa 2013/03/05 03:30:24 Done.
231 const std::string& shared_secret) {
232 DCHECK_EQ(state_, WAITING_EXTERNAL);
233 DCHECK(!is_host_side());
234 token_ = third_party_token;
235 if (!token_.empty() && !shared_secret.empty()) {
236 this->OnThirdPartyTokenValidated(resume_callback, shared_secret);
237 return;
238 }
239 state_ = REJECTED;
240 rejection_reason_ = INVALID_CREDENTIALS;
241 resume_callback.Run();
242 }
243
244 void ThirdPartyAuthenticator::OnThirdPartyTokenValidated(
245 const base::Closure& resume_callback, const std::string& shared_secret) {
Sergey Ulanov 2013/02/26 01:14:50 one argument per line please
rmsousa 2013/03/05 03:30:24 Done.
246 DCHECK_EQ(state_, WAITING_EXTERNAL);
247 shared_secret_ = shared_secret;
248 Authenticator::State initial_state;
249 if (!shared_secret_.empty()) {
250 if (pending_message_) {
251 // The other side already started the SPAKE authentication.
252 state_ = ACCEPTED;
253 initial_state = WAITING_MESSAGE;
254 } else {
255 // The other side still needs data from this side to start SPAKE.
256 state_ = MESSAGE_READY;
257 initial_state = MESSAGE_READY;
258 }
259 if (is_host_side()) {
260 underlying_ = V2Authenticator::CreateForHost(
261 local_cert_, key_pair_->Copy(), shared_secret_,
262 initial_state);
263 } else {
264 underlying_ = V2Authenticator::CreateForClient(
265 shared_secret_, initial_state);
266 }
267 if (pending_message_) {
268 underlying_->ProcessMessage(pending_message_.release());
269 DCHECK_NE(underlying_->state(), WAITING_MESSAGE);
270 }
271 } else {
272 state_ = REJECTED;
273 rejection_reason_ = INVALID_CREDENTIALS;
274 }
275 resume_callback.Run();
276 }
277
278 } // namespace protocol
279 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698