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.
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 Red Hat Single Sign-On, but unacceptable in production environments. Red Hat Single Sign-On has a rich set of password policies you can enable 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.
Password Policy
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:
Failed Password Policy
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.
Here’s an explanation of each policy type:
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.
Red Hat Single Sign-On 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.
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 Red Hat Single Sign-On has. The bar code is also generated from information configured on the OTP Policy
tab.
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 the all 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 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 Red Hat Single Sign-On 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 Red Hat Single Sign-On it is planned that you will be able to configure whether TOTP checks older OTPs in the time interval.
An authentication flow is a container for all authentications, screens, and actions that must happen during login, registration, and other Red Hat Single Sign-On 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. This section does a walk through of the browser login flow. In the left drop down list select browser
to come to the screen shown below:
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.
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:
OTP Form
to Required
, users that don’t have an OTP generator configured will be asked to do so.
This is better described in an example. Let’s walk through the browser
authentication flow.
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. 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.
Cookie
authentication type passed. This subflow contains additional authentication type that needs to be executed. The executions for this subflow are loaded and the same processing logic occurs
Red Hat Single Sign-On 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, Red Hat Single Sign-On also supports login with Kerberos username/password.
A typical use case for web authentication is the following:
WWW-Authenticate: Negotiate
Authorization: Negotiate 'spnego-token'
. Otherwise it just displays the login screen.
For setup there are 3 main parts:
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.
At least you will need to:
Add service principal for "HTTP" service. For example if your Red Hat Single Sign-On 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.
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:
sudo kadmin.local
Then add HTTP principal and export his key to a keytab file with the commands like:
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 Red Hat Single Sign-On server will be running.
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:
[domain_realm] .mydomain.org = MYDOMAIN.ORG 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 Red Hat Single Sign-On 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 Red Hat Single Sign-On are running on same host, you have that file already available.
Red Hat Single Sign-On does not have the SPNEGO protocol support turned on by default. So, you have to go to the browser flow and enable Kerberos
.
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 Red Hat Single Sign-On 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.
Now that the SPNEGO protocol is turned on at the authentication server, you’ll need to configure how Red Hat Single Sign-On interprets the Kerberos ticket. This is done through User Storage Federation. We have 2 different federation providers with Kerberos authentication support.
If you want to authenticate with Kerberos backed by an LDAP server, you have to first configure the LDAP Federation Provider. If you look at the configuration page for your LDAP provider you’ll see a Kerberos Integration
section.
LDAP Kerberos Integration
Turning on the switch Allow Kerberos authentication
will make Red Hat Single Sign-On use the Kerberos principal to lookup information about the user so that it can be imported into the Red Hat Single Sign-On 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.
Kerberos User Storage Provider
This provider parses the Kerberos ticket for simple principal information and does a small import into the local Red Hat Single Sign-On database. User profile information like first name, last name, and email are not provisioned.
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 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.
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.
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 Red Hat Single Sign-On 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 Red Hat Single Sign-On 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 chapter for more details.
Applications will need to deserialize the claim it receives from Red Hat Single Sign-On 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:
// Obtain accessToken in your application. KeycloakPrincipal keycloakPrincipal = (KeycloakPrincipal) servletReq.getUserPrincipal(); AccessToken accessToken = keycloakPrincipal.getKeycloakSecurityContext().getToken(); // 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 GSSContext context = gssManager.createContext(serviceName, krb5Oid, deserializedGssCredential, GSSContext.DEFAULT_LIFETIME);
Note that you also need to configure forwardable
kerberos tickets in krb5.conf
file and add support for delegated credentials to your browser.
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 this article for more details.
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.
Kerberos cross-realm trust
The Red Hat Single Sign-On server has support for cross-realm trust. There are few things which need to be done to achieve this:
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.
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 Red Hat Single Sign-On server
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 Red Hat Single Sign-On, as Red Hat Single Sign-On 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.
HTTP/mydomain.com@B
and users from both Kerberos realms A and B should be able to authenticate.
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 Red Hat Single Sign-On user. This is also something, which we want to improve in future versions and provide some more flexible mappings from Kerberos principals to Red Hat Single Sign-On usernames.
If you have issues, we recommend that you enable additional logging to debug the problem:
Debug
flag in admin console for Kerberos or LDAP federation providers
org.keycloak
in logging section of standalone/configuration/standalone.xml
to receive more info standalone/log/server.log
-Dsun.security.krb5.debug=true
and -Dsun.security.spnego.debug=true
Red Hat Single Sign-On supports login with a X.509 client certificate if the server is configured for mutual SSL authentication.
A typical workflow is as follows:
The x.509 client certificate authenticator validates the client certificate as follows:
Once the certificate is mapped to an existing user, the behavior diverges depending on the authentication flow:
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
.
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.
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 following sections describe how to configure Wildfly/Undertow and the Red Hat Single Sign-On Server to enable X.509 client certificate authentication.
See Enable SSL and SSL for the instructions how to enable SSL in Wildfly.
<security-realms> <security-realm name="ssl-realm"> <server-identities> <ssl> <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" keystore-password="truststore password"/> </authentication> </security-realm> </security-realms>
ssl/keystore
ssl
element contains the keystore
element that defines how to load the server public key pair from a JKS keystore
ssl/keystore/path
ssl/keystore/relative-to
ssl/keystore/keystore-password
ssl/keystore/alias
(optional)ssl/keystore/key-password
(optional)authentication/truststore
authentication/truststore/path
authentication/truststore/relative-to
authentication/truststore/keystore-password
See HTTPS Listener for the instructions how to enable HTTPS in Wildfly.
<subsystem xmlns="urn:jboss:domain:undertow:4.0"> .... <server name="default-server"> <https-listener name="default" socket-binding="https" security-realm="ssl-realm" verify-client="REQUESTED"/> </server> </subsystem>
https-listener/security-realm
https-listener/verify-client
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.
User Identity Source
A regular expression
(optional)User Mapping Method
A name of user attribute
(optional)CRL Checking Enabled
(optional)Enable CRL Distribution Point to check certificate revocation status
(optional)CRL file path
(optional)CRL Checking Enabled
option is turned on.
OCSP Checking Enabled
(optional)OCSP Responder URI
(optional)Validate Key Usage
(optional)Validate Extended Key Usage
(optional)Bypass identity confirmation
Requirement
to REQUIRED.
When an HTTP request is sent directly to Red Hat Single Sign-On server, the JBoss EAP 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 Red Hat Single Sign-On X509 authenticator will be then able to lookup the certificate from this attribute.
However, when the Red Hat Single Sign-On 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 Red Hat Single Sign-On server. In this case, Red Hat Single Sign-On 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.
If Red Hat Single Sign-On is behind a reverse proxy, you usually need to configure alternative provider of the x509cert-lookup
SPI in RHSSO_HOME/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.
You can use this provider when your Red Hat Single Sign-On server is behind an HAProxy reverse proxy. Configure the server like this:
<spi name="x509cert-lookup"> <default-provider>haproxy</default-provider> <provider name="haproxy" enabled="true"> <properties> <property name="sslClientCert" value="SSL_CLIENT_CERT"/> <property name="sslCertChainPrefix" value="CERT_CHAIN"/> <property name="certificateChainLength" value="10"/> </properties> </provider> </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
.
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.
You can use this provider when your Red Hat Single Sign-On server is behind an Apache reverse proxy. Configure the server like this:
<spi name="x509cert-lookup"> <default-provider>apache</default-provider> <provider name="apache" enabled="true"> <properties> <property name="sslClientCert" value="SSL_CLIENT_CERT"/> <property name="sslCertChainPrefix" value="CERT_CHAIN"/> <property name="certificateChainLength" value="10"/> </properties> </provider> </spi>
The configuration is same as for the haproxy
provider. Consult the Apache documentation for the details of how the HTTP Headers for the client certificate and client certificate chain can be configured and their proper names.
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 Server Developer Guide for the details on how to add your own provider.
$ curl https://[host][:port]/auth/realms/master/protocol/openid-connect/token \ --insecure \ --data "grant_type=password&scope=openid profile&username=&password=&client_id=CLIENT_ID&client_secret=CLIENT_SECRET" \ -E /path/to/client_cert.crt \ --key /path/to/client_cert.key
[host][:port]
CLIENT_ID
CLIENT_SECRET
client_cert.crt
client_cert.key