WebAuthnAuthnConfiguration

Alpha software: this plugin is only a prototype at the moment and should not be used in production!

Status: alpha version released. Requires IdP v5 and onward.

Overview

The authn/WebAuthn login flow supports the Web Authentication API (WebAuthn). This allows public-key-based strong authentication of users. The plugin can operate as either a single-factor within a wider multi-factor authentication, as a first-factor where the username is supplied by the user (passwordless flow), or a first-factor where the username is not supplied by the user (usernameless flows using passkeys).

Plugin Installation

Plugin

Plugin ID

Module(s)

Depends On

Authentication Flow ID

Latest Version

Bug Reporting

Plugin

Plugin ID

Module(s)

Depends On

Authentication Flow ID

Latest Version

Bug Reporting

WebAuthn Authentication Plugin

net.shibboleth.idp.plugin.authn.webauthn

idp.authn.WebAuthn

 

authn/WebAuthn

0.0.2-alpha

JWEBAUTHN

Installation of Pre-release Plugin

In summary, use the plugin command that ships with the IdP to install the plugin from either a local file pre-downloaded from https://shibboleth.net/downloads/prerelease/ or directly via the pluggin URL.

Note: during the Alpha phase, the --noCheck option is required for successful installation.

Installation

C:>\opt\shibboleth-idp\bin\plugin.bat --noCheck -i https://shibboleth.net/downloads/prerelease/idp-plugin-webauthn-0.0.2.tar.gz

or

$ /opt/shibboleth-idp/bin/plugin.sh --noCheck -i https://shibboleth.net/downloads/prerelease/idp-plugin-webauthn-0.0.2.tar.gz

or

$ /opt/shibboleth-idp/bin/plugin.sh --noCheck -i <plugin.tar.gz>

If installing from a local file, you need to ensure the GPG detached signature (e.g. the .asc file) is placed alongside the main plugin archive on disk.

If it has not been seen before, you will be asked to accept the key signing that signed the module into the trust store for this plugin. See https://shibboleth.atlassian.net/wiki/spaces/DEV/pages/1196393148 for more information on how to ensure the contents of the plugin have not been modified.

Listing Installed Plugins

$ /opt/shibboleth-idp/bin/plugin.sh -l

or

C:>\opt\shibboleth-idp\bin\plugin.bat -l

Enabling the Module

For a detailed guide on configuring modules, see the ModuleConfiguration topic. Once the plugin has been installed, its module should be enabled automatically for you:

Check Module Is Enabled
/%{idp.home}/bin$ ./module.sh -l ... Module: idp.authn.WebAuthn [ENABLED]

However, if you need to enable it you can using the module command:

Enable the module
/%{idp.home}/bin$ ./module.sh -e idp.authn.WebAuthn

Either manual or automatic module enablement will copy across the following configuration files from the jar:

Configuration files

File

Description

File

Description

conf/authn/webauthn.properties

Properties file for configuration the plugin

conf/authn/webauthn-config.xml

XML file for configuration of new beans for the plugin

views/webauthn/webauthn-authn.vm

The authentication view

views/webauthn/webauthn-authn-username.vm

A username view for passwordless authentication

views/webauthn/webauthn-register.vm

The WebAuthn credential registration view

views/webauthn/webauthn-register-username.vm

A username view for the registration view

edit-webapp/css/webauthn.css

Additional styling for the WebAuthn views

edit-webapp/js/webauthn-json.browser-ponyfill.js

Javascript library that wraps the WebAuthn API for encoding binary data

edit-webapp/js/webauthn-support.js

Additional Javascript to support functions on the WebAuthn views

Authentication Flow

Overview of Configuration Steps

  • Configure the plugin

    • Add the relyingPartyId to conf/authn/webauthn.properties

    • Add the relyingPartyName to conf/authn/webauthn.properties

  • Configure the MFA flow to use the WebAuthn authentication method

  • Decide how the flow should be used.

  • Register a credential through the registration admin flow

Configuration of the WebAuthn Relying Party

The IdP acts as a WebAuthn Relying Party when initiating the Web Authentication API to register and authenticate users. The identity of the Relying Party (IdP) must be configured in conf/authn/webauthn.properties.

  • The relyingPartyId: A valid domain string. Set to the IdP’s origin’s effective domain. WebAuthn credentials are scoped to, and can only be used for, a relying party. Does not include a scheme or port (as a normal origin would). Credentials are scoped to the Relying Party ID.

    • Note, ‘localhost’ can be used for testing.

  • The relyingPartyName: a human-palatable identifier for the relying party. Used for display purposes.

  • Optional allowPortOrigin: If true, any port is allowed for the given origin.

  • Optional allowOriginSubdomain: If true, any subdomain (of any depth) is allowed for the given origin.

  • Optional allowed origins: Comma-separated set of origins to allow in responses from an authenticator for this Relying Party. If not set, the Relying Party ID is used (assuming the https scheme and the default port). Note, unlike the Relying Party ID, this includes the scheme and port.

