/
WebAuthnRegistration

WebAuthnRegistration

Overview

The plugin comes with an administration flow for registering and managing FIDO2 credentials. The inbuilt flow represents the minimum viable product for implementing such a feature. In the future other plugins may provide this functionality.

The registration flow can be accessed by navigating to:

http[s]://hostname/idp/profile/admin/webauthn-registration

Configuration Steps

Other than following steps 1 and 2, you do not need to change any of the default registration options to register and use a FIDO2 credential with the IdP successfully. If you do want more control over the process, there are a few options available:

  1. (Required) Decide how the user should authenticate to the registration flow.

  2. (Required) Configure a suitable access control policy.

  3. (Optional) Configure how user account details are passed to the WebAuthn API and authenticator.

  4. (Optional) Decide what type of authenticator you want to support.

  5. (Optional) Decide if you want to require only ‘trusted’ (from FIDO Alliance Metadata) authenticators to be registered

Integration with the authentication flow

The registration flow uses the normal authentication process of the IdP to verify the user that intends to register a credential. It is recommended to implement authentication through the MFA flow, and the following instructions assume you have completed that step.

By default, the flow collects the username as a first step so it can look up any existing credentials before passing control to the authentication system. This information can be accessed in the MFA configuration using the isWebAuthnAvailable() method on the WebAuthnRegistrationContext, to decide which flow to use. The example MFA Flow With Password Fallback is a suitable initial setup that allows users to register their first credentials upon inputting their username and password; other combinations are possible.

AccessPolicy Configuration

The user and client accessing the registration flow are subject to an AccessControlConfiguration set by the property idp.authn.webauthn.admin.registration.accessPolicy. The default policy, AccessByCurrentUser, is not defined in the IdP's access control configuration and needs to be added for the flow to load: you can add it to the map in conf/access-control.xml like so:

... <entry key="AccessByCurrentUser"> <bean parent="shibboleth.PredicateAccessControl"> <constructor-arg> <bean id="AccessByCurrentUserPredicate" class="net.shibboleth.idp.plugin.authn.webauthn.admin.impl.AllowCurrentUserAccessPredicate"> </bean> </constructor-arg> </bean> </entry> ...

This policy is essential if you plan on creating an MFA flow (such as MFA Flow With Password Bypass) which provides another authentication method if the user has no registered credentials (e.g., either using isWebAuthnAvailable() or when signalling a custom event).

The AccessByCurrentUser policy checks the username found in the registration context—collected by the username view when the user first enters the registration flow—is the same as the principal name (identity) of the user that authenticated. This is important, if we imagine a scenario where a nefarious user wanted to ‘change' or possibly 'downgrade’ a user’s authenticate method from WebAuthn to, say, username and password (or whatever else was configured as a ‘backup’), all they would need to do is enter a non-existent username into the username collection step of the registration page and then have the MFA flow direct them to a different flow (because they do not have any registered credentials) where, for example, they can proceed to try different usernames and passwords for authentication. Importantly, the registration flow uses the principal name of the authenticated user to register credentials against.

The AccessByCurrentUser policy safeguards this by ensuring that the username initially entered into the registration page—for which the credentials are retrieved, and any flow decision is based—matches the authenticating user's principal name. If they do not match, access to the registration page is denied. This measure prevents a user from switching usernames between the registration and authentication flows.

Access Policies and Subject Canonicalization

There are some caveats to consider when enabling the access policy. The principal name that results from authentication is determined by the Authentication flow, the SubjectCanonicalization flow, and possibly any transformations that have been applied to the username. It is, therefore, entirely possible that the user who entered the registration flow is the same as the user who authenticated, but their username and principal name do not match.

To address this, the registration process collects the username from the username input view and applies two transformations. The first transformation utilizes configurable string manipulations, while the second executes the SubjectCanonicalization subflow. Together, these two steps create a final output, which is then matched against the principal name obtained during the authentication process.

Registration Username String Transformations

The following properties control the string transformations applied to the registration username:

  1. idp.authn.webauthn.registration.username.uppercase : upper case the username?

  2. idp.authn.webauthn.registration.username.lowercase : lowercase the username?

  3. idp.authn.webauthn.registration.username.trim : trim the username?

You can supply a custom transformation by defining the bean, shibboleth.authn.webauthn.registration.UsernameTransformations.

