forked from Yubico/java-webauthn-server
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathREADME
381 lines (278 loc) · 13.7 KB
/
README
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
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
java-webauthn-server
====================
:toc:
:toc-placement: macro
:toc-title:
image:https://github.com/Yubico/java-webauthn-server/workflows/build/badge.svg["Build Status", link="https://github.com/Yubico/java-webauthn-server/actions"]
image:https://coveralls.io/repos/github/Yubico/java-webauthn-server/badge.svg["Coverage Status", link="https://coveralls.io/github/Yubico/java-webauthn-server"]
Server-side https://www.w3.org/TR/webauthn/[Web Authentication] library for
Java. Provides implementations of the
https://www.w3.org/TR/webauthn/#rp-operations[Relying Party operations] required
for a server to support Web Authentication. This includes registering
authenticators and authenticating registered authenticators.
toc::[]
== Dependency configuration
Maven:
----------
<dependency>
<groupId>com.yubico</groupId>
<artifactId>webauthn-server-core</artifactId>
<version>1.9.1</version>
<scope>compile</scope>
</dependency>
----------
Gradle:
----------
compile 'com.yubico:webauthn-server-core:1.9.1'
----------
=== Semantic versioning
This library uses link:https://semver.org/[semantic versioning].
The public API consists of all public classes, methods and fields in the `com.yubico.webauthn` package and its subpackages,
i.e., everything covered by the
link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/latest/com/yubico/webauthn/package-summary.html[Javadoc].
Package-private classes and methods are NOT part of the public API.
The `com.yubico:yubico-util` module is NOT part of the public API.
Breaking changes to these will NOT be reflected in version numbers.
=== Additional modules
In addition to the main `webauthn-server-core` module, there are also:
- `webauthn-server-attestation`: A simple implementation of the
link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/latest/com/yubico/webauthn/attestation/MetadataService.html[`MetadataService`]
interface, which by default comes preloaded with attestation metadata for Yubico devices.
- `webauthn-server-core-minimal`: Alternative distribution of `webauthn-server-core`,
without a dependency on BouncyCastle.
If depending on this module instead of `webauthn-server-core`,
you may have to add your own JCA providers to support some signature algorithms.
In particular, OpenJDK 14 and earlier does not include providers for the EdDSA family of algorithms.
== Features
- Generates request objects suitable as parameters to
`navigator.credentials.create()` and `.get()`
- Performs all necessary
https://www.w3.org/TR/webauthn/#rp-operations[validation logic] on the
response from the client
- No mutable state or side effects - everything (except builders) is thread safe
- Optionally integrates with a "metadata service" to verify
https://www.w3.org/TR/webauthn/#sctn-attestation[authenticator attestations]
and annotate responses with additional authenticator metadata
- Reproducible builds: release signatures match fresh builds from source. See
[Building](#Building) below.
=== Non-features
This library has no concept of accounts, sessions, permissions or identity
federation, and it's not an authentication framework; it only deals with
executing the WebAuthn authentication mechanism. Sessions, account management
and other higher level concepts can make use of this authentication mechanism,
but the authentication mechanism alone does not make a security system.
== Documentation
See the
link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/latest/com/yubico/webauthn/package-summary.html[Javadoc]
for in-depth API documentation.
== Quick start
Implement the
link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/latest/com/yubico/webauthn/CredentialRepository.html[`CredentialRepository`]
interface with your database access logic. See
link:https://github.com/Yubico/java-webauthn-server/blob/master/webauthn-server-demo/src/main/java/demo/webauthn/InMemoryRegistrationStorage.java[`InMemoryRegistrationStorage`]
for an example.
Instantiate the
link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/latest/com/yubico/webauthn/RelyingParty.html[`RelyingParty`]
class:
[source,java]
----------
RelyingPartyIdentity rpIdentity = RelyingPartyIdentity.builder()
.id("example.com")
.name("Example Application")
.build();
RelyingParty rp = RelyingParty.builder()
.identity(rpIdentity)
.credentialRepository(new MyCredentialRepository())
.build();
----------
=== Registration
Initiate a registration ceremony:
[source,java]
----------
byte[] userHandle = new byte[64];
random.nextBytes(userHandle);
PublicKeyCredentialCreationOptions request = rp.startRegistration(StartRegistrationOptions.builder()
.user(UserIdentity.builder()
.name("alice")
.displayName("Alice Hypothetical")
.id(new ByteArray(userHandle))
.build())
.build());
----------
Serialize `request` to JSON and send it to the client:
[source,java]
----------
import com.fasterxml.jackson.databind.ObjectMapper;
ObjectMapper jsonMapper = new ObjectMapper()
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
.setSerializationInclusion(Include.NON_ABSENT)
.registerModule(new Jdk8Module());
String json = jsonMapper.writeValueAsString(request);
return json;
----------
Get the response from the client:
[source,java]
----------
String responseJson = /* ... */;
PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs> pkc =
PublicKeyCredential.parseRegistrationResponseJson(responseJson);
----------
Validate the response:
[source,java]
----------
try {
RegistrationResult result = rp.finishRegistration(FinishRegistrationOptions.builder()
.request(request)
.response(pkc)
.build());
} catch (RegistrationFailedException e) { /* ... */ }
----------
Update your database:
[source,java]
----------
storeCredential("alice", result.getKeyId(), result.getPublicKeyCose());
----------
=== Authentication
Initiate an authentication ceremony:
[source,java]
----------
AssertionRequest request = rp.startAssertion(StartAssertionOptions.builder()
.username(Optional.of("alice"))
.build());
String json = jsonMapper.writeValueAsString(request);
return json;
----------
Validate the response:
[source,java]
----------
String responseJson = /* ... */;
PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> pkc =
PublicKeyCredential.parseAssertionResponseJson(responseJson);
try {
AssertionResult result = rp.finishAssertion(FinishAssertionOptions.builder()
.request(request)
.response(pkc)
.build());
if (result.isSuccess()) {
return result.getUsername();
}
} catch (AssertionFailedException e) { /* ... */ }
throw new RuntimeException("Authentication failed");
----------
For more detailed example usage, see
link:webauthn-server-demo[`webauthn-server-demo`] for a complete demo server.
== Architecture
The library tries to place as few requirements on the overall application
architecture as possible. For this reason it is stateless and free from side
effects, and does not directly interact with any database. This means it is
database agnostic and thread safe. The following diagram illustrates an example
architecture for an application using the library.
image::https://raw.githubusercontent.com/Yubico/java-webauthn-server/master/docs/img/demo-architecture.svg?sanitize=true["Example application architecture",align="center"]
The application manages all state and database access, and communicates with the
library via POJO representations of requests and responses. The following
diagram illustrates the data flow during a WebAuthn registration or
authentication ceremony.
image::https://raw.githubusercontent.com/Yubico/java-webauthn-server/master/docs/img/demo-sequence-diagram.svg?sanitize=true["WebAuthn ceremony sequence diagram",align="center"]
In this diagram, the *Client* is the user's browser and the application's
client-side scripts. The *Server* is the application and its business logic, the
*Library* is this library, and the *Users* database stores registered WebAuthn
credentials.
. The client requests to start the ceremony, for example by submitting a form.
The `username` may or may not be known at this point. For example, the user
might be requesting to create a new account, or we might be using
username-less authentication.
. If the user does not already have a
https://www.w3.org/TR/webauthn/#user-handle[user handle], the application
creates one in some application-specific way.
. The application may choose to authenticate the user with a password or the
like before proceeding.
. The application calls one of the library's "start" methods to generate a
parameter object to be passed to `navigator.credentials.create()` or `.get()`
on the client.
. The library generates a random challenge and an assortment of other arguments
depending on configuration set by the application.
. If the `username` is known, the library uses a read-only database adapter
provided by the application to look up the user's credentials.
. The returned list of https://www.w3.org/TR/webauthn/#credential-id[credential
IDs] is used to populate the
https://www.w3.org/TR/webauthn/#dom-publickeycredentialcreationoptions-excludecredentials[`excludeCredentials`]
or
https://www.w3.org/TR/webauthn/#dom-publickeycredentialrequestoptions-allowcredentials[`allowCredentials`]
parameter.
. The library returns a `request` object which can be serialized to JSON and
passed as the `publicKey` argument to `navigator.credentials.create()` or
`.get()`. For registration ceremonies this will be a
https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialcreationoptions[`PublicKeyCredentialCreationOptions`],
and for authentication ceremonies it will be a
https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialrequestoptions[`PublicKeyCredentialRequestOptions`].
The application stores the `request` in temporary storage.
. The application's client-side script runs `navigator.credentials.create()` or
`.get()` with `request` as the `publicKey` argument.
. The user confirms the operation and the client returns a
https://www.w3.org/TR/webauthn/#public-key-credential[`PublicKeyCredential`]
object `response` to the application.
. The application retrieves the `request` from temporary storage and passes
`request` and `response` to one of the library's "finish" methods to run the
response validation logic.
. The library verifies that the `response` contents - challenge, origin, etc. -
are valid.
. If this is an authentication ceremony, the library uses the database adapter
to look up the public key for the credential named in `response.id`.
. The database adapter returns the public key.
. The library verifies the authentication signature.
. The library returns a POJO representation of the result of the ceremony. For
registration ceremonies, this will include the credential ID and public key of
the new credential. The application may opt in to also getting
information about the authenticator model and whether the authenticator
attestation is trusted. For authentication ceremonies, this will include the
username and user handle, the credential ID of the credential used, and the
new https://www.w3.org/TR/webauthn/#signature-counter[signature counter] value
for the credential.
. The application inspects the result object and takes any appropriate actions
as defined by its business logic.
. If the result is not satisfactory, the application reports failure to the
client.
. If the result is satisfactory, the application proceeds with storing the new
credential if this is a registration ceremony.
. If this is an authentication ceremony, the application updates the signature
counter stored in the database for the credential.
. Finally, the application reports success and resumes its business logic.
== Building
Use the included
https://docs.gradle.org/current/userguide/gradle_wrapper.html[Gradle wrapper] to
build the `.jar` artifact:
----------
$ ./gradlew :webauthn-server-core:jar
----------
The output is built in the `webauthn-server-core/build/libs/` directory, and the
version is derived from the most recent Git tag. Builds done on a tagged commit
will have a plain `x.y.z` version number, while a build on any other commit will
result in a version number containing the abbreviated commit hash.
Starting in version `1.4.0-RC2`, artifacts are built reproducibly. Fresh builds from
tagged commits should therefore be verifiable by signatures from Maven Central
and GitHub releases:
```
$ git checkout 1.4.0-RC2
$ ./gradlew :webauthn-server-core:jar
$ wget https://repo1.maven.org/maven2/com/yubico/webauthn-server-core/1.4.0-RC2/webauthn-server-core-1.4.0-RC2.jar.asc
$ gpg --verify webauthn-server-core-1.4.0-RC2.jar.asc webauthn-server-core/build/libs/webauthn-server-core-1.4.0-RC2.jar
$ wget https://github.com/Yubico/java-webauthn-server/releases/download/1.4.0-RC2/webauthn-server-core-1.4.0-RC2.jar.asc
$ gpg --verify webauthn-server-core-1.4.0-RC2.jar.asc webauthn-server-core/build/libs/webauthn-server-core-1.4.0-RC2.jar
```
Note that building with a different JDK may produce a different artifact. To
ensure binary reproducibility, please build with the same JDK as specified in
the release notes. Reproducible builds also require building from a Git
repository, since the build embeds version number and Git commit ID into the
built artifacts.
Official Yubico software signing keys are listed on the
https://developers.yubico.com/Software_Projects/Software_Signing.html[Yubico
Developers site].
To run the tests:
----------
$ ./gradlew check
----------
To run the http://pitest.org/[PIT mutation tests] (this may take upwards of 30
minutes):
----------
$ ./gradlew pitest
----------