# The IdP's origin idp.authn.webauthn.relyingPartyId = localhost idp.authn.webauthn.relyingPartyName = My IdP Name # Allow any port of 'localhost' idp.authn.webauthn.allowOriginPort = true # Do not allow any subdomain of 'localhost' idp.authn.webauthn.allowOriginSubdomain = false

Configuration of the MFA flow

This configuration is for testing only, and will likely change as the plugin evolves

Make sure to enable the MFA login module and configure the flow in conf/authn/authn.properties. The WebAuthn plugin operates within an MFA flow, even when used alone to provide first-factor authentication.

Example WebAuthn MFA flow with password bypass for registration

The following MFA configuration sets up the WebAuthn plugin as a first-factor authentication method. However, it also permits the auth/Password flow to be used if the user is in a WebAuthn Registration flow and has not yet enrolled any WebAuthn credentials. This allows users to register their first WebAuthn credential by authenticating against their username and password. After the first credential has been enrolled, there is no fallback option, and subsequent registration attempts will require the use of the WebAuthn credential.

conf/authn/mfa-authn-config.xml

Authentication flows

The WebAuthn flow is capable of running as either a second, single-factor of authentication (similar to U2F, but using the WebAuthn APIs) or as a first and only factor of authentication in multi-factor mode (passkeys for example incorporate two factors; something the user has and something the user is). When acting in a first-factor authentication mode, the flow can be configured as either a usernameless (passkey) flow or passwordless flow: this is toggled using the idp.authn.webauthn.usernameless.enabled property.

Usernameless (Passkey) flow

A usernameless flow does not require the user to enter their username during authentication. To support a usernameless flow, the authenticator must allow discoverable credentials (previously known as a Resident Key and now referred to as a passkey) where the private key and associated metadata is stored on the authenticator (FIDO2 compatible authenticators should work). This is important, as the IdP, without a known username, will not be able to preselect a user and credential to use; this must come instead from the user selecting the correct credential—suitable for the IdPs origin—from the authenticator itself.

During authentication, the authenticator is required to:

  • test the user is present by using some form of authorization gesture (for example, by touching the authenticator or clicking on a key to use), and

  • verify the user’s identity by some form of local authorization (for example, using a pin code or biometric recognition).

Passwordless flow

Collecting the username is the initial step in a passwordless flow, and therefore, it does not require storing credentials on the authenticator. Instead, for example, the credential can be encrypted and stored on the server (possibly in the credential ID sent to the server during registration and returned by the IdP during authentication).

During authentication, the authenticator is required to:

  • test the user is present by using some form of authorization gesture (for example, by touching the authenticator or clicking on a key to use), and

  • verify the user’s identity by some form of local authorization (for example, using a pin code or biometric recognition), and

  • test the credential requested by the IdP and used by the authenticator is allowed (has been registered with the IdP).

Second factor authentication (2FA) flow

The WebAuthn flow will operate in second-factor mode automatically only if three conditions are met. First, the property idp.authn.webauthn.2fa.enabled must be set to true. Second, a previous factor of authentication must have produced an Authentication Result from the MFA context. Finally, a principal name must be found through a lookup strategy, which is done by default from the C14N context or the Session Context using the CanonicalUsernameLookupStrategy.

The acceptable previous factors can be controlled by listing (comma-separated) authentication flows in the property idp.authn.webauthn.2fa.allowedPreviousFactors. The default is authn/Password.

If enabled, and you want to completely bypass the existing logic such that the WebAuthn flow for 2FA is always used, you can set the property idp.authn.webauthn.2fa.forceSecondFactorFlow to true.

When acting as a 2nd factor of authentication, the username is gathered from the result of the first factor by lookup strategy and any credentials registered to that username are retrieved. During authentication, the authenticator is then required to:

  • test the user is present by using some form of authorization gesture (for example, by touching the authenticator or clicking on a key to use), and

  • test the credential used is allowed (has been registered with the IdP).

This mode must be used within an appropriate MFA flow, where the authn/WebAuthn is used as the second factor.

Signalling Custom Events When The User Has No Registered Credentials