Note, if you do this and you are using the passwordless authentication mode, you will need to supply the same transformation settings to the authentication flow, otherwise, it will not match with the username used to register the credential.

  1. idp.authn.webauthn.passwordless.username.uppercase : upper case the username?

  2. idp.authn.webauthn.passwordless.username.lowercase : lower case the username?

  3. idp.authn.webauthn.passwordless.username.trim : trim the username?

You can supply a custom transformation by defining the bean, shibboleth.authn.webauthn.passwordless.UsernameTransformations.

Subject Canonicalization

The SubjectCanonicalization subflow is run immediatly after username collection. By default, the IdP wide shibboleth.PostLoginSubjectCanonicalizationFlows are run, but a different list of flows can be configured by setting the property idp.authn.webauthn.registration.c14n.postUsernameFlows.

Custom Comparison Predicate

If the default comparison predicate used by the access policy is not sufficient for your needs. You can create a different comparison predicate and plug it into AccessByCurrentUser: see the example below.

<entry key="AccessByCurrentUser"> <bean parent="shibboleth.PredicateAccessControl"> <constructor-arg> <bean id="AccessByCurrentUserPredicate" class="net.shibboleth.idp.plugin.authn.webauthn.admin.impl.AllowCurrentUserAccessPredicate"> <property name="comparisonPredicate"> <bean id="StringMatchComparisonPredicate" class="net.shibboleth.idp.plugin.authn.webauthn.admin.impl.AllowCurrentUserAccessPredicate$DefaultCurrentUserComparisonPredicate"> <property name="comparisonPredicate"> <bean ... </bean> </property> </bean> </property> </bean> </constructor-arg> </bean> </entry>

Disabling Registration Username Collection

It is possible to turn off the username collection step in the registration flow to simplify this problem by setting the property idp.authn.webauthn.registration.collectUsername to false. You’d then need to think about how best to support users trying to register their first credential.

User Identity for Credential Generation

The IdP will pass user account details to the WebAuthn API during registration. Some of this information is used to improve the user experience whilst creating credentials, and the authenticator uses some to bind credentials to user accounts at the IdP. The generation of this information is described in the following sections.

User ID (UserHandle) Population

The user ID (user.id) should be the primary key of the user account within the IdP. It must not exceed 64 bytes in length and should not include personally identifiable information. The ID should not change for a given user and is used by the authenticator to bind a credential to a user during registration with the IdP. In an authentication response, it is returned as the user handle.

In the federated context, the credential is registered against the IdP and so the user ID of the credential will be the same no matter who the requesting, upstream, service provider is—an authenticator will only store one credential for the IdP per user ID.

By default, the user ID is generated at runtime using a random byte sequence of 64 bytes. To ensure that each user has only one ID, an ID will only be generated if the authenticated user does not already have one linked to an existing credential.

You may prefer to pull this value from the attribute resolver. This can be achieved by modifying the following properties. in conf/authn/webauthn-registration.properties:

  1. change the property idp.authn.webauthn.registration.userid.strategy to reference the bean shibboleth.authn.webauthn.registration.AttributeContextUserIdLookupStrategy.

  2. ensure the attribute resolver is enabled after authentication, idp.authn.webauthn.admin.registration.resolveAttributes=true.

  3. decide which attribute from the resolver context to use using idp.authn.webauthn.registration.userid.attributeId.

    1. Note, the AttributeContextUserIdLookupStrategy requires the attribute to be a single StringAttributeValue converted to a byte array assuming a UTF-8 character set.

Complete control over the strategy is possible by defining your own bean in conf/authn/webauthn-registration-config.xml of type Function<ProfileRequestContext, byte[]> and referenced by the idp.authn.webauthn.registration.userid.strategy property in conf/authn/webauthn-registration.properties

User Name Population

The WebAuthn name (user.name) is a human-palatable identifier for a user’s account a credential is associated with. This is separate from the internal username the IdP uses to store the credential against and is only used by the authenticator to help the user select the correct credential to authenticate with. It may be truncated by the authenticator to 64 bytes.

