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

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: TokenFetcher/Validator ownership, move parameters to Validator, remove client/host glue 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/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 "remoting/base/constants.h"
12 #include "remoting/base/rsa_key_pair.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 namespace {
18
19 const buzz::StaticQName kTokenUrlTag = { remoting::kChromotingXmlNamespace,
20 "third-party-token-url" };
Sergey Ulanov 2013/03/05 04:09:11 nit: indent
rmsousa 2013/03/06 00:54:16 Done.
21 const buzz::StaticQName kTokenScopeTag = { remoting::kChromotingXmlNamespace,
22 "third-party-token-scope" };
23 const buzz::StaticQName kTokenTag = { remoting::kChromotingXmlNamespace,
24 "third-party-token" };
25 } // namespace
26
27 namespace remoting {
28 namespace protocol {
29
30 class ClientThirdPartyAuthenticator : public ThirdPartyAuthenticator {
Sergey Ulanov 2013/03/05 04:09:11 Why does this need to be in .cc file? I suggest re
rmsousa 2013/03/06 00:54:16 Done.
31 public:
32 ClientThirdPartyAuthenticator(const std::string& host_public_key,
33 scoped_ptr<TokenFetcher> token_fetcher,
34 Authenticator::State initial_state);
Wez 2013/03/05 22:55:53 nit: Need public virtual dtor.
rmsousa 2013/03/06 00:54:16 Done.
35
36 protected:
37 // ThirdPartyAuthenticator implementation.
38 virtual void ProcessMessageInternal(
39 const buzz::XmlElement* message,
40 const base::Closure& resume_callback) OVERRIDE;
41 virtual void GetNextMessageInternal(buzz::XmlElement* message) OVERRIDE;
42
43 private:
44 void OnThirdPartyTokenFetched(const base::Closure& resume_callback,
45 const std::string& third_party_token,
46 const std::string& shared_secret);
47
48 std::string host_public_key_;
49 std::string token_;
50 scoped_ptr<TokenFetcher> token_fetcher_;
51 };
52
53 class HostThirdPartyAuthenticator : public ThirdPartyAuthenticator {
Wez 2013/03/05 22:55:53 nit: I'd normally define one class and implement i
rmsousa 2013/03/06 00:54:16 separated into different files.
54 public:
55 HostThirdPartyAuthenticator(const std::string& local_cert,
56 scoped_refptr<RsaKeyPair> key_pair,
57 scoped_ptr<TokenValidator> token_validator,
58 Authenticator::State initial_state);
Wez 2013/03/05 22:55:53 nit: Need public virtual dtor.
59
60 protected:
61 // ThirdPartyAuthenticator implementation.
62 virtual void ProcessMessageInternal(
63 const buzz::XmlElement* message,
64 const base::Closure& resume_callback) OVERRIDE;
65 virtual void GetNextMessageInternal(buzz::XmlElement* message) OVERRIDE;
66
67 private:
68 void OnThirdPartyTokenValidated(const buzz::XmlElement* message,
69 const base::Closure& resume_callback,
70 const std::string& shared_secret);
Wez 2013/03/05 22:55:53 nit: Blank line after this.
71 bool has_sent_urls_;
72 std::string local_cert_;
73 scoped_refptr<RsaKeyPair> key_pair_;
74 scoped_ptr<TokenValidator> token_validator_;
75 };
76
77 // static
78 scoped_ptr<Authenticator> ThirdPartyAuthenticator::CreateForClient(
79 const std::string& host_public_key,
80 scoped_ptr<ThirdPartyAuthenticator::TokenFetcher> token_fetcher,
81 Authenticator::State initial_state) {
82 scoped_ptr<Authenticator> result(new ClientThirdPartyAuthenticator(
83 host_public_key, token_fetcher.Pass(), initial_state));
84 return result.Pass();
85 }
86
87 // static
88 scoped_ptr<Authenticator> ThirdPartyAuthenticator::CreateForHost(
89 const std::string& local_cert,
90 scoped_refptr<RsaKeyPair> key_pair,
91 scoped_ptr<HostThirdPartyAuthenticator::TokenValidator> token_validator,
92 Authenticator::State initial_state) {
93 scoped_ptr<Authenticator> result(new HostThirdPartyAuthenticator(
94 local_cert, key_pair, token_validator.Pass(), initial_state));
95 return result.Pass();
96 }
97
98 ThirdPartyAuthenticator::ThirdPartyAuthenticator(
99 Authenticator::State initial_state)
100 : state_(initial_state),
101 rejection_reason_(INVALID_CREDENTIALS) {
102 }
103
104 ThirdPartyAuthenticator::~ThirdPartyAuthenticator() {
105 }
106
107 Authenticator::State ThirdPartyAuthenticator::state() const {
108 if (state_ == ACCEPTED) {
109 return underlying_->state();
110 }
111 return state_;
112 }
113
114 Authenticator::RejectionReason ThirdPartyAuthenticator::rejection_reason()
115 const {
116 DCHECK_EQ(state(), REJECTED);
117
118 if (state_ == REJECTED) {
119 return rejection_reason_;
120 } else {
121 return underlying_->rejection_reason();
122 }
123 }
124
125 void ThirdPartyAuthenticator::ProcessMessage(
126 const buzz::XmlElement* message,
127 const base::Closure& resume_callback) {
128 DCHECK_EQ(state(), WAITING_MESSAGE);
129
130 if (state_ == WAITING_MESSAGE) {
131 ProcessMessageInternal(message, resume_callback);
132 } else {
133 DCHECK(state_ == ACCEPTED);
134 DCHECK(underlying_);
135 DCHECK(underlying_->state() == WAITING_MESSAGE);
Wez 2013/03/05 22:55:53 If these are DCHECKs then will ProcessMessage() do
rmsousa 2013/03/06 00:54:16 The DCHECK means (and documents) that this code is
136 underlying_->ProcessMessage(message, resume_callback);
137 }
138 }
139
140 scoped_ptr<buzz::XmlElement> ThirdPartyAuthenticator::GetNextMessage() {
141 DCHECK_EQ(state(), MESSAGE_READY);
142
143 scoped_ptr<buzz::XmlElement> message;
144 if (underlying_ && underlying_->state() == MESSAGE_READY) {
145 message = underlying_->GetNextMessage().Pass();
146 } else {
147 message = CreateEmptyAuthenticatorMessage();
Wez 2013/03/05 22:55:53 How can we be in the MESSAGE_READY state with no m
rmsousa 2013/03/06 00:54:16 There are two states, the state for the token nego
148 }
149 GetNextMessageInternal(message.get());
150 return message.Pass();
151 }
152
153 scoped_ptr<ChannelAuthenticator>
154 ThirdPartyAuthenticator::CreateChannelAuthenticator() const {
155 DCHECK_EQ(state(), ACCEPTED);
156
157 return underlying_->CreateChannelAuthenticator();
158 }
159
160 ClientThirdPartyAuthenticator::ClientThirdPartyAuthenticator(
161 const std::string& host_public_key,
162 scoped_ptr<TokenFetcher> token_fetcher,
163 Authenticator::State initial_state)
164 : ThirdPartyAuthenticator(initial_state),
165 host_public_key_(host_public_key),
166 token_fetcher_(token_fetcher.Pass()) {
167 }
168
169 void ClientThirdPartyAuthenticator::ProcessMessageInternal(
170 const buzz::XmlElement* message,
171 const base::Closure& resume_callback) {
172 std::string token_url = message->TextNamed(kTokenUrlTag);
Wez 2013/03/05 22:55:53 What happens if we manage to see two consecutive m
rmsousa 2013/03/06 00:54:16 JingleSession has code that explicitly rejects mes
173 std::string token_scope = message->TextNamed(kTokenScopeTag);
174 if (!token_url.empty() && !token_scope.empty()) {
175 state_ = PROCESSING_MESSAGE;
176 // |token_fetcher_| is owned, so Unretained() is safe here.
Wez 2013/03/05 22:55:53 nit: Blank line before this comment.
177 token_fetcher_->FetchThirdPartyToken(
178 token_url, host_public_key_, token_scope, base::Bind(
179 &ClientThirdPartyAuthenticator::OnThirdPartyTokenFetched,
180 base::Unretained(this), resume_callback));
181 return;
182 }
183
184 LOG(WARNING) << "Missing token issue URL/verification URL/scope.";
185 state_ = REJECTED;
186 rejection_reason_ = PROTOCOL_ERROR;
187 resume_callback.Run();
188 return;
Wez 2013/03/05 22:55:53 nit: No need for return here.
189 }
190
191 void ClientThirdPartyAuthenticator::GetNextMessageInternal(
192 buzz::XmlElement* message) {
193 if (state_ == MESSAGE_READY) {
194 if (!token_.empty()) {
195 buzz::XmlElement* token_tag = new buzz::XmlElement(kTokenTag);
196 token_tag->SetBodyText(token_);
197 message->AddElement(token_tag);
198 state_ = ACCEPTED;
199 } else {
200 // The client doesn't really have anything to send yet, it's just
201 // waiting for the host to send the token_url.
202 state_ = WAITING_MESSAGE;
Wez 2013/03/05 22:55:53 Again, we shouldn't ever reach the MESSAGE_READY s
rmsousa 2013/03/06 00:54:16 Please read the previous comments and replies abou
203 }
204 }
205 }
206
207 void ClientThirdPartyAuthenticator::OnThirdPartyTokenFetched(
208 const base::Closure& resume_callback, const std::string& third_party_token,
209 const std::string& shared_secret) {
210 token_ = third_party_token;
211 if (!token_.empty() && !shared_secret.empty()) {
212 state_ = MESSAGE_READY;
213 underlying_ = V2Authenticator::CreateForClient(
214 shared_secret, MESSAGE_READY);
215 } else {
216 state_ = REJECTED;
217 rejection_reason_ = INVALID_CREDENTIALS;
218 }
219 resume_callback.Run();
220 }
221
222 HostThirdPartyAuthenticator::HostThirdPartyAuthenticator(
223 const std::string& local_cert,
224 scoped_refptr<RsaKeyPair> key_pair,
225 scoped_ptr<TokenValidator> token_validator,
226 Authenticator::State initial_state)
227 : ThirdPartyAuthenticator(initial_state),
228 has_sent_urls_(false),
229 local_cert_(local_cert),
230 key_pair_(key_pair),
231 token_validator_(token_validator.Pass()) {
232 }
233
234 void HostThirdPartyAuthenticator::ProcessMessageInternal(
235 const buzz::XmlElement* message,
236 const base::Closure& resume_callback) {
237 if (!has_sent_urls_) {
238 // The host hasn't sent the token URLs to the client yet, so ignore the
239 // first message and send the URLs to the client.
Wez 2013/03/05 22:55:53 Why are we receiving a first message if we're not
rmsousa 2013/03/06 00:54:16 NegotiatingAuthenticator has baked in assumptions
240 DCHECK(!underlying_);
241
242 state_ = MESSAGE_READY;
243 resume_callback.Run();
244 return;
245 }
246 // Host has already sent the URL and expects a token from the client.
Wez 2013/03/05 22:55:53 Blank line before this comment.
247 std::string token = message->TextNamed(kTokenTag);
248 if (!token.empty()) {
249 state_ = PROCESSING_MESSAGE;
250 // This message also contains the client's first SPAKE message. Copy the
Wez 2013/03/05 22:55:53 nit: Blank line before this comment.
251 // message into the callback, so that OnThirdPartyTokenValidated can give it
252 // to the underlying SPAKE authenticator that will be created.
253 // |token_validator_| is owned, so Unretained() is safe here.
Wez 2013/03/05 22:55:53 Is there ever a possibility that we'd want to have
rmsousa 2013/03/06 00:54:16 No. There are two possibilities here: (1) The cli
254 token_validator_->ValidateThirdPartyToken(token, base::Bind(
255 &HostThirdPartyAuthenticator::OnThirdPartyTokenValidated,
256 base::Unretained(this),
257 base::Owned(new buzz::XmlElement(*message)),
258 resume_callback));
259 return;
260 }
261
262 LOG(WARNING) << "Missing token.";
263 state_ = REJECTED;
264 rejection_reason_ = PROTOCOL_ERROR;
265 resume_callback.Run();
266 return;
Wez 2013/03/05 22:55:53 No need for return here.
267 }
268
269 void HostThirdPartyAuthenticator::GetNextMessageInternal(
270 buzz::XmlElement* message) {
271 if (state_ == MESSAGE_READY) {
272 DCHECK(token_validator_->token_url().is_valid());
273 DCHECK(!token_validator_->token_scope().empty());
274
275 buzz::XmlElement* token_url_tag = new buzz::XmlElement(
276 kTokenUrlTag);
277 token_url_tag->SetBodyText(token_validator_->token_url().spec());
278 message->AddElement(token_url_tag);
279 buzz::XmlElement* token_scope_tag = new buzz::XmlElement(
280 kTokenScopeTag);
281 token_scope_tag->SetBodyText(token_validator_->token_scope());
282 message->AddElement(token_scope_tag);
283 has_sent_urls_ = true;
284 state_ = WAITING_MESSAGE;
285 }
286 }
287
288 void HostThirdPartyAuthenticator::OnThirdPartyTokenValidated(
289 const buzz::XmlElement* message,
290 const base::Closure& resume_callback,
291 const std::string& shared_secret) {
292 if (!shared_secret.empty()) {
293 // The other side already started the SPAKE authentication.
Wez 2013/03/05 22:55:53 nit: Clarify that we know this because the message
rmsousa 2013/03/06 00:54:16 We aren't inspecting the message to see what it co
294 state_ = ACCEPTED;
295 underlying_ = V2Authenticator::CreateForHost(
296 local_cert_, key_pair_, shared_secret, WAITING_MESSAGE);
297 underlying_->ProcessMessage(message, resume_callback);
298 } else {
299 state_ = REJECTED;
300 rejection_reason_ = INVALID_CREDENTIALS;
301 resume_callback.Run();
302 }
303 }
304
305 } // namespace protocol
306 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698