In case the user has not registered any WebAuthn credentials, there are two ways to signal a custom event to the IdP. The first signal can be emitted just after collecting the username for the passwordless or 2fa flows. The second signal can be emitted after the authenticator has sent the attestation (authentication) response back to the IdP—this is the only signal you can expect from the usernameless (passkey) flow since there is no username collection step.

For the passwordless and second factor flows, setting idp.authn.webauthn.passwordless.signalEventOnNoCredentials to true will signal a custom event ID (described by the property idp.authn.webauthn.passwordless.noCredentialsEventId) If the user (identified by the username entered in the username input step) has no registered WebAuthn credentials. This will signal a custom event immediately after username collection, ending the flow. To have return controlled to the MFA orchestration layer, the event must be described to the system in the conf/authn/authn-events-flow.xml in the usual way (see the example below).

For all flows, but specifically for a usernameless (passkey) flow, setting idp.authn.webauthn.signalEventOnNoCredentialsRegisteredForUserHandle to true will signal a custom eventID (described by the property idp.authn.webauthn.userHandleNoRegisteredCredentialsEventId) if the user, identified by the userHandle (user.id) in the authenticator's attestation response, does not belong to a known user with at least one registered WebAuthn credential. The event is signalled just before the attestation (authentication) response is validated. Again, the event must be described to the system in the conf/authn/authn-events-flow.xml in the usual way if it is to be used as a transition in the MFA flow (see the example below).

To capture the new event IDs as signals to transition to an end-state of the WebAuthn flow (and not trigger an IdP InvalidEvent):

conf/authn/authn-events-flow.xml

Example MFA flow configuration that uses the new events after first running the WebAuthn flow:

conf/authn/mfa-authn-config.xml

Credential Repository

 

The default credential repository uses the Shibboleth InMemory Storage Service. Any Storage Service should be compatible with the plugin.

TODO. More on the credential repository

Credential Registration Flow

The plugin comes with an administration flow for registering and managing WebAuthn 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

The registration flow will use whichever authentication method is enabled. The example MFA Flow Configuration is a suitable initial setup that allows users to register their first credential upon inputting their username and password.

The client accessing the registration function is also subject to an AccessControlConfiguration set by the property idp.authn.webauthn.admin.registration.accessPolicy, by default this is the AccessByAnyone policy which is not defined in the IdP's access control configuration. For this to work it must added to the map in conf/access-control.xml like so:

 

Overview of Configuration Steps

You do not need to change any of the default registration options to successfully register and use a WebAuthn credential with the IdP. If you do want more control over the process, there are a few options available:

  1. Configure how user account details are passed to the WebAuthn API and authenticator.

  2. Decide what type of authenticator you want to support.

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

User Identity for Credential Generation

During registration, the IdP will pass user account details to the WebAuthn API. Some of this information is used to improve the user experience whilst creating credentials, and some are used by the authenticator 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 It should not include personally identifiable information. The ID should not change 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 this 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 in real-time using a random byte sequence of 64 bytes. However, you may prefer to pull this value from the attribute resolver. This is supported by changing the following properties in conf/authn/webauthn.properties:

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

  2. ensure the attribute resolver is enabled after authentication, idp.authn.webauthn.admin.registration.resolveIdentityAttributes=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 strategy of type Function<ProfileRequestContext, byte[]>.

User Name Population

The user name (user.name) is a human-palatable identifier for a user’s account a credential is associated with. It is only intended for display purposes. 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). This can be changed by creating a bean named idp.authn.webauthn.registration.usernameLookupStrategy in conf/authn/webauthn-config.xml.

TODO: you could use the same strategy as user display name population if you want to take it from the attribute context

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.

By default, the user display name is taken from the principal name in the SubjectContext. That is, the canonical principal name of the subject that 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.properties:

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

  2. ensure the attribute resolver is enabled after authentication, idp.authn.webauthn.admin.registration.resolveIdentityAttributes=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 strategy of type Function<ProfileRequestContext, String>.

Credential Generation Options

Discoverable Credentials (Passkeys)

TODO

Authenticator Attachment Options

TODO

Attestation Conveyance

TODO

User Verification

TODO

FIDO Metadata Service Support

The plugin supports Authenticator Metadata obtained from the FIDO metadata service (FIDO Alliance Metadata Service - FIDO Alliance). When enabled, this provides the following additional features during registration:

  1. Validation of authenticator attestations. Specifically, only allowing credentials to be registered from ‘trusted’ authenticators that are contained within the metadata.

  2. Enhancing the registration interface to display information about the user’s Authenticator: the device description and organisational icon.

