Chromium Code Reviews| OLD | NEW |
|---|---|
| 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" |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 23 | 23 |
| 24 const buzz::StaticQName kMethodAttributeQName = { "", "method" }; | 24 const buzz::StaticQName kMethodAttributeQName = { "", "method" }; |
| 25 const buzz::StaticQName kSupportedMethodsAttributeQName = | 25 const buzz::StaticQName kSupportedMethodsAttributeQName = |
| 26 { "", "supported-methods" }; | 26 { "", "supported-methods" }; |
| 27 | 27 |
| 28 const char kSupportedMethodsSeparator = ','; | 28 const char kSupportedMethodsSeparator = ','; |
| 29 | 29 |
| 30 } // namespace | 30 } // namespace |
| 31 | 31 |
| 32 // static | 32 // 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( | 33 scoped_ptr<Authenticator> NegotiatingAuthenticator::CreateForClient( |
| 40 const std::string& authentication_tag, | 34 const std::string& authentication_tag, |
| 41 const std::string& shared_secret, | 35 const FetchSecretCallback& fetch_secret_callback, |
| 42 const std::vector<AuthenticationMethod>& methods) { | 36 const std::vector<AuthenticationMethod>& methods) { |
| 43 scoped_ptr<NegotiatingAuthenticator> result( | 37 scoped_ptr<NegotiatingAuthenticator> result( |
| 44 new NegotiatingAuthenticator(MESSAGE_READY)); | 38 new NegotiatingAuthenticator(MESSAGE_READY)); |
| 45 result->authentication_tag_ = authentication_tag; | 39 result->authentication_tag_ = authentication_tag; |
| 46 result->shared_secret_ = shared_secret; | 40 result->fetch_secret_callback_ = fetch_secret_callback; |
| 47 | 41 |
| 48 DCHECK(!methods.empty()); | 42 DCHECK(!methods.empty()); |
| 49 for (std::vector<AuthenticationMethod>::const_iterator it = methods.begin(); | 43 for (std::vector<AuthenticationMethod>::const_iterator it = methods.begin(); |
| 50 it != methods.end(); ++it) { | 44 it != methods.end(); ++it) { |
| 51 result->AddMethod(*it); | 45 result->AddMethod(*it); |
| 52 } | 46 } |
| 53 | 47 |
| 54 return scoped_ptr<Authenticator>(result.Pass()); | 48 return scoped_ptr<Authenticator>(result.Pass()); |
| 55 } | 49 } |
| 56 | 50 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 68 | 62 |
| 69 result->AddMethod(AuthenticationMethod::Spake2(hash_function)); | 63 result->AddMethod(AuthenticationMethod::Spake2(hash_function)); |
| 70 | 64 |
| 71 return scoped_ptr<Authenticator>(result.Pass()); | 65 return scoped_ptr<Authenticator>(result.Pass()); |
| 72 } | 66 } |
| 73 | 67 |
| 74 NegotiatingAuthenticator::NegotiatingAuthenticator( | 68 NegotiatingAuthenticator::NegotiatingAuthenticator( |
| 75 Authenticator::State initial_state) | 69 Authenticator::State initial_state) |
| 76 : current_method_(AuthenticationMethod::Invalid()), | 70 : current_method_(AuthenticationMethod::Invalid()), |
| 77 state_(initial_state), | 71 state_(initial_state), |
| 78 rejection_reason_(INVALID_CREDENTIALS) { | 72 rejection_reason_(INVALID_CREDENTIALS), |
| 73 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | |
| 79 } | 74 } |
| 80 | 75 |
| 81 NegotiatingAuthenticator::~NegotiatingAuthenticator() { | 76 NegotiatingAuthenticator::~NegotiatingAuthenticator() { |
| 82 } | 77 } |
| 83 | 78 |
| 84 Authenticator::State NegotiatingAuthenticator::state() const { | 79 Authenticator::State NegotiatingAuthenticator::state() const { |
| 85 return state_; | 80 return state_; |
| 86 } | 81 } |
| 87 | 82 |
| 88 Authenticator::RejectionReason | 83 Authenticator::RejectionReason |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 138 if (!method.is_valid()) { | 133 if (!method.is_valid()) { |
| 139 // Failed to find a common auth method. | 134 // Failed to find a common auth method. |
| 140 state_ = REJECTED; | 135 state_ = REJECTED; |
| 141 rejection_reason_ = PROTOCOL_ERROR; | 136 rejection_reason_ = PROTOCOL_ERROR; |
| 142 resume_callback.Run(); | 137 resume_callback.Run(); |
| 143 return; | 138 return; |
| 144 } | 139 } |
| 145 | 140 |
| 146 // Drop the current message because we've chosen a different | 141 // Drop the current message because we've chosen a different |
| 147 // method. | 142 // method. |
| 148 state_ = MESSAGE_READY; | 143 current_method_ = method; |
| 144 state_ = PROCESSING_MESSAGE; | |
| 145 CreateAuthenticator(MESSAGE_READY, base::Bind( | |
| 146 &NegotiatingAuthenticator::UpdateState, | |
| 147 base::Unretained(this), resume_callback)); | |
| 148 } else { | |
|
Sergey Ulanov
2013/03/20 05:49:05
nit: add return above and then you won't need "els
rmsousa
2013/03/20 20:17:16
Done.
| |
| 149 if (method != current_method_) { | |
| 150 current_method_ = method; | |
| 151 state_ = PROCESSING_MESSAGE; | |
| 152 // Copy the message since the authenticator may process it asynchronously. | |
| 153 CreateAuthenticator(WAITING_MESSAGE, base::Bind( | |
| 154 &NegotiatingAuthenticator::ProcessMessageInternal, | |
| 155 base::Unretained(this), base::Owned(new buzz::XmlElement(*message)), | |
| 156 resume_callback)); | |
| 157 } else { | |
| 158 ProcessMessageInternal(message, resume_callback); | |
| 159 } | |
| 149 } | 160 } |
| 161 } | |
| 150 | 162 |
| 151 DCHECK(method.is_valid()); | 163 void NegotiatingAuthenticator::ProcessMessageInternal( |
|
Sergey Ulanov
2013/03/20 05:49:05
Move this below so order of functions here matches
rmsousa
2013/03/20 20:17:16
Done.
| |
| 152 | 164 const buzz::XmlElement* message, |
| 153 // Replace current authenticator if the method has changed. | 165 const base::Closure& resume_callback) { |
| 154 if (method != current_method_) { | 166 if (current_authenticator_->state() == WAITING_MESSAGE) { |
| 155 current_method_ = method; | 167 // If the message was not discarded and the authenticator is waiting for it, |
| 156 CreateAuthenticator(state_); | 168 // give it to the underlying authenticator to process. |
| 157 } | |
| 158 if (state_ == WAITING_MESSAGE) { | |
| 159 // |current_authenticator_| is owned, so Unretained() is safe here. | 169 // |current_authenticator_| is owned, so Unretained() is safe here. |
| 160 current_authenticator_->ProcessMessage(message, base::Bind( | 170 current_authenticator_->ProcessMessage(message, base::Bind( |
| 161 &NegotiatingAuthenticator::UpdateState, | 171 &NegotiatingAuthenticator::UpdateState, |
| 162 base::Unretained(this), resume_callback)); | 172 base::Unretained(this), resume_callback)); |
| 163 } else { | |
| 164 UpdateState(resume_callback); | |
| 165 } | 173 } |
| 166 } | 174 } |
| 167 | 175 |
| 168 void NegotiatingAuthenticator::UpdateState( | 176 void NegotiatingAuthenticator::UpdateState( |
| 169 const base::Closure& resume_callback) { | 177 const base::Closure& resume_callback) { |
| 170 // After the underlying authenticator finishes processing the message, the | 178 // After the underlying authenticator finishes processing the message, the |
| 171 // NegotiatingAuthenticator must update its own state before running the | 179 // NegotiatingAuthenticator must update its own state before running the |
| 172 // |resume_callback| to resume the session negotiation. | 180 // |resume_callback| to resume the session negotiation. |
| 173 state_ = current_authenticator_->state(); | 181 state_ = current_authenticator_->state(); |
| 174 if (state_ == REJECTED) | 182 if (state_ == REJECTED) |
| 175 rejection_reason_ = current_authenticator_->rejection_reason(); | 183 rejection_reason_ = current_authenticator_->rejection_reason(); |
| 176 resume_callback.Run(); | 184 resume_callback.Run(); |
| 177 } | 185 } |
| 178 | 186 |
| 179 scoped_ptr<buzz::XmlElement> NegotiatingAuthenticator::GetNextMessage() { | 187 scoped_ptr<buzz::XmlElement> NegotiatingAuthenticator::GetNextMessage() { |
| 180 DCHECK_EQ(state(), MESSAGE_READY); | 188 DCHECK_EQ(state(), MESSAGE_READY); |
| 181 | 189 |
| 182 bool add_supported_methods_attr = false; | 190 scoped_ptr<buzz::XmlElement> result; |
| 183 | 191 |
| 184 // Initialize current method in case it is not initialized | 192 // No method yet, just send a message with the list of supported methods. |
| 185 // yet. Normally happens only on client. | 193 // Normally happens only on client. |
| 186 if (!current_method_.is_valid()) { | 194 if (!current_method_.is_valid()) { |
| 187 CHECK(!methods_.empty()); | 195 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); | 196 std::stringstream supported_methods(std::stringstream::out); |
| 204 for (std::vector<AuthenticationMethod>::iterator it = methods_.begin(); | 197 for (std::vector<AuthenticationMethod>::iterator it = methods_.begin(); |
| 205 it != methods_.end(); ++it) { | 198 it != methods_.end(); ++it) { |
| 206 if (it != methods_.begin()) | 199 if (it != methods_.begin()) |
| 207 supported_methods << kSupportedMethodsSeparator; | 200 supported_methods << kSupportedMethodsSeparator; |
| 208 supported_methods << it->ToString(); | 201 supported_methods << it->ToString(); |
| 209 } | 202 } |
| 210 result->AddAttr(kSupportedMethodsAttributeQName, supported_methods.str()); | 203 result->AddAttr(kSupportedMethodsAttributeQName, supported_methods.str()); |
| 204 state_ = WAITING_MESSAGE; | |
| 205 } else { | |
| 206 if (current_authenticator_->state() == MESSAGE_READY) { | |
| 207 result = current_authenticator_->GetNextMessage(); | |
| 208 } else { | |
| 209 result = CreateEmptyAuthenticatorMessage(); | |
| 210 } | |
| 211 state_ = current_authenticator_->state(); | |
| 212 DCHECK_NE(state_, REJECTED); | |
|
Sergey Ulanov
2013/03/20 05:49:05
here state can be either WAITING_MESSAGE or ACCEPT
rmsousa
2013/03/20 20:17:16
Done.
| |
| 213 DCHECK_NE(state_, MESSAGE_READY); | |
| 214 result->AddAttr(kMethodAttributeQName, current_method_.ToString()); | |
| 211 } | 215 } |
| 212 | 216 |
| 213 return result.Pass(); | 217 return result.Pass(); |
| 214 } | 218 } |
| 215 | 219 |
| 216 void NegotiatingAuthenticator::AddMethod(const AuthenticationMethod& method) { | 220 void NegotiatingAuthenticator::AddMethod(const AuthenticationMethod& method) { |
| 217 DCHECK(method.is_valid()); | 221 DCHECK(method.is_valid()); |
| 218 methods_.push_back(method); | 222 methods_.push_back(method); |
| 219 } | 223 } |
| 220 | 224 |
| 221 scoped_ptr<ChannelAuthenticator> | 225 scoped_ptr<ChannelAuthenticator> |
| 222 NegotiatingAuthenticator::CreateChannelAuthenticator() const { | 226 NegotiatingAuthenticator::CreateChannelAuthenticator() const { |
| 223 DCHECK_EQ(state(), ACCEPTED); | 227 DCHECK_EQ(state(), ACCEPTED); |
| 224 return current_authenticator_->CreateChannelAuthenticator(); | 228 return current_authenticator_->CreateChannelAuthenticator(); |
| 225 } | 229 } |
| 226 | 230 |
| 227 bool NegotiatingAuthenticator::is_host_side() const { | 231 bool NegotiatingAuthenticator::is_host_side() const { |
| 228 return local_key_pair_.get() != NULL; | 232 return local_key_pair_.get() != NULL; |
| 229 } | 233 } |
| 230 | 234 |
| 231 void NegotiatingAuthenticator::CreateAuthenticator(State initial_state) { | 235 |
|
Sergey Ulanov
2013/03/20 05:49:05
nit: remove empty line
rmsousa
2013/03/20 20:17:16
Done.
| |
| 236 void NegotiatingAuthenticator::CreateAuthenticator( | |
| 237 Authenticator::State preferred_initial_state, | |
| 238 const base::Closure& resume_callback) { | |
| 232 if (is_host_side()) { | 239 if (is_host_side()) { |
| 233 current_authenticator_ = V2Authenticator::CreateForHost( | 240 current_authenticator_ = V2Authenticator::CreateForHost( |
| 234 local_cert_, local_key_pair_, shared_secret_hash_, initial_state); | 241 local_cert_, local_key_pair_, shared_secret_hash_, |
| 242 preferred_initial_state); | |
| 243 resume_callback.Run(); | |
|
Sergey Ulanov
2013/03/20 05:49:05
Do you need to set state_ here to something other
rmsousa
2013/03/20 20:17:16
The callbacks passed in here all call UpdateState
| |
| 235 } else { | 244 } else { |
| 236 current_authenticator_ = V2Authenticator::CreateForClient( | 245 fetch_secret_callback_.Run(base::Bind( |
| 237 AuthenticationMethod::ApplyHashFunction( | 246 &NegotiatingAuthenticator::CreateV2AuthenticatorWithSecret, |
| 238 current_method_.hash_function(), | 247 weak_factory_.GetWeakPtr(), preferred_initial_state, resume_callback)); |
| 239 authentication_tag_, shared_secret_), initial_state); | |
| 240 } | 248 } |
| 241 } | 249 } |
| 242 | 250 |
| 251 void NegotiatingAuthenticator::CreateV2AuthenticatorWithSecret( | |
| 252 Authenticator::State initial_state, | |
| 253 const base::Closure& resume_callback, | |
| 254 const std::string& shared_secret) { | |
| 255 current_authenticator_ = V2Authenticator::CreateForClient( | |
| 256 AuthenticationMethod::ApplyHashFunction( | |
| 257 current_method_.hash_function(), authentication_tag_, shared_secret), | |
| 258 initial_state); | |
| 259 resume_callback.Run(); | |
|
Sergey Ulanov
2013/03/20 05:49:05
Set state_ to MESSAGE_READY?
rmsousa
2013/03/20 20:17:16
Same applies, there's an UpdateState in the callba
| |
| 260 } | |
| 261 | |
| 243 } // namespace protocol | 262 } // namespace protocol |
| 244 } // namespace remoting | 263 } // namespace remoting |
| OLD | NEW |