// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef REMOTING_PROTOCOL_PAIRING_REGISTRY_H_ #define REMOTING_PROTOCOL_PAIRING_REGISTRY_H_ #include <map> #include <queue> #include <string> #include <vector> #include "base/callback.h" #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/time/time.h" namespace base { class DictionaryValue; class ListValue; class SingleThreadTaskRunner; } // namespace base namespace tracked_objects { class Location; } // namespace tracked_objects namespace remoting { namespace protocol { // PairingRegistry holds information about paired clients to support // PIN-less authentication. For each paired client, the registry holds // the following information: // * The name of the client. This is supplied by the client and is not // guaranteed to be unique. // * The unique id of the client. This is generated on-demand by this // class and sent in plain-text by the client during authentication. // * The shared secret for the client. This is generated on-demand by this // class and used in the SPAKE2 exchange to mutually verify identity. class PairingRegistry : public base::RefCountedThreadSafe<PairingRegistry> { public: struct Pairing { Pairing(); Pairing(const base::Time& created_time, const std::string& client_name, const std::string& client_id, const std::string& shared_secret); ~Pairing(); static Pairing Create(const std::string& client_name); static Pairing CreateFromValue(const base::DictionaryValue& pairing); scoped_ptr<base::DictionaryValue> ToValue() const; bool operator==(const Pairing& other) const; bool is_valid() const; base::Time created_time() const { return created_time_; } std::string client_id() const { return client_id_; } std::string client_name() const { return client_name_; } std::string shared_secret() const { return shared_secret_; } private: base::Time created_time_; std::string client_name_; std::string client_id_; std::string shared_secret_; }; // Mapping from client id to pairing information. typedef std::map<std::string, Pairing> PairedClients; // Delegate callbacks. typedef base::Callback<void(bool success)> DoneCallback; typedef base::Callback<void(scoped_ptr<base::ListValue> pairings)> GetAllPairingsCallback; typedef base::Callback<void(Pairing pairing)> GetPairingCallback; static const char kCreatedTimeKey[]; static const char kClientIdKey[]; static const char kClientNameKey[]; static const char kSharedSecretKey[]; // Interface representing the persistent storage back-end. class Delegate { public: virtual ~Delegate() {} // Retrieves all JSON-encoded pairings from persistent storage. virtual scoped_ptr<base::ListValue> LoadAll() = 0; // Deletes all pairings in persistent storage. virtual bool DeleteAll() = 0; // Retrieves the pairing identified by |client_id|. virtual Pairing Load(const std::string& client_id) = 0; // Saves |pairing| to persistent storage. virtual bool Save(const Pairing& pairing) = 0; // Deletes the pairing identified by |client_id|. virtual bool Delete(const std::string& client_id) = 0; }; PairingRegistry( scoped_refptr<base::SingleThreadTaskRunner> delegate_task_runner, scoped_ptr<Delegate> delegate); // Creates a pairing for a new client and saves it to disk. // // TODO(jamiewalch): Plumb the Save callback into the RequestPairing flow // so that the client isn't sent the pairing information until it has been // saved. Pairing CreatePairing(const std::string& client_name); // Gets the pairing for the specified client id. See the corresponding // Delegate method for details. If none is found, the callback is invoked // with an invalid Pairing. void GetPairing(const std::string& client_id, const GetPairingCallback& callback); // Gets all pairings with the shared secrets removed as a base::ListValue. void GetAllPairings(const GetAllPairingsCallback& callback); // Delete a pairing, identified by its client ID. |callback| is called with // the result of saving the new config, which occurs even if the client ID // did not match any pairing. void DeletePairing(const std::string& client_id, const DoneCallback& callback); // Clear all pairings from the registry. void ClearAllPairings(const DoneCallback& callback); protected: friend class base::RefCountedThreadSafe<PairingRegistry>; virtual ~PairingRegistry(); // Lets the tests override task posting to make all callbacks synchronous. virtual void PostTask( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, const tracked_objects::Location& from_here, const base::Closure& task); private: FRIEND_TEST_ALL_PREFIXES(PairingRegistryTest, AddPairing); friend class NegotiatingAuthenticatorTest; // Helper method for unit tests. void AddPairing(const Pairing& pairing); // Blocking helper methods used to call the delegate. void DoLoadAll( const protocol::PairingRegistry::GetAllPairingsCallback& callback); void DoDeleteAll( const protocol::PairingRegistry::DoneCallback& callback); void DoLoad( const std::string& client_id, const protocol::PairingRegistry::GetPairingCallback& callback); void DoSave( const protocol::PairingRegistry::Pairing& pairing, const protocol::PairingRegistry::DoneCallback& callback); void DoDelete( const std::string& client_id, const protocol::PairingRegistry::DoneCallback& callback); // "Trampoline" callbacks that schedule the next pending request and then // invoke the original caller-supplied callback. void InvokeDoneCallbackAndScheduleNext( const DoneCallback& callback, bool success); void InvokeGetPairingCallbackAndScheduleNext( const GetPairingCallback& callback, Pairing pairing); void InvokeGetAllPairingsCallbackAndScheduleNext( const GetAllPairingsCallback& callback, scoped_ptr<base::ListValue> pairings); // Sanitize |pairings| by parsing each entry and removing the secret from it. void SanitizePairings(const GetAllPairingsCallback& callback, scoped_ptr<base::ListValue> pairings); // Queue management methods. void ServiceOrQueueRequest(const base::Closure& request); void ServiceNextRequest(); // Task runner on which all public methods of this class should be called. scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_; // Task runner used to run blocking calls to the delegate. A single thread // task runner is used to guarantee that one one method of the delegate is // called at a time. scoped_refptr<base::SingleThreadTaskRunner> delegate_task_runner_; scoped_ptr<Delegate> delegate_; std::queue<base::Closure> pending_requests_; DISALLOW_COPY_AND_ASSIGN(PairingRegistry); }; } // namespace protocol } // namespace remoting #endif // REMOTING_PROTOCOL_PAIRING_REGISTRY_H_