Globally enabling the feature requires setting the idp.authn.webauthn.metadata.enabled property. Then, you have a choice of either downloading the metadata blob from the FIDO alliance Metadata Service URL (currently https://mds3.fidoalliance.org/), or, downloading the blob yourself, storing it locally, and pointing to the local file. The metadata does not change very often, but the FIDO guidelines suggest obtaining a new copy every month. Currently, this would require a restart of the IdP to pick up the new metadata.

For an authenticator to transmit an attestation statement to the IdP, which includes details about itself for matching with metadata entries, the IdP must initiate the registration request with an AttestationConveyancePreference. This can be set using the idp.authn.webauthn.registration.attestationConveyancePreference property. This defaults to ‘none’ (do not send an attestation statement), however a value of ‘direct’ or ‘enterprise’ would be needed to ensure this feature operated reliably (see the specification for more information). Please note that during registration, users must consent to sending the attestation statement to the IdP, and knowing the authenticators users are using may raise privacy concerns for the IdP.

 

Downloading the metadata blob from the FIDO metadata service URL

If you want to download metadata from the FIDO Alliance’s centralised repository when the IdP starts, you must specify a cache file (ending .bin) using the property idp.authn.webauthn.metadata.cacheFile, and the URL to fetch the metadata from using the property idp.authn.webauthn.metadata.metadataBlobUrl (by default this is https://mds3.fidoalliance.org/, although that can change, see https://fidoalliance.org/metadata/).

Downloading the metadata blob manually

As an alternative to downloading the metadata blob from a URL on startup of the IdP, you can choose to manage the metadata blob yourself. Download the blob JWT from the FIDO metadata service https://fidoalliance.org/metadata/ (currently, https://mds3.fidoalliance.org/) and load it using the property idp.authn.webauthn.metadata.metadataBlobFile.

Metadata Blob Trust Validation

To verify the integrity and authenticity of the metadata blob, you must download the trust root certificate listed at https://fidoalliance.org/metadata/ and load it using the property idp.authn.webauthn.metadata.trustRootFile. This is important because the metadata blob provides the trust roots for Authenticator Attestations and hence we need to first bootstrap trust for the metadata itself (as you would with SAML Metadata).

Revocation Checking

According to the FIDO MDS Specification, the revocation status of the certificates used in the metadata blob’s digital signature MUST be checked for the metadata to load. If you enable metadata support but do not enable revocation checking, the IdP will fail to start. There are two ways to enable this:

  1. Download and manage the CRLs present in the Metadata blob certificate path manually, and point to them using the idp.authn.webauthn.metadata.crls property.

    1. For the current signing certificate, these are at http://crl.globalsign.com/root-r3.crl and http://crl.globalsign.com/gs/gsextendvalsha2g3r3.crl. You’d need to keep these up to date to a) prevent them from expiring, and b) perform meaningful revocation checks.

  2. Comment out the idp.authn.webauthn.metadata.crls property and enable automated CRL checking from an online distribution point via the system property com.sun.security.enableCRLDP (as described in the CertPathDocs).

    1. This will enable CRL distribution points for the Sun PKIX engine across the IdP. So be careful this is what you want to do before enabling it.

Registration Options

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

TODO: all these options should have their own sections

Option

Default

Description

Option

Default

Description

idp.authn.webauthn.registration.residentKey

preferred

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

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 a best effort to create the most preferred it can.

idp.authn.webauthn.registration.authenticatorAttachment

any

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

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

idp.authn.webauthn.registration.attestationConveyancePreference

none

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

Administrative Credential Management Flow

In addition to user management of their credentials, there is an admin flow for administrators to manage other users' credentials. Specifically, to search for and remove a user's registered credential from the system.

The management flow can be accessed by navigating to:

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

As with the registration flow, the management flow will use whichever authentication method is enabled. Importantly, the client and user accessing the management function are subject to an AccessControlConfiguration set by the property idp.authn.webauthn.admin.management.accessPolicy; by default, this is the AccessByAdminpolicy. Given the purpose of this flow, it is important to ensure a suitably restrictive access policy is set.

The flow's function is pretty simple, first, you search for a user based on their User Name, which lists their registered credentials. You can then choose to remove one or more of those credentials before finishing the flow.

Debugging Registration and Authentication Requests

If you want to easily see and debug both the registration ceremony (PublicKeyCredentialCreationOptions) and authentication ceremony (PublicKeyCredentialRequestOptions), you can set the idp.authn.webauthn.ui.debug property to true in conf/authn/webauthn.properties. The requests should appear on the authentication and registration views in a drop-down box.