OLD | NEW |
---|---|
(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/pairing_authenticator_base.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "remoting/base/constants.h" | |
9 #include "remoting/protocol/channel_authenticator.h" | |
10 | |
11 namespace remoting { | |
12 namespace protocol { | |
13 | |
14 const buzz::StaticQName PairingAuthenticatorBase::kPairingInfoTag = | |
15 { kChromotingXmlNamespace, "pairing-info" }; | |
16 const buzz::StaticQName PairingAuthenticatorBase::kClientIdAttribute = | |
17 { "", "client-id" }; | |
18 | |
19 namespace { | |
20 const buzz::StaticQName kPairingFailedTag = | |
21 { kChromotingXmlNamespace, "pairing-failed" }; | |
22 const buzz::StaticQName kPairingErrorAttribute = { "", "error" }; | |
23 } // namespace | |
24 | |
Wez
2013/05/22 00:51:45
nit: Remove the extra blank line.
Jamie
2013/05/22 01:16:46
Done.
| |
25 | |
26 PairingAuthenticatorBase::PairingAuthenticatorBase() | |
27 : using_paired_secret_(false), | |
28 waiting_for_authenticator_(false), | |
29 weak_factory_(this) { | |
30 } | |
31 | |
32 Authenticator::State PairingAuthenticatorBase::state() const { | |
33 if (waiting_for_authenticator_) { | |
34 return PROCESSING_MESSAGE; | |
35 } | |
36 return v2_authenticator_->state(); | |
37 } | |
38 | |
39 Authenticator::RejectionReason | |
40 PairingAuthenticatorBase::rejection_reason() const { | |
41 if (!v2_authenticator_) { | |
42 return PROTOCOL_ERROR; | |
43 } | |
44 return v2_authenticator_->rejection_reason(); | |
45 } | |
46 | |
47 void PairingAuthenticatorBase::ProcessMessage( | |
48 const buzz::XmlElement* message, | |
49 const base::Closure& resume_callback) { | |
50 DCHECK_EQ(state(), WAITING_MESSAGE); | |
51 | |
52 // The client authenticator creates the underlying authenticator in the ctor | |
53 // and the host creates it in response to the first message before deferring | |
54 // to this class to process it. Either way, it should exist here. | |
55 DCHECK(v2_authenticator_); | |
56 | |
57 // If pairing failed, and we haven't already done so, try again with the PIN. | |
58 if (using_paired_secret_ && HasErrorMessage(message)) { | |
59 using_paired_secret_ = false; | |
60 waiting_for_authenticator_ = true; | |
61 v2_authenticator_.reset(); | |
62 SetAuthenticatorCallback set_authenticator = base::Bind( | |
63 &PairingAuthenticatorBase::SetAuthenticatorAndProcessMessage, | |
64 weak_factory_.GetWeakPtr(), base::Owned(new buzz::XmlElement(*message)), | |
65 resume_callback); | |
66 CreateV2AuthenticatorWithPIN(WAITING_MESSAGE, set_authenticator); | |
67 return; | |
68 } | |
69 | |
70 // Pass the message to the underlying authenticator for processing, but | |
71 // check for a failed SPAKE exchange if we're using the paired secret. In | |
72 // this case the pairing protocol can continue by communicating the error | |
73 // to the peer and retrying with the PIN. | |
74 v2_authenticator_->ProcessMessage( | |
75 message, | |
76 base::Bind(&PairingAuthenticatorBase::CheckForFailedSpakeExchange, | |
77 weak_factory_.GetWeakPtr(), resume_callback)); | |
78 } | |
79 | |
80 scoped_ptr<buzz::XmlElement> PairingAuthenticatorBase::GetNextMessage() { | |
81 DCHECK_EQ(state(), MESSAGE_READY); | |
82 scoped_ptr<buzz::XmlElement> result = v2_authenticator_->GetNextMessage(); | |
83 AddPairingElements(result.get()); | |
84 MaybeAddErrorMessage(result.get()); | |
85 return result.Pass(); | |
86 } | |
87 | |
88 scoped_ptr<ChannelAuthenticator> | |
89 PairingAuthenticatorBase::CreateChannelAuthenticator() const { | |
90 return v2_authenticator_->CreateChannelAuthenticator(); | |
91 } | |
92 | |
93 void PairingAuthenticatorBase::MaybeAddErrorMessage(buzz::XmlElement* message) { | |
94 if (!error_message_.empty()) { | |
95 buzz::XmlElement* pairing_failed_tag = | |
96 new buzz::XmlElement(kPairingFailedTag); | |
97 pairing_failed_tag->AddAttr(kPairingErrorAttribute, error_message_); | |
98 message->AddElement(pairing_failed_tag); | |
99 error_message_.clear(); | |
100 } | |
101 } | |
102 | |
103 bool PairingAuthenticatorBase::HasErrorMessage( | |
104 const buzz::XmlElement* message) const { | |
105 const buzz::XmlElement* pairing_failed_tag = | |
106 message->FirstNamed(kPairingFailedTag); | |
107 if (pairing_failed_tag) { | |
108 // If pairing failed, and we haven't already done so, prompt the | |
109 // user for the PIN and try again. | |
Wez
2013/05/22 00:51:45
This comment doesn't describe the code that follow
Jamie
2013/05/22 01:16:46
It's a remnant from where this code used to live.
| |
110 std::string error = pairing_failed_tag->Attr(kPairingErrorAttribute); | |
111 LOG(INFO) << "Pairing failed: " << error; | |
112 } | |
113 return pairing_failed_tag != NULL; | |
114 } | |
115 | |
116 void PairingAuthenticatorBase::CheckForFailedSpakeExchange( | |
117 const base::Closure& resume_callback) { | |
118 // If the SPAKE exchange failed due to invalid credentials, and those | |
119 // credentials were the paired secret, then notify the peer that the | |
120 // PIN-less connection failed and retry using the PIN. | |
121 if (v2_authenticator_->state() == REJECTED && | |
122 v2_authenticator_->rejection_reason() == INVALID_CREDENTIALS && | |
123 using_paired_secret_) { | |
124 using_paired_secret_ = false; | |
125 error_message_ = "invalid-shared-secret"; | |
126 v2_authenticator_.reset(); | |
127 SetAuthenticatorCallback set_authenticator = base::Bind( | |
128 &PairingAuthenticatorBase::SetAuthenticator, | |
129 weak_factory_.GetWeakPtr(), resume_callback); | |
130 CreateV2AuthenticatorWithPIN(MESSAGE_READY, set_authenticator); | |
131 return; | |
132 } | |
133 | |
134 resume_callback.Run(); | |
135 } | |
136 | |
137 void PairingAuthenticatorBase::SetAuthenticator( | |
138 const base::Closure& resume_callback, | |
139 scoped_ptr<Authenticator> authenticator) { | |
140 DCHECK(!v2_authenticator_); | |
141 DCHECK(authenticator); | |
142 waiting_for_authenticator_ = false; | |
143 v2_authenticator_ = authenticator.Pass(); | |
144 resume_callback.Run(); | |
145 } | |
146 | |
147 void PairingAuthenticatorBase::SetAuthenticatorAndProcessMessage( | |
Wez
2013/05/22 00:51:45
nit: Couldn't you fold this and SetAuthenticator t
Jamie
2013/05/22 01:16:46
Done.
| |
148 const buzz::XmlElement* message, | |
149 const base::Closure& resume_callback, | |
150 scoped_ptr<Authenticator> authenticator) { | |
151 DCHECK(!v2_authenticator_); | |
152 DCHECK(authenticator); | |
153 waiting_for_authenticator_ = false; | |
154 v2_authenticator_ = authenticator.Pass(); | |
155 ProcessMessage(message, resume_callback); | |
156 } | |
157 | |
158 } // namespace protocol | |
159 } // namespace remoting | |
OLD | NEW |