forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfido_request_handler_base.h
338 lines (275 loc) · 14 KB
/
fido_request_handler_base.h
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
// Copyright 2018 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 DEVICE_FIDO_FIDO_REQUEST_HANDLER_BASE_H_
#define DEVICE_FIDO_FIDO_REQUEST_HANDLER_BASE_H_
#include <array>
#include <functional>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/check.h"
#include "base/component_export.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_piece_forward.h"
#include "build/build_config.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_discovery_base.h"
#include "device/fido/fido_transport_protocol.h"
#include "device/fido/pin.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace device {
class BleAdapterManager;
class FidoAuthenticator;
class FidoDiscoveryFactory;
class PublicKeyCredentialUserEntity;
struct TransportAvailabilityCallbackReadiness;
// Base class that handles authenticator discovery/removal. Its lifetime is
// equivalent to that of a single WebAuthn request. For each authenticator, the
// per-device work is carried out by one FidoAuthenticator instance, which is
// constructed in a FidoDiscoveryBase and passed to the request handler via its
// Observer interface.
class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
: public FidoDiscoveryBase::Observer {
public:
using RequestCallback = base::RepeatingCallback<void(const std::string&)>;
using AuthenticatorMap =
std::map<std::string, FidoAuthenticator*, std::less<>>;
// Encapsulates data required to initiate WebAuthN UX dialog. Once all
// components of TransportAvailabilityInfo is set,
// AuthenticatorRequestClientDelegate should be notified.
struct COMPONENT_EXPORT(DEVICE_FIDO) TransportAvailabilityInfo {
TransportAvailabilityInfo();
TransportAvailabilityInfo(const TransportAvailabilityInfo& other);
TransportAvailabilityInfo& operator=(
const TransportAvailabilityInfo& other);
~TransportAvailabilityInfo();
FidoRequestType request_type = FidoRequestType::kMakeCredential;
// Indicates whether this is a GetAssertion request with an empty allow
// list.
bool has_empty_allow_list = false;
// The intersection of transports supported by the client and allowed by the
// relying party.
base::flat_set<FidoTransportProtocol> available_transports;
// Whether the platform authenticator has a matching credential for the
// request. This is only set for a GetAssertion request and if a platform
// authenticator has been added to the request handler. (The Windows
// WebAuthn API does NOT count as a platform authenticator in this case.)
absl::optional<bool> has_recognized_platform_authenticator_credential;
// The set of recognized platform credential user entities that can fulfill
// a GetAssertion request. Not all platform authenticators report this, so
// the set might be empty even if
// |has_recognized_platform_authenticator_credential| is true.
std::vector<PublicKeyCredentialUserEntity>
recognized_platform_authenticator_credentials;
bool is_ble_powered = false;
bool can_power_on_ble_adapter = false;
// Indicates whether the native Windows WebAuthn API is available.
// Dispatching to it should be controlled by the embedder.
//
// The embedder:
// - may choose not to dispatch immediately if caBLE is available
// - should dispatch immediately if no other transport is available
bool has_win_native_api_authenticator = false;
// Indicates whether the Windows native UI will include a privacy notice
// when creating a resident credential.
bool win_native_ui_shows_resident_credential_notice = false;
// Contains the authenticator ID of the native Windows
// authenticator if |has_win_native_api_authenticator| is true.
// This allows the observer to distinguish it from other
// authenticators.
std::string win_native_api_authenticator_id;
// Indicates whether the request is occurring in an off-the-record
// BrowserContext (e.g. Chrome Incognito mode).
bool is_off_the_record_context = false;
// Indicates the ResidentKeyRequirement of the current request. Only valid
// if |request_type| is |RequestType::kMakeCredential|. Requests with a
// value of |ResidentKeyRequirement::kPreferred| or
// |ResidentKeyRequirement::kRequired| can create a resident credential,
// which could be discovered by someone with physical access to the
// authenticator and thus have privacy implications.
ResidentKeyRequirement resident_key_requirement =
ResidentKeyRequirement::kDiscouraged;
};
class COMPONENT_EXPORT(DEVICE_FIDO) Observer {
public:
struct COMPONENT_EXPORT(DEVICE_FIDO) CollectPINOptions {
// Why this PIN is being collected.
pin::PINEntryReason reason;
// The error for which we are prompting for a PIN.
pin::PINEntryError error = pin::PINEntryError::kNoError;
// The minimum PIN length the authenticator will accept for the PIN.
uint32_t min_pin_length = device::kMinPinLength;
// The number of attempts remaining before a hard lock. Should be ignored
// unless |mode| is kChallenge.
int attempts = 0;
};
virtual ~Observer();
// This method will not be invoked until the observer is set.
virtual void OnTransportAvailabilityEnumerated(
TransportAvailabilityInfo data) = 0;
// If true, the request handler will defer dispatch of its request onto the
// given authenticator to the embedder. The embedder needs to call
// |StartAuthenticatorRequest| when it wants to initiate request dispatch.
//
// This method is invoked before |FidoAuthenticatorAdded|, and may be
// invoked multiple times for the same authenticator. Depending on the
// result, the request handler might decide not to make the authenticator
// available, in which case it never gets passed to
// |FidoAuthenticatorAdded|.
virtual bool EmbedderControlsAuthenticatorDispatch(
const FidoAuthenticator& authenticator) = 0;
virtual void BluetoothAdapterPowerChanged(bool is_powered_on) = 0;
virtual void FidoAuthenticatorAdded(
const FidoAuthenticator& authenticator) = 0;
virtual void FidoAuthenticatorRemoved(base::StringPiece device_id) = 0;
// SupportsPIN returns true if this observer supports collecting a PIN from
// the user. If this function returns false, |CollectPIN| and
// |FinishCollectPIN| will not be called.
virtual bool SupportsPIN() const = 0;
// CollectPIN is called when a PIN is needed to complete a request. The
// |attempts| parameter is either |nullopt| to indicate that the user needs
// to set a PIN, or contains the number of PIN attempts remaining before a
// hard lock.
virtual void CollectPIN(
CollectPINOptions options,
base::OnceCallback<void(std::u16string)> provide_pin_cb) = 0;
virtual void FinishCollectToken() = 0;
// Called when a biometric enrollment may be completed as part of the
// request and the user should be notified to collect samples.
// |next_callback| must be executed asynchronously at any time to move on to
// the next step of the request.
virtual void StartBioEnrollment(base::OnceClosure next_callback) = 0;
// Called when a biometric enrollment sample has been collected.
// |bio_samples_remaining| is the number of samples needed to finish the
// enrollment.
virtual void OnSampleCollected(int bio_samples_remaining) = 0;
// Called when an authenticator reports internal user verification has
// failed (e.g. not recognising the user's fingerprints) and the user should
// try again. Receives the number of |attempts| before the device locks
// internal user verification.
virtual void OnRetryUserVerification(int attempts) = 0;
};
FidoRequestHandlerBase();
// The |available_transports| should be the intersection of transports
// supported by the client and allowed by the relying party.
FidoRequestHandlerBase(
FidoDiscoveryFactory* fido_discovery_factory,
const base::flat_set<FidoTransportProtocol>& available_transports);
FidoRequestHandlerBase(const FidoRequestHandlerBase&) = delete;
FidoRequestHandlerBase& operator=(const FidoRequestHandlerBase&) = delete;
~FidoRequestHandlerBase() override;
// Triggers DispatchRequest() if |active_authenticators_| hold
// FidoAuthenticator with given |authenticator_id|.
void StartAuthenticatorRequest(const std::string& authenticator_id);
// Invokes |FidoAuthenticator::Cancel| on all authenticators, except if
// matching |exclude_id|, if one is provided. Cancelled authenticators are
// immediately removed from |active_authenticators_|.
//
// This function is invoked either when: (a) the entire WebAuthn API request
// is canceled or, (b) a successful response or "invalid state error" is
// received from the any one of the connected authenticators, in which case
// all other authenticators are cancelled.
// https://w3c.github.io/webauthn/#iface-pkcredential
void CancelActiveAuthenticators(base::StringPiece exclude_id = "");
virtual void OnBluetoothAdapterEnumerated(bool is_present,
bool is_powered_on,
bool can_power_on,
bool is_peripheral_role_supported);
void OnBluetoothAdapterPowerChanged(bool is_powered_on);
void PowerOnBluetoothAdapter();
base::WeakPtr<FidoRequestHandlerBase> GetWeakPtr();
void set_observer(Observer* observer);
// Returns whether FidoAuthenticator with id equal to |authenticator_id|
// exists. Fake FidoRequestHandler objects used in testing overrides this
// function to simulate scenarios where authenticator with |authenticator_id|
// is known to the system.
virtual bool HasAuthenticator(const std::string& authentiator_id) const;
TransportAvailabilityInfo& transport_availability_info() {
return transport_availability_info_;
}
const AuthenticatorMap& AuthenticatorsForTesting() {
return active_authenticators_;
}
std::unique_ptr<BleAdapterManager>&
get_bluetooth_adapter_manager_for_testing() {
return bluetooth_adapter_manager_;
}
void StopDiscoveries();
protected:
// Authenticators that return a response in less than this time are likely to
// have done so without interaction from the user.
static constexpr base::TimeDelta kMinExpectedAuthenticatorResponseTime =
base::Milliseconds(300);
// Subclasses implement this method to dispatch their request onto the given
// FidoAuthenticator. The FidoAuthenticator is owned by this
// FidoRequestHandler and stored in active_authenticators().
virtual void DispatchRequest(FidoAuthenticator*) = 0;
void InitDiscoveries(
FidoDiscoveryFactory* fido_discovery_factory,
base::flat_set<FidoTransportProtocol> available_transports);
void Start();
AuthenticatorMap& active_authenticators() { return active_authenticators_; }
std::vector<std::unique_ptr<FidoDiscoveryBase>>& discoveries() {
return discoveries_;
}
Observer* observer() const { return observer_; }
// FidoDiscoveryBase::Observer
void DiscoveryStarted(
FidoDiscoveryBase* discovery,
bool success,
std::vector<FidoAuthenticator*> authenticators) override;
void AuthenticatorAdded(FidoDiscoveryBase* discovery,
FidoAuthenticator* authenticator) override;
void AuthenticatorRemoved(FidoDiscoveryBase* discovery,
FidoAuthenticator* authenticator) override;
// GetPlatformCredentialStatus is called to learn whether a platform
// authenticator has credentials responsive to the current request. If this
// method is overridden in a subclass then either:
// · The method in this base class must be called immediately, or
// · |OnHavePlatformCredentialStatus| must eventually called.
//
// This method runs only after the platform discovery has started
// successfully. (The Windows API doesn't count as a platform authenticator
// for the purposes of this call.)
virtual void GetPlatformCredentialStatus(
FidoAuthenticator* platform_authenticator);
// OnHavePlatformCredentialStatus is called by subclasses (after
// |GetPlatformCredentialStatus| has been called) to report on whether the
// platform authenticator whether it has responsive discoverable credentials
// and whether it has responsive credentials at all.
void OnHavePlatformCredentialStatus(
std::vector<PublicKeyCredentialUserEntity> user_entities,
bool have_credential);
private:
friend class FidoRequestHandlerTest;
void MaybeSignalTransportsEnumerated();
// Invokes FidoAuthenticator::InitializeAuthenticator(), followed by
// DispatchRequest(). InitializeAuthenticator() sends a GetInfo command
// to FidoDeviceAuthenticator instances in order to determine their protocol
// versions before a request can be dispatched.
void InitializeAuthenticatorAndDispatchRequest(
const std::string& authenticator_id);
void ConstructBleAdapterPowerManager();
AuthenticatorMap active_authenticators_;
std::vector<std::unique_ptr<FidoDiscoveryBase>> discoveries_;
Observer* observer_ = nullptr;
TransportAvailabilityInfo transport_availability_info_;
std::unique_ptr<BleAdapterManager> bluetooth_adapter_manager_;
// transport_availability_callback_readiness_ keeps track of state which
// determines whether this object is ready to call
// |OnTransportAvailabilityEnumerated| on |observer_|.
std::unique_ptr<TransportAvailabilityCallbackReadiness>
transport_availability_callback_readiness_;
// internal_authenticator_found_ is used to check that at most one kInternal
// authenticator is discovered.
bool internal_authenticator_found_ = false;
base::WeakPtrFactory<FidoRequestHandlerBase> weak_factory_{this};
};
} // namespace device
#endif // DEVICE_FIDO_FIDO_REQUEST_HANDLER_BASE_H_