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#ifndef REMOTING_PROTOCOL_PAIRING_REGISTRY_H_
6#define REMOTING_PROTOCOL_PAIRING_REGISTRY_H_
7
8#include <map>
9#include <queue>
10#include <string>
11#include <vector>
12
13#include "base/callback.h"
14#include "base/gtest_prod_util.h"
15#include "base/memory/ref_counted.h"
16#include "base/memory/scoped_ptr.h"
17#include "base/time/time.h"
18
19namespace base {
20class DictionaryValue;
21class ListValue;
22class SingleThreadTaskRunner;
23}  // namespace base
24
25namespace tracked_objects {
26class Location;
27}  // namespace tracked_objects
28
29namespace remoting {
30namespace protocol {
31
32// PairingRegistry holds information about paired clients to support
33// PIN-less authentication. For each paired client, the registry holds
34// the following information:
35//   * The name of the client. This is supplied by the client and is not
36//     guaranteed to be unique.
37//   * The unique id of the client. This is generated on-demand by this
38//     class and sent in plain-text by the client during authentication.
39//   * The shared secret for the client. This is generated on-demand by this
40//     class and used in the SPAKE2 exchange to mutually verify identity.
41class PairingRegistry : public base::RefCountedThreadSafe<PairingRegistry> {
42 public:
43  struct Pairing {
44    Pairing();
45    Pairing(const base::Time& created_time,
46            const std::string& client_name,
47            const std::string& client_id,
48            const std::string& shared_secret);
49    ~Pairing();
50
51    static Pairing Create(const std::string& client_name);
52    static Pairing CreateFromValue(const base::DictionaryValue& pairing);
53
54    scoped_ptr<base::DictionaryValue> ToValue() const;
55
56    bool operator==(const Pairing& other) const;
57
58    bool is_valid() const;
59
60    base::Time created_time() const { return created_time_; }
61    std::string client_id() const { return client_id_; }
62    std::string client_name() const { return client_name_; }
63    std::string shared_secret() const { return shared_secret_; }
64
65   private:
66    base::Time created_time_;
67    std::string client_name_;
68    std::string client_id_;
69    std::string shared_secret_;
70  };
71
72  // Mapping from client id to pairing information.
73  typedef std::map<std::string, Pairing> PairedClients;
74
75  // Delegate callbacks.
76  typedef base::Callback<void(bool success)> DoneCallback;
77  typedef base::Callback<void(scoped_ptr<base::ListValue> pairings)>
78      GetAllPairingsCallback;
79  typedef base::Callback<void(Pairing pairing)> GetPairingCallback;
80
81  static const char kCreatedTimeKey[];
82  static const char kClientIdKey[];
83  static const char kClientNameKey[];
84  static const char kSharedSecretKey[];
85
86  // Interface representing the persistent storage back-end.
87  class Delegate {
88   public:
89    virtual ~Delegate() {}
90
91    // Retrieves all JSON-encoded pairings from persistent storage.
92    virtual scoped_ptr<base::ListValue> LoadAll() = 0;
93
94    // Deletes all pairings in persistent storage.
95    virtual bool DeleteAll() = 0;
96
97    // Retrieves the pairing identified by |client_id|.
98    virtual Pairing Load(const std::string& client_id) = 0;
99
100    // Saves |pairing| to persistent storage.
101    virtual bool Save(const Pairing& pairing) = 0;
102
103    // Deletes the pairing identified by |client_id|.
104    virtual bool Delete(const std::string& client_id) = 0;
105  };
106
107  PairingRegistry(
108      scoped_refptr<base::SingleThreadTaskRunner> delegate_task_runner,
109      scoped_ptr<Delegate> delegate);
110
111  // Creates a pairing for a new client and saves it to disk.
112  //
113  // TODO(jamiewalch): Plumb the Save callback into the RequestPairing flow
114  // so that the client isn't sent the pairing information until it has been
115  // saved.
116  Pairing CreatePairing(const std::string& client_name);
117
118  // Gets the pairing for the specified client id. See the corresponding
119  // Delegate method for details. If none is found, the callback is invoked
120  // with an invalid Pairing.
121  void GetPairing(const std::string& client_id,
122                  const GetPairingCallback& callback);
123
124  // Gets all pairings with the shared secrets removed as a base::ListValue.
125  void GetAllPairings(const GetAllPairingsCallback& callback);
126
127  // Delete a pairing, identified by its client ID. |callback| is called with
128  // the result of saving the new config, which occurs even if the client ID
129  // did not match any pairing.
130  void DeletePairing(const std::string& client_id,
131                     const DoneCallback& callback);
132
133  // Clear all pairings from the registry.
134  void ClearAllPairings(const DoneCallback& callback);
135
136 protected:
137  friend class base::RefCountedThreadSafe<PairingRegistry>;
138  virtual ~PairingRegistry();
139
140  // Lets the tests override task posting to make all callbacks synchronous.
141  virtual void PostTask(
142      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
143      const tracked_objects::Location& from_here,
144      const base::Closure& task);
145
146 private:
147  FRIEND_TEST_ALL_PREFIXES(PairingRegistryTest, AddPairing);
148  friend class NegotiatingAuthenticatorTest;
149
150  // Helper method for unit tests.
151  void AddPairing(const Pairing& pairing);
152
153  // Blocking helper methods used to call the delegate.
154  void DoLoadAll(
155      const protocol::PairingRegistry::GetAllPairingsCallback& callback);
156  void DoDeleteAll(
157      const protocol::PairingRegistry::DoneCallback& callback);
158  void DoLoad(
159      const std::string& client_id,
160      const protocol::PairingRegistry::GetPairingCallback& callback);
161  void DoSave(
162      const protocol::PairingRegistry::Pairing& pairing,
163      const protocol::PairingRegistry::DoneCallback& callback);
164  void DoDelete(
165      const std::string& client_id,
166      const protocol::PairingRegistry::DoneCallback& callback);
167
168  // "Trampoline" callbacks that schedule the next pending request and then
169  // invoke the original caller-supplied callback.
170  void InvokeDoneCallbackAndScheduleNext(
171      const DoneCallback& callback, bool success);
172  void InvokeGetPairingCallbackAndScheduleNext(
173      const GetPairingCallback& callback, Pairing pairing);
174  void InvokeGetAllPairingsCallbackAndScheduleNext(
175      const GetAllPairingsCallback& callback,
176      scoped_ptr<base::ListValue> pairings);
177
178  // Sanitize |pairings| by parsing each entry and removing the secret from it.
179  void SanitizePairings(const GetAllPairingsCallback& callback,
180                        scoped_ptr<base::ListValue> pairings);
181
182  // Queue management methods.
183  void ServiceOrQueueRequest(const base::Closure& request);
184  void ServiceNextRequest();
185
186  // Task runner on which all public methods of this class should be called.
187  scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
188
189  // Task runner used to run blocking calls to the delegate. A single thread
190  // task runner is used to guarantee that one one method of the delegate is
191  // called at a time.
192  scoped_refptr<base::SingleThreadTaskRunner> delegate_task_runner_;
193
194  scoped_ptr<Delegate> delegate_;
195
196  std::queue<base::Closure> pending_requests_;
197
198  DISALLOW_COPY_AND_ASSIGN(PairingRegistry);
199};
200
201}  // namespace protocol
202}  // namespace remoting
203
204#endif  // REMOTING_PROTOCOL_PAIRING_REGISTRY_H_
205