Skip to content

Commit

Permalink
WebAuthn: document the security constraints of WebAuthnUserProvider.s…
Browse files Browse the repository at this point in the history
…tore
  • Loading branch information
FroMage committed Nov 26, 2024
1 parent d4a6bd2 commit 343e2c0
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 0 deletions.
10 changes: 10 additions & 0 deletions docs/src/main/asciidoc/security-webauthn.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,8 @@ public class MyWebAuthnSetup implements WebAuthnUserProvider {
@Override
public Uni<Void> store(WebAuthnCredentialRecord credentialRecord) {
User newUser = new User();
// We can only store one credential per userName thanks to the unicity constraint
// which will cause this transaction to fail and throw if the userName already exists
newUser.userName = credentialRecord.getUserName();
WebAuthnCredential credential = new WebAuthnCredential(credentialRecord, newUser);
credential.persist();
Expand All @@ -398,6 +400,14 @@ public class MyWebAuthnSetup implements WebAuthnUserProvider {
}
----

Warning: When implementing your own `WebAuthnUserProvider.store` method, make sure that you never allow creating
new credentials for a `userName` that already exists. Otherwise you risk allowing third-parties to impersonate existing
users by letting them add their own credentials to existing accounts. If you want to allow existing users to register
more than one WebAuthn credential, you must make sure in `WebAuthnUserProvider.store` that the user is currently logged
in under the same `userName` to which you want to add new credentials. In every other case, make sure to return a failed
`Uni` from this method. In this particular example, this is checked using a unicity constraint on the user name, which
will cause the transaction to fail if the user already exists.

== Configuration

Because we want to delegate login and registration to the default Quarkus WebAuthn endpoints, we need to enable them
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,23 @@ public default Uni<Void> update(String credentialId, long counter) {
* You don't have to implement this method if you handle registration manually via
* {@link WebAuthnSecurity#register(WebAuthnRegisterResponse, io.vertx.ext.web.RoutingContext)}
*
* Make sure that you never allow creating
* new credentials for a `userName` that already exists. Otherwise you risk allowing third-parties to impersonate existing
* users by letting them add their own credentials to existing accounts. If you want to allow existing users to register
* more than one WebAuthn credential, you must make sure that the user is currently logged
* in under the same <code>userName</code> to which you want to add new credentials. In every other case, make sure to
* return a failed
* {@link Uni} from this method.
*
* The default behaviour is to not do anything.
*
* @param userName the userName's credentials
* @param credentialRecord the new credentials to store
* @return a uni completion object
* @throws Exception a failed {@link Uni} if the <code>credentialId</code> already exists, or the <code>userName</code>
* already
* has a credential and you disallow having more, or if trying to add credentials to other users than the current
* user.
*/
public default Uni<Void> store(WebAuthnCredentialRecord credentialRecord) {
return Uni.createFrom().voidItem();
Expand Down

0 comments on commit 343e2c0

Please sign in to comment.