Home | History | Annotate | Download | only in protocol
      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/libjingle/source/talk/xmllite/xmlelement.h"
     14 
     15 namespace remoting {
     16 namespace protocol {
     17 
     18 namespace {
     19 
     20 // Authenticator that accepts one message and rejects connection after that.
     21 class 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
     67 scoped_ptr<AuthenticatorFactory>
     68 Me2MeHostAuthenticatorFactory::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
     88 scoped_ptr<AuthenticatorFactory>
     89 Me2MeHostAuthenticatorFactory::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
    107 scoped_ptr<AuthenticatorFactory>
    108     Me2MeHostAuthenticatorFactory::CreateRejecting() {
    109   return scoped_ptr<AuthenticatorFactory>(new Me2MeHostAuthenticatorFactory());
    110 }
    111 
    112 Me2MeHostAuthenticatorFactory::Me2MeHostAuthenticatorFactory() {
    113 }
    114 
    115 Me2MeHostAuthenticatorFactory::~Me2MeHostAuthenticatorFactory() {
    116 }
    117 
    118 scoped_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