c/b/download: Replace usage of GetActiveEntry by GetLastCommittedEntry.
[chromium-blink-merge.git] / remoting / protocol / pairing_authenticator_base.cc
blob4375e6557a7e42734a9360e7559b07b9a2120912
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.
5 #include "remoting/protocol/pairing_authenticator_base.h"
7 #include "base/bind.h"
8 #include "remoting/base/constants.h"
9 #include "remoting/protocol/channel_authenticator.h"
11 namespace remoting {
12 namespace protocol {
14 const buzz::StaticQName PairingAuthenticatorBase::kPairingInfoTag =
15 { kChromotingXmlNamespace, "pairing-info" };
16 const buzz::StaticQName PairingAuthenticatorBase::kClientIdAttribute =
17 { "", "client-id" };
19 namespace {
20 const buzz::StaticQName kPairingFailedTag =
21 { kChromotingXmlNamespace, "pairing-failed" };
22 const buzz::StaticQName kPairingErrorAttribute = { "", "error" };
23 } // namespace
25 PairingAuthenticatorBase::PairingAuthenticatorBase()
26 : using_paired_secret_(false),
27 waiting_for_authenticator_(false),
28 weak_factory_(this) {
31 PairingAuthenticatorBase::~PairingAuthenticatorBase() {
34 Authenticator::State PairingAuthenticatorBase::state() const {
35 if (waiting_for_authenticator_) {
36 return PROCESSING_MESSAGE;
38 return v2_authenticator_->state();
41 bool PairingAuthenticatorBase::started() const {
42 if (!v2_authenticator_) {
43 return false;
45 return v2_authenticator_->started();
48 Authenticator::RejectionReason
49 PairingAuthenticatorBase::rejection_reason() const {
50 if (!v2_authenticator_) {
51 return PROTOCOL_ERROR;
53 return v2_authenticator_->rejection_reason();
56 void PairingAuthenticatorBase::ProcessMessage(
57 const buzz::XmlElement* message,
58 const base::Closure& resume_callback) {
59 DCHECK_EQ(state(), WAITING_MESSAGE);
61 // The client authenticator creates the underlying authenticator in the ctor
62 // and the host creates it in response to the first message before deferring
63 // to this class to process it. Either way, it should exist here.
64 DCHECK(v2_authenticator_);
66 // If pairing failed, and we haven't already done so, try again with the PIN.
67 if (using_paired_secret_ && HasErrorMessage(message)) {
68 using_paired_secret_ = false;
69 waiting_for_authenticator_ = true;
70 v2_authenticator_.reset();
71 SetAuthenticatorCallback set_authenticator = base::Bind(
72 &PairingAuthenticatorBase::SetAuthenticatorAndProcessMessage,
73 weak_factory_.GetWeakPtr(), base::Owned(new buzz::XmlElement(*message)),
74 resume_callback);
75 CreateV2AuthenticatorWithPIN(WAITING_MESSAGE, set_authenticator);
76 return;
79 // Pass the message to the underlying authenticator for processing, but
80 // check for a failed SPAKE exchange if we're using the paired secret. In
81 // this case the pairing protocol can continue by communicating the error
82 // to the peer and retrying with the PIN.
83 v2_authenticator_->ProcessMessage(
84 message,
85 base::Bind(&PairingAuthenticatorBase::CheckForFailedSpakeExchange,
86 weak_factory_.GetWeakPtr(), resume_callback));
89 scoped_ptr<buzz::XmlElement> PairingAuthenticatorBase::GetNextMessage() {
90 DCHECK_EQ(state(), MESSAGE_READY);
91 scoped_ptr<buzz::XmlElement> result = v2_authenticator_->GetNextMessage();
92 AddPairingElements(result.get());
93 MaybeAddErrorMessage(result.get());
94 return result.Pass();
97 const std::string& PairingAuthenticatorBase::GetAuthKey() const {
98 return v2_authenticator_->GetAuthKey();
101 scoped_ptr<ChannelAuthenticator>
102 PairingAuthenticatorBase::CreateChannelAuthenticator() const {
103 return v2_authenticator_->CreateChannelAuthenticator();
106 void PairingAuthenticatorBase::MaybeAddErrorMessage(buzz::XmlElement* message) {
107 if (!error_message_.empty()) {
108 buzz::XmlElement* pairing_failed_tag =
109 new buzz::XmlElement(kPairingFailedTag);
110 pairing_failed_tag->AddAttr(kPairingErrorAttribute, error_message_);
111 message->AddElement(pairing_failed_tag);
112 error_message_.clear();
116 bool PairingAuthenticatorBase::HasErrorMessage(
117 const buzz::XmlElement* message) const {
118 const buzz::XmlElement* pairing_failed_tag =
119 message->FirstNamed(kPairingFailedTag);
120 if (pairing_failed_tag) {
121 std::string error = pairing_failed_tag->Attr(kPairingErrorAttribute);
122 LOG(ERROR) << "Pairing failed: " << error;
124 return pairing_failed_tag != nullptr;
127 void PairingAuthenticatorBase::CheckForFailedSpakeExchange(
128 const base::Closure& resume_callback) {
129 // If the SPAKE exchange failed due to invalid credentials, and those
130 // credentials were the paired secret, then notify the peer that the
131 // PIN-less connection failed and retry using the PIN.
132 if (v2_authenticator_->state() == REJECTED &&
133 v2_authenticator_->rejection_reason() == INVALID_CREDENTIALS &&
134 using_paired_secret_) {
135 using_paired_secret_ = false;
136 error_message_ = "invalid-shared-secret";
137 v2_authenticator_.reset();
138 buzz::XmlElement* no_message = nullptr;
139 SetAuthenticatorCallback set_authenticator = base::Bind(
140 &PairingAuthenticatorBase::SetAuthenticatorAndProcessMessage,
141 weak_factory_.GetWeakPtr(), no_message, resume_callback);
142 CreateV2AuthenticatorWithPIN(MESSAGE_READY, set_authenticator);
143 return;
146 resume_callback.Run();
149 void PairingAuthenticatorBase::SetAuthenticatorAndProcessMessage(
150 const buzz::XmlElement* message,
151 const base::Closure& resume_callback,
152 scoped_ptr<Authenticator> authenticator) {
153 DCHECK(!v2_authenticator_);
154 DCHECK(authenticator);
155 waiting_for_authenticator_ = false;
156 v2_authenticator_ = authenticator.Pass();
157 if (message) {
158 ProcessMessage(message, resume_callback);
159 } else {
160 resume_callback.Run();
164 } // namespace protocol
165 } // namespace remoting