diff --git a/bundles/uds-bundle.yaml b/bundles/uds-bundle.yaml index 41aaeab0..3c1de7ef 100644 --- a/bundles/uds-bundle.yaml +++ b/bundles/uds-bundle.yaml @@ -85,7 +85,7 @@ packages: USERNAME_PASSWORD_AUTH_ENABLED: true X509_AUTH_ENABLED: true SOCIAL_AUTH_ENABLED: true - OTP_ENABLED: true + OTP_ENABLED: false - path: env[0] value: name: JAVA_OPTS_KC_HEAP diff --git a/docs/.images/diagrams/uds-core-auth-flow-diagrams.drawio b/docs/.images/diagrams/uds-core-auth-flow-diagrams.drawio index 546cae05..dd3fcd75 100644 --- a/docs/.images/diagrams/uds-core-auth-flow-diagrams.drawio +++ b/docs/.images/diagrams/uds-core-auth-flow-diagrams.drawio @@ -1,9 +1,9 @@ - + - + - + @@ -416,7 +416,7 @@ - + @@ -590,10 +590,8 @@ - - - - + + @@ -691,6 +689,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/.images/diagrams/uds-core-auth-flows-options.svg b/docs/.images/diagrams/uds-core-auth-flows-options.svg index 516e4185..97af422e 100644 --- a/docs/.images/diagrams/uds-core-auth-flows-options.svg +++ b/docs/.images/diagrams/uds-core-auth-flows-options.svg @@ -1,3 +1,3 @@ -
Username/Password
Username / Password Registration Form
MFA
Username / Password Login Form
No
Yes
MFA Setup ?
Setup MFA
Enter MFA
Username Form
Reset Password Email sent
No
Yes
MFA Setup ?
Setup MFA
Enter MFA
SSO
SSO Button
SSO Button
Redirect to IDP
Redirect to IDP
Disabled
x509
Username / Password Registration Form
x509 Button
Disabled
  Registration  
  Access Granted  
  Authentication  
  Access Granted  
  Reset Password  
  Password Reset  
\ No newline at end of file +
Username/Password
Username / Password Registration Form
MFA
Username / Password Login Form
No
Yes
MFA Setup ?
Setup MFA
Enter MFA
Username Form
Reset Password Email sent
No
Yes
MFA Setup ?
Setup MFA
Enter MFA
SSO
SSO Button
SSO Button
Redirect to IDP
Redirect to IDP
Disabled
x509
Username / Password Registration Form
x509 Button
Disabled
  Registration  
  Access Granted  
  Authentication  
  Access Granted  
  Reset Password  
  Password Reset  
