Upstream version 5.34.92.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 Authenticator::RejectionReason
42 PairingAuthenticatorBase::rejection_reason() const {
43   if (!v2_authenticator_) {
44     return PROTOCOL_ERROR;
45   }
46   return v2_authenticator_->rejection_reason();
47 }
48
49 void PairingAuthenticatorBase::ProcessMessage(
50     const buzz::XmlElement* message,
51     const base::Closure& resume_callback) {
52   DCHECK_EQ(state(), WAITING_MESSAGE);
53
54   // The client authenticator creates the underlying authenticator in the ctor
55   // and the host creates it in response to the first message before deferring
56   // to this class to process it. Either way, it should exist here.
57   DCHECK(v2_authenticator_);
58
59   // If pairing failed, and we haven't already done so, try again with the PIN.
60   if (using_paired_secret_ && HasErrorMessage(message)) {
61     using_paired_secret_ = false;
62     waiting_for_authenticator_ = true;
63     v2_authenticator_.reset();
64     SetAuthenticatorCallback set_authenticator = base::Bind(
65         &PairingAuthenticatorBase::SetAuthenticatorAndProcessMessage,
66         weak_factory_.GetWeakPtr(), base::Owned(new buzz::XmlElement(*message)),
67         resume_callback);
68     CreateV2AuthenticatorWithPIN(WAITING_MESSAGE, set_authenticator);
69     return;
70   }
71
72   // Pass the message to the underlying authenticator for processing, but
73   // check for a failed SPAKE exchange if we're using the paired secret. In
74   // this case the pairing protocol can continue by communicating the error
75   // to the peer and retrying with the PIN.
76   v2_authenticator_->ProcessMessage(
77       message,
78       base::Bind(&PairingAuthenticatorBase::CheckForFailedSpakeExchange,
79                  weak_factory_.GetWeakPtr(), resume_callback));
80 }
81
82 scoped_ptr<buzz::XmlElement> PairingAuthenticatorBase::GetNextMessage() {
83   DCHECK_EQ(state(), MESSAGE_READY);
84   scoped_ptr<buzz::XmlElement> result = v2_authenticator_->GetNextMessage();
85   AddPairingElements(result.get());
86   MaybeAddErrorMessage(result.get());
87   return result.Pass();
88 }
89
90 scoped_ptr<ChannelAuthenticator>
91 PairingAuthenticatorBase::CreateChannelAuthenticator() const {
92   return v2_authenticator_->CreateChannelAuthenticator();
93 }
94
95 void PairingAuthenticatorBase::MaybeAddErrorMessage(buzz::XmlElement* message) {
96   if (!error_message_.empty()) {
97     buzz::XmlElement* pairing_failed_tag =
98         new buzz::XmlElement(kPairingFailedTag);
99     pairing_failed_tag->AddAttr(kPairingErrorAttribute, error_message_);
100     message->AddElement(pairing_failed_tag);
101     error_message_.clear();
102   }
103 }
104
105 bool PairingAuthenticatorBase::HasErrorMessage(
106     const buzz::XmlElement* message) const {
107   const buzz::XmlElement* pairing_failed_tag =
108       message->FirstNamed(kPairingFailedTag);
109   if (pairing_failed_tag) {
110     std::string error = pairing_failed_tag->Attr(kPairingErrorAttribute);
111     LOG(ERROR) << "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     buzz::XmlElement* no_message = NULL;
128     SetAuthenticatorCallback set_authenticator = base::Bind(
129         &PairingAuthenticatorBase::SetAuthenticatorAndProcessMessage,
130         weak_factory_.GetWeakPtr(), no_message, resume_callback);
131     CreateV2AuthenticatorWithPIN(MESSAGE_READY, set_authenticator);
132     return;
133   }
134
135   resume_callback.Run();
136 }
137
138 void PairingAuthenticatorBase::SetAuthenticatorAndProcessMessage(
139     const buzz::XmlElement* message,
140     const base::Closure& resume_callback,
141     scoped_ptr<Authenticator> authenticator) {
142   DCHECK(!v2_authenticator_);
143   DCHECK(authenticator);
144   waiting_for_authenticator_ = false;
145   v2_authenticator_ = authenticator.Pass();
146   if (message) {
147     ProcessMessage(message, resume_callback);
148   } else {
149     resume_callback.Run();
150   }
151 }
152
153 }  // namespace protocol
154 }  // namespace remoting