Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / remoting / protocol / pairing_authenticator_base.cc
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
25 PairingAuthenticatorBase::PairingAuthenticatorBase()
26     : using_paired_secret_(false),
27       waiting_for_authenticator_(false),
28       weak_factory_(this) {
29 }
30
31 PairingAuthenticatorBase::~PairingAuthenticatorBase() {
32 }
33
34 Authenticator::State PairingAuthenticatorBase::state() const {
35   if (waiting_for_authenticator_) {
36     return PROCESSING_MESSAGE;
37   }
38   return v2_authenticator_->state();
39 }
40
41 bool PairingAuthenticatorBase::started() const {
42   if (!v2_authenticator_) {
43     return false;
44   }
45   return v2_authenticator_->started();
46 }
47
48 Authenticator::RejectionReason
49 PairingAuthenticatorBase::rejection_reason() const {
50   if (!v2_authenticator_) {
51     return PROTOCOL_ERROR;
52   }
53   return v2_authenticator_->rejection_reason();
54 }
55
56 void PairingAuthenticatorBase::ProcessMessage(
57     const buzz::XmlElement* message,
58     const base::Closure& resume_callback) {
59   DCHECK_EQ(state(), WAITING_MESSAGE);
60
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_);
65
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;
77   }
78
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));
87 }
88
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();
95 }
96
97 scoped_ptr<ChannelAuthenticator>
98 PairingAuthenticatorBase::CreateChannelAuthenticator() const {
99   return v2_authenticator_->CreateChannelAuthenticator();
100 }
101
102 void PairingAuthenticatorBase::MaybeAddErrorMessage(buzz::XmlElement* message) {
103   if (!error_message_.empty()) {
104     buzz::XmlElement* pairing_failed_tag =
105         new buzz::XmlElement(kPairingFailedTag);
106     pairing_failed_tag->AddAttr(kPairingErrorAttribute, error_message_);
107     message->AddElement(pairing_failed_tag);
108     error_message_.clear();
109   }
110 }
111
112 bool PairingAuthenticatorBase::HasErrorMessage(
113     const buzz::XmlElement* message) const {
114   const buzz::XmlElement* pairing_failed_tag =
115       message->FirstNamed(kPairingFailedTag);
116   if (pairing_failed_tag) {
117     std::string error = pairing_failed_tag->Attr(kPairingErrorAttribute);
118     LOG(ERROR) << "Pairing failed: " << error;
119   }
120   return pairing_failed_tag != NULL;
121 }
122
123 void PairingAuthenticatorBase::CheckForFailedSpakeExchange(
124     const base::Closure& resume_callback) {
125   // If the SPAKE exchange failed due to invalid credentials, and those
126   // credentials were the paired secret, then notify the peer that the
127   // PIN-less connection failed and retry using the PIN.
128   if (v2_authenticator_->state() == REJECTED &&
129       v2_authenticator_->rejection_reason() == INVALID_CREDENTIALS &&
130       using_paired_secret_) {
131     using_paired_secret_ = false;
132     error_message_ = "invalid-shared-secret";
133     v2_authenticator_.reset();
134     buzz::XmlElement* no_message = NULL;
135     SetAuthenticatorCallback set_authenticator = base::Bind(
136         &PairingAuthenticatorBase::SetAuthenticatorAndProcessMessage,
137         weak_factory_.GetWeakPtr(), no_message, resume_callback);
138     CreateV2AuthenticatorWithPIN(MESSAGE_READY, set_authenticator);
139     return;
140   }
141
142   resume_callback.Run();
143 }
144
145 void PairingAuthenticatorBase::SetAuthenticatorAndProcessMessage(
146     const buzz::XmlElement* message,
147     const base::Closure& resume_callback,
148     scoped_ptr<Authenticator> authenticator) {
149   DCHECK(!v2_authenticator_);
150   DCHECK(authenticator);
151   waiting_for_authenticator_ = false;
152   v2_authenticator_ = authenticator.Pass();
153   if (message) {
154     ProcessMessage(message, resume_callback);
155   } else {
156     resume_callback.Run();
157   }
158 }
159
160 }  // namespace protocol
161 }  // namespace remoting