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

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

Issue 12518027: Protocol / client plugin changes to support interactively asking for a PIN (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: 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
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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/protocol/negotiating_authenticator.h" 5 #include "remoting/protocol/negotiating_authenticator.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <sstream> 8 #include <sstream>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/callback.h" 11 #include "base/callback.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/strings/string_split.h" 13 #include "base/strings/string_split.h"
14 #include "remoting/base/rsa_key_pair.h" 14 #include "remoting/base/rsa_key_pair.h"
15 #include "remoting/protocol/channel_authenticator.h" 15 #include "remoting/protocol/channel_authenticator.h"
16 #include "remoting/protocol/v2_authenticator.h" 16 #include "remoting/protocol/v2_authenticator.h"
17 #include "remoting/protocol/pin_client_authenticator.h"
18 #include "remoting/protocol/pin_fetcher_factory.h"
17 #include "third_party/libjingle/source/talk/xmllite/xmlelement.h" 19 #include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
18 20
19 namespace remoting { 21 namespace remoting {
20 namespace protocol { 22 namespace protocol {
21 23
22 namespace { 24 namespace {
23 25
24 const buzz::StaticQName kMethodAttributeQName = { "", "method" }; 26 const buzz::StaticQName kMethodAttributeQName = { "", "method" };
25 const buzz::StaticQName kSupportedMethodsAttributeQName = 27 const buzz::StaticQName kSupportedMethodsAttributeQName =
26 { "", "supported-methods" }; 28 { "", "supported-methods" };
27 29
28 const char kSupportedMethodsSeparator = ','; 30 const char kSupportedMethodsSeparator = ',';
29 31
30 } // namespace 32 } // namespace
31 33
32 // static 34 // static
33 bool NegotiatingAuthenticator::IsNegotiableMessage(
34 const buzz::XmlElement* message) {
35 return message->HasAttr(kSupportedMethodsAttributeQName);
36 }
37
38 // static
39 scoped_ptr<Authenticator> NegotiatingAuthenticator::CreateForClient( 35 scoped_ptr<Authenticator> NegotiatingAuthenticator::CreateForClient(
40 const std::string& authentication_tag, 36 const std::string& authentication_tag,
41 const std::string& shared_secret, 37 const std::string& shared_secret,
38 PinFetcherFactory* pin_fetcher_factory,
42 const std::vector<AuthenticationMethod>& methods) { 39 const std::vector<AuthenticationMethod>& methods) {
43 scoped_ptr<NegotiatingAuthenticator> result( 40 scoped_ptr<NegotiatingAuthenticator> result(
44 new NegotiatingAuthenticator(MESSAGE_READY)); 41 new NegotiatingAuthenticator(MESSAGE_READY));
45 result->authentication_tag_ = authentication_tag; 42 result->authentication_tag_ = authentication_tag;
46 result->shared_secret_ = shared_secret; 43 result->shared_secret_ = shared_secret;
44 result->pin_fetcher_factory_ = pin_fetcher_factory;
47 45
48 DCHECK(!methods.empty()); 46 DCHECK(!methods.empty());
49 for (std::vector<AuthenticationMethod>::const_iterator it = methods.begin(); 47 for (std::vector<AuthenticationMethod>::const_iterator it = methods.begin();
50 it != methods.end(); ++it) { 48 it != methods.end(); ++it) {
51 result->AddMethod(*it); 49 result->AddMethod(*it);
52 } 50 }
53 51
54 return scoped_ptr<Authenticator>(result.Pass()); 52 return scoped_ptr<Authenticator>(result.Pass());
55 } 53 }
56 54
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 if (!method.is_valid()) { 136 if (!method.is_valid()) {
139 // Failed to find a common auth method. 137 // Failed to find a common auth method.
140 state_ = REJECTED; 138 state_ = REJECTED;
141 rejection_reason_ = PROTOCOL_ERROR; 139 rejection_reason_ = PROTOCOL_ERROR;
142 resume_callback.Run(); 140 resume_callback.Run();
143 return; 141 return;
144 } 142 }
145 143
146 // Drop the current message because we've chosen a different 144 // Drop the current message because we've chosen a different
147 // method. 145 // method.
148 state_ = MESSAGE_READY; 146 current_method_ = method;
147 state_ = PROCESSING_MESSAGE;
148 CreateAuthenticator(MESSAGE_READY, base::Bind(
149 &NegotiatingAuthenticator::UpdateState,
150 base::Unretained(this), resume_callback));
151 } else {
152 if (method != current_method_) {
153 current_method_ = method;
154 state_ = PROCESSING_MESSAGE;
155 // Copy the message since the authenticator may process it asynchronously.
156 CreateAuthenticator(WAITING_MESSAGE, base::Bind(
157 &NegotiatingAuthenticator::ProcessMessageInternal,
158 base::Unretained(this), base::Owned(new buzz::XmlElement(*message)),
159 resume_callback));
160 } else {
161 ProcessMessageInternal(message, resume_callback);
162 }
149 } 163 }
164 }
150 165
151 DCHECK(method.is_valid()); 166 void NegotiatingAuthenticator::ProcessMessageInternal(
152 167 const buzz::XmlElement* message,
153 // Replace current authenticator if the method has changed. 168 const base::Closure& resume_callback) {
154 if (method != current_method_) { 169 if (current_authenticator_->state() == WAITING_MESSAGE) {
155 current_method_ = method; 170 // If the message was not discarded and the authenticator is waiting for it,
156 CreateAuthenticator(state_); 171 // give it to the underlying authenticator to process.
157 }
158 if (state_ == WAITING_MESSAGE) {
159 // |current_authenticator_| is owned, so Unretained() is safe here. 172 // |current_authenticator_| is owned, so Unretained() is safe here.
160 current_authenticator_->ProcessMessage(message, base::Bind( 173 current_authenticator_->ProcessMessage(message, base::Bind(
161 &NegotiatingAuthenticator::UpdateState, 174 &NegotiatingAuthenticator::UpdateState,
162 base::Unretained(this), resume_callback)); 175 base::Unretained(this), resume_callback));
163 } else {
164 UpdateState(resume_callback);
165 } 176 }
166 } 177 }
167 178
168 void NegotiatingAuthenticator::UpdateState( 179 void NegotiatingAuthenticator::UpdateState(
169 const base::Closure& resume_callback) { 180 const base::Closure& resume_callback) {
170 // After the underlying authenticator finishes processing the message, the 181 // After the underlying authenticator finishes processing the message, the
171 // NegotiatingAuthenticator must update its own state before running the 182 // NegotiatingAuthenticator must update its own state before running the
172 // |resume_callback| to resume the session negotiation. 183 // |resume_callback| to resume the session negotiation.
173 state_ = current_authenticator_->state(); 184 state_ = current_authenticator_->state();
174 if (state_ == REJECTED) 185 if (state_ == REJECTED)
175 rejection_reason_ = current_authenticator_->rejection_reason(); 186 rejection_reason_ = current_authenticator_->rejection_reason();
176 resume_callback.Run(); 187 resume_callback.Run();
177 } 188 }
178 189
179 scoped_ptr<buzz::XmlElement> NegotiatingAuthenticator::GetNextMessage() { 190 scoped_ptr<buzz::XmlElement> NegotiatingAuthenticator::GetNextMessage() {
180 DCHECK_EQ(state(), MESSAGE_READY); 191 DCHECK_EQ(state(), MESSAGE_READY);
181 192
182 bool add_supported_methods_attr = false; 193 scoped_ptr<buzz::XmlElement> result;
183 194
184 // Initialize current method in case it is not initialized 195 // No method yet, just send a message with the list of supported methods.
185 // yet. Normally happens only on client. 196 // Normally happens only on client.
186 if (!current_method_.is_valid()) { 197 if (!current_method_.is_valid()) {
187 CHECK(!methods_.empty()); 198 result = CreateEmptyAuthenticatorMessage();
188
189 // Initially try the first method.
190 current_method_ = methods_[0];
191 CreateAuthenticator(MESSAGE_READY);
192 add_supported_methods_attr = true;
193 }
194
195 scoped_ptr<buzz::XmlElement> result =
196 current_authenticator_->GetNextMessage();
197 state_ = current_authenticator_->state();
198 DCHECK_NE(state_, REJECTED);
199
200 result->AddAttr(kMethodAttributeQName, current_method_.ToString());
201
202 if (add_supported_methods_attr) {
203 std::stringstream supported_methods(std::stringstream::out); 199 std::stringstream supported_methods(std::stringstream::out);
204 for (std::vector<AuthenticationMethod>::iterator it = methods_.begin(); 200 for (std::vector<AuthenticationMethod>::iterator it = methods_.begin();
205 it != methods_.end(); ++it) { 201 it != methods_.end(); ++it) {
206 if (it != methods_.begin()) 202 if (it != methods_.begin())
207 supported_methods << kSupportedMethodsSeparator; 203 supported_methods << kSupportedMethodsSeparator;
208 supported_methods << it->ToString(); 204 supported_methods << it->ToString();
209 } 205 }
210 result->AddAttr(kSupportedMethodsAttributeQName, supported_methods.str()); 206 result->AddAttr(kSupportedMethodsAttributeQName, supported_methods.str());
207 state_ = WAITING_MESSAGE;
208 } else {
209 if (current_authenticator_->state() == MESSAGE_READY) {
210 result = current_authenticator_->GetNextMessage();
211 } else {
212 result = CreateEmptyAuthenticatorMessage();
213 }
214 state_ = current_authenticator_->state();
215 DCHECK_NE(state_, REJECTED);
216 DCHECK_NE(state_, MESSAGE_READY);
217 result->AddAttr(kMethodAttributeQName, current_method_.ToString());
211 } 218 }
212 219
213 return result.Pass(); 220 return result.Pass();
214 } 221 }
215 222
216 void NegotiatingAuthenticator::AddMethod(const AuthenticationMethod& method) { 223 void NegotiatingAuthenticator::AddMethod(const AuthenticationMethod& method) {
217 DCHECK(method.is_valid()); 224 DCHECK(method.is_valid());
218 methods_.push_back(method); 225 methods_.push_back(method);
219 } 226 }
220 227
221 scoped_ptr<ChannelAuthenticator> 228 scoped_ptr<ChannelAuthenticator>
222 NegotiatingAuthenticator::CreateChannelAuthenticator() const { 229 NegotiatingAuthenticator::CreateChannelAuthenticator() const {
223 DCHECK_EQ(state(), ACCEPTED); 230 DCHECK_EQ(state(), ACCEPTED);
224 return current_authenticator_->CreateChannelAuthenticator(); 231 return current_authenticator_->CreateChannelAuthenticator();
225 } 232 }
226 233
227 bool NegotiatingAuthenticator::is_host_side() const { 234 bool NegotiatingAuthenticator::is_host_side() const {
228 return local_key_pair_.get() != NULL; 235 return local_key_pair_.get() != NULL;
229 } 236 }
230 237
231 void NegotiatingAuthenticator::CreateAuthenticator(State initial_state) { 238
239 void NegotiatingAuthenticator::CreateAuthenticator(
240 Authenticator::State preferred_initial_state,
241 const base::Closure& resume_callback) {
232 if (is_host_side()) { 242 if (is_host_side()) {
233 current_authenticator_ = V2Authenticator::CreateForHost( 243 current_authenticator_ = V2Authenticator::CreateForHost(
234 local_cert_, local_key_pair_, shared_secret_hash_, initial_state); 244 local_cert_, local_key_pair_, shared_secret_hash_,
245 preferred_initial_state);
235 } else { 246 } else {
236 current_authenticator_ = V2Authenticator::CreateForClient( 247 if (pin_fetcher_factory_) {
Sergey Ulanov 2013/03/17 21:29:21 Do we really need to distinguish between these two
rmsousa 2013/03/18 21:07:26 I think that would get ugly in the upper layers, w
Sergey Ulanov 2013/03/19 02:44:53 I think this is just a question of whether we shou
rmsousa 2013/03/19 23:14:31 Done.
237 AuthenticationMethod::ApplyHashFunction( 248 // No pre-entered secret, need to use the interactive authenticator.
238 current_method_.hash_function(), 249 current_authenticator_.reset(new PinClientAuthenticator(
239 authentication_tag_, shared_secret_), initial_state); 250 current_method_.hash_function(), authentication_tag_,
251 pin_fetcher_factory_->CreatePinFetcher(), preferred_initial_state,
Sergey Ulanov 2013/03/17 21:29:21 Why do we need the factory interface? Is there any
rmsousa 2013/03/18 21:07:26 It's to manage the lifetime for the callback appro
Sergey Ulanov 2013/03/19 02:44:53 The issue with possible lifetime mismatch is easy
rmsousa 2013/03/19 23:14:31 Done.
252 resume_callback));
253 return;
254 } else {
255 // Pre-entered secret (legacy client), just proceed with V2 authenticator.
256 current_authenticator_ = V2Authenticator::CreateForClient(
257 AuthenticationMethod::ApplyHashFunction(
258 current_method_.hash_function(),
259 authentication_tag_, shared_secret_), preferred_initial_state);
Sergey Ulanov 2013/03/17 21:29:21 nit: move the last parameter to a separate line fo
rmsousa 2013/03/18 21:07:26 Done.
260 }
240 } 261 }
262 resume_callback.Run();
241 } 263 }
242 264
243 } // namespace protocol 265 } // namespace protocol
244 } // namespace remoting 266 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698