1// Copyright (c) 2012 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/me2me_host_authenticator_factory.h"
6
7#include "base/base64.h"
8#include "base/strings/string_util.h"
9#include "remoting/base/rsa_key_pair.h"
10#include "remoting/protocol/channel_authenticator.h"
11#include "remoting/protocol/negotiating_host_authenticator.h"
12#include "remoting/protocol/token_validator.h"
13#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
14
15namespace remoting {
16namespace protocol {
17
18namespace {
19
20// Authenticator that accepts one message and rejects connection after that.
21class RejectingAuthenticator : public Authenticator {
22 public:
23  RejectingAuthenticator()
24      : state_(WAITING_MESSAGE) {
25  }
26  virtual ~RejectingAuthenticator() {
27  }
28
29  virtual State state() const OVERRIDE {
30    return state_;
31  }
32
33  virtual bool started() const OVERRIDE {
34    return true;
35  }
36
37  virtual RejectionReason rejection_reason() const OVERRIDE {
38    DCHECK_EQ(state_, REJECTED);
39    return INVALID_CREDENTIALS;
40  }
41
42  virtual void ProcessMessage(const buzz::XmlElement* message,
43                              const base::Closure& resume_callback) OVERRIDE {
44    DCHECK_EQ(state_, WAITING_MESSAGE);
45    state_ = REJECTED;
46    resume_callback.Run();
47  }
48
49  virtual scoped_ptr<buzz::XmlElement> GetNextMessage() OVERRIDE {
50    NOTREACHED();
51    return scoped_ptr<buzz::XmlElement>();
52  }
53
54  virtual scoped_ptr<ChannelAuthenticator>
55  CreateChannelAuthenticator() const OVERRIDE {
56    NOTREACHED();
57    return scoped_ptr<ChannelAuthenticator>();
58  }
59
60 protected:
61  State state_;
62};
63
64}  // namespace
65
66// static
67scoped_ptr<AuthenticatorFactory>
68Me2MeHostAuthenticatorFactory::CreateWithSharedSecret(
69    bool use_service_account,
70    const std::string& host_owner,
71    const std::string& local_cert,
72    scoped_refptr<RsaKeyPair> key_pair,
73    const SharedSecretHash& shared_secret_hash,
74    scoped_refptr<PairingRegistry> pairing_registry) {
75  scoped_ptr<Me2MeHostAuthenticatorFactory> result(
76      new Me2MeHostAuthenticatorFactory());
77  result->use_service_account_ = use_service_account;
78  result->host_owner_ = host_owner;
79  result->local_cert_ = local_cert;
80  result->key_pair_ = key_pair;
81  result->shared_secret_hash_ = shared_secret_hash;
82  result->pairing_registry_ = pairing_registry;
83  return scoped_ptr<AuthenticatorFactory>(result.Pass());
84}
85
86
87// static
88scoped_ptr<AuthenticatorFactory>
89Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth(
90    bool use_service_account,
91    const std::string& host_owner,
92    const std::string& local_cert,
93    scoped_refptr<RsaKeyPair> key_pair,
94    scoped_ptr<TokenValidatorFactory>
95        token_validator_factory) {
96  scoped_ptr<Me2MeHostAuthenticatorFactory> result(
97      new Me2MeHostAuthenticatorFactory());
98  result->use_service_account_ = use_service_account;
99  result->host_owner_ = host_owner;
100  result->local_cert_ = local_cert;
101  result->key_pair_ = key_pair;
102  result->token_validator_factory_ = token_validator_factory.Pass();
103  return scoped_ptr<AuthenticatorFactory>(result.Pass());
104}
105
106// static
107scoped_ptr<AuthenticatorFactory>
108    Me2MeHostAuthenticatorFactory::CreateRejecting() {
109  return scoped_ptr<AuthenticatorFactory>(new Me2MeHostAuthenticatorFactory());
110}
111
112Me2MeHostAuthenticatorFactory::Me2MeHostAuthenticatorFactory() {
113}
114
115Me2MeHostAuthenticatorFactory::~Me2MeHostAuthenticatorFactory() {
116}
117
118scoped_ptr<Authenticator> Me2MeHostAuthenticatorFactory::CreateAuthenticator(
119    const std::string& local_jid,
120    const std::string& remote_jid,
121    const buzz::XmlElement* first_message) {
122
123  std::string remote_jid_prefix;
124
125  if (!use_service_account_) {
126    // JID prefixes may not match the host owner email, for example, in cases
127    // where the host owner account does not have an email associated with it.
128    // In those cases, the only guarantee we have is that JIDs for the same
129    // account will have the same prefix.
130    size_t slash_pos = local_jid.find('/');
131    if (slash_pos == std::string::npos) {
132      LOG(DFATAL) << "Invalid local JID:" << local_jid;
133      return scoped_ptr<Authenticator>(new RejectingAuthenticator());
134    }
135    remote_jid_prefix = local_jid.substr(0, slash_pos);
136  } else {
137    // TODO(rmsousa): This only works for cases where the JID prefix matches
138    // the host owner email. Figure out a way to verify the JID in other cases.
139    remote_jid_prefix = host_owner_;
140  }
141
142  // Verify that the client's jid is an ASCII string, and then check that the
143  // client JID has the expected prefix. Comparison is case insensitive.
144  if (!base::IsStringASCII(remote_jid) ||
145      !StartsWithASCII(remote_jid, remote_jid_prefix + '/', false)) {
146    LOG(ERROR) << "Rejecting incoming connection from " << remote_jid;
147    return scoped_ptr<Authenticator>(new RejectingAuthenticator());
148  }
149
150  if (!local_cert_.empty() && key_pair_.get()) {
151    if (token_validator_factory_) {
152      return NegotiatingHostAuthenticator::CreateWithThirdPartyAuth(
153          local_cert_, key_pair_,
154          token_validator_factory_->CreateTokenValidator(
155              local_jid, remote_jid));
156    }
157
158    return NegotiatingHostAuthenticator::CreateWithSharedSecret(
159        local_cert_, key_pair_, shared_secret_hash_.value,
160        shared_secret_hash_.hash_function, pairing_registry_);
161  }
162
163  return scoped_ptr<Authenticator>(new RejectingAuthenticator());
164}
165
166}  // namespace protocol
167}  // namespace remoting
168