By default, this is taken from the principal name of the user who authenticated (contained in the SubjectContext). You may prefer to pull this value from the attribute resolver: this is supported out of the box by utilizing a built-in strategy, which can be activated by modifying the following properties in conf/authn/webauthn-registration.properties:

  1. change the property idp.authn.webauthn.registration.name.strategy to reference the bean shibboleth.authn.webauthn.registration.AttributeContextWebAuthnNameLookupStrategy.

  2. ensure the attribute resolver is enabled after authentication, idp.authn.webauthn.admin.registration.resolveAttributes=true.

  3. decide which attribute from the resolver context to use using idp.authn.webauthn.registration.name.attributeId.

Complete control over the strategy is possible by defining your own bean in conf/authn/webauthn-registration-config.xml of type Function<ProfileRequestContext, String> and referenced by the idp.authn.webauthn.registration.name.strategy property in conf/authn/webauthn-registration.properties

User Display Name Population

The user display name (user.displayName) is a human-palatable name for the user’s account. It is only intended for display to the user during registration. It is not used during authentication. Some authenticators do not currently show the display name.

By default, the user’s display name is taken from the principal name in the SubjectContext. That is, the canonical principal name of the subject that is authenticated to the registration endpoint. However, you may prefer to pull this value from the attribute resolver. This is supported by changing the following properties in conf/authn/webauthn-registration.properties:

  1. change the property idp.authn.webauthn.registration.displayname.strategy to reference the bean shibboleth.authn.webauthn.registration.AttributeContextDisplayNameLookupStrategy.

  2. ensure the attribute resolver is enabled after authentication, idp.authn.webauthn.admin.registration.resolveAttributes=true.

  3. decide which attribute from the resolver context to use using idp.authn.webauthn.registration.displayname.attributeId.

Complete control over the strategy is possible by defining your own bean in conf/authn/webauthn-registration-config.xml of type Function<ProfileRequestContext, String> and referenced by the idp.authn.webauthn.registration.displayname.strategy property in conf/authn/webauthn-registration.properties

Credential Generation Options

Discoverable Credentials (Passkeys)

A Discoverable Credential, formally a Resident Key, stores the private key and associated metadata on the authenticator. This allows usernameless flows and is strictly what is required for a FIDO2 credential to be a ‘passkey’. The alternative allows the private key to be stored, in a protected format, at the relying party (for example, packaged inside the credential ID). Noting that some security keys have limited space for Discoverable Credentials.

Technically, a Discoverable Credential can either be synchronised via some sync fabric (a multi-device or synched passkey e.g, cloud-synched via iCloud Keychain) or bound to the device (single-device or device-bound passkey e.g, a security key). Note that currently there is no way in the plugin to set or detect the different types, the W3C work on this is still a working draft.

During the registration of a FIDO2 credential, you can explicitly configure the ResidentKeyRequirement by setting the idp.authn.webauthn.registration.residentKey property. The possible values, set in conf/authn/webauthn-registration.properties, are listed below:

Option

Default

Description

Option

Default

Description

idp.authn.webauthn.registration.residentKey

preferred

Require a residentKey/DiscoverableCredential (passkey) to be created when registering a credential. One-of 'discouraged', 'preferred', 'required'

If you ‘preferred’ Discoverable Credentials during registration but require them for authentication, you may end up in a situation where the user registers a credential they can not later use.

Authenticator Attachment Options

Authenticator attachment modality specifies the mechanism by which a client can communicate with an authenticator. For example, can the authenticator be removed and ‘roam’ across platforms like a security key, or is the authenticator internal to the device and attached to the given platform like a Trusted Platform Module.

This distinction between roaming and platform attachments can be confusing when a platform authenticator can also be used in a roaming context. The most common example of this is that of a mobile device authenticator: when authenticating on the device itself it acts as a platform authenticator, but when authenticating another client via cross-device authentication (QR code and Bluetooth) it acts as a roaming authenticator.

During the registration of a FIDO2 credential, you can explicitly configure the AuthenticatorAttachment by setting the idp.authn.webauthn.registration.authenticatorAttachment property. The possible values, set in conf/authn/webauthn-registration.properties, are listed below:

Option

Default

Description

Option

Default

Description

idp.authn.webauthn.registration.authenticatorAttachment

any

The authenticator attachment (authenticator type) requirement. One-of 'any', 'cross-platform', or 'platform'

Attestation Conveyance