Yes
No
MFA Setup ?
Setup MFA
Enter MFA
Yes
No
X509 MFA Configured ?
\ No newline at end of file diff --git a/docs/dev/authentication-flow-toggle-maps.md b/docs/dev/authentication-flow-toggle-maps.md index 69f5c6eb..29a8a828 100644 --- a/docs/dev/authentication-flow-toggle-maps.md +++ b/docs/dev/authentication-flow-toggle-maps.md @@ -10,6 +10,7 @@ See the [Authentication Flow Customization](../reference/UDS%20Core/IdAM/authent | [X509_LOGIN_ENABLED](https://github.com/defenseunicorns/uds-core/blob/main/src/keycloak/chart/templates/secret-kc-realm.yaml#L22) | Control whether X509 ( CAC ) Login block is included on the login and registration pages. | `true`(default), `false`| | [USERNAME_PASSWORD_AUTH_ENABLED](https://github.com/defenseunicorns/uds-core/blob/main/src/keycloak/chart/templates/secret-kc-realm.yaml#L23) | Control whether Username Password Login block is included on the login and registration pages. This will also control the realm configuration for updating passwords or setting a new password from users account management. | `true`(default), `false`| | [REGISTER_BUTTON_ENABLED](https://github.com/defenseunicorns/uds-core/blob/main/src/keycloak/chart/templates/secret-kc-realm.yaml#L24) | Control whether the register button is included on the login page. | `true`(default), `false`| +| [WEBAUTHN_ENABLED](https://github.com/defenseunicorns/uds-core/blob/main/src/keycloak/chart/templates/secret-kc-realm.yaml#L24) | Control whether the `WebAuthn Passwordless Authenticator` pop-up shows the register new user. This can already be assumed since the WebAuthn is configured as an MFA. | `true`, `false`(default) | ### Realm Configuration Definitions | Setting | Description | Options | @@ -18,6 +19,12 @@ See the [Authentication Flow Customization](../reference/UDS%20Core/IdAM/authent | [RESET_CREDENTIAL_FLOW_ENABLED](https://github.com/defenseunicorns/uds-core/blob/main/src/keycloak/chart/templates/secret-kc-realm.yaml#L26) | Control whether a the Reset Credential Auth Flow can be reached by user to reset or set their password. | `REQUIRED`(default), `DISABLED` | | [REGISTRATION_FORM_ENABLED](https://github.com/defenseunicorns/uds-core/blob/main/src/keycloak/chart/templates/secret-kc-realm.yaml#L27) | Control whether the registration form can be reached for a new registration. | `REQUIRED`(default), `DISABLED` | | [OTP_ENABLED](https://github.com/defenseunicorns/uds-core/blob/main/src/keycloak/chart/templates/secret-kc-realm.yaml#L28) | Control whether One Time Password is allowed. | `true`(default), `false` | +| [OTP_FLOW_ENABLED](https://github.com/defenseunicorns/uds-core/blob/main/src/keycloak/chart/templates/secret-kc-realm.yaml#L28) | Control whether the OTP is required as an MFA method. | `REQUIRED`(default), `DISABLED` | +| [WEBAUTHN_ENABLED](https://github.com/defenseunicorns/uds-core/blob/main/src/keycloak/chart/templates/secret-kc-realm.yaml#L24) | Control whether the `WebAuthn Register Passwordless` required action is enabled. | `true`, `false`(default) | +| [WEBAUTHN_FLOW_ENABLED](https://github.com/defenseunicorns/uds-core/blob/main/src/keycloak/chart/templates/secret-kc-realm.yaml#L24) | Control whether the `WebAuthn Register Passwordless` required action is enabled. | `REQUIRED`, `DISABLED`(default) | +| [X509_MFA_ENABLED](https://github.com/defenseunicorns/uds-core/blob/main/src/keycloak/chart/templates/secret-kc-realm.yaml#L24) | Control whether X509 Authentication flows can also require MFA. This configuration is used in the custom `Registration Validation` plugin. | `true`, `false`(default) | +| [X509_MFA_FLOW_ENABLED](https://github.com/defenseunicorns/uds-core/blob/main/src/keycloak/chart/templates/secret-kc-realm.yaml#L24) | Control whether X509 Authentication flows require MFA. This is needed so that X509 MFA can be configured seperately from Username/Password MFA. | `REQUIRED`, `DISABLED`(default) | +| [MFA_FLOW_ENABLED](https://github.com/defenseunicorns/uds-core/blob/main/src/keycloak/chart/templates/secret-kc-realm.yaml#L24) | Control whether the `MFA` authentication is required. | `REQUIRED`(default), `DISABLED` | ### Common Configurations @@ -26,10 +33,11 @@ At this time, UDS Core supports three different avenues of authentication for us #### In Depth Configuration Map | Authentication Configuration Description | Theme Configurations | Realm Configurations | | - | - | - | -| Default | `SOCIAL_LOGIN_ENABLED: true`
`X509_LOGIN_ENABLED: true`
`USERNAME_PASSWORD_AUTH_ENABLED: true`
`REGISTER_BUTTON_ENABLED: true` | `DENY_USERNAME_PASSWORD_ENABLED: DISABLED`
`RESET_CREDENTIAL_FLOW_ENABLED: REQUIRED`
`REGISTRATION_FORM_ENABLED: REQUIRED`
`OTP_ENABLED: true` | -| Username Password Only | `SOCIAL_LOGIN_ENABLED: false`
`X509_LOGIN_ENABLED: false`
`USERNAME_PASSWORD_AUTH_ENABLED: true`
`REGISTER_BUTTON_ENABLED: true` | `DENY_USERNAME_PASSWORD_ENABLED: DISABLED`
`RESET_CREDENTIAL_FLOW_ENABLED: REQUIRED`
`REGISTRATION_FORM_ENABLED: REQUIRED`
`OTP_ENABLED: true` | -| Social (IDP) Only | `SOCIAL_LOGIN_ENABLED: true`
`X509_LOGIN_ENABLED: false`
`USERNAME_PASSWORD_AUTH_ENABLED: false`
`REGISTER_BUTTON_ENABLED: false` | `DENY_USERNAME_PASSWORD_ENABLED: REQUIRED`
`RESET_CREDENTIAL_FLOW_ENABLED: DISABLED`
`REGISTRATION_FORM_ENABLED: DISABLED`
`OTP_ENABLED: false` | -| X509 Only | `SOCIAL_LOGIN_ENABLED: false`
`X509_LOGIN_ENABLED: true`
`USERNAME_PASSWORD_AUTH_ENABLED: false`
`REGISTER_BUTTON_ENABLED: true` | `DENY_USERNAME_PASSWORD_ENABLED: REQUIRED`
`RESET_CREDENTIAL_FLOW_ENABLED: DISABLED`
`REGISTRATION_FORM_ENABLED: REQUIRED`
`OTP_ENABLED: false` | -| Username Password with X509 | `SOCIAL_LOGIN_ENABLED: false`
`X509_LOGIN_ENABLED: true`
`USERNAME_PASSWORD_AUTH_ENABLED: true`
`REGISTER_BUTTON_ENABLED: true` | `DENY_USERNAME_PASSWORD_ENABLED: DISABLED`
`RESET_CREDENTIAL_FLOW_ENABLED: REQUIRED`
`REGISTRATION_FORM_ENABLED: REQUIRED`
`OTP_ENABLED: true` | -| Username Password with Social (IDP) | `SOCIAL_LOGIN_ENABLED: true`
`X509_LOGIN_ENABLED: false`
`USERNAME_PASSWORD_AUTH_ENABLED: true`
`REGISTER_BUTTON_ENABLED: true` | `DENY_USERNAME_PASSWORD_ENABLED: DISABLED`
`RESET_CREDENTIAL_FLOW_ENABLED: REQUIRED`
`REGISTRATION_FORM_ENABLED: REQUIRED`
`OTP_ENABLED: true` | -| X509 with Social (IDP) | `SOCIAL_LOGIN_ENABLED: true`
`X509_LOGIN_ENABLED: true`
`USERNAME_PASSWORD_AUTH_ENABLED: false`
`REGISTER_BUTTON_ENABLED: true`| `DENY_USERNAME_PASSWORD_ENABLED: REQUIRED`
`RESET_CREDENTIAL_FLOW_ENABLED: DISABLED`
`REGISTRATION_FORM_ENABLED: REQUIRED`
`OTP_ENABLED: false` | \ No newline at end of file +| Default | `SOCIAL_LOGIN_ENABLED: true`
`X509_LOGIN_ENABLED: true`
`USERNAME_PASSWORD_AUTH_ENABLED: true`
`REGISTER_BUTTON_ENABLED: true` | `DENY_USERNAME_PASSWORD_ENABLED: DISABLED`
`RESET_CREDENTIAL_FLOW_ENABLED: REQUIRED`
`REGISTRATION_FORM_ENABLED: REQUIRED`
`OTP_ENABLED: true`
`WEBAUTHN_ENABLED: false`
`X509_MFA_ENABLED: false` | +| Username Password Only | `SOCIAL_LOGIN_ENABLED: false`
`X509_LOGIN_ENABLED: false`
`USERNAME_PASSWORD_AUTH_ENABLED: true`
`REGISTER_BUTTON_ENABLED: true` | `DENY_USERNAME_PASSWORD_ENABLED: DISABLED`
`RESET_CREDENTIAL_FLOW_ENABLED: REQUIRED`
`REGISTRATION_FORM_ENABLED: REQUIRED`
`OTP_ENABLED: true`
`WEBAUTHN_ENABLED: false`
`X509_MFA_ENABLED: false` | +| Social (IDP) Only | `SOCIAL_LOGIN_ENABLED: true`
`X509_LOGIN_ENABLED: false`
`USERNAME_PASSWORD_AUTH_ENABLED: false`
`REGISTER_BUTTON_ENABLED: false` | `DENY_USERNAME_PASSWORD_ENABLED: REQUIRED`
`RESET_CREDENTIAL_FLOW_ENABLED: DISABLED`
`REGISTRATION_FORM_ENABLED: DISABLED`
`OTP_ENABLED: false`
`WEBAUTHN_ENABLED: false`
`X509_MFA_ENABLED: false` | +| X509 Only | `SOCIAL_LOGIN_ENABLED: false`
`X509_LOGIN_ENABLED: true`
`USERNAME_PASSWORD_AUTH_ENABLED: false`
`REGISTER_BUTTON_ENABLED: true` | `DENY_USERNAME_PASSWORD_ENABLED: REQUIRED`
`RESET_CREDENTIAL_FLOW_ENABLED: DISABLED`
`REGISTRATION_FORM_ENABLED: REQUIRED`
`OTP_ENABLED: false`
`WEBAUTHN_ENABLED: false`
`X509_MFA_ENABLED: false` | +| Username Password with X509 | `SOCIAL_LOGIN_ENABLED: false`
`X509_LOGIN_ENABLED: true`
`USERNAME_PASSWORD_AUTH_ENABLED: true`
`REGISTER_BUTTON_ENABLED: true` | `DENY_USERNAME_PASSWORD_ENABLED: DISABLED`
`RESET_CREDENTIAL_FLOW_ENABLED: REQUIRED`
`REGISTRATION_FORM_ENABLED: REQUIRED`
`OTP_ENABLED: true`
`WEBAUTHN_ENABLED: false`
`X509_MFA_ENABLED: false` | +| Username Password with Social (IDP) | `SOCIAL_LOGIN_ENABLED: true`
`X509_LOGIN_ENABLED: false`
`USERNAME_PASSWORD_AUTH_ENABLED: true`
`REGISTER_BUTTON_ENABLED: true` | `DENY_USERNAME_PASSWORD_ENABLED: DISABLED`
`RESET_CREDENTIAL_FLOW_ENABLED: REQUIRED`
`REGISTRATION_FORM_ENABLED: REQUIRED`
`OTP_ENABLED: true`
`WEBAUTHN_ENABLED: false`
`X509_MFA_ENABLED: false` | +| X509 with Social (IDP) | `SOCIAL_LOGIN_ENABLED: true`
`X509_LOGIN_ENABLED: true`
`USERNAME_PASSWORD_AUTH_ENABLED: false`
`REGISTER_BUTTON_ENABLED: true`| `DENY_USERNAME_PASSWORD_ENABLED: REQUIRED`
`RESET_CREDENTIAL_FLOW_ENABLED: DISABLED`
`REGISTRATION_FORM_ENABLED: REQUIRED`
`OTP_ENABLED: false`
`WEBAUTHN_ENABLED: false`
`X509_MFA_ENABLED: false` | +| X509 MFA with OTP and WebAuthn | `SOCIAL_LOGIN_ENABLED: false`
`X509_LOGIN_ENABLED: true`
`USERNAME_PASSWORD_AUTH_ENABLED: false`
`REGISTER_BUTTON_ENABLED: true` | `DENY_USERNAME_PASSWORD_ENABLED: REQUIRED`
`RESET_CREDENTIAL_FLOW_ENABLED: DISABLED`
`REGISTRATION_FORM_ENABLED: REQUIRED`
`OTP_ENABLED: true`
`WEBAUTHN_ENABLED: true`
`X509_MFA_ENABLED: true` | diff --git a/docs/reference/UDS Core/IdAM/authentication-flows.md b/docs/reference/UDS Core/IdAM/authentication-flows.md index 0bdd20dd..63bd89bb 100644 --- a/docs/reference/UDS Core/IdAM/authentication-flows.md +++ b/docs/reference/UDS Core/IdAM/authentication-flows.md @@ -30,6 +30,36 @@ UDS Core comes equipped with a robust authentication framework that supports mul ![Authentication Flow Options](https://github.com/defenseunicorns/uds-identity-config/blob/main/docs/.images/diagrams/uds-core-auth-flows-options.svg?raw=true) +## MFA Authentication + +UDS Core comes with two different options for MFA requirements. One time password (OTP) and WebAuthn options can be configured. These options are available for both `Username and Password` and `x509` authentication flows. They are controlled individually, to provide the most amount of configurability. + +```yaml + - path: realmAuthFlows + value: + USERNAME_PASSWORD_AUTH_ENABLED: true + X509_AUTH_ENABLED: true + SOCIAL_AUTH_ENABLED: true + OTP_ENABLED: true + WEBAUTHN_ENABLED: false + X509_MFA_ENABLED: false +``` + +Above is the complete list of authentication configurations from a bundle override. Below is the description of what each of those do: + +| Name | Description | Default Value | +| - | - | - | +| `USERNAME_PASSWORD_AUTH_ENABLED` | Controls whether the `Username and Password` authentication flow is allowed and present on the login page. | `true`(default), `false` | +| `X509_AUTH_ENABLED` | Controls whether the `X509` authentication is allowed and present (when a proper certificate is present) on the login page. | `true`(default), `false` | +| `SOCIAL_AUTH_ENABLED` | Controls whether the `Social` authentication is allowed and present on the login page. This requires that an Identity Provider be configured as well. | `true`(default), `false` | +| `OTP_ENABLED` | Control whether `OTP` MFA is enabled, making it required for `Username and Password` authentication. | `true`(default), `false` | +| `WEBAUTHN_ENABLED` | Control whether `WebAuthn` MFA is enabled, making it required for `Username and Password` authentication. | `true`, `false`(default) | +| `X509_MFA_ENABLED` | Control whether `X509` authentication flow should also include MFA. Enabling this requires `OTP_ENABLED` or `WEBAUTHN_ENABLED` as well. | `true`, `false`(default) | + +:::warning +We shift all authn and authz responsibilies to the Identity Provider if choosing to use SSO, this means that MFA is not configurable for SSO options. +::: + ## Authentication Flows in UDS Core UDS Core is shipped with a basic authentication flow that includes all three options out of the box. The following diagram shows the basic authentication flows that are deployed with standard UDS Core: @@ -68,6 +98,7 @@ These settings allow for enabling/disabling one or more of the Auth flows. Be aw | [USERNAME_PASSWORD_AUTH_ENABLED](https://github.com/defenseunicorns/uds-core/blob/main/src/keycloak/chart/values.yaml#L30) | Toggle on/off the Username and Password Authentication flow. When disabled there will be no username password login, password / password confirm registration fields, no credential reset, and no update password options available. | `true`(default), `false` | | [X509_AUTH_ENABLED](https://github.com/defenseunicorns/uds-core/blob/main/src/keycloak/chart/values.yaml#L31) | Toggle on/off X509 (CAC) Authentication flow. | `true`(default), `false` | | [SOCIAL_AUTH_ENABLED](https://github.com/defenseunicorns/uds-core/blob/main/src/keycloak/chart/values.yaml#L32) | Toggle on/off Social (Google SSO, Azure AD, etc. ) Authentication flows.| `true`(default), `false` | +| [X509_MFA_ENABLED](https://github.com/defenseunicorns/uds-core/blob/main/src/keycloak/chart/values.yaml#L32) | Toggle on/off X509 to require additional MFA options (OTP, WebAuthn, etc).| `true`, `false`(default) | These three variables handle the complexities of configuring the following environment variables, which are responsible for both visual (theme) and security (realm). The following variables are not exposed for overriding. @@ -85,3 +116,4 @@ All Realm Configurations require accesss to the Keycloak admin portal. | `RESET_CREDENTIAL_FLOW_ENABLED` | 1. Realm Authentication tab
2. Select the `UDS Reset Credentials` Authentication Flow
3. `DISABLE` the `Reset Password` step | | `REGISTRATION_FORM_ENABLED` | 1. Realm Authentication tab
2. Select the `UDS Registration` Authentication Flow
3. `DISABLE` the `UDS Registration form` step | | `OTP_ENABLED` | 1. Realm Authentication tab
2. Select the `Required Action` tab at the top of the Authentication view
3. Toggle off the `Configure OTP` | +| `WEBAUTHN_ENABLED` | 1. Realm Authentication tab
2. Select the `Required Action` tab at the top of the Authentication view
3. Toggle on the `Webauthn Register Passwordless` `Enabled` column
4. Select the `Flows` tab at the top of the Authentication view
5. Select the `UDS Authentication` flow
6. Set the `MFA` sub-flow to `Required`
7. Set the `WebAuthn Passwordless Authenticator` in the `MFA` sub-flow to `Required` | diff --git a/docs/reference/UDS Core/IdAM/customization.md b/docs/reference/UDS Core/IdAM/customization.md index b1a35b14..ff3d24f9 100644 --- a/docs/reference/UDS Core/IdAM/customization.md +++ b/docs/reference/UDS Core/IdAM/customization.md @@ -93,6 +93,8 @@ overrides: X509_AUTH_ENABLED: true SOCIAL_AUTH_ENABLED: true OTP_ENABLED: true + WEBAUTHN_ENABLED: true + X509_MFA_ENABLED: true ``` > These environment variables can be found in the [realm.json](https://github.com/defenseunicorns/uds-identity-config/blob/main/src/realm.json). diff --git a/docs/reference/UDS Core/IdAM/upgrading-versions.md b/docs/reference/UDS Core/IdAM/upgrading-versions.md index 7365753d..96cb3fa0 100644 --- a/docs/reference/UDS Core/IdAM/upgrading-versions.md +++ b/docs/reference/UDS Core/IdAM/upgrading-versions.md @@ -10,62 +10,96 @@ This doc contains important information for upgrading uds-identity-config versio Upgrade Details In uds-identity-config versions v0.11.0+, the UDS Operator can automatically switch to Client Credentials Grant from using the Dynamic Client Registration. The new method works faster, is more reliable and doesn't require storing Registration Tokens in the Pepr Store. It is highly recommended to switch to it, which requires the following steps: - - Create the `uds-operator` Client: - - Go to `Clients` > `Client registration` > `Create` - - Client type: `openid-connect` - - Client ID: `uds-operator` - - Client Name: `uds-operator` - - Click `Next` - - Client authentication: on - - Uncheck all Authentications flows except from `Service account roles` - - Click `Next` - - Click `Save` - - Go to `Clients` > `uds-operator` > `Credentials` tab - - Set `Client Authenticator` to `Client Id and Kubernetes Secret` - - Click `Save` - - Configure the UDS Client Policy - - Go to `Realm Settings` > `Client Policies` > `Profiles` - - Click `Create Client Profile` - - Name: `uds-client-profile` - - Description: `UDS Client Profile` - - Click `Save` - - Click `Add Executor` - - Select `uds-operator-permissions` - - Click `Add` - - Go to `Realm Settings` > `Client Policies` > `Policies` - - Click `Create client policy` - - Name: `uds-client-policy` - - Description: `UDS Client Policy` - - Click `Add condition` - - Select `any-client` - - Click `Add` - - Click `Add client profile` - - Select `uds-client-profile` - - Click `Add` (there is a glitch in the UI where it seems all the profiles are selected, but only the selected one is actually chosen) - - Configure the Client Credentials Authentication Flow - - Go to `Authentication` > `Flows` - - Click `clients` - - Click `Actions` > `Duplicate` - - Name: `UDS Client Credentials` - - Description `UDS Client Credentials` - - Click `Duplicate` - - Go to `Authentication` > `UDS Client Credentials` - - Click `Add Step` - - Select `Client Id and Kubernetes Secret` - - Click `Add` - - Select `Requirement` and set it to `Alternative` - - Go to `Authentication`, select three dots on the right side of the panel for `UDS Client Credentials` and select `Bind flows` - - Select `Client authentication flow` - - Click `Save` - - Verify that everything is configured correctly - - Deploy a new package or update the existing one - - Check UDS Operator logs and verify if there are no errors - - Use `uds zarf tools kubectl logs deploy/pepr-uds-core-watcher -n pepr-system | grep "Client Credentials Keycloak Client is available"` command to verify if the UDS Operator uses the Client Credentials flow. + - Create the `uds-operator` Client: + - Go to `Clients` > `Client registration` > `Create` + - Client type: `openid-connect` + - Client ID: `uds-operator` + - Client Name: `uds-operator` + - Click `Next` + - Client authentication: on + - Uncheck all Authentications flows except from `Service account roles` + - Click `Next` + - Click `Save` + - Go to `Clients` > `uds-operator` > `Credentials` tab + - Set `Client Authenticator` to `Client Id and Kubernetes Secret` + - Click `Save` + - Configure the UDS Client Policy + - Go to `Realm Settings` > `Client Policies` > `Profiles` + - Click `Create Client Profile` + - Name: `uds-client-profile` + - Description: `UDS Client Profile` + - Click `Save` + - Click `Add Executor` + - Select `uds-operator-permissions` + - Click `Add` + - Go to `Realm Settings` > `Client Policies` > `Policies` + - Click `Create client policy` + - Name: `uds-client-policy` + - Description: `UDS Client Policy` + - Click `Add condition` + - Select `any-client` + - Click `Add` + - Click `Add client profile` + - Select `uds-client-profile` + - Click `Add` (there is a glitch in the UI where it seems all the profiles are selected, but only the selected one is actually chosen) + - Configure the Client Credentials Authentication Flow + - Go to `Authentication` > `Flows` + - Click `clients` + - Click `Actions` > `Duplicate` + - Name: `UDS Client Credentials` + - Description `UDS Client Credentials` + - Click `Duplicate` + - Go to `Authentication` > `UDS Client Credentials` + - Click `Add Step` + - Select `Client Id and Kubernetes Secret` + - Click `Add` + - Select `Requirement` and set it to `Alternative` + - Go to `Authentication`, select three dots on the right side of the panel for `UDS Client Credentials` and select `Bind flows` + - Select `Client authentication flow` + - Click `Save` + - Verify that everything is configured correctly + - Deploy a new package or update the existing one + - Check UDS Operator logs and verify if there are no errors + - Use `uds zarf tools kubectl logs deploy/pepr-uds-core-watcher -n pepr-system | grep "Client Credentials Keycloak Client is available"` command to verify if the UDS Operator uses the Client Credentials flow. After introducing the above changes, please ensure all Packages are reconciled correctly and there are no errors. If for some reason you see the UDS Operator throwing errors with `The Client doesn't have the created-by=uds-operator attribute. Rejecting request`, you need to disable the `UDS Client Policy` and give it a bit more time to process all the Packages. --- +In uds-identity-config version 0.11.0 we incorporated some big changes around MFA. +- Previous versions didn't allow for MFA on the X509 Authentication flow. Now that can be configured to required additional factors of authentication. By default this is disabled and will need to be enabled. +- Additionally, we've added support of WebAuthn MFA. This can assume many different forms such as biometrics, passkeys, etc. This also is disabled by default and is only used as an MFA option. + +If wanting to configure the MFA everywhere with both OTP and WebAuthn options, the following steps will help to manually configure these options on an upgrade: +1. There is a [new theme for webauthn-authentication](https://github.com/defenseunicorns/uds-identity-config/blob/main/src/theme/login/webauthn-authenticate.ftl) that conditionally removes the register button. This is removed because we assume that since you are doing MFA you have already provided enough details to be identified by Keycloak and don't need to register. +2. The Authentication `Required Actions` have a few changes as well: + - Click `Authentication` tab from left side menu + - Click `Required Actions` tab from Authentication page menu + - Enable the following `Required Actions`, only toggle the `Enabled` **DO NOT TOGGLE** `Set as default action`: + - `Configure OTP` + - `Webauthn Register` + - Disable the `WebAuthn Register Passwordless`, make sure this is **not** the `WebAuthn Register` option ( this one should be enabled ) +3. The `UDS Authentication` authentication flow has undergone significant changes. + - Click `Authentication` tab from left side menu + - Click `UDS Authentication` flow option + - **This can be very dangerous to modify so make sure you know what you're doing before making changes here** + - In the `Authentication` top level sub-flow of the `UDS Authentication` flow + - Click the `+` icon and add a `sub-flow` + - Name that sub-flow `X509 Authentication` + - Drag that new sub-flow up and drop below the `Cookie` and the `IDP Redirector` step + - Set the flow to `Alternative` + - in the new `X509 Authentication` sub-flow select the `+` icon and add a sub-flow called `X509 Conditional OTP` + - Set the `X509 Conditional OTP` to `Required` + - Click the `+` and add the `Condition` called `Condition - user configured` + - set this to be `Required` + - Click the `+` and add the step called `OTP Form` + - set this to be `Required` + - Click the `+` and add the step called `WebAuthn Authenticator` + - Drag the existing `X509/Validate Username Form` step into the `X509 Authentication` sub-flow, should be above the `X509 Conditional OTP` + - May have to drag this twice, make sure this is `Required` + +--- + To add an `IDP Redirector` option to the `UDS Authentication`, which enables bypassing the login page and jumping directly to the IDP login when using the `kc_idp_hint` URL parameter, do the following steps: - Click `Authentication` from the left sidebar under `Configure` - Select the `UDS Authentication` auth flow @@ -83,7 +117,7 @@ To add an `IDP Redirector` option to the `UDS Authentication`, which enables byp ## v0.10.0+ -
+
Upgrade Details In uds-identity-config versions 0.10.0+, the version of Keycloak was upgraded to Keycloak 26.1.0. In this release of Keycloak an unmentioned breaking change that added case sensitivity to the Client SAML Mappers. This resulted in breaking SAML Auth flows due to users IDP data not being correctly mapped into applications ( ex. Sonarqube, Gitlab, etc ). Manual steps to fix this issue: @@ -108,7 +142,7 @@ In uds-identity-config versions 0.10.0+, the version of Keycloak was upgraded to ## v0.9.1 to v0.10.0 -
+
Upgrade Details * For running Istio with Ambient Mesh, it is required to add two new entries to the trusted hosts list: `*.pepr-uds-core-watcher.pepr-system.svc.cluster.local` and `*.keycloak.svc.cluster.local`. This is done automatically for new deployments but when upgrading it is required to perform these extra steps: @@ -123,7 +157,7 @@ In uds-identity-config versions 0.10.0+, the version of Keycloak was upgraded to ## v0.5.1 to v0.5.2 -
+
Upgrade Details * An custom Keycloak event logger that replaces the default event logger is [included in this release](https://github.com/defenseunicorns/uds-identity-config/blob/v0.5.2/src/realm.json#L1669), if you wish to enable manually as part of an upgrade do the following (in the `Unicorn Delivery Service` realm): @@ -150,7 +184,7 @@ In uds-identity-config versions 0.10.0+, the version of Keycloak was upgraded to ## v0.5.0 to v0.5.1 -
+
Upgrade Details This version upgrade utilizes built in Keycloak functionality for User Managed Attributes. diff --git a/src/plugin/src/main/java/com/defenseunicorns/uds/keycloak/plugin/RegistrationValidation.java b/src/plugin/src/main/java/com/defenseunicorns/uds/keycloak/plugin/RegistrationValidation.java index a37a2020..57584fb8 100644 --- a/src/plugin/src/main/java/com/defenseunicorns/uds/keycloak/plugin/RegistrationValidation.java +++ b/src/plugin/src/main/java/com/defenseunicorns/uds/keycloak/plugin/RegistrationValidation.java @@ -32,9 +32,15 @@ private static void bindRequiredActions(final UserModel user, final String x509U // Default actions for all users user.addRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL); - if (x509Username == null) { - // This user must configure MFA for their login + // Read the environment variable "X509_MFA_ENABLED" + String x509MFAEnabled = System.getenv("X509_MFA_ENABLED"); + + // Determine whether to add MFA required actions + // If X509_MFA_ENABLED is set to "true", add required actions for every user. + // Otherwise, add them only if x509Username is null (i.e. for non-X509 users). + if ((x509MFAEnabled != null && x509MFAEnabled.equalsIgnoreCase("true")) || x509Username == null) { user.addRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP); + user.addRequiredAction("webauthn-register"); } } diff --git a/src/realm.json b/src/realm.json index 325681a8..edc28f50 100644 --- a/src/realm.json +++ b/src/realm.json @@ -956,8 +956,8 @@ "protocol": "openid-connect", "attributes": { "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${emailScopeConsentText}" + "consent.screen.text": "${emailScopeConsentText}", + "display.on.consent.screen": "true" }, "protocolMappers": [ { @@ -1001,8 +1001,8 @@ "protocol": "openid-connect", "attributes": { "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${profileScopeConsentText}" + "consent.screen.text": "${profileScopeConsentText}", + "display.on.consent.screen": "true" }, "protocolMappers": [ { @@ -1251,8 +1251,8 @@ "protocol": "openid-connect", "attributes": { "include.in.token.scope": "false", - "display.on.consent.screen": "true", - "consent.screen.text": "${rolesScopeConsentText}" + "consent.screen.text": "${rolesScopeConsentText}", + "display.on.consent.screen": "true" }, "protocolMappers": [ { @@ -1617,8 +1617,8 @@ "protocol": "openid-connect", "attributes": { "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${addressScopeConsentText}" + "consent.screen.text": "${addressScopeConsentText}", + "display.on.consent.screen": "true" }, "protocolMappers": [ { @@ -1925,8 +1925,8 @@ ], "allowed-client-scopes": [ "openid", - "bare-groups", "aws-groups", + "bare-groups", "mapper-saml-username-name", "mapper-saml-email-email", "mapper-saml-username-login", @@ -2115,12 +2115,11 @@ "userSetupAllowed": false }, { - "authenticatorConfig": "dod-cac", - "authenticator": "auth-x509-client-username-form", - "authenticatorFlow": false, + "authenticatorFlow": true, "requirement": "ALTERNATIVE", - "priority": 2, - "autheticatorFlow": false, + "priority": 1, + "autheticatorFlow": true, + "flowAlias": "x509 Authentication", "userSetupAllowed": false }, { @@ -2128,7 +2127,7 @@ "requirement": "ALTERNATIVE", "priority": 3, "autheticatorFlow": true, - "flowAlias": "MFA Login", + "flowAlias": "Username/Password Authentication", "userSetupAllowed": false } ] @@ -2194,8 +2193,8 @@ ] }, { - "id": "ae089c5c-0424-4fb7-9768-2346b32bb1b2", - "alias": "Conditional OTP", + "id": "6ba27e4e-b569-4531-857b-2e6a10077f02", + "alias": "Conditional Username/Password 2FA", "description": "", "providerId": "basic-flow", "topLevel": false, @@ -2212,10 +2211,52 @@ { "authenticator": "auth-otp-form", "authenticatorFlow": false, + "requirement": "${OTP_FLOW_ENABLED:REQUIRED}", + "priority": 1, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "webauthn-authenticator", + "authenticatorFlow": false, + "requirement": "${WEBAUTHN_FLOW_ENABLED:REQUIRED}", + "priority": 2, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "ae089c5c-0424-4fb7-9768-2346b32bb1b2", + "alias": "Conditional X509 2FA", + "description": "", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": false, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, "requirement": "REQUIRED", + "priority": 0, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "${OTP_FLOW_ENABLED:REQUIRED}", "priority": 1, "autheticatorFlow": false, "userSetupAllowed": false + }, + { + "authenticator": "webauthn-authenticator", + "authenticatorFlow": false, + "requirement": "${WEBAUTHN_FLOW_ENABLED:REQUIRED}", + "priority": 2, + "autheticatorFlow": false, + "userSetupAllowed": false } ] }, @@ -2271,6 +2312,24 @@ } ] }, + { + "id": "7d53187d-13f4-4ec6-ade0-20b7d88d9aa4", + "alias": "Group Protection Authorization", + "description": "", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": false, + "authenticationExecutions": [ + { + "authenticator": "uds-group-restriction", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 0, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, { "id": "b44188c2-ddf7-4268-a860-b20e32c7fbcf", "alias": "Handle Existing Account", @@ -2299,7 +2358,7 @@ }, { "id": "cdf1be21-4140-4652-9d68-3b60742cc8ad", - "alias": "MFA Login", + "alias": "Username/Password Authentication", "description": "", "providerId": "basic-flow", "topLevel": false, @@ -2323,10 +2382,10 @@ }, { "authenticatorFlow": true, - "requirement": "REQUIRED", + "requirement": "${MFA_FLOW_ENABLED:DISABLED}", "priority": 2, "autheticatorFlow": true, - "flowAlias": "Conditional OTP", + "flowAlias": "Conditional Username/Password 2FA", "userSetupAllowed": false } ] @@ -2377,27 +2436,9 @@ "authenticator": "uds-group-restriction", "authenticatorFlow": false, "requirement": "REQUIRED", - "priority": 1, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "id": "7d53187d-13f4-4ec6-ade0-20b7d88d9aa4", - "alias": "Group Protection Authorization", - "description": "", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": false, - "authenticationExecutions": [ - { - "authenticator": "uds-group-restriction", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 0, - "userSetupAllowed": false, - "autheticatorFlow": false + "priority": 2, + "autheticatorFlow": false, + "userSetupAllowed": false } ] }, @@ -2499,8 +2540,8 @@ "authenticatorFlow": false, "requirement": "REQUIRED", "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false } ] }, @@ -2542,8 +2583,8 @@ "authenticatorFlow": false, "requirement": "REQUIRED", "priority": 40, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false } ] }, @@ -2988,6 +3029,33 @@ "userSetupAllowed": false } ] + }, + { + "id": "2d1047c5-1ecd-40a9-8292-80f5d0cfda68", + "alias": "x509 Authentication", + "description": "", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": false, + "authenticationExecutions": [ + { + "authenticatorConfig": "dod-cac", + "authenticator": "auth-x509-client-username-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 1, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "${X509_MFA_FLOW_ENABLED:DISABLED}", + "priority": 2, + "autheticatorFlow": true, + "flowAlias": "Conditional X509 2FA", + "userSetupAllowed": false + } + ] } ], "authenticatorConfig": [ @@ -3113,7 +3181,7 @@ "alias": "webauthn-register-passwordless", "name": "Webauthn Register Passwordless", "providerId": "webauthn-register-passwordless", - "enabled": true, + "enabled": false, "defaultAction": false, "priority": 1002, "config": {} @@ -3122,7 +3190,7 @@ "alias": "webauthn-register", "name": "Webauthn Register", "providerId": "webauthn-register", - "enabled": true, + "enabled": "${WEBAUTHN_ENABLED:false}", "defaultAction": false, "priority": 1003, "config": {} @@ -3134,6 +3202,7 @@ "resetCredentialsFlow": "UDS Reset Credentials", "clientAuthenticationFlow": "UDS Client Credentials", "dockerAuthenticationFlow": "docker auth", + "firstBrokerLoginFlow": "first broker login", "attributes": { "cibaBackchannelTokenDeliveryMode": "poll", "cibaAuthRequestedUserHint": "login_hint", diff --git a/src/sync.sh b/src/sync.sh index 5c4b2fa0..41e660e9 100644 --- a/src/sync.sh +++ b/src/sync.sh @@ -26,6 +26,8 @@ cp -fv certs/* /opt/keycloak/conf/truststores echo "USERNAME_PASSWORD_AUTH_ENABLED=${USERNAME_PASSWORD_AUTH_ENABLED}" echo "REGISTER_BUTTON_ENABLED=${REGISTER_BUTTON_ENABLED}" echo "REALM_DISABLE_REGISTRATION_FIELDS=${REALM_DISABLE_REGISTRATION_FIELDS:-false}" + echo "WEBAUTHN_ENABLED=${WEBAUTHN_ENABLED}" + echo "X509_MFA_ENABLED=${X509_MFA_ENABLED}" } >> /opt/keycloak/themes/theme/login/theme.properties echo "Sync complete" diff --git a/src/test/cypress/realm.json b/src/test/cypress/realm.json index 18eecb06..cdc0feb1 100644 --- a/src/test/cypress/realm.json +++ b/src/test/cypress/realm.json @@ -998,8 +998,8 @@ "protocol": "openid-connect", "attributes": { "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${emailScopeConsentText}" + "consent.screen.text": "${emailScopeConsentText}", + "display.on.consent.screen": "true" }, "protocolMappers": [ { @@ -1043,8 +1043,8 @@ "protocol": "openid-connect", "attributes": { "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${profileScopeConsentText}" + "consent.screen.text": "${profileScopeConsentText}", + "display.on.consent.screen": "true" }, "protocolMappers": [ { @@ -1293,8 +1293,8 @@ "protocol": "openid-connect", "attributes": { "include.in.token.scope": "false", - "display.on.consent.screen": "true", - "consent.screen.text": "${rolesScopeConsentText}" + "consent.screen.text": "${rolesScopeConsentText}", + "display.on.consent.screen": "true" }, "protocolMappers": [ { @@ -1659,8 +1659,8 @@ "protocol": "openid-connect", "attributes": { "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${addressScopeConsentText}" + "consent.screen.text": "${addressScopeConsentText}", + "display.on.consent.screen": "true" }, "protocolMappers": [ { @@ -1967,8 +1967,8 @@ ], "allowed-client-scopes": [ "openid", - "bare-groups", - "aws-groups" + "aws-groups", + "bare-groups" ] } }, @@ -2148,12 +2148,11 @@ "userSetupAllowed": false }, { - "authenticatorConfig": "dod-cac", - "authenticator": "auth-x509-client-username-form", - "authenticatorFlow": false, + "authenticatorFlow": true, "requirement": "ALTERNATIVE", - "priority": 2, - "autheticatorFlow": false, + "priority": 1, + "autheticatorFlow": true, + "flowAlias": "x509 Authentication", "userSetupAllowed": false }, { @@ -2161,7 +2160,7 @@ "requirement": "ALTERNATIVE", "priority": 3, "autheticatorFlow": true, - "flowAlias": "MFA Login", + "flowAlias": "Username/Password Authentication", "userSetupAllowed": false } ] @@ -2227,8 +2226,8 @@ ] }, { - "id": "ae089c5c-0424-4fb7-9768-2346b32bb1b2", - "alias": "Conditional OTP", + "id": "6ba27e4e-b569-4531-857b-2e6a10077f02", + "alias": "Conditional Username/Password 2FA", "description": "", "providerId": "basic-flow", "topLevel": false, @@ -2245,10 +2244,52 @@ { "authenticator": "auth-otp-form", "authenticatorFlow": false, + "requirement": "${OTP_FLOW_ENABLED:REQUIRED}", + "priority": 1, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "webauthn-authenticator", + "authenticatorFlow": false, + "requirement": "${WEBAUTHN_FLOW_ENABLED:REQUIRED}", + "priority": 2, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "ae089c5c-0424-4fb7-9768-2346b32bb1b2", + "alias": "Conditional X509 2FA", + "description": "", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": false, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, "requirement": "REQUIRED", + "priority": 0, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "${OTP_FLOW_ENABLED:REQUIRED}", "priority": 1, "autheticatorFlow": false, "userSetupAllowed": false + }, + { + "authenticator": "webauthn-authenticator", + "authenticatorFlow": false, + "requirement": "${WEBAUTHN_FLOW_ENABLED:REQUIRED}", + "priority": 2, + "autheticatorFlow": false, + "userSetupAllowed": false } ] }, @@ -2304,6 +2345,24 @@ } ] }, + { + "id": "7d53187d-13f4-4ec6-ade0-20b7d88d9aa4", + "alias": "Group Protection Authorization", + "description": "", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": false, + "authenticationExecutions": [ + { + "authenticator": "uds-group-restriction", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 0, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, { "id": "b44188c2-ddf7-4268-a860-b20e32c7fbcf", "alias": "Handle Existing Account", @@ -2332,7 +2391,7 @@ }, { "id": "cdf1be21-4140-4652-9d68-3b60742cc8ad", - "alias": "MFA Login", + "alias": "Username/Password Authentication", "description": "", "providerId": "basic-flow", "topLevel": false, @@ -2356,10 +2415,10 @@ }, { "authenticatorFlow": true, - "requirement": "DISABLED", + "requirement": "${MFA_FLOW_ENABLED:DISABLED}", "priority": 2, "autheticatorFlow": true, - "flowAlias": "Conditional OTP", + "flowAlias": "Conditional Username/Password 2FA", "userSetupAllowed": false } ] @@ -2411,26 +2470,8 @@ "authenticatorFlow": false, "requirement": "REQUIRED", "priority": 2, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "id": "7d53187d-13f4-4ec6-ade0-20b7d88d9aa4", - "alias": "Group Protection Authorization", - "description": "", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": false, - "authenticationExecutions": [ - { - "authenticator": "uds-group-restriction", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 0, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false } ] }, @@ -2532,8 +2573,8 @@ "authenticatorFlow": false, "requirement": "REQUIRED", "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false } ] }, @@ -2575,8 +2616,8 @@ "authenticatorFlow": false, "requirement": "REQUIRED", "priority": 40, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false } ] }, @@ -3021,6 +3062,33 @@ "userSetupAllowed": false } ] + }, + { + "id": "2d1047c5-1ecd-40a9-8292-80f5d0cfda68", + "alias": "x509 Authentication", + "description": "", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": false, + "authenticationExecutions": [ + { + "authenticatorConfig": "dod-cac", + "authenticator": "auth-x509-client-username-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 1, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "${X509_MFA_FLOW_ENABLED:DISABLED}", + "priority": 2, + "autheticatorFlow": true, + "flowAlias": "Conditional X509 2FA", + "userSetupAllowed": false + } + ] } ], "authenticatorConfig": [ @@ -3146,7 +3214,7 @@ "alias": "webauthn-register-passwordless", "name": "Webauthn Register Passwordless", "providerId": "webauthn-register-passwordless", - "enabled": true, + "enabled": false, "defaultAction": false, "priority": 1002, "config": {} @@ -3155,7 +3223,7 @@ "alias": "webauthn-register", "name": "Webauthn Register", "providerId": "webauthn-register", - "enabled": true, + "enabled": "${WEBAUTHN_ENABLED:false}", "defaultAction": false, "priority": 1003, "config": {} @@ -3167,6 +3235,7 @@ "resetCredentialsFlow": "UDS Reset Credentials", "clientAuthenticationFlow": "UDS Client Credentials", "dockerAuthenticationFlow": "docker auth", + "firstBrokerLoginFlow": "first broker login", "attributes": { "cibaBackchannelTokenDeliveryMode": "poll", "cibaAuthRequestedUserHint": "login_hint", @@ -3219,4 +3288,4 @@ } ] } -} +} \ No newline at end of file diff --git a/src/theme/login/webauthn-authenticate.ftl b/src/theme/login/webauthn-authenticate.ftl new file mode 100644 index 00000000..fca9426e --- /dev/null +++ b/src/theme/login/webauthn-authenticate.ftl @@ -0,0 +1,111 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout displayInfo=(realm.registrationAllowed && !registrationDisabled??); section> + <#if section = "title"> + title + <#elseif section = "header"> + ${kcSanitize(msg("webauthn-login-title"))?no_esc} + <#elseif section = "form"> +
+ + +
+ <#if authenticators??> + + + <#if shouldDisplayAuthenticators?? && shouldDisplayAuthenticators> + <#if authenticators.authenticators?size gt 1> +

+ ${kcSanitize(msg("webauthn-available-authenticators"))?no_esc} +

+ + +
    + <#list authenticators.authenticators as authenticator> +
  • +
    +
    +
    + +
    +
    +
    +
    + ${kcSanitize(msg('${authenticator.label}'))?no_esc} +
    + + <#if authenticator.transports?? && authenticator.transports.displayNameProperties?has_content> +
    + <#list authenticator.transports.displayNameProperties as nameProperty> + ${kcSanitize(msg('${nameProperty!}'))?no_esc} + <#if nameProperty?has_next> + , + + +
    + + +
    + + ${kcSanitize(msg('webauthn-createdAt-label'))?no_esc} + + + ${kcSanitize(authenticator.createdAt)?no_esc} + +
    +
    +
    +
    +
  • + +
+ + + +
+ +
+
+
+ + + + <#elseif section = "info" && properties["WEBAUTHN_ENABLED"] == "false"> + <#if realm.registrationAllowed && !registrationDisabled??> +
+ ${msg("noAccount")} ${msg("doRegister")} +
+ + + diff --git a/src/theme/login/webauthn-register.ftl b/src/theme/login/webauthn-register.ftl new file mode 100644 index 00000000..72d234e1 --- /dev/null +++ b/src/theme/login/webauthn-register.ftl @@ -0,0 +1,74 @@ +<#import "template.ftl" as layout> +<#import "password-commons.ftl" as passwordCommons> + +<@layout.registrationLayout; section> + <#if section = "title"> + title + <#elseif section = "header"> + + ${kcSanitize(msg("webauthn-registration-title"))?no_esc} + <#elseif section = "form"> + +

+ ${kcSanitize(msg("webauthn-registration-title"))?no_esc} +

+

+ Follow your browser’s prompts to register your security key and complete setup. +

+

+ Make sure your device is ready and connected. +

+ +
+
+ + + + + + + <@passwordCommons.logoutOtherSessions/> +
+
+ + + + + + <#if !isSetRetry?has_content && isAppInitiatedAction?has_content> +
+ +
+ + + + \ No newline at end of file