Fido2AuthState
Introduction and overview
The Fido2AuthState AuthState manages the FIDO2 authentication in a nevisFIDO server.
The section refers to protocol messages defined in the FIDO2: Conformance testing server API.
Input Activity
Depending on the received inputs, the Fido2AuthState may behave differently, as also illustrated on the activity diagram below. The following list of configuration properties heavily influence these behaviors. In order of priority:
clientResult: if this configuration property resolves into a non-empty value (and is also an allowed client result), everything else is ignored, and the AuthState sets the received client result.fido2SessionIdInHeader: if the header referenced by this property is received (and noclientResultis received),Fido2AuthStatewill try to contact nevisFIDO to verify the success of an authentication ceremony. Only set this if the ceremony has succeeded at nevisFIDO.fido2Username: if this configuration property resolves into a non-null value (and none of the above properties resolved), theFido2AuthStatewill initiate the authentication ceremony at nevisFIDO.
A common pitfall to configure fido2Username into a value that is resolved immediately, before a GUI would be rendered and the client-side Javascript could be loaded. For example, consider the following: fido2Username is configured with the value ${notes:loginId} and the AuthState that preceeds the Fido2AuthState already sets loginId into the notes. This means, the moment Fido2AuthState starts processing, instead of asking to render a GUI, it will initiate the authentication at nevisFIDO, which means the client-side Javascript is completely out of the loop, even if it loads at all - no authentication can happen in the browser. As such, it is recommended to keep fido2Username at default value ${inargs:o.username.v}, which means the AuthState will wait for the client to send the username in an HTTP POST request's body, keeping the client in the FIDO2 ceremony.
Authentication flow
The FIDO2 authentication process including nevisAuth and the Fido2AuthState is as follows:
A GUI is rendered and client-side Javascript is loaded that is capable of handling the FIDO2 protocol in the browser.
The client-side Javascript sends an HTTP POST with a JSON payload containing user information. (Example:
{"username": "charlesdexterward"})The
Fido2AuthStateretreives the username with thefido2Usernameconfiguration property from the incoming request and then sends aServerPublicKeyCredentialGetOptionsRequestto the nevisFIDO server with it. The value of this attribute can be retrieved in various ways (theoretically, even without a GUI), but it is recommended that the HTTP client provides the FIDO2 username directly in the incoming request as JSON or FORM parameters. The username value can be a variable expression usinginargsin this case, such as the default of this property, which is${inargs:o.username.v}.The nevisFIDO server returns a
ServerPublicKeyCredentialGetOptionsResponseto nevisAuth, which it forwards to the client. Thefido2SessionIdis in this request, which nevisAuth stores in the session for later.The client processes the
ServerPublicKeyCredentialGetOptionsResponseand authenticates the user on the FIDO2 authenticator. As mentioned above, theServerPublicKeyCredentialGetOptionsResponsecontains a FIDO2 session ID, which the client must store. Example session ID in theServerPublicKeyCredentialGetOptionsResponse:{
"fido2SessionId": "asdetwdIDsdfsewSAdsds09823423sdfsd9ds"
}The client sends a
ServerPublicKeyCredentialdirectly to the nevisFIDO server.The client queries nevisAuth. It depends on the configuration of the
fido2SessionIdInHeaderproperty in theFido2AuthStatewhat header the client is to provide the value in. By default, the client is required to send the property in an HTTP header like this:"nevis-fido2-session-id" : "asdetwdIDsdfsewSAdsds09823423sdfsd9ds"The
Fido2AuthStatecompares the receivedfido2SessionIdwith the one stored in the session. On a match the AuthState will query the status service of nevisFIDO to verify whether the user is successfully authenticated. If so, theFido2AuthStatesets the result condition took, which triggers a transition in the AuthStates to whatever follows theFido2AuthState.
Description
The following table and chapters describe the characteristics of the AuthState.
| Topic | Description |
|---|---|
| Class | ch.nevis.auth.fido.fido2.authstate.Fido2AuthState |
| Logging | Fido2 |
| Auditing | none |
| Marker | none |
| Methods | process |
Properties
fido2Username(string, optional)Username of the user in the nevisFIDO server.
Default value:
${inargs:o.username.v}This means, it is expected that the client-side Javascript posts the username to nevisAuth with a JSON payload. Example:
{ "username" : "username_of_the_user" }Once this configuration entry is resolved into a non-null value, the FIDO2 authentication ceremony is started at the FIDO2 server, nevisFIDO.
fido2UserVerification(string, optional)Will be incorporated into the FIDO2 options that is delivered to the browser. This property signals whether the user is to be verified or not by the FIDO2 authenticator / browser. See also UserVerificationRequirement
Default value: ${inargs:o.userVerification.v} Allowed static values:
required,preferred,discouraged.The default value means, it is expected that the client-side Javascript posts the
userVerificationto nevisAuth with a JSON payload. Example:{ "userVerification" : "required" }It is recommended to specify a static value that represents the desired business. If a null or empty value is provided, the default
preferredwill take effect in nevisFIDO.fido2ServerUrl(string, required)Base URL of the nevisFIDO server with the path prefix of the component. You cannot use variable expressions to specify this value.
Example:
https://siven.ch:8443/nevisfido.With this configuration the FIDO2 AuthState will send the ServerPublicKeyCredentialGetOptionsRequest to
https://siven.ch:8443/nevisfido/fido2/attestation/options.fido2SessionIdHeader(string, optional)The name of the header the session ID is provided in by the client. The value is used to query the status service of nevisFIDO regarding ongoing authentication ceremonies. If header is provided, it is assumed the authentication ceremony has already been initiated.
Default value:
nevis-fido2-session-id.With the default value, the client is expected to send an HTTP request with the header:
"nevis-fido2-session-id" : "the_session_ID"userExtId(string, optional)The nevisIDM
extIdof the user. If resolved to a non-empty value, theFido2AuthStatewill verify that theextIdit received from nevisFIDO matches the resolved value. It is recommended to configure this property for stepup scenarios, where the user data is already loaded into the session. Usually the nevisIDM user is loaded into the session for these scenarios, which means this property will automatically take effect with its default value seen below.Default value:
${sess:ch.adnovum.nevisidm.user.extId}.clientResult(string, optional)The
Fido2AuthStatemakes it possible for the client to influence the flow with results resolved in this property - if any valid result is resolved, it takes precedence over other actions of theFido2AuthState, so only provide this in case it is certain the FIDO2 ceremony cannot continue.Default value:
${inargs:clientResult}With the default value, the client is expected to send an HTTP form with the
clientResultcontent set. Example:"clientResult"="cancelled"Allowed results:
cancelled: we recommend to send this in case the user cancels the ceremony explicitly.notSupported: we recommend to send this in case the client-side detects the client's lack of support for FIDO2.
httpclient.*(String)Configure the outgoing HTTP communication towards nevisFIDO. For a list of valid HTTP properties, see HTTP Client configuration.
Input
fido2SessionIdHeaderThe
Fido2AuthStatequeries the nevisFIDO server to check whether the session with the provided ID is authenticated. The FIDO2 session ID can be provided using a header in an HTTP request:"nevis-fido2-session-id" : "the_session_ID"
Transitions
errorIf an error occurred in the communication with nevisFIDO.
failedIf nevisFIDO reports a failed authentication (in response to the client’s query for the authentication status).
cancelledOnly happens if signalled explicitly to theFido2AuthStatewith theclientResultproperty. It is recommended to use this for explicit cancellations requested by the user on the client-side.notSupportedOnly happens if signalled explicitly to theFido2AuthStatewith theclientResultproperty. It is recommended to use this for the case when the client-side code detects that the client does not support FIDO2.okIf nevisAuth detects a successfully authenticated user in nevisFIDO. In this case, nevisFIDO responses positively to the client’s query for the authentication status.
Output
ServerPublicKeyCredentialGetOptionsResponseIf the
Fido2AuthStategenerates aServerPublicKeyCredentialGetOptionsRequest, it will forward the response from the nevisFIDO server, aServerPublicKeyCredentialGetOptionsResponseobject, to the client. The client must process thisServerPublicKeyCredentialGetOptionsResponse, authenticate the user and eventually send aServerPublicKeyCredentialdirectly to the nevisFIDO server.Payload with authentication status:
If the
Fido2AuthStatequeried nevisFIDO regarding the authentication status of the session, it will return a JSON object describing the status. Example:{
"challenge": "6283u0svT-YIF3pSolzkQHStwkJCaLKx",
"timeout": 20000,
"rpId": "nevis.net",
"allowCredentials": [
{
"id": "m7xl_TkTcCe0WcXI2M-4ro9vJAuwcj4m",
"type": "public-key"
}
],
"userVerification": "required",
"fido2SessionId": "asdetwdIDsdfsewSAdsds09823423sdfsd9ds"
}
Errors
none
Notes
none
Example
The AuthState in the following example integrates FIDO2 authentication in nevisAuth using the nevisFIDO server located in siven.ch with port 8443. The FIDO2 username is retrieved from the incoming JSON {"username": "the_username"} the client must send from the rendered GUI.
<AuthState name="Fido2Authentication" class="ch.nevis.auth.fido.fido2.authstate.Fido2AuthState" final="true" resumeState="true"
classPath="/opt/nevisfidocl/nevisauth/lib">
<ResultCond name="ok" next="AuthDone"/>
<ResultCond name="failed" next="AuthError"/>
<ResultCond name="error" next="AuthError"/>
<ResultCond name="cancelled" next="AuthError"/>
<ResultCond name="notSupported" next="AuthError"/>
<Response value="AUTH_CONTINUE">
<Gui name="fido2dialog" label="FIDO2 Dialog" target="">
<GuiElem name="lasterror" type="error" label="${notes:lasterrorinfo}" value="${notes:lasterror}"/>
<GuiElem name="username" optional="true" type="text" label="Username" />
<GuiElem name="displayName" optional="true" type="text" label="Display Name" />
<GuiElem name="btnFido2Authentication" type="button" label="Authentication" />
<GuiElem name="btnFido2Cancel" type="button" label="Cancel" />
</Gui>
</Response>
<property name="fido2SessionIdHeader" value="nevis-fido2-session-id"/>
<property name="fido2UserName" value="${inargs:o.username.v}"/>
<property name="fido2ServerUrl" value="https://siven.ch.8443/nevisfido"/>
<property name="httpclient.tls.trustStoreRef" value="TrustStoreForNevisFido"/>
<property name="httpclient.tls.keyObjectRef" value="DefaultSigner" />
</AuthState>
Request and Response Examples
Request Body Providing Username
It is assumed that the fido2Username attribute value is ${inargs:o.username.v} and the transactions attribute is ${inargs:o.transaction.v}.
{
"username": "charlesdexterward",
}
Response
HTTP/1.1 200 OK
Date: Mon, 25 Jul 2022 11:31:19 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Content-Length: 375
{
"status" : "ok",
"errorMessage" : "",
"fido2SessionId" : "673c1466-2fb8-43fe-8898-a94a06d1793c",
"challenge" : "bs1rWtPCQrmEDrBGAfjcKg",
"timeout" : 300000,
"rpId" : "siven.ch",
"allowCredentials" : [ {
"type" : "public-key",
"id" : "Y3JlZGVudGlhbElk",
"transports" : [ "usb", "internal", "ble", "nfc" ]
} ],
"userVerification" : "preferred"
}
Status Request Body
It is assumed that the fido2SessionIdHeader attribute value is nevis-fido2-session-id.
"fido2SessionIdHeader": "1c8a5b00-165c-4a63-ae13-2e03fb7f57ce"
Status Response
HTTP/1.1 200 OK
Date: Mon, 25 Jul 2022 11:31:19 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Content-Length: 187
{
"status" : "succeeded",
"fido2SessionId" : "7fea6065-17fd-47d4-a5b0-85f513687c8d",
"timestamp" : "2022-07-25T11:31:18.987Z",
"username" : "Jeff ",
"userId" : "[email protected]"
}