Attestation allows the IdP (acting as a WebAuthn RP) to verify the provenance of the authenticator used when registering a FIDO2 credential. This is provided in the form of an attestation statement. Attestation is optional as it can provide a poor user experience (the user must consent to the release of the attestation statement during registration), has an unclear meaning if the credential is synchronised around multiple devices (what created it might not be the same as what eventually uses it), and is a possible privacy concern (adds another data point for fingerprinting).

During registration of a FIDO2 credential, you can explicitly configure the AttestationConveyencePreference by setting the idp.authn.webauthn.registration.attestationConveyancePreference property. The possible values, set in conf/authn/webauthn-registration.properties, are listed below:

Option

Default

Description

Option

Default

Description

idp.authn.webauthn.registration.attestationConveyancePreference

none

How should the attestation be conveyed during registration? One-of 'none', 'indirect', 'direct', or 'enterprise'.

Indirect allows the client to anonymise the attestation. Enterprise may include uniquely identifying information and might be required to only allow organizationally attested authenticators.

Noting, if you want to use the basic support for only allowing credentials to be registered from ‘trusted’ authenticators that are contained within the FIDO metadata feed, you’d typically need to enable ‘direct’ attestation.

User Verification

User verification requires an authenticator to authorise a user to create or use credentials. Typically this involves some kind of authorization guester such as fingerprint recognition, face recognition, or a PIN. Whilst this is required during authentication to enable passwordless or usernameless modes, you can separately choose how it is handled during registration.

During the registration of a FIDO2 credential, you can explicitly configure the UserVerificationPreference by setting the idp.authn.webauthn.registration.userVerification property. The possible values, set in conf/authn/webauthn-registration.properties, are listed below:

Option

Default

Description

Option

Default

Description

idp.authn.webauthn.registration.userVerification

discouraged (so a registered key can be used as a second factor as well as a first factor)

Require User Verification on registration. One-of ‘discouraged’, ‘preferred’, ‘required’.

Note that if user verification is required during registration, you may exclude authenticators that are usable in second-factor scenarios (which don’t require a user-verification-capable authenticator).

Other Registration Options

The following additional registration options can be set in conf/authn/webauthn-registration.properties.

Option

Default

Description

Option

Default

Description

idp.authn.webauthn.preferredPublicKeyParams

EdDSA,ES256,ES384,ES512,RS1,RS256,RS384,RS512

The preferred set of COSE signature algorithms which a created credential will use. The sequence is ordered from the most preferred to the least. The client makes the best effort to create the most preferred it can.

Credential Registration Policies

The registration flow comes with a basic, extendable, policy engine for accepting and rejecting credentials based on the authenticator that created them. To enable policy checks, set the property idp.authn.webauthn.registration.authenticator.policy.enabled to true in conf/authn/webauthn-registration.properties.

Policies typically work off an Authenticator’s Attestation GUID (AAGUID) and require attestation statements from the authenticator. See the attestation conveyance section on how to configure this.

The default policy is defined by a list shibboleth.authn.WebAuthn.registration.ChainedRegistrationPolicyList of policies configured in conf/authn/webauthn-registration-config.xml. The following policies are included out of the box:

Policy Name

Description

Value

Policy Name

Description

Value

AllowlistAuthenticatorPolicy

An allowed list of authenticators based on their Authenticator Attestation GUID (AAGUID)

The comma-separated list of authenticators can be directly specified in the XML configuration or, for convenience, set by the idp.authn.webauthn.registration.authenticator.policy.allowedAuthenticators property.

Labelling Credentials

In the registration interface, authenticators and credentials can be enhanced with labels using a basic and extensible labelling engine. Labels are for display purposes only and do not add any extra functionality to the registration or authentication process.

The labelling engine works for both the user registration view and the admin registration view. It is enabled by default and controllable by the list bean shibboleth.authn.WebAuthn.CredentialLabellerList defined in both conf/authn/webauthn-registration-config.xml and conf/authn/webauthn-management-config.xml. The following labellers are included out of the box:

Labeller

Description

Default Label

Value

Labeller

Description

Default Label

Value

SecondFactorOnlyCredentialLabeller

A list of authenticators based on their Authenticator Attestation GUID (AAGUID) that can only be used for second-factor authentication.

SecondFactorOnly

The comma-separated list of authenticators can be directly specified in the XML configuration or, for convenience, set by the idp.authn.webauthn.authenticator.policy.secondFactorOnlyAuthenticators property.

