Keycloak 15698 (#47)
* Rewords first 3 chapters * Rewrites flows module * Post kerberos rewording * x509 changes * Pre proof read * post visual review * post ccutil changes * Removing apostrophies * Post feedback changes * Post feedback rewording changes * Another minor change
This commit is contained in:
parent
824bceaf3e
commit
ba807279bd
32 changed files with 723 additions and 649 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -56,3 +56,5 @@ html
|
|||
# vim
|
||||
######
|
||||
*.swp
|
||||
|
||||
.vale.ini
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
|
||||
== Authentication
|
||||
|
||||
There are a few features you should be aware of when configuring authentication for your realm. Many organizations
|
||||
have strict password and OTP policies that you can enforce via settings in the Admin Console. You may or may not
|
||||
want to require different credential types for authentication. You may want to give users the option to login via
|
||||
Kerberos or disable or enable various built-in credential types. This chapter covers all of these topics.
|
||||
This chapter covers several authentication topics. These topics include:
|
||||
|
||||
* Enforcing strict password and One Time Password (OTP) policies.
|
||||
* Managing different credential types.
|
||||
* Logging in with Kerberos.
|
||||
* Disabling and enabling built-in credential types.
|
||||
|
|
|
@ -2,197 +2,227 @@
|
|||
|
||||
=== Authentication Flows
|
||||
|
||||
An _authentication flow_ is a container for all authentications, screens, and actions that must happen during login, registration, and other
|
||||
{project_name} workflows.
|
||||
If you go to the admin console `Authentication` left menu item and go to the `Flows` tab, you can view all the defined flows
|
||||
in the system and what actions and checks each flow requires.
|
||||
An _authentication flow_ is a container of authentications, screens, and actions, during log in, registration, and other {project_name} workflows.
|
||||
To view all the flows, actions, and checks, each flow requires:
|
||||
|
||||
.Procedure
|
||||
. Click *Authentication* in the menu.
|
||||
. Click the *Flows* tab.
|
||||
|
||||
==== Built-in flows
|
||||
|
||||
{project_name} comes with a certain number of built-in flows. These flows cannot be modified, but the requirements can be modified to
|
||||
suit your needs.
|
||||
{project_name} has several built-in flows. You cannot modify these flows, but you can alter the flow's requirements to suit your needs.
|
||||
|
||||
This section does a walk-through of the built-in browser login flow. In the
|
||||
left drop-down list select `browser` to come to the screen shown below:
|
||||
In the drop-down list, select *browser* to display the Browser Flow screen.
|
||||
|
||||
.Browser Flow
|
||||
image:{project_images}/browser-flow.png[]
|
||||
image:{project_images}/browser-flow.png[Browser Flow]
|
||||
|
||||
If you hover over the tooltip (the tiny question mark) to the right of the flow selection list, this will describe what the
|
||||
flow is and does.
|
||||
Hover over the question-mark tooltip of the drop-down list to view a description of the flow. Two sections exist.
|
||||
|
||||
The `Auth Type` column is the name of authentication or action that will be executed. If an authentication is indented
|
||||
this means it is in a sub-flow and may or may not be executed depending on the behavior of its parent. The `Requirement`
|
||||
column is a set of radio buttons which define whether or not the action will execute. Let's describe what each radio
|
||||
button means in this context.
|
||||
===== Auth type
|
||||
The name of the authentication or the action to execute. If an authentication is indented, it is in a sub-flow. It may or may not be executed, depending on the behavior of its parent.
|
||||
|
||||
. Cookie
|
||||
+
|
||||
The first time a user logs in successfully, {project_name} sets a session cookie. If the cookie is already set, this authentication type is successful. Since the cookie provider returned success and each execution at this level of the flow is _alternative_, {project_name} does not perform any other execution. This results in a successful login.
|
||||
|
||||
. Kerberos
|
||||
+
|
||||
This authenticator is disabled by default and is skipped during the Browser Flow.
|
||||
|
||||
. Identity Provider Redirector
|
||||
+
|
||||
This action is configured through the *Actions* > *Config* link. It redirects to another IdP for <<_identity_broker, identity brokering>>.
|
||||
|
||||
. Forms
|
||||
+
|
||||
Since this sub-flow is marked as _alternative_, it will not be executed if the *Cookie* authentication type passed. This sub-flow contains an additional authentication type that needs to be executed. {project_name} loads the executions for this sub-flow and processes them.
|
||||
|
||||
The first execution is the *Username Password Form*, an authentication type that renders the username and password page. It is marked as _required_, so the user must enter a valid username and password.
|
||||
|
||||
The second execution is the *Browser - Conditional OTP* sub-flow. This sub-flow is _conditional_ and executes depending on the result of the *Condition - User Configured* execution. If the result is true, {project_name} loads the executions for this sub-flow and processes them.
|
||||
|
||||
The next execution is the *Condition - User Configured* authentication. This authentication checks if {project_name} has configured other executions in the flow for the user. The *Browser - Conditional OTP* sub-flow executes only when the user has a configured OTP credential.
|
||||
|
||||
The final execution is the *OTP Form*. {project_name} marks this execution as _required_ but it runs only when the user has an OTP credential set up because of the setup in the _conditional_ sub-flow. If not, the user does not see an OTP form.
|
||||
|
||||
===== Requirement
|
||||
A set of radio buttons that control the execution of an action executes.
|
||||
|
||||
[[_execution-requirements]]
|
||||
===== Execution requirements
|
||||
====== Required
|
||||
|
||||
Required::
|
||||
For a flow to be evaluated as successful, all required elements in the flow must evaluate as successful. This means that all _Required_ elements in the flow
|
||||
must be sequentially executed, from top to bottom, unless one of the elements causes the flow to fail. However, this is only true for the current flow.
|
||||
Any _Required_ element within a sub-flow is only processed if that sub-flow is entered.
|
||||
Alternative::
|
||||
When a flow contains only _Alternative_ elements, only a single element must evaluate as successful for the flow to evaluate as successful.
|
||||
Because the _Required_ flow elements within a flow are sufficient to mark a flow as successful, any _Alternative_ flow element within a flow
|
||||
that contains _Required_ flow elements will never be executed. In this case, they are functionally _Disabled_.
|
||||
Disabled::
|
||||
Any _Disabled_ element is not evaluated and does not count to mark a flow as successful.
|
||||
Conditional::
|
||||
This requirement type can only be set on sub-flows. A _Conditional_ sub-flow can contain a "Condition" execution. These "Condition" executions must evaluate as
|
||||
logical statements. If all "Condition" executions evaluate as _true_ then the _Conditional_ sub-flow acts as _Required_. If not, the _Conditional_ sub-flow
|
||||
acts as _Disabled_. If no "Condition" execution is set, the _Conditional_ sub-flow acts as _Disabled_. If a flow contains "Condition" executions and is not set to
|
||||
_Conditional_, the "Condition" executions are not evaluated, and can be considered functionally _Disabled_.
|
||||
All _Required_ elements in the flow must be successfully sequentially executed. The flow terminates if a required element fails.
|
||||
|
||||
This is better described in an example. Let's walk through the `browser` authentication flow.
|
||||
====== Alternative
|
||||
|
||||
. The first authentication type is `Cookie`. When a user successfully logs in for the first time, a session cookie is set.
|
||||
If this cookie has already been set, then this authentication type is successful. In this case,
|
||||
since the cookie provider returned success and each execution at this level of the flow is _alternative_, no other execution is executed and this results in a successful login.
|
||||
. The second execution of the flow looks at the `Kerberos` execution. This authenticator is disabled by default and will be skipped.
|
||||
. The third execution is the `Identity Provider Redirector`. It can be configured through the `Actions` > `Config` link to automatically redirect to another IdP for <<_identity_broker, identity brokering>>.
|
||||
. The next execution is a sub-flow called `Forms`. Since this sub-flow is marked as _alternative_ it will not be executed if the `Cookie` authentication type passed.
|
||||
This sub-flow contains additional authentication type that needs to be executed.
|
||||
The executions for this sub-flow are loaded and the same processing logic occurs.
|
||||
. The first execution in the Forms sub-flow is the `Username Password Form`. This authentication type renders the username and password page.
|
||||
It is marked as _required_ so the user must enter in a valid username and password.
|
||||
. The second execution in the Forms sub-flow is a new sub-flow: the `Browser - Conditional OTP` sub-flow. Since this sub-flow is _conditional_, whether it is executed depends on the result of the
|
||||
evaluation of the `Condition - User Configured` execution. If it is, the executions for this sub-flow are loaded and the same processing logic occurs
|
||||
. The next execution is the `Condition - User Configured`. This checks if the other executions in the flow are configured for the user.
|
||||
Meaning that the `Browser - Conditional OTP` sub-flow will only be executed if the user has an OTP credential configured.
|
||||
. The final execution is the `OTP Form`. This is marked as _required_, but because of the setup in the _conditional_ subflow, it will only be run if the user
|
||||
has an OTP credential set up. If he doesn't, the user will not see an OTP form.
|
||||
Only a single element must successfully execute for the flow to evaluate as successful. Because the _Required_ flow elements are sufficient to mark a flow as successful, any _Alternative_ flow element within a flow containing _Required_ flow elements will not execute.
|
||||
|
||||
====== Disabled
|
||||
|
||||
The element does not count to mark a flow as successful.
|
||||
|
||||
====== Conditional
|
||||
|
||||
This requirement type is only set on sub-flows.
|
||||
|
||||
* A _Conditional_ sub-flow contains executions. These executions must evaluate to logical statements.
|
||||
* If all executions evaluate as _true_, the _Conditional_ sub-flow acts as _Required_.
|
||||
* If all executions evaluate as _false_, the _Conditional_ sub-flow acts as _Disabled_.
|
||||
* If you do not set an execution, the _Conditional_ sub-flow acts as _Disabled_.
|
||||
* If a flow contains executions and the flow is not set to _Conditional_, {project_name} does not evaluate the executions, and the executions are considered functionally _Disabled_.
|
||||
|
||||
==== Creating flows
|
||||
|
||||
This section explains in greater depth how flows work, and how to create your own flows. Note that there are important functionality and security
|
||||
considerations when designing your own flow. A badly created flow could either let no one log in, let users in with less verification than you would
|
||||
like, or simply result in an error.
|
||||
Important functionality and security considerations apply when you design a flow.
|
||||
|
||||
To create a flow, you can either:
|
||||
To create a flow, perform the following:
|
||||
|
||||
. Copy and then modify an existing flow. To do this select an existing flow (for example the `Browser` flow), and press the `Copy` button.
|
||||
This will then ask you to set a name for the new flow, before creating it.
|
||||
. Create a new flow from scratch. To do this press the `New` button. Since this is the more general case, we will use this for our example.
|
||||
.Procedure
|
||||
. Click *Authentication* in the menu.
|
||||
. Click *New*.
|
||||
|
||||
When creating a new flow, you will have to create a top level flow
|
||||
[NOTE]
|
||||
====
|
||||
You can copy and then modify an existing flow. Select a flow, click *Copy*, and enter a name for the new flow.
|
||||
====
|
||||
|
||||
.Create a top level flow
|
||||
image:{project_images}/Create-top-level-flow.png[]
|
||||
|
||||
With the following options:
|
||||
When creating a new flow, you must create a top-level flow first with the following options:
|
||||
|
||||
Alias::
|
||||
The name of the flow.
|
||||
Description::
|
||||
The description you can set to the flow.
|
||||
Top Level Flow Type::
|
||||
The type of flow. The type `client` is used only for the authentication of clients (applications). For all other cases choose `generic`.
|
||||
Top-Level Flow Type::
|
||||
The type of flow. The type *client* is used only for the authentication of clients (applications). For all other cases, choose *generic*.
|
||||
|
||||
Once the flow is created, in addition to the `New` and `Copy` buttons, you now have, `Delete`, `Add execution` and `Add flow`.
|
||||
.Create a top-level flow
|
||||
image:{project_images}/Create-top-level-flow.png[Top Level Flow]
|
||||
|
||||
When {project_name} has created the flow, {project_name} displays the *Delete*, *Add execution*, and *Add flow* buttons.
|
||||
|
||||
.An empty new flow
|
||||
image:{project_images}/New-flow.png[]
|
||||
image:{project_images}/New-flow.png[New Flow]
|
||||
|
||||
What a flow finally does is determined by the structure of the flow and sub-flows, the executions in those flows, and the requirements set on the
|
||||
sub-flows and the executions.
|
||||
Three factors determine the behavior of flows and sub-flows.
|
||||
|
||||
Executions can be added with the `Add execution` button. Executions can have a wide variety of actions, from sending a reset email to validating an OTP. If you hover over the
|
||||
tooltip (the tiny question mark) next to `Provider`, this will describe what the execution does.
|
||||
* The structure of the flow and sub-flows.
|
||||
* The executions within the flows
|
||||
* The requirements set within the sub-flows and the executions.
|
||||
|
||||
Executions have a wide variety of actions, from sending a reset email to validating an OTP. Add executions with the *Add execution* button. Hover over the question mark next to *Provider*, to see a description of the execution.
|
||||
|
||||
.Adding an authentication execution
|
||||
image:{project_images}/Create-authentication-execution.png[]
|
||||
image:{project_images}/Create-authentication-execution.png[Adding an Authentication Execution]
|
||||
|
||||
These can be divided into _automatic executions_ and _interactive executions_. _Automatic executions_ are similar to the `Cookie` execution, and will automatically
|
||||
perform their action when they are encountered in the flow. _Interactive executions_ will halt the flow, usually to get some user input. Executions that execute
|
||||
successfully will get the _success_ status. This is important, because this is part of whether a flow is successful or not. For example, an empty `Browser` flow
|
||||
would not allow anyone to log in. For that it would need at least one execution that successfully evaluates, for example a `Username Password Form` that is correctly
|
||||
filled and submitted.
|
||||
Two types of executions exist, _automatic executions_ and _interactive executions_. _Automatic executions_ are similar to the *Cookie* execution and will automatically
|
||||
perform their action in the flow. _Interactive executions_ halt the flow to get input. Executions executing successfully set their status to _success_. For a flow to complete, it needs at least one execution with a status of _success_.
|
||||
|
||||
Sub-flows can be added in top level flow with the `Add flow` button, which opens a `Create Execution Flow` page that is very similar to the `Create Top Level Form`
|
||||
page. The only difference is that the `Flow Type` can be either `generic` (like before), or `form`. The `form` type is used to construct a sub-flow that generates
|
||||
a single form for the user, like what is done for the built-in `Registration` flow. Sub-flows are a special type of execution that evaluate as successful
|
||||
depending on how the executions they contain evaluate (and this includes the evaluation of their contained sub-flows). And the logic of this evaluation
|
||||
depends on the Requirement of each execution and sub-flow.
|
||||
You can add sub-flows to top-level flows with the *Add flow* button. The *Add flow* button displays the *Create Execution Flow* page. This page is similar to the *Create Top Level Form* page. The difference is that the *Flow Type* can be *generic* (default) or *form*. The *form* type constructs a sub-flow that generates a form for the user, similar to the built-in *Registration* flow.
|
||||
Sub-flows success depends on how their executions evaluate, including their contained sub-flows. See the <<_execution-requirements, execution requirements section>> for an in-depth explanation of how sub-flows work.
|
||||
|
||||
Fully understanding this requires a more complete explanation of how requirements work when evaluating a flow, and this also applies to sub-flows.
|
||||
Refer to the <<_execution-requirements, execution requirements section>> above for more details.
|
||||
[NOTE]
|
||||
====
|
||||
After adding an execution, check the requirement has the correct value.
|
||||
====
|
||||
|
||||
Note that after adding an execution, you should check that the Requirement is set to the correct value. Even if there is only a single possible Requirement, it
|
||||
can happen that it is not set.
|
||||
All elements in a flow have a *Delete* option in the *Actions* menu. This action removes the element from the flow.
|
||||
Executions have a *Config* menu option to configure the execution. It is also possible to add executions and sub-flows to sub-flows with the *Add execution* and *Add flow* menu options.
|
||||
|
||||
When constructing a flow, all elements added to the flow will have an `Actions` menu on the right-hand side. All elements added to the flow have a `Delete`
|
||||
option in this menu to remove it from the flow. Executions can contain a `Config` menu option to configure the execution, as is the case for the
|
||||
`Identity Provider Redirector`. Sub-flows can also have executions and sub-flows added to them, with their `Add execution` and `Add flow` menu options.
|
||||
|
||||
Finally, since the order of execution is important, you can move executions and sub-flows up and down within their respective flows with the up and down buttons
|
||||
that are set to left of their name.
|
||||
Since the order of execution is important, you can move executions and sub-flows up and down within their flows using the up and down buttons beside their names.
|
||||
|
||||
==== Creating a password-less browser login flow
|
||||
|
||||
To illustrate the creation of flows, this section describes the creation of a more advanced browser login flow. The purpose of this flow is to allow a
|
||||
user to choose between logging in in a password-less manner using <<_webauthn, WebAuthn>>, and a two-factor authentication with password and OTP.
|
||||
The flow to create is similar to the standard browser login, but diverges when reaching the username selection. Instead of copying the flow however, you'll be
|
||||
creating the flow from the start:
|
||||
|
||||
* Select a realm, click on Authentication link
|
||||
* Select "new", and give the new flow a distinctive Alias, i.e. "Browser Password-less"
|
||||
* Select "Add execution", and using the drop-down select "Cookie". After pressing "Save", set its Requirement to _Alternative_.
|
||||
* Select "Add execution", and using the drop-down select "Kerberos".
|
||||
* Select "Add execution", and using the drop-down select "Identity Provider Redirector". After pressing "Save", set its Requirement to _Alternative_.
|
||||
* Select "Add flow", and choose an representative Alias, e.g. "Forms". After pressing "Save", set its Requirement to _Alternative_.
|
||||
To illustrate the creation of flows, this section describes creating an advanced browser login flow. The purpose of this flow is to allow a user a choice between logging in using a password-less manner with <<_webauthn, WebAuthn>>, or two-factor authentication with a password and OTP.
|
||||
|
||||
.Procedure
|
||||
. Click *Authentication* in the menu.
|
||||
. Click the *Flows* tab.
|
||||
. Click *New*.
|
||||
. Enter `Browser Password-less` as an alias.
|
||||
. Click *Save*.
|
||||
. Click *Add execution*.
|
||||
. Select *Cookie* from the drop-down list.
|
||||
. Click *Save*.
|
||||
. Click *Alternative* for the *Cookie* authentication type to set its requirement to alternative.
|
||||
. Click *Add execution*.
|
||||
. Select *Kerberos* from the drop-down list.
|
||||
. Click *Add execution*.
|
||||
. Select *Identity Provider Redirector* from the drop-down list.
|
||||
. Click *Save*.
|
||||
. Click *Alternative* for the *Identity Provider Redirector* authentication type to set its requirement to alternative.
|
||||
. Click *Add flow*.
|
||||
. Enter *Forms* as an alias.
|
||||
. Click *Save*.
|
||||
. Click *Alternative* for the *Forms* authentication type to set its requirement to alternative.
|
||||
+
|
||||
.The common part with the browser flow
|
||||
image:images/Passwordless-browser-login-common.png[]
|
||||
+
|
||||
. Click *Actions for the *Forms* execution.
|
||||
. Select *Add execution*.
|
||||
. Select *Username Form* from the drop-down list.
|
||||
. Click *Save*.
|
||||
. Click *Required* for the *Username Form* authentication type to set its requirement to required.
|
||||
|
||||
* Using the `Actions` menu on the right-hand side of the "Forms" subflow, select "Add execution". Using the drop-down select
|
||||
"Username Form". After pressing "Save", set its Requirement to _Required_.
|
||||
At this stage, the form requires a username but no password. We must enable password authentication to avoid security risks.
|
||||
|
||||
The Username form is similar to "Browser" flow's Username Password Form, but only asks for a username, allowing a user to perform a password-less login.
|
||||
However, note that this inevitably allows a user enumeration attack on your {project_name} server. This is an unavoidable security risk for the convenience,
|
||||
so the flow should make sure that an attacker cannot just have to guess a password to be able to enter.
|
||||
. Click *Actions* for the *Forms* sub-flow.
|
||||
. Click *Add flow*.
|
||||
. Enter `Authentication` as an alias.
|
||||
. Click *Save*.
|
||||
. Click *Required* for the *Authentication* authentication type to set its requirement to required.
|
||||
. Click *Actions* for the *Authentication* sub-flow.
|
||||
. Click *Add execution*.
|
||||
. Select *Webauthn Passwordless Authenticator* from the drop-down list.
|
||||
. Click *Save*.
|
||||
. Click *Alternative* for the *Webauthn Passwordless Authenticator* authentication type to set its requirement to alternative.
|
||||
. Click *Actions* for the *Authentication* sub-flow.
|
||||
. Click *Add flow*.
|
||||
. Enter `Password with OTP` as an alias.
|
||||
. Click *Save*.
|
||||
. Click *Alternative* for the *Password with OTP* authentication type to set its requirement to alternative.
|
||||
. Click *Actions* for the *Password with OTP* sub-flow.
|
||||
. Click *Add execution*.
|
||||
. Select *Password Form* from the drop-down list.
|
||||
. Click *Save*.
|
||||
. Click *Required* for the *Password Form* authentication type to set its requirement to required.
|
||||
. Click *Actions* for the *Password with OTP* sub-flow.
|
||||
. Click *Add execution*.
|
||||
. Select *OTP Form* from the drop-down list.
|
||||
. Click *Save*.
|
||||
. Click *Required* for the *OTP Form* authentication type to set its requirement to required.
|
||||
|
||||
* Using the `Actions` menu on the right-hand side of the "Forms" subflow, select "Add flow". Choose an representative Alias, e.g. "Authentication".
|
||||
After pressing "Save", set its Requirement to _Required_.
|
||||
* Using the `Actions` menu on the right-hand side of the "Authentication" subflow, select "Add execution". Using the drop-down select
|
||||
"Webauthn Passwordless Authenticator". After pressing "Save", set its Requirement to _Alternative_.
|
||||
* Using the `Actions` menu on the right-hand side of the "Authentication" subflow, select "Add flow". Choose an representative Alias, e.g. "Password with OTP".
|
||||
After pressing "Save", set its Requirement to _Alternative_.
|
||||
* Using the `Actions` menu on the right-hand side of the "Password with OTP" subflow, select "Add execution". Using the drop-down select
|
||||
"Password Form". After pressing "Save", set its Requirement to Required.
|
||||
* Using the `Actions` menu on the right-hand side of the "Password with OTP" subflow, select "Add execution". Using the drop-down select
|
||||
"OTP Form". After pressing "Save", set its Requirement to Required.
|
||||
* In the "Bindings" menu, change the browser flow from "Browser" to "Browser Password-less"
|
||||
Finally, change the bindings.
|
||||
|
||||
The final flow that is produced is the following:
|
||||
. Click the *Bindings* tab.
|
||||
. Click the *Browser Flow* drop-down list.
|
||||
. Select *Browser Password-less* from the drop-down list.
|
||||
. Click *Save*.
|
||||
|
||||
.A password-less browser login
|
||||
image:images/Passwordless-browser-login.png[]
|
||||
|
||||
After entering the username, the way this flow works is the following:
|
||||
After entering the username, the flow works as follows:
|
||||
|
||||
* If the user has any WebAuthn passwordless credentials recorded, that user will be able to use any of them to log in directly. This is the password-less login.
|
||||
The user can instead select "Password with OTP". The user can do this because the "WebAuthn Passwordless" execution and the "Password with OTP"
|
||||
flow are set to _Alternative_. Were they set to _Required_ the user would have to enter WebAuthn, password, and OTP.
|
||||
* If the user selects `Try another way` link on the screen with "WebAuthn passwordless" authentication, the user can choose between "Password" and
|
||||
"Security Key" (WebAuthn passwordless). When selecting the password, the user will need to continue and log in with the assigned OTP as well.
|
||||
If the user has no WebAuthn credentials, he will have to first enter his
|
||||
password, and then his OTP. If the user has no OTP credential, he will be asked to record one.
|
||||
If users have WebAuthn passwordless credentials recorded, they can use these credentials to log in directly. This is the password-less login. The user can also select *Password with OTP* because the `WebAuthn Passwordless` execution and the `Password with OTP` flow are set to *Alternative*. If they are set to *Required*, the user has to enter WebAuthn, password, and OTP.
|
||||
|
||||
It is important to note that since the WebAuthn Passwordless execution is set to _Alternative_ instead of _Required_, this flow will never ask the user to register a WebAuthn credential. For a user
|
||||
to have a Webauthn credential, that user must have a required action added by an administrator. This is done first by making sure that the `Webauthn Register Passwordless`
|
||||
required action is enabled in the realm (see the <<_webauthn,WebAuthn>> documentation), and then by setting the required action by using the `Credential Reset` part of a
|
||||
user's xref:ref-user-credentials_{context}[Credentials] management menu.
|
||||
If the user selects the *Try another way* link with `WebAuthn passwordless` authentication, the user can choose between `Password` and `Security Key` (WebAuthn passwordless). When selecting the password, the user will need to continue and log in with the assigned OTP. If the user has no WebAuthn credentials, the user must enter the password and then the OTP. If the user has no OTP credential, they will be asked to record one.
|
||||
|
||||
Creating a more advanced flow such as this one can have some subtle side effects. For example, if you were to enable the ability to reset the password
|
||||
for the user, then this would be accessible from the password form. In the default "Reset Credentials" flow, the user has to enter his username. Since
|
||||
he's already entered his username earlier in the "Browser Password-less" flow, this would be unnecessary for {project_name}, and a sub-optimal in terms of user
|
||||
experience. To correct this, you could:
|
||||
[NOTE]
|
||||
====
|
||||
Since the WebAuthn Passwordless execution is set to *Alternative* rather than *Required*, this flow will never ask the user to register a WebAuthn credential. For a user to have a Webauthn credential, an administrator must add a required action to the user. Do this by:
|
||||
|
||||
* Copy the "Reset Credentials" flow, setting its name to, for example "Reset Credentials for password-less"
|
||||
* Use the `Actions` menu on the right-hand side of the "Choose user" execution, select "Delete"
|
||||
* In the "Bindings" menu, change the reset credential flow from "Reset Credentials" to "Reset Credentials for password-less"
|
||||
. Enabling the *Webauthn Register Passwordless* required action in the realm (see the <<_webauthn,WebAuthn>> documentation).
|
||||
. Setting the required action using the *Credential Reset* part of a user's xref:ref-user-credentials_{context}[Credentials] management menu.
|
||||
|
||||
Creating an advanced flow such as this can have side effects. For example, if you enable the ability to reset the password for users, this would be accessible from the password form. In the default `Reset Credentials` flow, users must enter their username. Since the user has already entered a username earlier in the `Browser Password-less` flow, this action is unnecessary for {project_name} and sub-optimal for user experience. To correct this problem, you can:
|
||||
|
||||
* Copy the `Reset Credentials` flow. Set its name to `Reset Credentials for password-less`, for example.
|
||||
* Select *Delete* in the *Actions* menu of the *Choose user* execution.
|
||||
* In the *Bindings* menu, change the reset credential flow from *Reset Credentials* to *Reset Credentials for password-less*
|
||||
====
|
||||
|
||||
ifeval::[{project_community}==true]
|
||||
=== Script Authenticator
|
||||
|
|
|
@ -1,73 +1,68 @@
|
|||
|
||||
[[_kerberos]]
|
||||
|
||||
=== Kerberos
|
||||
|
||||
{project_name} supports login with a Kerberos ticket through the SPNEGO protocol.
|
||||
SPNEGO (Simple and Protected GSSAPI Negotiation Mechanism) is used to authenticate transparently through the web browser after the user
|
||||
has been authenticated when logging-in his session.
|
||||
For non-web cases or when ticket is not available during login, {project_name} also supports login with Kerberos username/password.
|
||||
{project_name} supports login with a Kerberos ticket through the Simple and Protected GSSAPI Negotiation Mechanism (SPNEGO) protocol. SPNEGO authenticates transparently through the web browser after the user authenticates the session. For non-web cases, or when a ticket is not available during login, {project_name} supports login with Kerberos username and password.
|
||||
|
||||
A typical use case for web authentication is the following:
|
||||
|
||||
. User logs into his desktop (Such as a Windows machine in Active Directory domain or Linux machine with Kerberos integration enabled).
|
||||
. User then uses his browser (IE/Firefox/Chrome) to access a web application secured by {project_name}.
|
||||
. Application redirects to {project_name} login.
|
||||
. {project_name} renders HTML login screen together with status 401 and HTTP header `WWW-Authenticate: Negotiate`
|
||||
. In case that the browser has Kerberos ticket from desktop login, it transfers the desktop sign on information to the {project_name}
|
||||
in header `Authorization: Negotiate 'spnego-token'` . Otherwise it just displays the login screen.
|
||||
. {project_name} validates token from the browser and authenticates the user.
|
||||
It provisions user data from LDAP (in case of LDAPFederationProvider with Kerberos authentication support) or let user
|
||||
to update his profile and prefill data (in case of KerberosFederationProvider).
|
||||
. {project_name} returns back to the application.
|
||||
Communication between {project_name} and application happens through OpenID Connect or SAML messages.
|
||||
The fact that {project_name} was authenticated through Kerberos is hidden from the application.
|
||||
So {project_name} acts as broker to Kerberos/SPNEGO login.
|
||||
. The user logs into the desktop.
|
||||
. The user accesses a web application secured by {project_name} using a browser.
|
||||
. The application redirects to {project_name} login.
|
||||
. {project_name} renders the HTML login screen with status 401 and HTTP header `WWW-Authenticate: Negotiate`
|
||||
. If the browser has a Kerberos ticket from desktop login, the browser transfers the desktop sign-on information to {project_name} in header `Authorization: Negotiate 'spnego-token'`. Otherwise, it displays the standard login screen, and the user enters the login credentials.
|
||||
. {project_name} validates the token from the browser and authenticates the user.
|
||||
. If using LDAPFederationProvider with Kerberos authentication support, {project_name} provisions user data from LDAP. If using KerberosFederationProvider, {project_name} lets the user update the profile and pre-fill login data.
|
||||
. {project_name} returns to the application. {project_name} and the application communicate through OpenID Connect or SAML messages. {project_name} acts as a broker to Kerberos/SPNEGO login. Therefore {project_name} authenticating through Kerberos is hidden from the application.
|
||||
|
||||
For setup there are 3 main parts:
|
||||
Perform the following steps to set up Kerberos authentication:
|
||||
|
||||
. Setup and configuration of Kerberos server (KDC)
|
||||
. Setup and configuration of {project_name} server
|
||||
. Setup and configuration of client machines
|
||||
. The setup and configuration of the Kerberos server (KDC).
|
||||
. The setup and configuration of the {project_name} server.
|
||||
. The setup and configuration of the client machines.
|
||||
|
||||
==== Setup of Kerberos server
|
||||
|
||||
This is platform dependent.
|
||||
Exact steps depend on your OS and the Kerberos vendor you're going to use.
|
||||
Consult Windows Active Directory, MIT Kerberos and your OS documentation for how exactly to setup and configure Kerberos server.
|
||||
The steps to set up a Kerberos server depends on the operating system (OS) and the Kerberos vendor. Consult Windows Active Directory, MIT Kerberos, and your OS documentation for instructions on setting up and configuring a Kerberos server.
|
||||
|
||||
At least you will need to:
|
||||
During setup, perform these steps:
|
||||
|
||||
* Add some user principals to your Kerberos database.
|
||||
You can also integrate your Kerberos with LDAP, which means that user accounts will be provisioned from LDAP server.
|
||||
* Add service principal for "HTTP" service.
|
||||
For example if your {project_name} server will be running on `www.mydomain.org` you may need to add principal `HTTP/www.mydomain.org@MYDOMAIN.ORG`
|
||||
assuming that MYDOMAIN.ORG will be your Kerberos realm.
|
||||
. Add some user principals to your Kerberos database.
|
||||
You can also integrate your Kerberos with LDAP, so user accounts provision from the LDAP server.
|
||||
. Add service principal for "HTTP" service.
|
||||
For example, if the {project_name} server runs on `www.mydomain.org`, add the service principal `HTTP/www.mydomain.org@<kerberos realm>`.
|
||||
+
|
||||
For example on MIT Kerberos you can run a "kadmin" session.
|
||||
If you are on the same machine where is MIT Kerberos, you can simply use the command:
|
||||
On MIT Kerberos, you run a "kadmin" session. On a machine with MIT Kerberos, you can use the command:
|
||||
|
||||
[source]
|
||||
----
|
||||
sudo kadmin.local
|
||||
----
|
||||
Then add HTTP principal and export his key to a keytab file with the commands like:
|
||||
Then, add HTTP principal and export its key to a keytab file with commands such as:
|
||||
|
||||
[source]
|
||||
----
|
||||
|
||||
addprinc -randkey HTTP/www.mydomain.org@MYDOMAIN.ORG
|
||||
ktadd -k /tmp/http.keytab HTTP/www.mydomain.org@MYDOMAIN.ORG
|
||||
----
|
||||
|
||||
The Keytab file `/tmp/http.keytab` will need to be accessible on the host where {project_name} server will be running.
|
||||
Ensure the keytab file `/tmp/http.keytab` is accessible on the host where {project_name} is running.
|
||||
|
||||
==== Setup and configuration of {project_name} server
|
||||
|
||||
You need to install a kerberos client on your machine. This is also platform dependent.
|
||||
If you are on Fedora, Ubuntu or RHEL, you can install the package `freeipa-client`, which contains a Kerberos client and several other utilities.
|
||||
Configure the kerberos client (on Linux it's in file `/etc/krb5.conf` ). You need to put your Kerberos realm and at least configure the HTTP domains your server will be running on.
|
||||
For the example realm MYDOMAIN.ORG you may configure the `domain_realm` section like this:
|
||||
[[_server_setup]]
|
||||
|
||||
Install a Kerberos client on your machine.
|
||||
|
||||
.Procedure
|
||||
. Install a Kerberos client. If your machine runs Fedora, Ubuntu, or RHEL, install the link:https://www.freeipa.org/page/Downloads[freeipa-client] package, containing a Kerberos client and other utilities.
|
||||
. Configure the Kerberos client (on Linux, the configuration settings are in the link:https://web.mit.edu/kerberos/krb5-1.12/doc/admin/conf_files/krb5_conf.html`[/etc/krb5.conf] file ).
|
||||
+
|
||||
Add your Kerberos realm to the configuration and configure the HTTP domains your server runs on.
|
||||
+
|
||||
For example, for the MYDOMAIN.ORG realm, you can configure the `domain_realm` section like this:
|
||||
+
|
||||
[source]
|
||||
----
|
||||
[domain_realm]
|
||||
|
@ -75,87 +70,72 @@ For the example realm MYDOMAIN.ORG you may configure the `domain_realm` section
|
|||
mydomain.org = MYDOMAIN.ORG
|
||||
----
|
||||
|
||||
Next you need to export the keytab file with the HTTP principal and make sure the file is accessible to the process under which {project_name} server is running.
|
||||
For production, it's ideal if it's readable just by this process and not by someone else.
|
||||
For the MIT Kerberos example above, we already exported keytab to `/tmp/http.keytab` . If your KDC and {project_name} are running on same host,
|
||||
you have that file already available.
|
||||
. Export the keytab file with the HTTP principal and ensure the file is accessible to the process running the {project_name} server. For production, ensure that the file is readable by this process only.
|
||||
+
|
||||
For the MIT Kerberos example above, we exported keytab to the `/tmp/http.keytab` file. If your _Key Distribution Centre (KDC)_ and {project_name} run on the same host, the file is already available.
|
||||
|
||||
===== Enable SPNEGO Processing
|
||||
===== Enabling SPNEGO Processing
|
||||
|
||||
{project_name} does not have the SPNEGO protocol support turned on by default. So, you have to go to the <<_authentication-flows, browser flow>>
|
||||
and enable `Kerberos`.
|
||||
By default, {project_name} disables SPNEGO protocol support. To enable it, go to the <<_authentication-flows, browser flow>> and enable *Kerberos*.
|
||||
|
||||
.Browser Flow
|
||||
image:{project_images}/browser-flow.png[]
|
||||
image:{project_images}/browser-flow.png[Browser Flow]
|
||||
|
||||
Switch the `Kerberos` requirement from _disabled_ to either _alternative_ or _required_. _Alternative_ basically means that Kerberos is optional. If
|
||||
the user's browser hasn't been configured to work with SPNEGO/Kerberos, then {project_name} will fall back to the regular login screens. If you set the requirement
|
||||
to _required_ then all users must have Kerberos enabled for their browser.
|
||||
Set the *Kerberos* requirement from _disabled_ to _alternative_ (Kerberos is optional) or _required_ (browser must have Kerberos enabled). If you have not configured the browser to work with SPNEGO or Kerberos, {project_name} falls back to the regular login screen.
|
||||
|
||||
===== Configure Kerberos User Storage Federation Provider
|
||||
|
||||
Now that the SPNEGO protocol is turned on at the authentication server, you'll need to configure how {project_name} interprets the Kerberos ticket.
|
||||
This is done through <<_user-storage-federation,User Storage Federation>>. We have 2 different federation providers with Kerberos authentication support.
|
||||
You must now use <<_user-storage-federation,User Storage Federation>> to configure how {project_name} interprets Kerberos tickets. Two different federation providers exist with Kerberos authentication support.
|
||||
|
||||
If you want to authenticate with Kerberos backed by an LDAP server, you have to first configure the <<_ldap, LDAP Federation Provider>>.
|
||||
If you look at the configuration page for your LDAP provider you'll see a `Kerberos Integration` section.
|
||||
To authenticate with Kerberos backed by an LDAP server, configure the <<_ldap, LDAP Federation Provider>>.
|
||||
|
||||
.Procedure
|
||||
. Go to the configuration page for your LDAP provider.
|
||||
+
|
||||
.LDAP Kerberos Integration
|
||||
image:{project_images}/ldap-kerberos.png[]
|
||||
image:{project_images}/ldap-kerberos.png[LDAP Kerberos Integration]
|
||||
+
|
||||
. Toggle *Allow Kerberos authentication* to *ON*
|
||||
|
||||
Turning on the switch `Allow Kerberos authentication` will make {project_name} use the Kerberos principal to lookup information about the user so that it can
|
||||
be imported into the {project_name} environment.
|
||||
*Allow Kerberos authentication* makes {project_name} use the Kerberos principal access user information so information can import into the {project_name} environment.
|
||||
|
||||
If your Kerberos solution is not backed by an LDAP server, you have to use the `Kerberos` User Storage Federation Provider. Go to the `User Federation`
|
||||
left menu item and select `Kerberos` from the `Add provider` select box.
|
||||
If an LDAP server is not backing up your Kerberos solution, use the *Kerberos* User Storage Federation Provider.
|
||||
|
||||
.Procedure
|
||||
. Click *User Federation* in the menu.
|
||||
. Select *Kerberos* from the *Add provider* select box.
|
||||
+
|
||||
.Kerberos User Storage Provider
|
||||
image:{project_images}/kerberos-provider.png[]
|
||||
image:{project_images}/kerberos-provider.png[Kerberos User Storage Provider]
|
||||
|
||||
This provider parses the Kerberos ticket for simple principal information and does a small import into the local {project_name} database.
|
||||
User profile information like first name, last name, and email are not provisioned.
|
||||
The *Kerberos* provider parses the Kerberos ticket for simple principal information and imports the information into the local {project_name} database.
|
||||
User profile information, such as first name, last name, and email, are not provisioned.
|
||||
|
||||
==== Setup and configuration of client machines
|
||||
|
||||
Clients need to install kerberos client and setup krb5.conf as described above.
|
||||
Additionally they need to enable SPNEGO login support in their browser.
|
||||
See link:https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system-level_authentication_guide/configuring_applications_for_sso[configuring Firefox for Kerberos] if you are using that browser.
|
||||
URI `.mydomain.org` must be allowed in the `network.negotiate-auth.trusted-uris` config option.
|
||||
Client machines must have a Kerberos client and set up the `krb5.conf` as described <<_server_setup, above>>. The client machines must also enable SPNEGO login support in their browser. See link:https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system-level_authentication_guide/configuring_applications_for_sso[configuring Firefox for Kerberos] if you are using the Firefox browser.
|
||||
|
||||
In a Windows domain, clients usually don't need to configure anything special as IE is already able to participate in SPNEGO authentication for the Windows domain.
|
||||
The `.mydomain.org` URI must be in the `network.negotiate-auth.trusted-uris` configuration option.
|
||||
|
||||
In Windows domains, clients do not need to adjust their configuration. Internet Explorer and Edge can already participate in SPNEGO authentication.
|
||||
|
||||
ifeval::[{project_community}==true]
|
||||
==== Example setups
|
||||
|
||||
For easier testing with Kerberos, we provided some example setups to test.
|
||||
|
||||
===== {project_name} and FreeIPA docker image
|
||||
|
||||
Once you install https://www.docker.com/[docker], you can run docker image with FreeIPA server installed.
|
||||
FreeIPA provides integrated security solution with MIT Kerberos and 389 LDAP server among other things . The image provides also {project_name}
|
||||
server configured with LDAP Federation provider and enabled SPNEGO/Kerberos authentication against the FreeIPA server.
|
||||
See details https://github.com/mposolda/keycloak-freeipa-docker/blob/master/README.md[here] .
|
||||
When you install https://www.docker.com/[docker], run a docker image with the FreeIPA server installed. FreeIPA provides an integrated security solution with MIT Kerberos and 389 LDAP server. The image also contains a {project_name} server configured with an LDAP Federation provider and enabled SPNEGO/Kerberos authentication against the FreeIPA server. See details https://github.com/mposolda/keycloak-freeipa-docker/blob/master/README.md[here].
|
||||
|
||||
===== ApacheDS testing Kerberos server
|
||||
|
||||
For quick testing and unit tests, we use a very simple http://directory.apache.org/apacheds/[ApacheDS] Kerberos server.
|
||||
You need to build {project_name} from sources and then run the Kerberos server with maven-exec-plugin from our testsuite.
|
||||
See details https://github.com/keycloak/keycloak/blob/master/docs/tests.md#kerberos-server[here] .
|
||||
For quick testing and unit tests, use a simple http://directory.apache.org/apacheds/[ApacheDS] Kerberos server. You must build {project_name} from the source and then run the Kerberos server with the maven-exec-plugin from our test suite. See details https://github.com/keycloak/keycloak/blob/master/docs/tests.md#kerberos-server[here].
|
||||
endif::[]
|
||||
|
||||
==== Credential Delegation
|
||||
|
||||
Kerberos 5 supports the concept of credential delegation. In this scenario, your applications may want access to the Kerberos ticket so that
|
||||
they can re-use it to interact with other services secured by Kerberos. Since the SPNEGO protocol is processed in the {project_name} server,
|
||||
you have to propagate the GSS credential to your application
|
||||
within the OpenID Connect token claim or a SAML assertion attribute that is transmitted to your application from the {project_name} server.
|
||||
To have this claim inserted into the token or assertion, each application will need to enable the built-in protocol mapper called `gss delegation credential`.
|
||||
This is enabled in the `Mappers` tab of the application's
|
||||
client page. See <<_protocol-mappers, Protocol Mappers>> chapter for more details.
|
||||
Kerberos supports the credential delegation. Applications may need access to the Kerberos ticket so they can re-use it to interact with other services secured by Kerberos. Because the {project_name} server processed the SPNEGO protocol, you must propagate the GSS credential to your application within the OpenID Connect token claim or a SAML assertion attribute. {project_name} transmits this to your application from the {project_name} server. To insert this claim into the token or assertion, each application must enable the built-in protocol mapper `gss delegation credential`. This mapper is available in the *Mappers* tab of the application's client page. See <<_protocol-mappers, Protocol Mappers>> chapter for more details.
|
||||
|
||||
Applications will need to deserialize the claim it receives from {project_name} before it can use it to make GSS calls against other services.
|
||||
Once you deserialize the credential from the access token to the GSSCredential object, the GSSContext will need to be created with this credential
|
||||
passed to the method `GSSManager.createContext` for example like this:
|
||||
Applications must deserialize the claim it receives from {project_name} before using it to make GSS calls against other services. When you deserialize the credential from the access token to the GSSCredential object, create the GSSContext with this credential passed to the `GSSManager.createContext` method. For example:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
|
@ -163,77 +143,67 @@ passed to the method `GSSManager.createContext` for example like this:
|
|||
KeycloakPrincipal keycloakPrincipal = (KeycloakPrincipal) servletReq.getUserPrincipal();
|
||||
AccessToken accessToken = keycloakPrincipal.getKeycloakSecurityContext().getToken();
|
||||
|
||||
// Retrieve kerberos credential from accessToken and deserialize it
|
||||
// Retrieve Kerberos credential from accessToken and deserialize it
|
||||
String serializedGssCredential = (String) accessToken.getOtherClaims().
|
||||
get(org.keycloak.common.constants.KerberosConstants.GSS_DELEGATION_CREDENTIAL);
|
||||
|
||||
GSSCredential deserializedGssCredential = org.keycloak.common.util.KerberosSerializationUtils.
|
||||
deserializeCredential(serializedGssCredential);
|
||||
|
||||
// Create GSSContext to call other kerberos-secured services
|
||||
// Create GSSContext to call other Kerberos-secured services
|
||||
GSSContext context = gssManager.createContext(serviceName, krb5Oid,
|
||||
deserializedGssCredential, GSSContext.DEFAULT_LIFETIME);
|
||||
----
|
||||
|
||||
ifeval::[{project_community}==true]
|
||||
We have an example, that shows this in detail.
|
||||
It's in `examples/kerberos` in the {project_name} example distribution or demo distribution download.
|
||||
You can also check the example sources directly https://github.com/keycloak/keycloak/tree/master/examples/kerberos[here] .
|
||||
Examples of this code exist in `examples/kerberos` in the {project_name} example distribution or demo distribution download. You can also check the example sources directly https://github.com/keycloak/keycloak/tree/master/examples/kerberos[here].
|
||||
endif::[]
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Configure `forwardable` Kerberos tickets in `krb5.conf` file and add support for delegated credentials to your browser.
|
||||
====
|
||||
|
||||
Note that you also need to configure `forwardable` kerberos tickets in `krb5.conf` file and add support for delegated credentials to your browser.
|
||||
|
||||
WARNING: Credential delegation has some security implications so only use it if you really need it.
|
||||
It's highly recommended to use it together with HTTPS.
|
||||
See for example https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system-level_authentication_guide/configuring_applications_for_sso[this article] for more details.
|
||||
[WARNING]
|
||||
====
|
||||
Credential delegation has security implications, so use it only if necessary and only with HTTPS. See https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system-level_authentication_guide/configuring_applications_for_sso[this article] for more details and an example.
|
||||
====
|
||||
|
||||
==== Cross-realm trust
|
||||
|
||||
In the Kerberos V5 protocol, the `realm` is a set of Kerberos principals defined in the Kerberos database (typically LDAP server).
|
||||
The Kerberos protocol has a concept of cross-realm trust. For example, if there are 2 kerberos realms A and B, the cross-realm trust
|
||||
will allow the users from realm A to access resources (services) of realm B. This means that realm B trusts the realm A.
|
||||
In the Kerberos protocol, the `realm` is a set of Kerberos principals. The definition of these principals exists in the Kerberos database, which is typically an LDAP server.
|
||||
|
||||
The Kerberos protocol allows cross-realm trust. For example, if 2 Kerberos realms, A and B, exist, then cross-realm trust will allow the users from realm A to access realm B's resources. Realm B trusts realm A.
|
||||
|
||||
.Kerberos cross-realm trust
|
||||
image:images/kerberos-trust-basic.png[]
|
||||
|
||||
The {project_name} server supports cross-realm trust. To implement this, perform the following:
|
||||
|
||||
The {project_name} server has support for cross-realm trust. There are few things which need to be done to achieve this:
|
||||
|
||||
* Configure the Kerberos servers for the cross-realm trust. This step is dependent on the concrete Kerberos server implementations used.
|
||||
In general, it is needed to add the Kerberos principal `krbtgt/B@A` to both Kerberos databases of realm A and B. It is needed that
|
||||
this principal has same keys on both Kerberos realms. This is usually achieved when the principals have same password, key version number
|
||||
and there are same ciphers used in both realms. It is recommended to consult the Kerberos server documentation for more details.
|
||||
|
||||
NOTE: The cross-realm trust is unidirectional by default. If you want bidirectional trust to have realm A also trust realm B,
|
||||
you must also add the principal `krbtgt/A@B` to both Kerberos databases. However, trust is transitive by default. If realm B
|
||||
trusts realm A and realm C trusts realm B, then realm C automatically trusts realm A without a need to have principal `krbtgt/C@A`
|
||||
available. Some additional configuration (for example `capaths`) may be needed to configure on Kerberos client side, so that
|
||||
the clients are able to find the trust path. Consult the Kerberos documentation for more details.
|
||||
* Configure the Kerberos servers for the cross-realm trust. Implementing this step depends on the Kerberos server implementations. This step is necessary to add the Kerberos principal `krbtgt/B@A` to the Kerberos databases of realm A and B. This principal must have the same keys on both Kerberos realms. The principals must have the same password, key version numbers, and ciphers in both realms. Consult the Kerberos server documentation for more details.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
The cross-realm trust is unidirectional by default. You must add the principal `krbtgt/A@B` to both Kerberos databases for bidirectional trust between realm A and realm B. However, trust is transitive by default. If realm B trusts realm A and realm C trusts realm B, then realm C trusts realm A without the principal, `krbtgt/C@A`, available. Additional configuration (for example, `capaths`) may be necessary on the Kerberos client-side so clients can find the trust path. Consult the Kerberos documentation for more details.
|
||||
====
|
||||
|
||||
* Configure {project_name} server
|
||||
|
||||
** If you use an LDAP storage provider with Kerberos support, you need to configure the server principal for realm B as in this
|
||||
example: `HTTP/mydomain.com@B`. The LDAP server must be able to find the users from realm A if you want users from realm A to
|
||||
successfully authenticate to {project_name}, as {project_name} server must be able to do SPNEGO flow and then find the users.
|
||||
For example, kerberos principal user `john@A` must be available as a user in the LDAP under an LDAP DN
|
||||
such as `uid=john,ou=People,dc=example,dc=com`. If you want both users from realm A and B to authenticate, you need to ensure
|
||||
that LDAP is able to find users from both realms A and B. We want to improve this limitation in future versions, so you can
|
||||
potentially create more separate LDAP providers for separate realms and ensure that SPNEGO works for both of them.
|
||||
** When using an LDAP storage provider with Kerberos support, configure the server principal for realm B, as in this example: `HTTP/mydomain.com@B`. The LDAP server must find the users from realm A if users from realm A are to successfully authenticate to {project_name}, because {project_name} must perform the SPNEGO flow and then find the users.
|
||||
|
||||
** If you use a Kerberos user storage provider (typically the Kerberos without LDAP integration), you need to configure the
|
||||
server principal as `HTTP/mydomain.com@B` and users from both Kerberos realms A and B should be able to authenticate.
|
||||
For example, Kerberos principal user `john@A` must be available in the LDAP under an LDAP DN such as `uid=john,ou=People,dc=example,dc=com`. If you want users from realm A and B to authenticate, ensure that LDAP can find users from both realms A and B.
|
||||
|
||||
WARNING: For the Kerberos user storage provider, it is recommended that there are no conflicting users among kerberos realms. If
|
||||
conflicting users exist, they will be mapped to the same {project_name} user. This is also something, which we want to improve in
|
||||
future versions and provide some more flexible mappings from Kerberos principals to {project_name} usernames.
|
||||
** When using a Kerberos user storage provider (typically, Kerberos without LDAP integration), configure the server principal as `HTTP/mydomain.com@B`, and users from Kerberos realms A and B must be able to authenticate.
|
||||
|
||||
[WARNING]
|
||||
====
|
||||
When using the Kerberos user storage provider, there cannot be conflicting users among Kerberos realms. If conflicting users exist, {project_name} maps them to the same user.
|
||||
====
|
||||
|
||||
==== Troubleshooting
|
||||
|
||||
If you have issues, we recommend that you enable additional logging to debug the problem:
|
||||
If you have issues, enable additional logging to debug the problem:
|
||||
|
||||
* Enable `Debug` flag in admin console for Kerberos or LDAP federation providers
|
||||
* Enable TRACE logging for category `org.keycloak` in logging section of `standalone/configuration/standalone.xml` to receive more info `standalone/log/server.log`
|
||||
* Enable `Debug` flag in the Admin Console for Kerberos or LDAP federation providers
|
||||
* Enable TRACE logging for category `org.keycloak` in the logging section of `standalone/configuration/standalone.xml` to receive more information in `standalone/log/server.log`
|
||||
* Add system properties `-Dsun.security.krb5.debug=true` and `-Dsun.security.spnego.debug=true`
|
||||
|
||||
|
|
|
@ -1,55 +1,57 @@
|
|||
|
||||
=== OTP Policies
|
||||
=== One Time Password (OTP) Policies
|
||||
|
||||
{project_name} has a number of policies you can set up for your FreeOTP or Google Authenticator One-Time Password
|
||||
generator. Click on the `Authentication` left menu item and go to the `OTP Policy` tab.
|
||||
{project_name} has several policies for setting up a FreeOTP or Google Authenticator One-Time Password generator. Click the *Authentication* menu and click the *OTP Policy* tab.
|
||||
|
||||
.OTP Policy
|
||||
image:{project_images}/otp-policy.png[]
|
||||
image:{project_images}/otp-policy.png[OTP Policy]
|
||||
|
||||
Any policies you set here will be used to validate one-time passwords. When configuring OTP, FreeOTP and Google Authenticator
|
||||
can scan a QR code that is generated on the OTP set up page that {project_name} has. The bar code is also
|
||||
generated from information configured on the `OTP Policy` tab.
|
||||
{project_name} generates a QR code on the OTP set-up page, based on information configured in the *OTP Policy* tab. FreeOTP and Google Authenticator scan the QR code when configuring OTP.
|
||||
|
||||
==== TOTP vs. HOTP
|
||||
==== Time-Based One Time Passwords (TOTP) compared to Counter Based One Time Passwords (HOTP)
|
||||
|
||||
There are two different algorithms to choose from for your OTP generators. Time Based (TOTP) and Counter Based (HOTP).
|
||||
For TOTP, your token generator will hash the current time and a shared secret. The server validates the OTP by comparing
|
||||
all the hashes within a certain window of time to the submitted value. So, TOTPs are valid only for a short window of time (usually 30 seconds).
|
||||
For HOTP a shared counter is used instead of the current time. The server increments the counter with each successful OTP login. So, valid OTPs only
|
||||
The algorithms available in {project_name} for your OTP generators are time-based and counter-based.
|
||||
|
||||
With TOTP, the token generator will hash the current time and a shared secret. The server validates the OTP by comparing the hashes within a window of time to the submitted value. TOTPs are valid for a short window of time.
|
||||
|
||||
With HOTP, {project_name} uses a shared counter rather than the current time. The {project_name} server increments the counter with each successful OTP login. Valid OTPs
|
||||
change after a successful login.
|
||||
|
||||
TOTP is considered a little more secure because the matchable OTP is only valid for a short window of time while the OTP for HOTP can
|
||||
be valid for an indeterminate amount of time. HOTP is much more user friendly as the user won't have to hurry to enter in their
|
||||
OTP before the time interval is up. With the way {project_name} has implemented TOTP this distinction becomes a little more
|
||||
blurry. HOTP requires a database update every time the server wants to increment the counter. This can be a performance drain
|
||||
on the authentication server when there is heavy load. So, to provide a more efficient alternative, TOTP does not remember passwords
|
||||
used. This bypasses the need to do any DB updates, but the downside is that TOTPs can be re-used in the valid time interval. For future
|
||||
versions of {project_name} it is planned that you will be able to configure whether TOTP checks older OTPs in the time interval.
|
||||
TOTP is more secure than HOTP because the matchable OTP is valid for a short window of time, while the OTP for HOTP is valid for an indeterminate amount of time. HOTP is more user-friendly than TOTP because no time limit exists to enter the OTP.
|
||||
|
||||
HOTP requires a database update every time the server increments the counter. This update is a performance drain on the authentication server during heavy load. To increase efficiency, TOTP does not remember passwords used, so there is no need to perform database updates. The drawback is that it is possible to re-use TOTPs in the valid time interval.
|
||||
|
||||
==== TOTP Configuration Options
|
||||
|
||||
OTP Hash Algorithm::
|
||||
Default is SHA1, more secure options are SHA256 and SHA512.
|
||||
Number of Digits::
|
||||
How many characters is the OTP? Short means more user friendly as it is less the user has to type. More means more security.
|
||||
Look Ahead Window::
|
||||
How many intervals ahead should the server try and match the hash? This exists so just in case the clock of the TOTP generator
|
||||
or authentication server get out of sync. The default value of 1 is usually good enough. For example, if the time interval
|
||||
for a new token is every 30 seconds, the default value of 1 means that it will only accept valid tokens in that 30 second window.
|
||||
Each increment of this config value will increase the valid window by 30 seconds.
|
||||
OTP Token Period::
|
||||
Time interval in seconds during which the server will match a hash. Each time the interval passes, a new TOTP will be generated by the token generator.
|
||||
===== OTP Hash Algorithm
|
||||
|
||||
The default algorithm is SHA1. The other, more secure options are SHA256 and SHA512.
|
||||
|
||||
===== Number of Digits
|
||||
|
||||
The length of the OTP. Short OTP's are user-friendly, easier to type, and easier to remember. Longer OTP's are more secure than shorter OTP's.
|
||||
|
||||
===== Look Ahead Window
|
||||
|
||||
The number of intervals the server attempts to match the hash. This option is present in {project_name} if the clock of the TOTP generator or authentication server become out-of-sync. The default value of 1 is adequate. For example, if the time interval for a token is 30 seconds, the default value of 1 means it will accept valid tokens in the 30-second window. Every increment of this value increases the valid window by 30 seconds.
|
||||
|
||||
===== OTP Token Period
|
||||
|
||||
The time interval in seconds the server matches a hash. Each time the interval passes, the token generator generates a TOTP.
|
||||
|
||||
==== HOTP Configuration Options
|
||||
|
||||
OTP Hash Algorithm::
|
||||
Default is SHA1, more secure options are SHA256 and SHA512.
|
||||
Number of Digits::
|
||||
How many characters is the OTP? Short means more user friendly as it is less the user has to type. More means more security.
|
||||
Look Ahead Window::
|
||||
How many counters ahead should the server try and match the hash? The default value is 1. This exists to cover the case
|
||||
where the user's counter gets ahead of the server's. This can often happen as users often increment the counter
|
||||
manually too many times by accident. This value really should be increased to a value of 10 or so.
|
||||
Initial Counter::
|
||||
What is the value of the initial counter?
|
||||
===== OTP Hash Algorithm
|
||||
|
||||
The default algorithm is SHA1. The other, more secure options are SHA256 and SHA512.
|
||||
|
||||
===== Number of Digits
|
||||
|
||||
The length of the OTP. Short OTPs are user-friendly, easier to type, and easier to remember. Longer OTPs are more secure than shorter OTPs.
|
||||
|
||||
===== Look Ahead Window
|
||||
The number of intervals the server attempts to match the hash. This option is present in {project_name} if the clock of the TOTP generator or authentication server become out-of-sync. The default value of 1 is adequate. This option is present in {project_name} to cover when the user's counter gets ahead of the server.
|
||||
|
||||
===== Initial Counter
|
||||
|
||||
The value of the initial counter.
|
||||
|
|
|
@ -1,75 +1,99 @@
|
|||
|
||||
[[_password-policies]]
|
||||
|
||||
=== Password Policies
|
||||
|
||||
Each new realm created has no password policies associated with it. Users can have as short, as long, as complex,
|
||||
as insecure a password, as they want. Simple settings are fine for development or learning {project_name},
|
||||
but unacceptable in production environments. {project_name} has a rich set of password policies you can enable
|
||||
through the Admin Console.
|
||||
When {project_name} creates a realm, it does not associate password policies with the realm. You can set a simple password with no restrictions on its length, security, or complexity. Simple passwords are unacceptable in production environments. {project_name} has a set of password policies available through the Admin Console.
|
||||
|
||||
Click on the `Authentication` left menu item and go to the `Password Policy` tab. Choose the policy you want to add in the
|
||||
right side drop down list box. This will add the policy in the table on the screen. Choose the parameters for the policy.
|
||||
Hit the `Save` button to store your changes.
|
||||
.Procedure
|
||||
. Click *Authentication* in the menu.
|
||||
. Click the *Password Policy* tab.
|
||||
. Select the policy to add in the *Add policy* drop-down box.
|
||||
. Enter a value for the *Policy Value* corresponding with the policy chosen.
|
||||
. Click *Save*.
|
||||
+
|
||||
Password Policy
|
||||
image:{project_images}/password-policy.png[Password Policy]
|
||||
|
||||
.Password Policy
|
||||
image:{project_images}/password-policy.png[]
|
||||
|
||||
After saving your policy, user registration and the Update Password required action will enforce your new policy. An example of a user
|
||||
failing the policy check:
|
||||
After saving the policy, {project_name} enforces the policy for new users and sets an Update Password action for existing users to ensure they change their password the next time they log in. For example:
|
||||
|
||||
.Failed Password Policy
|
||||
image:{project_images}/failed-password-policy.png[]
|
||||
|
||||
|
||||
If the password policy is updated, an Update Password action must be set for every user. An automatic trigger is scheduled as a future enhancement.
|
||||
image:{project_images}/failed-password-policy.png[Failed Password Policy]
|
||||
|
||||
==== Password Policy Types
|
||||
|
||||
Here's an explanation of each policy type:
|
||||
|
||||
ifeval::[{project_community}==true]
|
||||
HashAlgorithm::
|
||||
Passwords are not stored as clear text. Instead they are hashed using standard hashing algorithms before they are stored or validated.
|
||||
The only built-in and default algorithm available is PBKDF2. See the link:{developerguide_link}[{developerguide_name}]
|
||||
on how to plug in your own algorithm. Note that if you do change the algorithm, password hashes will not change in storage until
|
||||
the next time the user logs in.
|
||||
|
||||
===== HashAlgorithm
|
||||
|
||||
Passwords are not stored in cleartext. Before storage or validation, {project_name} hashes passwords using standard hashing algorithms. PBKDF2 is the only built-in and default algorithm available. See the link:{developerguide_link}[{developerguide_name}] on how to add your own hashing algorithm.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
If you change the hashing algorithm, password hashes in storage will not change until the user logs in.
|
||||
====
|
||||
|
||||
endif::[]
|
||||
|
||||
ifeval::[{project_product}==true]
|
||||
Hashing Algorithm::
|
||||
Passwords are not stored as clear text. Instead they are hashed using standard hashing algorithms before they are stored or validated.
|
||||
Supported values are pbkdf2, pbkdf2-sha256 and pbkdf2-sha512.
|
||||
===== Hashing Algorithm
|
||||
|
||||
Passwords are not stored in clear text. Before storage or validation, {project_name} hashes passwords using standard hashing algorithms {project_name} that support the PBKDF2, PBKDF2-SHA256 and PBKDF-SHA512 hashing algorithms.
|
||||
|
||||
endif::[]
|
||||
Hashing Iterations::
|
||||
This value specifies the number of times a password will be hashed before it is stored or verified. The default value is 27,500.
|
||||
This hashing is done in the rare case that a hacker gets access to your password database. Once they have access to the database,
|
||||
they can reverse engineer user passwords.
|
||||
The industry recommended value for this parameter changes every year as CPU power improves. A higher hashing iteration value takes more CPU power for hashing,
|
||||
and can impact performance. You'll have to weigh what is more important to you: performance or protecting your passwords stores.
|
||||
There may be more cost effective ways of protecting your password stores.
|
||||
Digits::
|
||||
The number of digits required to be in the password string.
|
||||
Lowercase Characters::
|
||||
The number of lower case letters required to be in the password string.
|
||||
Uppercase Characters::
|
||||
The number of upper case letters required to be in the password string.
|
||||
Special Characters::
|
||||
The number of special characters like '?!#%$' required to be in the password string.
|
||||
Not Username::
|
||||
When set, the password is not allowed to be the same as the username.
|
||||
Not Email::
|
||||
When set, the password is not allowed to be the same as the email address.
|
||||
Regular Expression::
|
||||
Define one or more regular expression patterns (defined in `java.util.regex.Pattern`) that passwords must match.
|
||||
Expire Password::
|
||||
The number of days for which the password is valid. After the number of days has expired, the user is required to change their password.
|
||||
Not Recently Used::
|
||||
This policy saves a history of previous passwords. The number of old passwords stored is configurable. When a user changes their password
|
||||
they cannot use any stored passwords.
|
||||
Password Blacklist::
|
||||
This policy checks if a given password (converted to lowercase) is contained in a blacklist file, which is potentially a very large file.
|
||||
Password blacklists are UTF-8 plain-text files with Unix line endings where every line represents a blacklisted password.
|
||||
All passwords in the blacklist must be lowercase to facilitate case-insensitive comparison.
|
||||
The file name of the blacklist file must be provided as the password policy value, e.g. `10_million_password_list_top_1000000.txt`.
|
||||
Blacklist files are resolved against `${jboss.server.data.dir}/password-blacklists/` by default.
|
||||
This path can be customized via the `keycloak.password.blacklists.path` system property,
|
||||
or the `blacklistsPath` property of the `passwordBlacklist` policy SPI configuration.
|
||||
|
||||
===== Hashing Iterations
|
||||
Specifies the number of times {project_name} hashes passwords before storage or verification. The default value is 27,500.
|
||||
|
||||
{project_name} hashes passwords to ensure that hostile actors with access to the password database cannot read passwords through reverse engineering.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
A high hashing iteration value can impact performance as it requires higher CPU power.
|
||||
====
|
||||
|
||||
===== Digits
|
||||
|
||||
The number of numerical digits required in the password string.
|
||||
|
||||
===== Lowercase Characters
|
||||
|
||||
The number of lower case letters required in the password string.
|
||||
|
||||
===== Uppercase Characters
|
||||
|
||||
The number of upper case letters required in the password string.
|
||||
|
||||
===== Special Characters
|
||||
|
||||
The number of special characters required in the password string.
|
||||
|
||||
===== Not Username
|
||||
|
||||
The password cannot be the same as the username.
|
||||
|
||||
===== Not Email
|
||||
|
||||
The password cannot be the same as the email address of the user.
|
||||
|
||||
===== Regular Expression
|
||||
|
||||
Password must match one or more defined regular expression patterns.
|
||||
|
||||
===== Expire Password
|
||||
|
||||
The number of days the password is valid. When the number of days has expired, the user must change their password.
|
||||
|
||||
===== Not Recently Used
|
||||
|
||||
Password cannot be already used by the user. {project_name} stores a history of used passwords. The number of old passwords stored is configurable in {project_name}.
|
||||
|
||||
===== Password Blacklist
|
||||
Password must not be in a blacklist file.
|
||||
|
||||
* Blacklist files are UTF-8 plain-text files with Unix line endings. Every line represents a blacklisted password.
|
||||
* {project_name} compares passwords in a case-insensitive manner. All passwords in the blacklist must be lowercase.
|
||||
* The value of the blacklist file must be the name of the blacklist file.
|
||||
* Blacklist files resolve against `${jboss.server.data.dir}/password-blacklists/` by default. Customize this path using:
|
||||
** The `keycloak.password.blacklists.path` property.
|
||||
** The `blacklistsPath` property of the `passwordBlacklist` policy SPI configuration.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
=== W3C Web Authentication (WebAuthn)
|
||||
|
||||
{project_name} provides the limited support for https://www.w3.org/TR/webauthn/[W3C Web Authentication (WebAuthn)]. {project_name} works as a WebAuthn's https://www.w3.org/TR/webauthn/#sctn-rp-operations[Relying Party (RP)].
|
||||
{project_name} provides limited support for https://www.w3.org/TR/webauthn/[W3C Web Authentication (WebAuthn)]. {project_name} works as a WebAuthn's https://www.w3.org/TR/webauthn/#rp-operations[Relying Party (RP)].
|
||||
|
||||
ifeval::[{project_product}==true]
|
||||
:tech_feature_name: WebAuthn
|
||||
|
@ -11,226 +11,235 @@ include::../templates/techpreview.adoc[]
|
|||
endif::[]
|
||||
|
||||
ifeval::[{project_community}==true]
|
||||
IMPORTANT: Please note that WebAuthn support is still in development and not yet complete, so we recommend that you use this feature experimentally. Also, this support's specification and user interfaces may change.
|
||||
|
||||
[IMPORTANT]
|
||||
====
|
||||
Please note that WebAuthn support is in development. Use this feature experimentally.
|
||||
====
|
||||
|
||||
endif::[]
|
||||
|
||||
NOTE: Whether WebAuthn's operations succeed depends on a user's WebAuthn supporting authenticator, browser and platform. If you use this WebAuthn support, please clarify to what extent those entities support the WebAuthn specification.
|
||||
[NOTE]
|
||||
====
|
||||
WebAuthn's operations success depends on the user's WebAuthn supporting authenticator, browser, and platform. Make sure your authenticator, browser, and platform support the WebAuthn specification.
|
||||
====
|
||||
|
||||
==== Setup
|
||||
|
||||
The setup procedure of WebAuthn support for 2FA is the following :
|
||||
|
||||
[[_webauthn-register]]
|
||||
===== Enable Webauthn Authenticator Registration
|
||||
===== Enable WebAuthn Authenticator Registration
|
||||
|
||||
An administrator carries out the following operations on the `Admin Console` :
|
||||
. Click *Authentication* in the menu.
|
||||
. Click the *Required Actions* tab.
|
||||
. Click *Register*.
|
||||
. Click the *Required Action* drop-down list.
|
||||
. Click *Webauthn Register*.
|
||||
. Click *Ok*.
|
||||
|
||||
- Open the `Authentication -> Required Actions` tab.
|
||||
- Click `Register`.
|
||||
- Select `Webauthn Register` as `Required Action`.
|
||||
- Mark `Enabled` checkbox. Optionally mark `Default Action` checkbox if you want all new created users to be required to register WebAuthn credential.
|
||||
Mark the *Default Action* checkbox if you want all new users to be required to register their WebAuthn credentials.
|
||||
|
||||
[[_webauthn-authenticator-setup]]
|
||||
===== Adding WebAuthn Authentication to a Browser Flow
|
||||
|
||||
* Select a realm, click on `Authentication` link, select the `Browser` flow
|
||||
* Make a copy of the built-in "Browser" flow. You may want to give the new flow a distinctive name, for example "WebAuthn Browser"
|
||||
* Using the drop down, select the copied flow
|
||||
* Delete the `WebAuthn Browser Browser - Conditional OTP` sub-flow using its `Actions` menu
|
||||
. Click *Authentication* in the menu.
|
||||
. Click the *Browser* flow.
|
||||
. Click *Copy* to make a copy of the built-in *Browser* flow.
|
||||
. Enter a name for the copy.
|
||||
. Click *Ok*.
|
||||
. Click the _Actions_ link for *WebAuthn Browser Browser - Conditional OTP* and click _Delete_.
|
||||
. Click *Delete*.
|
||||
|
||||
If you want to have WebAuthn required for all users:
|
||||
|
||||
* Using the `Actions` menu of the `WebAuthn Browser Forms`, click on `Add execution`
|
||||
* Select `WebAuthn Authenticator` using the drop down and click on `Save`
|
||||
* Set its Requirement to _Required_.
|
||||
If you require WebAuthn for all users:
|
||||
|
||||
. Click on the _Actions_ link for *WebAuthn Browser Forms*.
|
||||
. Click *Add execution*.
|
||||
. Click the *Provider* drop-down list.
|
||||
. Click *WebAuthn Authenticator*.
|
||||
. Click *Save*.
|
||||
. Click _REQUIRED_ for *WebAuthn Authenticator*
|
||||
+
|
||||
image:images/webauthn-browser-flow-required.png[]
|
||||
+
|
||||
. Click the *Bindings* tab.
|
||||
. Click the *Browser Flow* drop-down list.
|
||||
. Click *WebAuthn Browser*.
|
||||
. Click *Save*.
|
||||
|
||||
* In the `Bindings` menu, change the browser flow to `WebAuthn Browser`
|
||||
[NOTE]
|
||||
====
|
||||
If a user does not have WebAuthn credentials, the user must register WebAuthn credentials.
|
||||
====
|
||||
|
||||
Note that in this scenario, if a user doesn't have a WebAuthn credential, a required action will be set that forces that user
|
||||
to register one.
|
||||
|
||||
Alternatively, you can have users log in with WebAuthn only if they have a WebAuthn credential registered, so instead of adding
|
||||
the `WebAuthn Authenticator` execution:
|
||||
|
||||
* Using the `Actions` menu of the `WebAuthn Browser Forms`, click on `Add flow`
|
||||
* Set the alias to "Conditional 2FA" and click on `Save`
|
||||
* Set the Requirement of `Conditional 2FA` to _Conditional_
|
||||
* Using the `Actions` menu of the `Conditional 2FA`, click on `Add execution`
|
||||
* Select `Condition - User Configured` using the drop down and click on `Save`
|
||||
* Set the Requirement of `Condition - User Configured` execution to _Required_
|
||||
* Using the `Actions` menu of the `Conditional 2FA`, click on `Add execution`
|
||||
* Select `WebAuthn Authenticator` using the drop down and click on `Save`
|
||||
* Set its Requirement to _Alternative_.
|
||||
Users can log in with WebAuthn if they have a WebAuthn credential registered only. So instead of adding the *WebAuthn Authenticator* execution, you can:
|
||||
|
||||
.Procedure
|
||||
. Click on the _Actions_ link for *WebAuthn Browser Forms*.
|
||||
. Click *Add flow*.
|
||||
. Enter "Conditional 2FA" for the _Alias_ field.
|
||||
. Click *Save*.
|
||||
. Click _CONDITIONAL_ for *Conditional 2FA*
|
||||
. Click on the _Actions_ link for *Conditional 2FA*.
|
||||
. Click *Add execution*.
|
||||
. Click the *Provider* drop-down list.
|
||||
. Click *Condition - User Configured*.
|
||||
. Click *Save*.
|
||||
. Click _REQUIRED_ for *Conditional 2FA*
|
||||
. Click on the _Actions_ link for *Conditional 2FA*.
|
||||
. Click *Add execution*.
|
||||
. Click the *Provider* drop-down list.
|
||||
. Click *WebAuthn Authenticator*.
|
||||
. Click *Save*.
|
||||
. Click _ALTERNATIVE_ for *Conditional 2FA*
|
||||
+
|
||||
image:images/webauthn-browser-flow-conditional.png[]
|
||||
|
||||
You can also allow the user to choose between using WebAuthn and OTP for his second factor:
|
||||
|
||||
* Using the `Actions` menu of the `Conditional 2FA`, click on `Add execution`
|
||||
* Select `OTP Form` using the drop down and click on `Save`
|
||||
* Set its Requirement to _Alternative_.
|
||||
The user can choose between using WebAuthn and OTP for the second factor:
|
||||
|
||||
.Procedure
|
||||
. Click the _Actions_ link for *Conditional 2FA*.
|
||||
. Click *Add execution*.
|
||||
. Click the *Provider* drop-down list.
|
||||
. Click *ITP Form*.
|
||||
. Click *Save*.
|
||||
. Click _ALTERNATIVE_ for *Conditional 2FA*
|
||||
+
|
||||
image:images/webauthn-browser-flow-conditional-with-OTP.png[]
|
||||
|
||||
==== Authenticate with WebAuthn Authenticator
|
||||
|
||||
After registering a WebAuthn authenticator, the user carries out the following operations
|
||||
assuming that authentication flow configuration above with the conditional subflow using `WebAuthn Authenticator` was used:
|
||||
After registering a WebAuthn authenticator, the user carries out the following operations:
|
||||
|
||||
- Open the login form. The user must authenticate with a username and password.
|
||||
- The user's browser asks the user to authenticate by their WebAuthn authenticator.
|
||||
* Open the login form. The user must authenticate with a username and password.
|
||||
* The user's browser asks the user to authenticate by using their WebAuthn authenticator.
|
||||
|
||||
==== Managing WebAuthn as an administrator
|
||||
|
||||
===== Managing Credentials
|
||||
|
||||
WebAuthn credentials are managed in a similar manner as other credentials, such as OTP, from the xref:ref-user-credentials_{context}[User credential management]:
|
||||
{project_name} manages WebAuthn credentials similarly to other credentials from xref:ref-user-credentials_{context}[User credential management]:
|
||||
|
||||
* Users can be assigned a required action to create a WebAuthn credential from the `Reset Actions` list, and selecting `Webauthn Register`
|
||||
* The administrator can delete a WebAuthn credential by pressing `Delete`.
|
||||
* The administrator can view the credential's data such as the AAGUID by selecting `Show data...`.
|
||||
* The administrator can set a label for the credential by setting a value in the `User Label` field and saving the data.
|
||||
* {project_name} assigns users a required action to create a WebAuthn credential from the *Reset Actions* list and select *Webauthn Register*.
|
||||
* Administrators can delete a WebAuthn credential by clicking *Delete*.
|
||||
* Administrators can view the credential's data, such as the AAGUID, by selecting *Show data...*.
|
||||
* Administrators can set a label for the credential by setting a value in the *User Label* field and saving the data.
|
||||
|
||||
[[_webauthn-policy]]
|
||||
===== Managing Policy
|
||||
|
||||
An administrator can configure WebAuthn related operations as `WebAuthn Policy` per realm.
|
||||
Administrators can configure WebAuthn related operations as *WebAuthn Policy* per realm.
|
||||
|
||||
An administrator carries out the following operations on the `Admin Console` :
|
||||
.Procedure
|
||||
. Click *Authentication* in the menu.
|
||||
. Click the *WebAuthn Policy* tab.
|
||||
. Configure the items within the policy (see description below).
|
||||
. Click *Save*.
|
||||
|
||||
- Open the `Authentication -> WebAuthn Policy` tab.
|
||||
- Configure items and click `Save`.
|
||||
|
||||
The configurable items and their description follow.
|
||||
The configurable items and their description are as follows:
|
||||
|
||||
|===
|
||||
|Configuration|Description
|
||||
|
||||
|Relying Party Entity Name
|
||||
|Human-readable server name as a WebAuthn Relying Party. This is a mandatory configuration, which is applied to the operation of registering the WebAuthn authenticator. The default setting is "keycloak".
|
||||
For more details, see https://www.w3.org/TR/webauthn/#dictionary-pkcredentialentity[WebAuthn Specification].
|
||||
|The readable server name as a WebAuthn Relying Party. This item is mandatory and applies to the registration of the WebAuthn authenticator. The default setting is "keycloak". For more details, see https://www.w3.org/TR/webauthn/#dictionary-pkcredentialentity[WebAuthn Specification].
|
||||
|
||||
|Signature Algorithms
|
||||
|It tells the WebAuthn authenticator which signature algorithms to use for the https://www.w3.org/TR/webauthn/#public-key-credential[Public Key Credential] that can be used for signing and verifying the https://www.w3.org/TR/webauthn/#authentication-assertion[Authentication Assertion]. Multiple algorithms can be specified. If no algorithm is specified, https://datatracker.ietf.org/doc/html/rfc8152#section-8.1[ES256] is adapted. The default setting is ES256. This is an optional configuration item that is applied to the operation of registering a WebAuthn authenticator.
|
||||
For more details, see https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialparameters[WebAuthn Specification].
|
||||
|The algorithms telling the WebAuthn authenticator which signature algorithms to use for the https://www.w3.org/TR/webauthn/#public-key-credential[Public Key Credential]. {project_name} uses the Public Key Credential to sign and verify https://www.w3.org/TR/webauthn/#authentication-assertion[Authentication Assertions]. If no algorithms exist, the default https://tools.ietf.org/html/rfc8152#section-8.1[ES256] is adapted. ES256 is an optional configuration item applying to the registration of WebAuthn authenticators. For more details, see https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialparameters[WebAuthn Specification].
|
||||
|
||||
|Relying Party ID
|
||||
|This is the ID as a WebAuthn Relying Party and determines the scope of Public Key Credentials. It must be origin's effective domain. This is an optional configuration item that is applied to the operation of registering a WebAuthn authenticator. If no entry is entered, the host part of the base URL of {project_name}'s server is adapted.
|
||||
For more details, see https://www.w3.org/TR/webauthn/#rp-id[WebAuthn Specification].
|
||||
|The ID of a WebAuthn Relying Party that determines the scope of https://www.w3.org/TR/webauthn/#public-key-credential[Public Key Credentials]. The ID must be the origin's effective domain. This ID is an optional configuration item applied to the registration of WebAuthn authenticators. If this entry is blank, {project_name} adapts the host part of {project_name}'s base URL. For more details, see https://www.w3.org/TR/webauthn/#rp-id[WebAuthn Specification].
|
||||
|
||||
|Attestation Conveyance Preference
|
||||
|It tells the WebAuthn API implementation on the browser (https://www.w3.org/TR/webauthn/#webauthn-client[WebAuthn Client]) the preference of how to generate an Attestation Statement. This is an optional configuration item that is applied to the operation of registering a WebAuthn authenticator. If no option is selected, its behavior is the same as selecting "none".
|
||||
For more details, see https://www.w3.org/TR/webauthn/#attestation-conveyance[WebAuthn Specification].
|
||||
|The WebAuthn API implementation on the browser (https://www.w3.org/TR/webauthn/#webauthn-client[WebAuthn Client]) is the preferential method to generate Attestation statements. This preference is an optional configuration item applying to the registration of the WebAuthn authenticator. If no option exists, its behavior is the same as selecting "none". For more details, see https://www.w3.org/TR/webauthn/#attestation-convey[WebAuthn Specification].
|
||||
|
||||
|Authenticator Attachment
|
||||
|It tells the WebAuthn Client an acceptable attachment pattern of a WebAuthn authenticator. This is an optional configuration item that is applied to the operation of registering a WebAuthn authenticator. If no option is selected, the WebAuthn Client does not consider the attachment pattern.
|
||||
For more details, see https://www.w3.org/TR/webauthn/#enumdef-authenticatorattachment[WebAuthn Specification].
|
||||
|The acceptable attachment pattern of a WebAuthn authenticator for the WebAuthn Client. This pattern is an optional configuration item applying to the registration of the WebAuthn authenticator. For more details, see https://www.w3.org/TR/webauthn/#enumdef-authenticatorattachment[WebAuthn Specification].
|
||||
|
||||
|Require Resident Key
|
||||
|It tells the WebAuthn authenticator to generate the Public Key Credential as https://www.w3.org/TR/webauthn/#client-side-discoverable-public-key-credential-source[Client-side-resident Public Key Credential Source]. This is an optional configuration item that is applied to the operation of registering a WebAuthn authenticator. If no option is selected, its behavior is the same as selecting "No".
|
||||
For more details, see https://www.w3.org/TR/webauthn/#dom-authenticatorselectioncriteria-requireresidentkey[WebAuthn Specification].
|
||||
|The option requiring that the WebAuthn authenticator generates the Public Key Credential as https://www.w3.org/TR/webauthn/#client-side-resident-public-key-credential-source[Client-side-resident Public Key Credential Source]. This option applies to the registration of the WebAuthn authenticator. If left blank, its behavior is the same as selecting "No". For more details, see https://www.w3.org/TR/webauthn/#dom-authenticatorselectioncriteria-requireresidentkey[WebAuthn Specification].
|
||||
|
||||
|User Verification Requirement
|
||||
|It tells the WebAuthn authenticator to confirm actually verifying a user. This is an optional configuration item that is applied to the operation of registering a WebAuthn authenticator and authenticating the user by a WebAuthn authenticator. If no option is selected, its behavior is the same as selecting "preferred".
|
||||
For more details, see https://www.w3.org/TR/webauthn/#dom-authenticatorselectioncriteria-userverification[WebAuthn Specification for registering a WebAuthn authenticator] and https://www.w3.org/TR/webauthn/#dom-publickeycredentialrequestoptions-userverification[WebAuthn Specification for authenticating the user by a WebAuthn authenticator].
|
||||
|The option requiring that the WebAuthn authenticator confirms the verification of a user. This is an optional configuration item applying to the registration of a WebAuthn authenticator and the authentication of a user by a WebAuthn authenticator. If no option exists, its behavior is the same as selecting "preferred". For more details, see https://www.w3.org/TR/webauthn/#dom-authenticatorselectioncriteria-userverification[WebAuthn Specification for registering a WebAuthn authenticator] and https://www.w3.org/TR/webauthn/#dom-publickeycredentialrequestoptions-userverification[WebAuthn Specification for authenticating the user by a WebAuthn authenticator].
|
||||
|
||||
|Timeout
|
||||
|It specifies the timeout value in seconds for registering a WebAuthn authenticator and authenticating the user by a WebAuthn authenticator. If set to 0, its behavior depends on the WebAuthn authenticator's implementation. The default value is 0.
|
||||
For more details, see https://www.w3.org/TR/webauthn/#dom-publickeycredentialcreationoptions-timeout[WebAuthn Specification for registering a WebAuthn authenticator] and https://www.w3.org/TR/webauthn/#dom-publickeycredentialrequestoptions-timeout[WebAuthn Specification for authenticating the user by a WebAuthn authenticator].
|
||||
|The timeout value, in seconds, for registering a WebAuthn authenticator and authenticating the user by using a WebAuthn authenticator. If set to zero, its behavior depends on the WebAuthn authenticator's implementation. The default value is 0. For more details, see https://www.w3.org/TR/webauthn/#dom-publickeycredentialcreationoptions-timeout[WebAuthn Specification for registering a WebAuthn authenticator] and https://www.w3.org/TR/webauthn/#dom-publickeycredentialrequestoptions-timeout[WebAuthn Specification for authenticating the user by a WebAuthn authenticator].
|
||||
|
||||
|Avoid Same Authenticator Registration
|
||||
|If set to "ON", the WebAuthn authenticator that has already been registered can not be newly registered. This is applied to the operation of registering a WebAuthn authenticator. The default setting is "OFF".
|
||||
|If enabled, {project_name} cannot re-register an already registered WebAuthn authenticator.
|
||||
|
||||
|Acceptable AAGUIDs
|
||||
|The white list of AAGUID of which a WebAuthn authenticator can be registered. This is applied to the operation of registering a WebAuthn authenticator. If no entry is set on this list, any WebAuthn authenticator can be registered.
|
||||
|The white list of AAGUIDs which a WebAuthn authenticator must register against.
|
||||
|
||||
|===
|
||||
|
||||
==== Attestation Statement Verification
|
||||
|
||||
When registering a WebAuthn authenticator, {project_name} verifies an attestation statement generated by this WebAuthn authenticator. On this verification process, {project_name} validates this attestation statement's trustworthiness. It requires trust anchor's certificates. {project_name} uses the link:{installguide_truststore_link}[{installguide_truststore_name}] so that you need to import these certificates onto it in advance.
|
||||
When registering a WebAuthn authenticator, {project_name} verifies the trustworthiness of the attestation statement generated by the WebAuthn authenticator. {project_name} requires the trust anchor's certificates for this. {project_name} uses the link:{installguide_truststore_link}[{installguide_truststore_name}], so you must import these certificates into it in advance.
|
||||
|
||||
If you want to omit this attestation statement trustworthiness validation, please disable this truststore or set the WebAuthn policy's configuration item "Attestation Conveyance Preference" to "none".
|
||||
To omit this validation, disable this truststore or set the WebAuthn policy's configuration item "Attestation Conveyance Preference" to "none".
|
||||
|
||||
|
||||
==== Managing WebAuthn credentials as a user
|
||||
|
||||
===== Register WebAuthn Authenticator
|
||||
|
||||
The appropriate method to register a WebAuthn authenticator depends on if the user has or has not already registered an account on {project_name}.
|
||||
The appropriate method to register a WebAuthn authenticator depends on whether the user has already registered an account on {project_name}.
|
||||
|
||||
New user::
|
||||
===== New user
|
||||
|
||||
If the `WebAuthn Register` required action is set as `Default Action` in a realm, new users are required to
|
||||
set up the WebAuthn security key after the first successful login. A new user carries out the following operations :
|
||||
If the *WebAuthn Register* required action is *Default Action* in a realm, new users must set up the WebAuthn security key after their first login.
|
||||
|
||||
- Open the login form.
|
||||
- Click the `Register` link.
|
||||
- Fill in items on the register form and click `Register`.
|
||||
- The user's browser asks the user to register their WebAuthn authenticator.
|
||||
- After successful registration, the user's browser asks the user to enter the text as their just registered WebAuthn authenticator's label.
|
||||
.Procedure
|
||||
|
||||
Existing user::
|
||||
. Open the login form.
|
||||
. Click *Register*.
|
||||
. Fill in the items on the form.
|
||||
. Click *Register*.
|
||||
|
||||
If `WebAuthn Authenticator` is set up as required as shown in the first example, then when existing users try to log in,
|
||||
they are required to register their WebAuthn authenticator automatically :
|
||||
After successfully registering, the browser asks the user to enter the text of their WebAuthn authenticator's label.
|
||||
|
||||
- Open the login form.
|
||||
- Fill in items, click `Save` and click `Login`.
|
||||
- When the users log in, they are required to register their WebAuthn authenticator.
|
||||
- After successful registration, the user's browser asks the user to enter the text as their just registered WebAuthn authenticator's label.
|
||||
===== Existing user
|
||||
|
||||
[[_webauthn_passwordless]]
|
||||
==== Passwordless WebAuthn together with Two-Factor
|
||||
|
||||
WebAuthn is often used for two-factor authentication, however it can be desired to use it also as first factor authentication. In this case,
|
||||
a user with `passwordless` WebAuthn credential will be able to authenticate to {project_name} without a password. {project_name} allows to use WebAuthn
|
||||
as both the passwordless and two-factor authentication mechanism in the context of a single realm and even in the context of a single authentication flow.
|
||||
.Procedure
|
||||
. Open the login form.
|
||||
. Enter the items on the form.
|
||||
. Click *Save*.
|
||||
. Click *Login*.
|
||||
|
||||
Administrator may typically require that Security Keys registered by users for the WebAuthn passwordless authentication must meet different
|
||||
(usually stronger) requirements. For example, those security keys may require users to authenticate to that security key using a PIN, or the
|
||||
security key should be attested with stronger certificate authority.
|
||||
After successful registration, the user's browser asks the user to enter the text of their WebAuthn authenticator's label.
|
||||
|
||||
Because of this situation, {project_name} allows administrator to configure separate `WebAuthn Passwordless Policy`. There is a separate required action
|
||||
of type `Webauthn Register Passwordless` and separate authenticator of type `WebAuthn Passwordless Authenticator`.
|
||||
==== Passwordless WebAuthn together with Two-Factor
|
||||
|
||||
{project_name} uses WebAuthn for two-factor authentication, but you can use WebAuthn as the first-factor authentication. In this case, users with `passwordless` WebAuthn credentials can authenticate to {project_name} without a password. {project_name} can use WebAuthn as both the passwordless and two-factor authentication mechanism in the context of a realm and a single authentication flow.
|
||||
|
||||
An administrator typically requires that Security Keys registered by users for the WebAuthn passwordless authentication meet different requirements. For example, the security keys may require users to authenticate to the security key using a PIN, or the security key attests with a stronger certificate authority.
|
||||
|
||||
Because of this, {project_name} permits administrators to configure a separate `WebAuthn Passwordless Policy`. There is a required `Webauthn Register Passwordless` action of type and separate authenticator of type `WebAuthn Passwordless Authenticator`.
|
||||
|
||||
===== Setup
|
||||
|
||||
The setup procedure of WebAuthn passwordless support is the following :
|
||||
Set up WebAuthn passwordless support as follows:
|
||||
|
||||
* Register new required action for WebAuthn passwordless support. Use the same steps as described <<_webauthn-register, above>>
|
||||
with the only difference, that you need to register the action called `Webauthn Register Passwordless`.
|
||||
. Register a new required action for WebAuthn passwordless support. Use the steps described in <<_webauthn-register, Enable WebAuthn Authenticator Registration>>. Register the `Webauthn Register Passwordless` action.
|
||||
|
||||
* Configure the policy. You can use same steps and configuration options as described <<_webauthn-policy, above>>, however you
|
||||
need to configure them in the admin console in the tab `WebAuthn Passwordless Policy`. You can configure this policy as you want, however
|
||||
typically the requirements for the security key will be stronger than for the two-factor policy. For example the `User Verification Requirement` can
|
||||
be set to `Required` when you configure the passwordless policy.
|
||||
. Configure the policy. You can use the steps and configuration options described in <<_webauthn-policy, Managing Policy>>. Perform the configuration in the Admin Console in the tab *WebAuthn Passwordless Policy*. Typically the requirements for the security key will be stronger than for the two-factor policy. For example, you can set the *User Verification Requirement* to *Required* when you configure the passwordless policy.
|
||||
|
||||
* Finally configure the authentication flow. Let's assume that we will use same flow called `WebAuthn Browser` as described
|
||||
<<_webauthn-authenticator-setup, above>>, but
|
||||
we will configure it as follows:
|
||||
. Configure the authentication flow. Use the *WebAuthn Browser* flow described in <<_webauthn-authenticator-setup, Adding WebAuthn Authentication to a Browser Flow>>. Configure the flow as follows:
|
||||
+
|
||||
** The *WebAuthn Browser Forms* subflow contains *Username Form* as the first authenticator. Delete the default *Username Password Form* authenticator and add the *Username Form* authenticator. This action requires the user to provide a username as the first step.
|
||||
+
|
||||
** There will be a required subflow, which can be named *Passwordless Or Two-factor*, for example. This subflow indicates the user can authenticate with Passwordless WebAuthn credential or with Two-factor authentication.
|
||||
+
|
||||
** The flow contains *WebAuthn Passwordless Authenticator* as the first alternative.
|
||||
+
|
||||
** The second alternative will be a subflow named *Password And Two-factor Webauthn*, for example. This subflow contains a *Password Form* and a *WebAuthn Authenticator*.
|
||||
|
||||
** The `WebAuthn Browser Forms` subflow will contain `Username Form` as the first authenticator. Delete the default `Username Password Form`
|
||||
authenticator and add the `Username Form` authenticator instead. This setting means that the user will provide just his or her username as the first step.
|
||||
|
||||
** There will be a required subflow, which can be named for example `Passwordless Or Two-factor` . This setting indicates that user can
|
||||
authenticate either with Passwordless WebAuthn credential or with Two-factor authentication.
|
||||
|
||||
** Flow will contain `WebAuthn Passwordless Authenticator` as the first alternative.
|
||||
|
||||
** The second alternative will be a subflow named for example `Password And Two-factor Webauthn`. This subflow will contain a `Password Form` and
|
||||
a `WebAuthn Authenticator`.
|
||||
|
||||
The final configuration of the flow will look like the following:
|
||||
The final configuration of the flow looks similar to this:
|
||||
|
||||
image:images/webauthn-passwordless-flow.png[]
|
||||
|
||||
You can now add `WebAuthn Register Passwordless` as the required action to some user, already known to {project_name}, to test this.
|
||||
During the first authentication, the user will be still required to use the password and second-factor WebAuthn credential. However, once
|
||||
the user registers the credentials, that user will be able
|
||||
to choose during future authentications. If he uses his or her WebAuthn Passwordless credential, he won't need to
|
||||
provide the password and second-factor WebAuthn credential at all.
|
||||
|
||||
|
||||
You can now add *WebAuthn Register Passwordless* as the required action to a user, already known to {project_name}, to test this. During the first authentication, the user must use the password and second-factor WebAuthn credential. The user does not need to provide the password and second-factor WebAuthn credential if they use the WebAuthn Passwordless credential.
|
||||
|
|
|
@ -2,23 +2,26 @@
|
|||
|
||||
=== X.509 Client Certificate User Authentication
|
||||
|
||||
{project_name} supports login with a X.509 client certificate if the server is configured for mutual SSL authentication.
|
||||
{project_name} supports logging in with an X.509 client certificate if you have configured the server to use mutual SSL authentication.
|
||||
|
||||
A typical workflow is as follows:
|
||||
A typical workflow:
|
||||
|
||||
- A client sends an authentication request over SSL/TLS channel
|
||||
- During SSL/TLS handshake, the server and the client exchange their x.509/v3 certificates
|
||||
- The web container (either the reverse proxy or {appserver_name} where {project_name} is deployed) validates the certificate PKIX path and the certificate expiration
|
||||
- The x.509 client certificate authenticator validates the client certificate as follows:
|
||||
* Optionally checks the certificate revocation status using CRL and/or CRL Distribution Points
|
||||
* Optionally checks the Certificate revocation status using OCSP (Online Certificate Status Protocol)
|
||||
* Optionally validates whether the key usage in the certificate matches the expected key usage
|
||||
* Optionally validates whether the extended key usage in the certificate matches the expected extended key usage
|
||||
- If any of the above checks fails, the x.509 authentication fails
|
||||
- Otherwise, the authenticator extracts the certificate identity and maps it to an existing user
|
||||
- Once the certificate is mapped to an existing user, the behavior diverges depending on the authentication flow:
|
||||
* In the Browser Flow, the server prompts the user to confirm identity or to ignore it and instead sign in with username/password
|
||||
* In the case of the Direct Grant Flow, the server signs in the user
|
||||
* A client sends an authentication request over SSL/TLS channel.
|
||||
* During the SSL/TLS handshake, the server and the client exchange their x.509/v3 certificates.
|
||||
* The container ({appserver_name}) validates the certificate PKIX path and the certificate expiration date.
|
||||
* The x.509 client certificate authenticator validates the client certificate by using the following methods:
|
||||
+
|
||||
** Checks the certificate revocation status by using CRL or CRL Distribution Points.
|
||||
** Checks the Certificate revocation status by using OCSP (Online Certificate Status Protocol).
|
||||
** Validates whether the key in the certificate matches the expected key.
|
||||
** Validates whether the extended key in the certificate matches the expected extended key.
|
||||
+
|
||||
* If any of the these checks fail, the x.509 authentication fails. Otherwise, the authenticator extracts the certificate identity and maps it to an existing user.
|
||||
|
||||
When the certificate maps to an existing user, the behavior diverges depending on the authentication flow:
|
||||
|
||||
* In the Browser Flow, the server prompts users to confirm their identity or sign in with a username and password.
|
||||
* In the Direct Grant Flow, the server signs in the user.
|
||||
|
||||
IMPORTANT: Note that it is the responsibility of the web container to validate certificate PKIX path. X.509 authenticator on the
|
||||
{project_name} side provides just the additional support for check the certificate expiration, certificate revocation status and key usage. If you are
|
||||
|
@ -28,51 +31,55 @@ as it is configured as described below.
|
|||
|
||||
==== Features
|
||||
|
||||
Supported Certificate Identity Sources::
|
||||
- Match SubjectDN using regular expression
|
||||
- X500 Subject's e-mail attribute
|
||||
- X500 Subject's e-mail from Subject Alternative Name Extension (RFC822Name General Name)
|
||||
- X500 Subject's other name from Subject Alternative Name Extension. This is typically UPN (User Principal Name)
|
||||
- X500 Subject's Common Name attribute
|
||||
- Match IssuerDN using regular expression
|
||||
- Certificate Serial Number
|
||||
- Certificate Serial Number and IssuerDN
|
||||
- SHA-256 Certificate thumbprint
|
||||
- Full certificate in PEM format
|
||||
Supported Certificate Identity Sources:
|
||||
|
||||
* Match SubjectDN by using regular expressions
|
||||
* X500 Subject's email attribute
|
||||
* X500 Subject's email from Subject Alternative Name Extension (RFC822Name General Name)
|
||||
* X500 Subject's other name from Subject Alternative Name Extension. This other name is the User Principal Name (UPN), typically.
|
||||
* X500 Subject's Common Name attribute
|
||||
* Match IssuerDN by using regular expressions
|
||||
* Certificate Serial Number
|
||||
* Certificate Serial Number and IssuerDN
|
||||
* SHA-256 Certificate thumbprint
|
||||
* Full certificate in PEM format
|
||||
|
||||
===== Regular Expressions
|
||||
{project_name} extracts the certificate identity from Subject DN or Issuer DN by using a regular expression as a filter. For example, this regular expression matches the email attribute:
|
||||
|
||||
Regular Expressions::
|
||||
The certificate identity can be extracted from either Subject DN or Issuer DN using a regular expression as a filter. For example, the regular expression below will match the e-mail attribute:
|
||||
```
|
||||
emailAddress=(.*?)(?:,|$)
|
||||
```
|
||||
The regular expression filtering is applicable only if the `Identity Source` is set to either `Match SubjectDN using regular expression` or `Match IssuerDN using regular expression`.
|
||||
|
||||
Mapping certificate identity to an existing user::
|
||||
The regular expression filtering applies if the `Identity Source` is set to either `Match SubjectDN using regular expression` or `Match IssuerDN using regular expression`.
|
||||
|
||||
The certificate identity mapping can be configured to map the extracted user identity to an existing user's username or e-mail or to a custom attribute which value matches the certificate identity. For example, setting the `Identity source` to _Subject's e-mail_ and `User mapping method` to _Username or email_ will have the X.509 client certificate authenticator use the e-mail attribute in the certificate's Subject DN as a search criteria to look up an existing user by username or by e-mail.
|
||||
====== Mapping certificate identity to an existing user
|
||||
|
||||
IMPORTANT: Please notice that if we disable `Login with email` at realm settings, the same rules will be applied to certificate authentication. In other words, users won't be able to log in using e-mail attribute.
|
||||
The certificate identity mapping can map the extracted user identity to an existing user's username, email, or a custom attribute whose value matches the certificate identity. For example, setting `Identity source` to _Subject's email_ or `User mapping method` to _Username or email_ makes the X.509 client certificate authenticator use the email attribute in the certificate's Subject DN as the search criteria when searching for an existing user by username or by email.
|
||||
|
||||
IMPORTANT: Usage of `Certificate Serial Number and IssuerDN` as an identity source requires two custom attributes - one for serial number and the other for IssuerDN.
|
||||
[IMPORTANT]
|
||||
====
|
||||
* If you disable *Login with email* at realm settings, the same rules apply to certificate authentication. Users are unable to log in by using the email attribute.
|
||||
* Using `Certificate Serial Number and IssuerDN` as an identity source requires two custom attributes for the serial number and the IssuerDN.
|
||||
* `SHA-256 Certificate thumbprint` is the lowercase hexadecimal representation of SHA-256 certificate thumbprint.
|
||||
* Using `Full certificate in PEM format` as an identity source is limited to the custom attributes mapped to external federation sources, such as LDAP. {project_name} cannot store certificates in its database due to length limitations, so in the case of LDAP, you must enable `Always Read Value From LDAP`.
|
||||
====
|
||||
|
||||
IMPORTANT: `SHA-256 Certificate thumbprint` is lowercase hexadecimal representation of SHA-256 certificate thumbprint.
|
||||
|
||||
IMPORTANT: Usage of `Full certificate in PEM format` as an identity source is limited to custom attributes mapped to external federation sources like LDAP. You must enable `Always Read Value From LDAP` in this case, because certificates cannot be stored in Keycloak database due to a length limitation.
|
||||
|
||||
Other Features: Extended Certificate Validation::
|
||||
- Revocation status checking using CRL
|
||||
- Revocation status checking using CRL/Distribution Point
|
||||
- Revocation status checking using OCSP/Responder URI
|
||||
- Certificate KeyUsage validation
|
||||
- Certificate ExtendedKeyUsage validation
|
||||
====== Extended Certificate Validation
|
||||
* Revocation status checking using CRL.
|
||||
* Revocation status checking using CRL/Distribution Point.
|
||||
* Revocation status checking using OCSP/Responder URI.
|
||||
* Certificate KeyUsage validation.
|
||||
* Certificate ExtendedKeyUsage validation.
|
||||
|
||||
==== Enable X.509 Client Certificate User Authentication
|
||||
|
||||
The following sections describe how to configure {appserver_name}/Undertow and the {project_name} Server to enable X.509 client certificate authentication.
|
||||
|
||||
[[_enable-mtls-wildfly]]
|
||||
Enable mutual SSL in {appserver_name}::
|
||||
See link:https://docs.wildfly.org/19/Admin_Guide.html#enable-ssl[Enable SSL] for the instructions how to enable SSL in {appserver_name}.
|
||||
===== Enable mutual SSL in {appserver_name}
|
||||
|
||||
See link:https://docs.wildfly.org/19/Admin_Guide.html#enable-ssl[Enable SSL] for the instructions to enable SSL in {appserver_name}.
|
||||
|
||||
* Open {project_dirref}/standalone/configuration/standalone.xml and add a new realm:
|
||||
```xml
|
||||
|
@ -80,14 +87,14 @@ See link:https://docs.wildfly.org/19/Admin_Guide.html#enable-ssl[Enable SSL] for
|
|||
<security-realm name="ssl-realm">
|
||||
<server-identities>
|
||||
<ssl>
|
||||
<keystore path="servercert.jks"
|
||||
relative-to="jboss.server.config.dir"
|
||||
<keystore path="servercert.jks"
|
||||
relative-to="jboss.server.config.dir"
|
||||
keystore-password="servercert password"/>
|
||||
</ssl>
|
||||
</server-identities>
|
||||
<authentication>
|
||||
<truststore path="truststore.jks"
|
||||
relative-to="jboss.server.config.dir"
|
||||
<truststore path="truststore.jks"
|
||||
relative-to="jboss.server.config.dir"
|
||||
keystore-password="truststore password"/>
|
||||
</authentication>
|
||||
</security-realm>
|
||||
|
@ -95,41 +102,41 @@ See link:https://docs.wildfly.org/19/Admin_Guide.html#enable-ssl[Enable SSL] for
|
|||
```
|
||||
|
||||
`ssl/keystore`::
|
||||
The `ssl` element contains the `keystore` element that defines how to load the server public key pair from a JKS keystore
|
||||
The `ssl` element contains the `keystore` element that contains the details to load the server public key pair from a JKS keystore.
|
||||
|
||||
`ssl/keystore/path`::
|
||||
A path to a JKS keystore
|
||||
The path to the JKS keystore.
|
||||
|
||||
`ssl/keystore/relative-to`::
|
||||
Defines a path the keystore path is relative to
|
||||
The path that the keystore path is relative to.
|
||||
|
||||
`ssl/keystore/keystore-password`::
|
||||
The password to open the keystore
|
||||
The password to open the keystore.
|
||||
|
||||
`ssl/keystore/alias` (optional)::
|
||||
The alias of the entry in the keystore. Set it if the keystore contains multiple entries
|
||||
The alias of the entry in the keystore. Set if the keystore contains multiple entries.
|
||||
|
||||
`ssl/keystore/key-password` (optional)::
|
||||
The private key password, if different from the keystore password.
|
||||
|
||||
`authentication/truststore`::
|
||||
Defines how to load a trust store to verify the certificate presented by the remote side of the inbound/outgoing connection. Typically, the truststore contains a collection of trusted CA certificates.
|
||||
Defines how to load a trust store to verify the certificate presented by the remote side of the inbound/outgoing connection. Typically, the truststore contains a collection of trusted CA certificates.
|
||||
|
||||
`authentication/truststore/path`::
|
||||
A path to a JKS keystore that contains the certificates of the trusted CAs (certificate authorities)
|
||||
The path to the JKS keystore containing the certificates of the trusted certificate authorities.
|
||||
|
||||
`authentication/truststore/relative-to`::
|
||||
Defines a path the truststore path is relative to
|
||||
The path that the truststore path is relative to.
|
||||
|
||||
`authentication/truststore/keystore-password`::
|
||||
The password to open the truststore
|
||||
The password to open the truststore.
|
||||
|
||||
|
||||
Enable https listener::
|
||||
===== Enable HTTPS listener
|
||||
|
||||
See link:https://docs.wildfly.org/19/Admin_Guide.html#https-listener[HTTPS Listener] for the instructions how to enable HTTPS in WildFly.
|
||||
See link:https://docs.wildfly.org/19/Admin_Guide.html#https-listener[HTTPS Listener] for the instructions to enable HTTPS in WildFly.
|
||||
|
||||
* Add the <https-listener> element as shown below:
|
||||
* Add the <https-listener> element.
|
||||
|
||||
[source,xml,subs="attributes+"]
|
||||
----
|
||||
|
@ -145,112 +152,131 @@ See link:https://docs.wildfly.org/19/Admin_Guide.html#https-listener[HTTPS Liste
|
|||
----
|
||||
|
||||
`https-listener/security-realm`::
|
||||
The value must match the name of the realm from the previous section
|
||||
This value must match the name of the realm from the previous section.
|
||||
|
||||
`https-listener/verify-client`::
|
||||
If set to `REQUESTED`, the server will optionally ask for a client certificate. Setting the attribute to `REQUIRED` will have the server to refuse inbound connections if no client certificate has been provided.
|
||||
If set to *REQUESTED*, the server optionally asks for a client certificate.
|
||||
If set to *REQUIRED*, the server refuses inbound connections if no client certificate has been provided.
|
||||
|
||||
==== Adding X.509 Client Certificate Authentication to a Browser Flow
|
||||
[[_browser_flow]]
|
||||
==== Adding X.509 Client Certificate Authentication to browser flows
|
||||
|
||||
* Select a realm, click on Authentication link, select the "Browser" flow
|
||||
* Make a copy of the built-in "Browser" flow. You may want to give the new flow a distinctive name, i.e. "X.509 Browser"
|
||||
* Using the drop down, select the copied flow, and click on "Add execution"
|
||||
* Select "X509/Validate Username Form" using the drop down and click on "Save"
|
||||
. Click *Authentication* in the menu.
|
||||
. Click the "Browser" flow.
|
||||
. Click *Copy* to make a copy of the built-in "Browser" flow.
|
||||
. Enter a name for the copy.
|
||||
. Click *Ok*.
|
||||
. Click the copy in the *Add policy* drop-down box.
|
||||
. Click *Add execution*.
|
||||
. Click "X509/Validate Username Form".
|
||||
. Click *Save*.
|
||||
+
|
||||
.X509 Execution
|
||||
image:images/x509-execution.png[X509 Execution]
|
||||
+
|
||||
. Click the up/down arrow buttons to move the "X509/Validate Username Form" over the "Browser Forms" execution.
|
||||
. Set the requirement to "ALTERNATIVE".
|
||||
+
|
||||
.X509 Browser Flow
|
||||
image:images/x509-browser-flow.png[X509 Browser Flow]
|
||||
+
|
||||
. Click the *Bindings* tab.
|
||||
. Click the *Browser Flow* drop-down list.
|
||||
. Click the copy of the browser flow from the drop-down list.
|
||||
. Click *Save*.
|
||||
+
|
||||
.X509 Browser Flow Bindings
|
||||
image:images/x509-browser-flow-bindings.png[X509 Browser Flow Bindings]
|
||||
|
||||
image:images/x509-execution.png[]
|
||||
==== Configuring X.509 Client Certificate Authentication
|
||||
|
||||
* Using the up/down arrows, change the order of the "X509/Validate Username Form" by moving it above the "Browser Forms" execution, and set the requirement to "ALTERNATIVE"
|
||||
.X509 Configuration
|
||||
image:images/x509-configuration.png[X509 Configuration]
|
||||
|
||||
image:images/x509-browser-flow.png[]
|
||||
*User Identity Source*::
|
||||
Defines the method for extracting the user identity from a client certificate.
|
||||
|
||||
* Select the "Bindings" tab, find the drop down for "Browser Flow". Select the newly created X509 browser flow from the drop down and click on "Save".
|
||||
*Canonical DN representation enabled*::
|
||||
Defines whether to use canonical format to determine a distinguished name. The official link:https://docs.oracle.com/javase/8/docs/api/javax/security/auth/x500/X500Principal.html#getName-java.lang.String-[Java API documentation] describes the format. This option affects the two User Identity Sources _Match SubjectDN using regular expression_ and _Match IssuerDN using regular expression_ only. Enable this option when you set up a new {project_name} instance. Disable this option to retain backward compatibility with existing {project_name} instances.
|
||||
|
||||
image:images/x509-browser-flow-bindings.png[]
|
||||
*Enable Serial Number hexadecimal representation*::
|
||||
Represent the link:https://tools.ietf.org/html/rfc5280#section-4.1.2.2[serial number] as hexadecimal. The serial number with the sign bit set to 1 must be left padded with 00 octet. For example, a serial number with decimal value _161_, or _a1_ in hexadecimal representation is encoded as _00a1_, according to RFC5280. See link:https://tools.ietf.org/html/rfc5280#appendix-B[RFC5280, appendix-B] for more details.
|
||||
|
||||
Configuring X.509 Client Certificate Authentication::
|
||||
*A regular expression*::
|
||||
A regular expression to use as a filter for extracting the certificate identity. The expression must contain a single group.
|
||||
|
||||
image:images/x509-configuration.png[]
|
||||
*User Mapping Method*::
|
||||
Defines the method to match the certificate identity with an existing user. _Username or email_ searches for existing users by username or email. _Custom Attribute Mapper_ searches for existing users with a custom attribute that matches the certificate identity. The name of the custom attribute is configurable.
|
||||
|
||||
`User Identity Source`::
|
||||
Defines how to extract the user identity from a client certificate.
|
||||
*A name of user attribute*::
|
||||
A custom attribute whose value matches against the certificate identity. Use multiple custom attributes when attribute mapping is related to multiple values, For example, 'Certificate Serial Number and IssuerDN'.
|
||||
|
||||
`Canonical DN representation enabled` (optional)::
|
||||
Defines whether to use the canonical format to determine a distinguished name.
|
||||
The format is described in detail in the official link:https://docs.oracle.com/javase/8/docs/api/javax/security/auth/x500/X500Principal.html#getName-java.lang.String-[Java API documentation] .
|
||||
This option only affects the two User Identity Sources _Match SubjectDN using regular expression_ and _Match IssuerDN using regular expression_.
|
||||
If you setup a new {project_name} instance it is recommended to enable this option. Leave this option disabled to remain beckward compatible with existing {project_name} instances.
|
||||
*CRL Checking Enabled*::
|
||||
Check the revocation status of the certificate by using the Certificate Revocation List. The location of the list is defined in the *CRL file path* attribute.
|
||||
|
||||
`Enable Serial Number hexadecimal representation` (optional)::
|
||||
An option to use hexadecimal representation of the Serial Number. See link:https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.2[RFC5280, Section-4.1.2.2]. Serial Number with sign bit set to 1 should be left padded with 00 octet. E.g. Serial number with decimal value _161_, or _a1_ in hexadecimal representation according to RFC5280 must be encoded as _00a1_. More details can be found: link:https://datatracker.ietf.org/doc/html/rfc5280#appendix-B[RFC5280, appendix-B].
|
||||
*Enable CRL Distribution Point to check certificate revocation status*::
|
||||
Use CDP to check the certificate revocation status. Most PKI authorities include CDP in their certificates.
|
||||
|
||||
`A regular expression` (optional)::
|
||||
Defines a regular expression to use as a filter to extract the certificate identity. The regular expression must contain a single group.
|
||||
*CRL file path*::
|
||||
The path to a file containing a CRL list. The value must be a path to a valid file if the *CRL Checking Enabled* option is enabled.
|
||||
|
||||
`User Mapping Method`::
|
||||
Defines how to match the certificate identity to an existing user. _Username or e-mail_ will search for an existing user by username or e-mail. _Custom Attribute Mapper_ will search for an existing user with a custom attribute which value matches the certificate identity. The name of the custom attribute is configurable.
|
||||
*OCSP Checking Enabled*::
|
||||
Checks the certificate revocation status by using Online Certificate Status Protocol.
|
||||
|
||||
`A name of user attribute` (optional)::
|
||||
A custom attribute which value will be matched against the certificate identity. Multiple custom attributes are relevant when attribute mapping is related to multiple values, e.g. 'Certificate Serial Number and IssuerDN'.
|
||||
*OCSP Responder URI*::
|
||||
Override the value of the OCSP responder URI in the certificate.
|
||||
|
||||
WARNING: It is highly recommended that attribute used here is read-only for the users. By default, only the `usercertificate` attribute is read-only by {project_name}.
|
||||
If you use a different attribute name, you may need to add it to the list of read-only attributes. See the details in the link:#_read_only_user_attributes[Threat model mitigation chapter].
|
||||
*Validate Key Usage*::
|
||||
Verifies the certificate's KeyUsage extension bits are set. For example, "digitalSignature,KeyEncipherment" verifies if bits 0 and 2 in the KeyUsage extension are set.
|
||||
Leave this parameter empty to disable the Key Usage validation. See link:https://tools.ietf.org/html/rfc5280#section-4.2.1.3[RFC5280, Section-4.2.1.3] for more information. {project_name} raises an error when a key usage mismatch occurs.
|
||||
|
||||
`CRL Checking Enabled` (optional)::
|
||||
Defines whether to check the revocation status of the certificate using Certificate Revocation List.
|
||||
*Validate Extended Key Usage*::
|
||||
Verifies one or more purposes defined in the Extended Key Usage extension. See link:https://tools.ietf.org/html/rfc5280#section-4.2.1.12[RFC5280, Section-4.2.1.12] for more information. Leave this parameter empty to disable the Extended Key Usage validation. {project_name} raises an error when flagged as critical by the issuing CA and a key usage extension mismatch occurs.
|
||||
|
||||
`Enable CRL Distribution Point to check certificate revocation status` (optional)::
|
||||
Defines whether to use CDP to check the certificate revocation status. Most PKI authorities include CDP in their certificates.
|
||||
|
||||
`CRL file path` (optional)::
|
||||
Defines a path to a file that contains a CRL list. The value must be a path to a valid file if `CRL Checking Enabled` option is turned on.
|
||||
|
||||
`OCSP Checking Enabled`(optional)::
|
||||
Defines whether to check the certificate revocation status using Online Certificate Status Protocol.
|
||||
|
||||
`OCSP Responder URI` (optional)::
|
||||
Allows to override a value of the OCSP responder URI in the certificate.
|
||||
|
||||
`Validate Key Usage` (optional)::
|
||||
Verifies whether the certificate's KeyUsage extension bits are set. For example, "digitalSignature,KeyEncipherment" will verify if bits 0 and 2 in the KeyUsage extension are asserted. Leave the parameter empty to disable the Key Usage validation. See link:https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3[RFC5280, Section-4.2.1.3]. The server will raise an error only when flagged as critical by the issuing CA and there is a key usage extension mismatch.
|
||||
|
||||
`Validate Extended Key Usage` (optional)::
|
||||
Verifies one or more purposes as defined in the Extended Key Usage extension. See link:https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.12[RFC5280, Section-4.2.1.12]. Leave the parameter empty to disable the Extended Key Usage validation. The server will raise an error only when flagged as critical by the issuing CA and there is a key usage extension mismatch.
|
||||
|
||||
`Bypass identity confirmation`::
|
||||
If set, X.509 client certificate authentication will not prompt the user to confirm the certificate identity and will automatically sign in the user upon successful authentication.
|
||||
*Bypass identity confirmation*::
|
||||
If enabled, X.509 client certificate authentication does not prompt the user to confirm the certificate identity. {project_name} signs in the user upon successful authentication.
|
||||
|
||||
`Revalidate client certificate`::
|
||||
If set, the client certificate trust chain will be always verified at the application level using the certificates present in the configured trust store. This can be useful if the underlying web server does not enforce client certificate chain validation, for example because it is behind a non-validating load balancer or reverse proxy, or when the number of allowed CAs is too large for the mutual SSL negotiation (most browsers cap the maximum SSL negotiation packet size at 32767 bytes, which corresponds to about 200 advertised CAs). By default this option is off.
|
||||
|
||||
==== Adding X.509 Client Certificate Authentication to a Direct Grant Flow
|
||||
|
||||
* Using {project_name} admin console, click on "Authentication" and select the "Direct Grant" flow,
|
||||
* Make a copy of the build-in "Direct Grant" flow. You may want to give the new flow a distinctive name, i.e. "X509 Direct Grant",
|
||||
* Delete "Username Validation" and "Password" authenticators,
|
||||
* Click on "Add execution" and add "X509/Validate Username" and click on "Save" to add the execution step to the parent flow.
|
||||
|
||||
image:images/x509-directgrant-execution.png[]
|
||||
|
||||
* Change the `Requirement` to _REQUIRED_.
|
||||
|
||||
image:images/x509-directgrant-flow.png[]
|
||||
|
||||
* Set up the x509 authentication configuration by following the steps described earlier in the x.509 Browser Flow section.
|
||||
* Select the "Bindings" tab, find the drop down for "Direct Grant Flow". Select the newly created X509 direct grant flow from the drop down and click on "Save".
|
||||
|
||||
image:images/x509-directgrant-flow-bindings.png[]
|
||||
. Click *Authentication* in the menu.
|
||||
. Click the "Direct Grant" flow.
|
||||
. Click *Copy* to make a copy of the "Direct Grant" flow.
|
||||
. Enter a name for the copy.
|
||||
. Click *Ok*.
|
||||
. Click on the *Actions* link for "Username Validation" and click *Delete*.
|
||||
. Click *Delete*.
|
||||
. Click on the *Actions* link for "Password" and click *Delete*.
|
||||
. Click *Delete*.
|
||||
. Click *Add execution*.
|
||||
. Click "X509/Validate Username".
|
||||
. Click *Save*.
|
||||
+
|
||||
.X509 Direct Grant Execution
|
||||
image:images/x509-directgrant-execution.png[X509 Direct Grant Execution]
|
||||
+
|
||||
. Set up the x509 authentication configuration by following the steps described in the <<_browser_flow, x509 Browser Flow>> section.
|
||||
. Click the *Bindings* tab.
|
||||
. Click the *Direct Grant Flow* drop-down list.
|
||||
. Click the newly created "x509 Direct Grant" flow.
|
||||
. Click *Save*.
|
||||
+
|
||||
.X509 Direct Grant Flow Bindings
|
||||
image:images/x509-directgrant-flow-bindings.png[X509 Direct Grant Flow Bindings]
|
||||
|
||||
==== Client certificate lookup
|
||||
|
||||
When an HTTP request is sent directly to {project_name} server, the {appserver_name} undertow subsystem will establish an SSL handshake and extract the client certificate. The client certificate will be then saved to the attribute `javax.servlet.request.X509Certificate` of the HTTP request, as specified in the servlet specification. The {project_name} X509 authenticator will be then able to lookup the certificate from this attribute.
|
||||
When the {project_name} server receives a direct HTTP request, the {appserver_name} undertow subsystem establishes an SSL handshake and extracts the client certificate. The {appserver_name} saves the client certificate to the `javax.servlet.request.X509Certificate` attribute of the HTTP request, as specified in the servlet specification. The {project_name} X509 authenticator can look up the certificate from this attribute.
|
||||
|
||||
However, when the {project_name} server listens to HTTP requests behind a load balancer or reverse proxy, it may be the proxy server which extracts the client certificate and establishes the mutual SSL connection. A reverse proxy usually puts the authenticated client certificate in the HTTP header of the underlying request and forwards it to the back end {project_name} server. In this case, {project_name} must be able to look up the X.509 certificate chain from the HTTP headers instead of from the attribute of HTTP request, as is done for Undertow.
|
||||
However, when the {project_name} server listens to HTTP requests behind a load balancer or reverse proxy, the proxy server may extract the client certificate and establish a mutual SSL connection. A reverse proxy generally puts the authenticated client certificate in the HTTP header of the underlying request. The proxy forwards the request to the back end {project_name} server. In this case, {project_name} must look up the X.509 certificate chain from the HTTP headers rather than the attribute of the HTTP request.
|
||||
|
||||
If {project_name} is behind a reverse proxy, you usually need to configure alternative provider of the `x509cert-lookup` SPI in {project_dirref}/standalone/configuration/standalone.xml. Along with the `default` provider, which looks up the certificate from the HTTP header, we also have two additional built-in providers: `haproxy` and `apache`, which are described next.
|
||||
If {project_name} is behind a reverse proxy, you generally need to configure the alternative provider of the `x509cert-lookup` SPI in {project_dirref}/standalone/configuration/standalone.xml. With the `default` provider looking up the HTTP header certificate, two additional built-in providers exist: `haproxy` and `apache`.
|
||||
|
||||
===== HAProxy certificate lookup provider
|
||||
|
||||
You can use this provider when your {project_name} server is behind an HAProxy reverse proxy. Configure the server like this:
|
||||
You use this provider when your {project_name} server is behind an HAProxy reverse proxy. Use the following configuration for your server:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
|
@ -266,13 +292,13 @@ You can use this provider when your {project_name} server is behind an HAProxy r
|
|||
</spi>
|
||||
----
|
||||
|
||||
In this example configuration, the client certificate will be looked up from the HTTP header, `SSL_CLIENT_CERT`, and the other certificates from its chain will be looked up from HTTP headers like `CERT_CHAIN_0` , `CERT_CHAIN_1`, ..., `CERT_CHAIN_9` . The attribute `certificateChainLength` is the maximum length of the chain, so the last one tried attribute would be `CERT_CHAIN_9` .
|
||||
In this example configuration, the client certificate is looked up from the HTTP header, `SSL_CLIENT_CERT`, and the other certificates from its chain are looked up from HTTP headers such as `CERT_CHAIN_0` through `CERT_CHAIN_9`. The attribute `certificateChainLength` is the maximum length of the chain so the last attribute is `CERT_CHAIN_9`.
|
||||
|
||||
Consult the HAProxy documentation for the details of how the HTTP Headers for the client certificate and client certificate chain can be configured and their proper names.
|
||||
Consult the HAProxy documentation for the details of configuring the HTTP Headers for the client certificate and client certificate chain.
|
||||
|
||||
===== Apache certificate lookup provider
|
||||
|
||||
You can use this provider when your {project_name} server is behind an Apache reverse proxy. Configure the server like this:
|
||||
You can use this provider when your {project_name} server is behind an Apache reverse proxy. Use the following configuration for your server:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
|
@ -288,11 +314,11 @@ You can use this provider when your {project_name} server is behind an Apache re
|
|||
</spi>
|
||||
----
|
||||
|
||||
The configuration is same as for the `haproxy` provider. Consult the Apache documentation on link:https://httpd.apache.org/docs/current/mod/mod_ssl.html[mod_ssl] and link:https://httpd.apache.org/docs/current/mod/mod_headers.html[mod_headers] for the details of how the HTTP Headers for the client certificate and client certificate chain can be configured and their proper names.
|
||||
This configuration is the same as the `haproxy` provider. Consult the Apache documentation on link:https://httpd.apache.org/docs/current/mod/mod_ssl.html[mod_ssl] and link:https://httpd.apache.org/docs/current/mod/mod_headers.html[mod_headers] for details on how the HTTP Headers for the client certificate and client certificate chain are configured.
|
||||
|
||||
===== Nginx certificate lookup provider
|
||||
===== NGINX certificate lookup provider
|
||||
|
||||
You can use this provider when your {project_name} server is behind an Nginx reverse proxy. Configure the server like this:
|
||||
You can use this provider when your {project_name} server is behind an NGINX reverse proxy. Use the following configuration for your server:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
|
@ -308,14 +334,18 @@ You can use this provider when your {project_name} server is behind an Nginx rev
|
|||
</spi>
|
||||
----
|
||||
|
||||
NOTE: NGINX link:http://nginx.org/en/docs/http/ngx_http_ssl_module.html#variables[SSL/TLS module] does not expose the client certificate chain, so Keycloak NGINX certificate lookup provider is rebuilding it using the link:{installguide_truststore_link}[{installguide_truststore_name}]. Please populate Keycloak truststore using keytool CLI with all root and intermediate CA's needed for rebuilding client certificate chain.
|
||||
[NOTE]
|
||||
====
|
||||
The NGINX link:http://nginx.org/en/docs/http/ngx_http_ssl_module.html#variables[SSL/TLS module] does not expose the client certificate chain. {project_name}'s NGINX certificate lookup provider rebuilds it by using the link:{installguide_truststore_link}[{installguide_truststore_name}]. Populate the {project_name} truststore by using the keytool CLI with all root and intermediate CA's for rebuilding client certificate chain.
|
||||
====
|
||||
|
||||
Consult the NGINX documentation for the details of configuring the HTTP Headers for the client certificate.
|
||||
|
||||
Consult the NGINX documentation for the details of how the HTTP Headers for the client certificate can be configured.
|
||||
Example of NGINX configuration file :
|
||||
[source,txt]
|
||||
----
|
||||
...
|
||||
server {
|
||||
server {
|
||||
...
|
||||
ssl_client_certificate trusted-ca-list-for-client-auth.pem;
|
||||
ssl_verify_client optional_no_ca;
|
||||
|
@ -330,16 +360,19 @@ Example of NGINX configuration file :
|
|||
}
|
||||
----
|
||||
|
||||
NOTE: all certificates in trusted-ca-list-for-client-auth.pem must be added to link:{installguide_truststore_link}[{installguide_truststore_name}].
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
All certificates in trusted-ca-list-for-client-auth.pem must be added to link:{installguide_truststore_link}[{installguide_truststore_name}].
|
||||
====
|
||||
|
||||
===== Other reverse proxy implementations
|
||||
|
||||
We do not have built-in support for other reverse proxy implementations. However, it is possible that other reverse proxies can be made to behave in a similar way to `apache` or `haproxy` and that some of those providers can be used. If none of those works, you may need to create your own implementation of the `org.keycloak.services.x509.X509ClientCertificateLookupFactory` and `org.keycloak.services.x509.X509ClientCertificateLookup` provider. See the link:{developerguide_link}[{developerguide_name}] for the details on how to add your own provider.
|
||||
{project_name} does not have built-in support for other reverse proxy implementations. However, you can make other reverse proxies behave in a similar way to `apache` or `haproxy`. If none of these work, create your implementation of the `org.keycloak.services.x509.X509ClientCertificateLookupFactory` and `org.keycloak.services.x509.X509ClientCertificateLookup` providers. See the link:{developerguide_link}[{developerguide_name}] for details on how to add your provider.
|
||||
|
||||
==== Troubleshooting
|
||||
|
||||
Dumping HTTP headers::
|
||||
If you want to view what the reverse proxy is sending to Keycloak, enable the `RequestDumpingHandler` Undertow filter and consult `server.log` file.
|
||||
To view what the reverse proxy sends to Keycloak, enable the `RequestDumpingHandler` Undertow filter and consult the `server.log` file.
|
||||
|
||||
Enable TRACE logging under the logging subsystem::
|
||||
[source,xml]
|
||||
|
@ -355,10 +388,13 @@ Enable TRACE logging under the logging subsystem::
|
|||
<level name="TRACE"/>
|
||||
</logger>
|
||||
----
|
||||
WARNING: Don't use RequestDumpingHandler or TRACE logging in production.
|
||||
|
||||
[WARNING]
|
||||
====
|
||||
Do not use RequestDumpingHandler or TRACE logging in production.
|
||||
====
|
||||
|
||||
Direct Grant authentication with X.509::
|
||||
The following template can be used to request a token using the Resource Owner Password Credentials Grant:
|
||||
You can use the following template to request a token by using the Resource Owner Password Credentials Grant:
|
||||
|
||||
```
|
||||
$ curl https://[host][:port]/auth/realms/master/protocol/openid-connect/token \
|
||||
|
@ -369,17 +405,16 @@ $ curl https://[host][:port]/auth/realms/master/protocol/openid-connect/token \
|
|||
```
|
||||
|
||||
`[host][:port]`::
|
||||
The host and the port number of a remote {project_name} server that has been configured to allow users authenticate with x.509 client certificates using the Direct Grant Flow.
|
||||
The host and the port number of the remote {project_name} server.
|
||||
|
||||
`CLIENT_ID`::
|
||||
A client id.
|
||||
The client id.
|
||||
|
||||
`CLIENT_SECRET`::
|
||||
For confidential clients, a client secret; otherwise, leave it empty.
|
||||
For confidential clients, a client secret.
|
||||
|
||||
`client_cert.crt`::
|
||||
A public key certificate that will be used to verify the identity of the client in mutual SSL authentication. The certificate should be in PEM format.
|
||||
A public key certificate to verify the identity of the client in mutual SSL authentication. The certificate must be in PEM format.
|
||||
|
||||
`client_cert.key`::
|
||||
A private key in the public key pair. Also expected in PEM format.
|
||||
|
||||
A private key in the public key pair. This key must be in PEM format.
|
||||
|
|
Loading…
Reference in a new issue