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 = | |
rmsousa
2013/05/21 23:17:07
Nit: I'd make these class members for consistency.
Jamie
2013/05/22 00:19:14
The reason I didn't is that they're an implementat
| |
21 { kChromotingXmlNamespace, "pairing-failed" }; | |
22 const buzz::StaticQName kPairingErrorAttribute = { "", "error" }; | |
23 } // namespace | |
24 | |
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 (v2_authenticator_) { | |
34 return v2_authenticator_->state(); | |
35 } else if (waiting_for_authenticator_) { | |
36 return PROCESSING_MESSAGE; | |
37 } else { | |
38 return WAITING_MESSAGE; | |
rmsousa
2013/05/21 23:17:07
Nit: can you add a comment explaining why this sta
Jamie
2013/05/22 00:19:14
Done (without the DCHECK, since operator-> has one
| |
39 } | |
40 } | |
41 | |
42 Authenticator::RejectionReason | |
43 PairingAuthenticatorBase::rejection_reason() const { | |
44 if (!v2_authenticator_) { | |
45 return PROTOCOL_ERROR; | |
rmsousa
2013/05/21 23:17:07
rejection_reason() is only queried if state() is R
Jamie
2013/05/22 00:19:14
Wez asked me to add this on the basis that it's be
| |
46 } | |
47 return v2_authenticator_->rejection_reason(); | |
48 } | |
49 | |
50 void PairingAuthenticatorBase::ProcessMessage( | |
51 const buzz::XmlElement* message, | |
52 const base::Closure& resume_callback) { | |
53 DCHECK_EQ(state(), WAITING_MESSAGE); | |
54 | |
55 // If pairing failed, and we haven't already done so, try again with the PIN. | |
56 if (using_paired_secret_ && HasErrorMessage(message)) { | |
57 using_paired_secret_ = false; | |
58 waiting_for_authenticator_ = true; | |
59 v2_authenticator_.reset(); | |
60 SetAuthenticatorCallback set_authenticator = base::Bind( | |
61 &PairingAuthenticatorBase::SetAuthenticatorAndProcessMessage, | |
62 weak_factory_.GetWeakPtr(), base::Owned(new buzz::XmlElement(*message)), | |
63 resume_callback); | |
64 CreateV2AuthenticatorWithPIN(WAITING_MESSAGE, set_authenticator); | |
65 return; | |
66 } | |
67 | |
68 // If there isn't already an underlying authenticator, ask the derived class | |
69 // to create one based on the contents of the message. | |
70 if (!v2_authenticator_) { | |
rmsousa
2013/05/21 23:17:07
This whole block is host only. It should be part o
Jamie
2013/05/22 00:19:14
That's much cleaner, thanks. Done.
| |
71 v2_authenticator_ = CreateV2AuthenticatorFromInitialMessage(message); | |
72 DCHECK(v2_authenticator_); | |
73 // Depending on the contents of the message, the derived class may decline | |
74 // to process it. For example, the PairingHostAuthenticator class does this | |
75 // if it doesn't recognize the client id. | |
76 if (state() != WAITING_MESSAGE) { | |
77 resume_callback.Run(); | |
78 return; | |
79 } | |
80 } | |
81 | |
82 // Pass the message to the underlying authenticator for processing, but | |
83 // check for a failed SPAKE exchange if we're using the paired secret. In | |
84 // this case the pairing protocol can continue by communicating the error | |
85 // to the peer and retrying with the PIN. | |
86 v2_authenticator_->ProcessMessage( | |
87 message, | |
88 base::Bind(&PairingAuthenticatorBase::CheckForFailedSpakeExchange, | |
89 weak_factory_.GetWeakPtr(), resume_callback)); | |
90 } | |
91 | |
92 scoped_ptr<buzz::XmlElement> PairingAuthenticatorBase::GetNextMessage() { | |
93 DCHECK_EQ(state(), MESSAGE_READY); | |
94 scoped_ptr<buzz::XmlElement> result = v2_authenticator_->GetNextMessage(); | |
rmsousa
2013/05/21 23:17:07
Nit: In ThirdPartyAuth the two lines below are enc
Jamie
2013/05/22 00:19:14
I don't want the subclasses to be able to avoid th
| |
95 AmendProtocolMessage(result.get()); | |
96 MaybeAddErrorMessage(result.get()); | |
97 return result.Pass(); | |
98 } | |
99 | |
100 scoped_ptr<ChannelAuthenticator> | |
101 PairingAuthenticatorBase::CreateChannelAuthenticator() const { | |
102 return v2_authenticator_->CreateChannelAuthenticator(); | |
103 } | |
104 | |
105 void PairingAuthenticatorBase::MaybeAddErrorMessage(buzz::XmlElement* message) { | |
106 if (!error_message_.empty()) { | |
107 buzz::XmlElement* pairing_failed_tag = | |
108 new buzz::XmlElement(kPairingFailedTag); | |
109 pairing_failed_tag->AddAttr(kPairingErrorAttribute, error_message_); | |
110 message->AddElement(pairing_failed_tag); | |
111 error_message_.clear(); | |
112 } | |
113 } | |
114 | |
115 bool PairingAuthenticatorBase::HasErrorMessage( | |
116 const buzz::XmlElement* message) const { | |
117 const buzz::XmlElement* pairing_failed_tag = | |
118 message->FirstNamed(kPairingFailedTag); | |
119 if (pairing_failed_tag) { | |
120 // If pairing failed, and we haven't already done so, prompt the | |
121 // user for the PIN and try again. | |
122 std::string error = pairing_failed_tag->Attr(kPairingErrorAttribute); | |
123 LOG(INFO) << "Pairing failed: " << error; | |
124 } | |
125 return pairing_failed_tag != NULL; | |
126 } | |
127 | |
128 void PairingAuthenticatorBase::CheckForFailedSpakeExchange( | |
129 const base::Closure& resume_callback) { | |
130 // If the SPAKE exchange failed due to invalid credentials, and those | |
131 // credentials were the paired secret, then notify the peer that the | |
132 // PIN-less connection failed and retry using the PIN. | |
133 if (v2_authenticator_->state() == REJECTED && | |
134 v2_authenticator_->rejection_reason() == INVALID_CREDENTIALS && | |
135 using_paired_secret_) { | |
136 using_paired_secret_ = false; | |
137 error_message_ = "invalid-shared-secret"; | |
138 v2_authenticator_.reset(); | |
139 SetAuthenticatorCallback set_authenticator = base::Bind( | |
140 &PairingAuthenticatorBase::SetAuthenticator, | |
141 weak_factory_.GetWeakPtr(), resume_callback); | |
142 CreateV2AuthenticatorWithPIN(MESSAGE_READY, set_authenticator); | |
143 return; | |
144 } | |
145 | |
146 resume_callback.Run(); | |
147 } | |
148 | |
149 void PairingAuthenticatorBase::SetAuthenticator( | |
150 const base::Closure& resume_callback, | |
151 scoped_ptr<Authenticator> authenticator) { | |
152 DCHECK(!v2_authenticator_); | |
153 DCHECK(authenticator); | |
154 waiting_for_authenticator_ = false; | |
155 v2_authenticator_ = authenticator.Pass(); | |
156 resume_callback.Run(); | |
157 } | |
158 | |
159 void PairingAuthenticatorBase::SetAuthenticatorAndProcessMessage( | |
160 const buzz::XmlElement* message, | |
161 const base::Closure& resume_callback, | |
162 scoped_ptr<Authenticator> authenticator) { | |
163 DCHECK(!v2_authenticator_); | |
164 DCHECK(authenticator); | |
165 waiting_for_authenticator_ = false; | |
166 v2_authenticator_ = authenticator.Pass(); | |
167 ProcessMessage(message, resume_callback); | |
168 } | |
169 | |
170 } // namespace protocol | |
171 } // namespace remoting | |
OLD | NEW |