PasskeyCredentialLabeller

Labels credentials as ‘passkey’s if they are discoverable credentials.

Passkey

Defined in either conf/authn/webauthn-registration-config.xml or conf/authn/webauthn-management-config.xml

Inline Registration

During the authentication process, the user has the option to 'Register a new credential.' This action will guide them to a new registration flow where they can create a credential. Once the registration is complete, the registration page will display a button to 'Resume' authentication. Clicking this button will return the user to the point in the authentication flow they left off, allowing them to continue the authentication process.

This feature is enabled by default but can be disabled using the property idp.authnwebauthn.registration.allowInline in conf/authn/webauthn-registration.properties.

Reference

Name

Type

Default

Description

Name

Type

Default

Description

idp.authn.webauthn.allowUntrustedAttestation

Boolean

true

Allow untrusted authenticators to be registered. FIDO metadata is required to determine trusted authenticators (and they are hardware authenticators)

dp.authn.webauthn.registration.collectUsername

Boolean

true

Collect a username as a first step of the registration flow.

idp.authn.webauthn.admin.registration.authenticate

Boolean

true

Require authentication to the registration flow

idp.authn.webauthn.admin.registration.accessPolicy

Predicate<ProfileRequestContext>

AccessByCurrentUser

Allow access by the current user only. That is, the user who identified themselves as part of the registration process is the same as the user who authenticated to the registration flow.

idp.authn.webauthn.admin.registration.authenticationFlows

Function<ProfileRequestContext,Collection<String>>

 

Restrict the usable authentication flows

idp.authn.webauthn.admin.registration.defaultAuthenticationMethods

Function<ProfileRequestContext,Collection<Principal>>

 

Limits, the authentication flows to use for requests by supported principals

idp.authn.webauthn.admin.registration.logging

String

WebAuthnCredentialRegistration

The flow logging ID

idp.authn.webauthn.admin.registration.resolveAttributes

Boolean

true

Resolve attributes about the user after authentication. Required if you want to resolve WebAuthn user.id etc from identity attributes.

idp.authn.webauthn.registration.name.strategy

Bean reference

shibboleth.authn.WebAuthn.registration.SubjectContextUsernameLookupStrategy

How should the WebAuthn user.name be resolved.

idp.authn.webauthn.registration.name.attributeId

String

WebAuthnUsername

If using the attribute context lookup strategy, which attribute should the user.name be taken from

idp.authn.webauthn.registration.userid.strategy

Bean reference

shibboleth.authn.WebAuthn.registration.RandomUserIdGenerator

How should the WebAuth user.id be resolved

idp.authn.webauthn.registration.userid.attributeId

String

WebAuthnUserID

If using the attribute context lookup strategy, which attribute should the user.id be taken from

idp.authn.webauthn.registration.displayname.strategy

Bean reference

shibboleth.authn.WebAuthn.registration.SubjectContextDisplayNameLookupStrategy

How should the WebAuth user.displayName be resolved

idp.authn.webauthn.registration.displayname.attributeId

String

mail

If using the attribute context lookup strategy, which attribute should the user.displayName be taken from

idp.authn.webauthn.registration.residentKey

String

preferred

Require a resident/discoverable key (passkey) to be created when registering a credential. One-of 'discouraged', 'preferred', 'required'

idp.authn.webauthn.preferredPublicKeyParams

Strring

EdDSA,ES256,ES384,ES512,RS1,RS256,RS384,RS512

The comma-separated list of authenticators can be directly specified in the XML configuration or, for convenience, set by the idp.authn.webauthn.registration.authenticator.policy.allowedAuthenticators property.

idp.authn.webauthn.registration.authenticatorAttachment

String

any

The authenticator attachment (authenticator type) requirement. One-of 'any', 'cross-platform', or 'platform'

idp.authn.webauthn.registration.userVerification

String

discouraged (so a registered key can be used as a second factor as well as a first factor)

Require User Verification on registration. One-of ‘discouraged’, ‘preferred’, ‘required’.

idp.authn.webauthn.registration.attestationConveyancePreference

String

none

How should the attestation be conveyed during registration? One-of 'none', 'indirect', 'direct', or 'enterprise'.

