Chromium Code Reviews| Index: remoting/protocol/negotiating_authenticator.cc |
| diff --git a/remoting/protocol/negotiating_authenticator.cc b/remoting/protocol/negotiating_authenticator.cc |
| index 7b794d2a05f69a1f8de26ea3dc64b6d80b4773fe..e2f639a0e2473f444075f253e2c02a86551ddb0b 100644 |
| --- a/remoting/protocol/negotiating_authenticator.cc |
| +++ b/remoting/protocol/negotiating_authenticator.cc |
| @@ -14,6 +14,8 @@ |
| #include "remoting/base/rsa_key_pair.h" |
| #include "remoting/protocol/channel_authenticator.h" |
| #include "remoting/protocol/v2_authenticator.h" |
| +#include "remoting/protocol/pin_client_authenticator.h" |
| +#include "remoting/protocol/pin_fetcher_factory.h" |
| #include "third_party/libjingle/source/talk/xmllite/xmlelement.h" |
| namespace remoting { |
| @@ -30,20 +32,16 @@ const char kSupportedMethodsSeparator = ','; |
| } // namespace |
| // static |
| -bool NegotiatingAuthenticator::IsNegotiableMessage( |
| - const buzz::XmlElement* message) { |
| - return message->HasAttr(kSupportedMethodsAttributeQName); |
| -} |
| - |
| -// static |
| scoped_ptr<Authenticator> NegotiatingAuthenticator::CreateForClient( |
| const std::string& authentication_tag, |
| const std::string& shared_secret, |
| + PinFetcherFactory* pin_fetcher_factory, |
| const std::vector<AuthenticationMethod>& methods) { |
| scoped_ptr<NegotiatingAuthenticator> result( |
| new NegotiatingAuthenticator(MESSAGE_READY)); |
| result->authentication_tag_ = authentication_tag; |
| result->shared_secret_ = shared_secret; |
| + result->pin_fetcher_factory_ = pin_fetcher_factory; |
| DCHECK(!methods.empty()); |
| for (std::vector<AuthenticationMethod>::const_iterator it = methods.begin(); |
| @@ -145,23 +143,36 @@ void NegotiatingAuthenticator::ProcessMessage( |
| // Drop the current message because we've chosen a different |
| // method. |
| - state_ = MESSAGE_READY; |
| - } |
| - |
| - DCHECK(method.is_valid()); |
| - |
| - // Replace current authenticator if the method has changed. |
| - if (method != current_method_) { |
| current_method_ = method; |
| - CreateAuthenticator(state_); |
| + state_ = PROCESSING_MESSAGE; |
| + CreateAuthenticator(MESSAGE_READY, base::Bind( |
| + &NegotiatingAuthenticator::UpdateState, |
| + base::Unretained(this), resume_callback)); |
| + } else { |
| + if (method != current_method_) { |
| + current_method_ = method; |
| + state_ = PROCESSING_MESSAGE; |
| + // Copy the message since the authenticator may process it asynchronously. |
| + CreateAuthenticator(WAITING_MESSAGE, base::Bind( |
| + &NegotiatingAuthenticator::ProcessMessageInternal, |
| + base::Unretained(this), base::Owned(new buzz::XmlElement(*message)), |
| + resume_callback)); |
| + } else { |
| + ProcessMessageInternal(message, resume_callback); |
| + } |
| } |
| - if (state_ == WAITING_MESSAGE) { |
| +} |
| + |
| +void NegotiatingAuthenticator::ProcessMessageInternal( |
| + const buzz::XmlElement* message, |
| + const base::Closure& resume_callback) { |
| + if (current_authenticator_->state() == WAITING_MESSAGE) { |
| + // If the message was not discarded and the authenticator is waiting for it, |
| + // give it to the underlying authenticator to process. |
| // |current_authenticator_| is owned, so Unretained() is safe here. |
| current_authenticator_->ProcessMessage(message, base::Bind( |
| &NegotiatingAuthenticator::UpdateState, |
| base::Unretained(this), resume_callback)); |
| - } else { |
| - UpdateState(resume_callback); |
| } |
| } |
| @@ -179,27 +190,12 @@ void NegotiatingAuthenticator::UpdateState( |
| scoped_ptr<buzz::XmlElement> NegotiatingAuthenticator::GetNextMessage() { |
| DCHECK_EQ(state(), MESSAGE_READY); |
| - bool add_supported_methods_attr = false; |
| + scoped_ptr<buzz::XmlElement> result; |
| - // Initialize current method in case it is not initialized |
| - // yet. Normally happens only on client. |
| + // No method yet, just send a message with the list of supported methods. |
| + // Normally happens only on client. |
| if (!current_method_.is_valid()) { |
| - CHECK(!methods_.empty()); |
| - |
| - // Initially try the first method. |
| - current_method_ = methods_[0]; |
| - CreateAuthenticator(MESSAGE_READY); |
| - add_supported_methods_attr = true; |
| - } |
| - |
| - scoped_ptr<buzz::XmlElement> result = |
| - current_authenticator_->GetNextMessage(); |
| - state_ = current_authenticator_->state(); |
| - DCHECK_NE(state_, REJECTED); |
| - |
| - result->AddAttr(kMethodAttributeQName, current_method_.ToString()); |
| - |
| - if (add_supported_methods_attr) { |
| + result = CreateEmptyAuthenticatorMessage(); |
| std::stringstream supported_methods(std::stringstream::out); |
| for (std::vector<AuthenticationMethod>::iterator it = methods_.begin(); |
| it != methods_.end(); ++it) { |
| @@ -208,6 +204,17 @@ scoped_ptr<buzz::XmlElement> NegotiatingAuthenticator::GetNextMessage() { |
| supported_methods << it->ToString(); |
| } |
| result->AddAttr(kSupportedMethodsAttributeQName, supported_methods.str()); |
| + state_ = WAITING_MESSAGE; |
| + } else { |
| + if (current_authenticator_->state() == MESSAGE_READY) { |
| + result = current_authenticator_->GetNextMessage(); |
| + } else { |
| + result = CreateEmptyAuthenticatorMessage(); |
| + } |
| + state_ = current_authenticator_->state(); |
| + DCHECK_NE(state_, REJECTED); |
| + DCHECK_NE(state_, MESSAGE_READY); |
| + result->AddAttr(kMethodAttributeQName, current_method_.ToString()); |
| } |
| return result.Pass(); |
| @@ -228,16 +235,31 @@ bool NegotiatingAuthenticator::is_host_side() const { |
| return local_key_pair_.get() != NULL; |
| } |
| -void NegotiatingAuthenticator::CreateAuthenticator(State initial_state) { |
| + |
| +void NegotiatingAuthenticator::CreateAuthenticator( |
| + Authenticator::State preferred_initial_state, |
| + const base::Closure& resume_callback) { |
| if (is_host_side()) { |
| current_authenticator_ = V2Authenticator::CreateForHost( |
| - local_cert_, local_key_pair_, shared_secret_hash_, initial_state); |
| + local_cert_, local_key_pair_, shared_secret_hash_, |
| + preferred_initial_state); |
| } else { |
| - current_authenticator_ = V2Authenticator::CreateForClient( |
| - AuthenticationMethod::ApplyHashFunction( |
| - current_method_.hash_function(), |
| - authentication_tag_, shared_secret_), initial_state); |
| + 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.
|
| + // No pre-entered secret, need to use the interactive authenticator. |
| + current_authenticator_.reset(new PinClientAuthenticator( |
| + current_method_.hash_function(), authentication_tag_, |
| + 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.
|
| + resume_callback)); |
| + return; |
| + } else { |
| + // Pre-entered secret (legacy client), just proceed with V2 authenticator. |
| + current_authenticator_ = V2Authenticator::CreateForClient( |
| + AuthenticationMethod::ApplyHashFunction( |
| + current_method_.hash_function(), |
| + 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.
|
| + } |
| } |
| + resume_callback.Run(); |
| } |
| } // namespace protocol |