summaryrefslogtreecommitdiffstats
path: root/remoting/protocol/pairing_registry.h
blob: b34404e1ad86a366523e8c246b6e6ab65cc704ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// 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/macros.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(const Pairing& other);
    ~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_