Indirect allows the client to anonymise the attestation. Enterprise may include uniquely identifying information and might be required to only allow organizationally attested authenticators.

dp.authn.webauthn.registration.authenticator.policy.enabled

Boolean

false

Enable the registration policy engine

idp.authn.webauthn.registration.authenticator.policy

Bean reference

shibboleth.authn.WebAuthn.registration.ChainedAuthenticatorPolicy

Set the authenticator policy to use.

idp.authn.webauthn.registration.authenticator.policy.chainedlist

Bean reference

shibboleth.authn.WebAuthn.ChainedCredentialPolicyList

When using the chained policy; name the policy list bean

idp.authn.webauthn.registration.authenticator.policy.allowedAuthenticators

List<String>

 

When using the default chained policy; list allowed authenticator's by their attestation GUIDs (AAGUID)

idp.authnwebauthn.registration.allowInline

Boolean

true

Enable inline self-enrollment. Records the user's state in the authentication flow to allow resumption after registration.

idp.authn.webauthn.registration.username.uppercas

Boolean

false

Uppser case transformation that should be applied to the username that is initially collected in the registration flow

idp.authn.webauthn.registration.username.lowercase

Boolean

false

Lower case transformation that should be applied to the username that is initially collected in the registration flow

idp.authn.webauthn.registration.username.trim

Boolean

false

String trimming transformation that should be applied to the username that is initially collected in the registration flow

idp.authn.webauthn.registration.c14n.postUsernameFlows

Bean reference

shibboleth.PostLoginSubjectCanonicalizationFlows

The ID of the bean that supplies the c14n flows that are applied to the username entered during the registration flo

idp.authn.webauthn.registration.genericMessageID

 

 

 

idp.authn.webauthn.registration.infoMessageFunction

Bean reference

DefaultRegistrationInfoMessageFunction

Information message function to pull out INFO messages for the views

idp.authn.webauthn.registration.errorMessageFunction

Bean reference

DefaultRegistrationErrorMessageFunction

Error message function to pull out ERROR messages for the views

idp.authn.webauthn.registration.audit.enabled

Boolean

false

Enable registration auditing.

idp.authn.webauthn.registration.audit.category

String

Shibboleth-Audit.WebAuthnRegistration

The category name of the registration audit logger.

idp.authn.webauthn.registration.audit.format

String

%a|%T|%u|%WebAuthnAdminAO|%WebAuthnAdminAction|%WebAuthnAdminCR|%WebAuthnAdminCA|%WebAuthnAdminAU|%UA

The registration audit format

Name

Type

Description

Name

Type

Description

shibboleth.authn.WebAuthn.WebAuthnAuthenticationClientFactory

WebAuthnAuthenticationClientFactory

The WebAuthn client factory that creates a WebAuthnAuthenticationClient that performs critical WebAuthn functions.

shibboleth.authn.WebAuthn.CredentialRepository

WebAuthnCredentialRepository

The credential repository to use

shibboleth.authn.WebAuthn.WebAuthnFidoMetadataServiceFactory

FidoMetadataServiceFactory

The FIDO metadata factory that creates a FidoMetadataService.

shibboleth.authn.WebAuthn.registration.UsernameTransformations

List<Pair<Pattern,String>>

Match patterns and replacement strings to apply to the username collected for passwordless authentication

shibboleth.authn.WebAuthn.registration.AttestationConveyancePreferenceLookupStrategy

Function<ProfileRequestContext, AttestationConveyancePreference>

The lookup strategy used to determine which AttestationConveyencePreference to use.

shibboleth.authn.WebAuthn.registration.ResidentKeyRequirementLookupStrategy

Function<ProfileRequestContext, ResidentKeyRequirement>

The lookup strategy used to determine which ResidentKeyRequirement to use

shibboleth.authn.WebAuthn.registration.AuthenticatorAttachmentRequirementLookupStrategy

Function<ProfileRequestContext, AuthenticatorAttachment>

The lookup strategy used to determine which AuthenticatorAttachmentRequirement to use

shibboleth.authn.WebAuthn.ChallengeGeneratorStrategy

Function<ProfileRequestContext,byte[]>

The strategy used to generate the WebAuthn challenge

shibboleth.authn.WebAuthn.registration.audit.AuditExtractors

MapFactoryBean

A Map of audit extractors to use

Related pages