3.1. Java Adapters
Keycloak comes with a range of different adapters for Java application. Selecting the correct adapter depends on the target platform.
3.1.1. General Adapter Config
Each SAML client adapter supported by Keycloak can be configured by a simple XML text file. This is what one might look like:
<keycloak-saml-adapter xmlns="urn:keycloak:saml:adapter"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:keycloak:saml:adapter http://www.keycloak.org/schema/keycloak_saml_adapter_1_9.xsd">
<SP entityID="http://localhost:8081/sales-post-sig/"
sslPolicy="EXTERNAL"
nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
logoutPage="/logout.jsp"
forceAuthentication="false"
isPassive="false"
turnOffChangeSessionIdOnLogin="false"
autodetectBearerOnly="false">
<Keys>
<Key signing="true" >
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
<PrivateKey alias="http://localhost:8080/sales-post-sig/" password="test123"/>
<Certificate alias="http://localhost:8080/sales-post-sig/"/>
</KeyStore>
</Key>
</Keys>
<PrincipalNameMapping policy="FROM_NAME_ID"/>
<RoleIdentifiers>
<Attribute name="Role"/>
</RoleIdentifiers>
<IDP entityID="idp"
signaturesRequired="true">
<SingleSignOnService requestBinding="POST"
bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
/>
<SingleLogoutService
requestBinding="POST"
responseBinding="POST"
postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
/>
<Keys>
<Key signing="true">
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
<Certificate alias="demo"/>
</KeyStore>
</Key>
</Keys>
</IDP>
</SP>
</keycloak-saml-adapter>
Some of these configuration switches may be adapter specific and some are common across all adapters.
For Java adapters you can use ${…}
enclosure as System property replacement.
For example ${jboss.server.config.dir}
.
SP Element
Here is the explanation of the SP element attributes:
<SP entityID="sp"
sslPolicy="ssl"
nameIDPolicyFormat="format"
forceAuthentication="true"
isPassive="false"
autodetectBearerOnly="false">
...
</SP>
- entityID
-
This is the identifier for this client. The IdP needs this value to determine who the client is that is communicating with it. This setting is REQUIRED.
- sslPolicy
-
This is the SSL policy the adapter will enforce. Valid values are:
ALL
,EXTERNAL
, andNONE
. ForALL
, all requests must come in via HTTPS. ForEXTERNAL
, only non-private IP addresses must come over the wire via HTTPS. ForNONE
, no requests are required to come over via HTTPS. This setting is OPTIONAL. Default value isEXTERNAL
. - nameIDPolicyFormat
-
SAML clients can request a specific NameID Subject format. Fill in this value if you want a specific format. It must be a standard SAML format identifier:
urn:oasis:names:tc:SAML:2.0:nameid-format:transient
. This setting is OPTIONAL. By default, no special format is requested. - forceAuthentication
-
SAML clients can request that a user is re-authenticated even if they are already logged in at the IdP. Set this to
true
to enable. This setting is OPTIONAL. Default value isfalse
. - isPassive
-
SAML clients can request that a user is never asked to authenticate even if they are not logged in at the IdP. Set this to
true
if you want this. Do not use together withforceAuthentication
as they are opposite. This setting is OPTIONAL. Default value isfalse
. - turnOffChangeSessionIdOnLogin
-
The session ID is changed by default on a successful login on some platforms to plug a security attack vector. Change this to
true
to disable this. It is recommended you do not turn it off. Default value isfalse
. - autodetectBearerOnly
-
This should be set to true if your application serves both a web application and web services (e.g. SOAP or REST). It allows you to redirect unauthenticated users of the web application to the Keycloak login page, but send an HTTP
401
status code to unauthenticated SOAP or REST clients instead as they would not understand a redirect to the login page. Keycloak auto-detects SOAP or REST clients based on typical headers likeX-Requested-With
,SOAPAction
orAccept
. The default value is false.
Service Provider Keys and Key Elements
If the IdP requires that the client application (or SP) sign all of its requests and/or if the IdP will encrypt assertions, you must define the keys used to do this. For client-signed documents you must define both the private and public key or certificate that is used to sign documents. For encryption, you only have to define the private key that is used to decrypt it.

They can be stored within a Java KeyStore or you can copy/paste the keys directly within keycloak-saml.xml
in the PEM format.
<Keys>
<Key signing="true" >
...
</Key>
</Keys>
The Key
element has two optional attributes signing
and encryption
.
When set to true these tell the adapter what the key will be used for.
If both attributes are set to true, then the key will be used for both signing documents and decrypting encrypted assertions.
You must set at least one of these attributes to true.
KeyStore element
Within the Key
element you can load your keys and certificates from a Java Keystore. This is declared within
a KeyStore
element.
<Keys>
<Key signing="true" >
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
<PrivateKey alias="myPrivate" password="test123"/>
<Certificate alias="myCertAlias"/>
</KeyStore>
</Key>
</Keys>
Here are the XML config attributes that are defined with the KeyStore
element.
- file
-
File path to the key store. This option is OPTIONAL. The file or resource attribute must be set.
- resource
-
WAR resource path to the KeyStore. This is a path used in method call to ServletContext.getResourceAsStream(). This option is OPTIONAL. The file or resource attribute must be set.
- password
-
The password of the KeyStore. This option is REQUIRED.
If you are defining keys that the SP will use to sign document, you must also specify references to your private keys
and certificates within the Java KeyStore.
The PrivateKey
and Certificate
elements in the above example define an alias
that points to the key or cert
within the keystore. Keystores require an additional password to access private keys.
In the PrivateKey
element you must define this password within a password
attribute.
Key PEMS
Within the Key
element you declare your keys and certificates directly using the sub elements
PrivateKeyPem
, PublicKeyPem
, and CertificatePem
.
The values contained in these elements must conform to the PEM key format.
You usually use this option if you are generating keys using openssl
or similar command line tool.
<Keys>
<Key signing="true">
<PrivateKeyPem>
2341251234AB31234==231BB998311222423522334
</PrivateKeyPem>
<CertificatePem>
211111341251234AB31234==231BB998311222423522334
</CertificatePem>
</Key>
</Keys>
SP PrincipalNameMapping element
This element is optional.
When creating a Java Principal object that you obtain from methods such as HttpServletRequest.getUserPrincipal()
, you can define what name is returned by the Principal.getName()
method.
<SP ...>
<PrincipalNameMapping policy="FROM_NAME_ID"/>
</SP>
<SP ...>
<PrincipalNameMapping policy="FROM_ATTRIBUTE" attribute="email" />
</SP>
The policy
attribute defines the policy used to populate this value.
The possible values for this attribute are:
- FROM_NAME_ID
-
This policy just uses whatever the SAML subject value is. This is the default setting
- FROM_ATTRIBUTE
-
This will pull the value from one of the attributes declared in the SAML assertion received from the server. You’ll need to specify the name of the SAML assertion attribute to use within the
attribute
XML attribute.
RoleIdentifiers Element
The RoleIdentifiers
element defines what SAML attributes within the assertion received from the user should be used
as role identifiers within the Java EE Security Context for the user.
<RoleIdentifiers>
<Attribute name="Role"/>
<Attribute name="member"/>
<Attribute name="memberOf"/>
</RoleIdentifiers>
By default Role
attribute values are converted to Java EE roles.
Some IdPs send roles using a member
or memberOf
attribute assertion.
You can define one or more Attribute
elements to specify which SAML attributes must be converted into roles.
IDP Element
Everything in the IDP element describes the settings for the identity provider (authentication server) the SP is communicating with.
<IDP entityID="idp"
signaturesRequired="true"
signatureAlgorithm="RSA_SHA1"
signatureCanonicalizationMethod="http://www.w3.org/2001/10/xml-exc-c14n#">
...
</IDP>
Here are the attribute config options you can specify within the IDP
element declaration.
- entityID
-
This is the issuer ID of the IDP. This setting is REQUIRED.
- signaturesRequired
-
If set to
true
, the client adapter will sign every document it sends to the IDP. Also, the client will expect that the IDP will be signing any documents sent to it. This switch sets the default for all request and response types, but you will see later that you have some fine grain control over this. This setting is OPTIONAL and will default tofalse
. - signatureAlgorithm
-
This is the signature algorithm that the IDP expects signed documents to use. Allowed values are:
RSA_SHA1
,RSA_SHA256
,RSA_SHA512
, andDSA_SHA1
. This setting is OPTIONAL and defaults toRSA_SHA256
. - signatureCanonicalizationMethod
-
This is the signature canonicalization method that the IDP expects signed documents to use. This setting is OPTIONAL. The default value is
http://www.w3.org/2001/10/xml-exc-c14n#
and should be good for most IDPs.
IDP SingleSignOnService sub element
The SingleSignOnService
sub element defines the login SAML endpoint of the IDP.
The client adapter will send requests
to the IDP formatted via the settings within this element when it wants to login.
<SingleSignOnService signRequest="true"
validateResponseSignature="true"
requestBinding="post"
bindingUrl="url"/>
Here are the config attributes you can define on this element:
- signRequest
-
Should the client sign authn requests? This setting is OPTIONAL. Defaults to whatever the IDP
signaturesRequired
element value is. - validateResponseSignature
-
Should the client expect the IDP to sign the assertion response document sent back from an auhtn request? This setting OPTIONAL. Defaults to whatever the IDP
signaturesRequired
element value is. - requestBinding
-
This is the SAML binding type used for communicating with the IDP. This setting is OPTIONAL. The default value is
POST
, but you can set it toREDIRECT
as well. - responseBinding
-
SAML allows the client to request what binding type it wants authn responses to use. The values of this can be
POST
orREDIRECT
. This setting is OPTIONAL. The default is that the client will not request a specific binding type for responses. - assertionConsumerServiceUrl
-
URL of the assertion consumer service (ACS) where the IDP login service should send responses to. This setting is OPTIONAL. By default it is unset, relying on the configuration in the IdP. When set, it must end in
/saml
, e.g.http://sp.domain.com/my/endpoint/for/saml
. The value of this property is sent inAssertionConsumerServiceURL
attribute of SAMLAuthnRequest
message. This property is typically accompanied by theresponseBinding
attribute. - bindingUrl
-
This is the URL for the IDP login service that the client will send requests to. This setting is REQUIRED.
IDP SingleLogoutService sub element
The SingleLogoutService
sub element defines the logout SAML endpoint of the IDP. The client adapter will send requests
to the IDP formatted via the settings within this element when it wants to logout.
<SingleLogoutService validateRequestSignature="true"
validateResponseSignature="true"
signRequest="true"
signResponse="true"
requestBinding="redirect"
responseBinding="post"
postBindingUrl="posturl"
redirectBindingUrl="redirecturl">
- signRequest
-
Should the client sign logout requests it makes to the IDP? This setting is OPTIONAL. Defaults to whatever the IDP
signaturesRequired
element value is. - signResponse
-
Should the client sign logout responses it sends to the IDP requests? This setting is OPTIONAL. Defaults to whatever the IDP
signaturesRequired
element value is. - validateRequestSignature
-
Should the client expect signed logout request documents from the IDP? This setting is OPTIONAL. Defaults to whatever the IDP
signaturesRequired
element value is. - validateResponseSignature
-
Should the client expect signed logout response documents from the IDP? This setting is OPTIONAL. Defaults to whatever the IDP
signaturesRequired
element value is. - requestBinding
-
This is the SAML binding type used for communicating SAML requests to the IDP. This setting is OPTIONAL. The default value is
POST
, but you can set it to REDIRECT as well. - responseBinding
-
This is the SAML binding type used for communicating SAML responses to the IDP. The values of this can be
POST
orREDIRECT
. This setting is OPTIONAL. The default value isPOST
, but you can set it toREDIRECT
as well. - postBindingUrl
-
This is the URL for the IDP’s logout service when using the POST binding. This setting is REQUIRED if using the
POST
binding. - redirectBindingUrl
-
This is the URL for the IDP’s logout service when using the REDIRECT binding. This setting is REQUIRED if using the REDIRECT binding.
IDP Keys sub element
The Keys sub element of IDP is only used to define the certificate or public key to use to verify documents signed by the IDP. It is defined in the same way as the SP’s Keys element. But again, you only have to define one certificate or public key reference. Note that, if both IDP and SP are realized by Keycloak server and adapter, respectively, there is no need to specify the keys for signature validation, see below.
It is possible to configure SP to obtain public keys for IDP signature validation from published certificates automatically, provided both SP and IDP are implemented by Keycloak. This is done by removing all declarations of signature validation keys in Keys sub element. If the Keys sub element would then remain empty, it can be omitted completely. The keys are then automatically obtained by SP from SAML descriptor, location of which is derived from SAML endpoint URL specified in the IDP SingleSignOnService sub element. Settings of the HTTP client that is used for SAML descriptor retrieval usually needs no additional configuration, however it can be configured in the IDP HttpClient sub element.
It is also possible to specify multiple keys for signature verification. This is done by declaring multiple Key elements
within Keys sub element that have signing
attribute set to true
.
This is useful for example in situation when the IDP signing keys are rotated: There is
usually a transition period when new SAML protocol messages and assertions are signed
with the new key but those signed by previous key should still be accepted.
It is not possible to configure Keycloak to both obtain the keys for signature verification automatically and define additional static signature verification keys.
<IDP entityID="idp">
...
<Keys>
<Key signing="true">
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
<Certificate alias="demo"/>
</KeyStore>
</Key>
</Keys>
</IDP>
IDP HttpClient sub element
The HttpClient
optional sub element defines the properties of HTTP client used
for automatic obtaining of certificates containing public keys for IDP signature
verification via SAML descriptor of the IDP when
enabled.
<HttpClient connectionPoolSize="10"
disableTrustManager="false"
allowAnyHostname="false"
clientKeystore="classpath:keystore.jks"
clientKeystorePassword="pwd"
truststore="classpath:truststore.jks"
truststorePassword="pwd"
proxyUrl="http://proxy/" />
- connectionPoolSize
-
Adapters will make separate HTTP invocations to the Keycloak server to turn an access code into an access token. This config option defines how many connections to the Keycloak server should be pooled. This is OPTIONAL. The default value is
10
. - disableTrustManager
-
If the Keycloak server requires HTTPS and this config option is set to
true
you do not have to specify a truststore. This setting should only be used during development and never in production as it will disable verification of SSL certificates. This is OPTIONAL. The default value isfalse
. - allowAnyHostname
-
If the Keycloak server requires HTTPS and this config option is set to
true
the Keycloak server’s certificate is validated via the truststore, but host name validation is not done. This setting should only be used during development and never in production as it will partly disable verification of SSL certificates. This seting may be useful in test environments. This is OPTIONAL. The default value isfalse
. - truststore
-
The value is the file path to a keystore file. If you prefix the path with
classpath:
, then the truststore will be obtained from the deployment’s classpath instead. Used for outgoing HTTPS communications to the Keycloak server. Client making HTTPS requests need a way to verify the host of the server they are talking to. This is what the trustore does. The keystore contains one or more trusted host certificates or certificate authorities. You can create this truststore by extracting the public certificate of the Keycloak server’s SSL keystore. This is REQUIRED unlessdisableTrustManager
istrue
. - truststorePassword
-
Password for the truststore keystore. This is REQUIRED if
truststore
is set and the truststore requires a password. - clientKeystore
-
This is the file path to a keystore file. This keystore contains client certificate for two-way SSL when the adapter makes HTTPS requests to the Keycloak server. This is OPTIONAL.
- clientKeystorePassword
-
Password for the client keystore and for the client’s key. This is REQUIRED if
clientKeystore
is set. - proxyUrl
-
URL to HTTP proxy to use for HTTP connections. This is OPTIONAL.
3.1.2. JBoss EAP/Wildfly Adapter
To be able to secure WAR apps deployed on JBoss EAP or Wildfly, you must install and configure the Keycloak SAML Adapter Subsystem.
You then provide a keycloak config, /WEB-INF/keycloak-saml.xml
file in your WAR and change the auth-method to KEYCLOAK-SAML within web.xml.
Both methods are described in this section.
Adapter Installation
Each adapter is a separate download on the Keycloak download site.
Install on Wildfly 9 or 10, 11 or JBoss EAP 7:
$ cd $WILDFLY_HOME
$ unzip keycloak-saml-wildfly-adapter-dist.zip
Install on JBoss EAP 6.x:
$ cd $JBOSS_HOME
$ unzip keycloak-saml-eap6-adapter-dist.zip
These zip files create new JBoss Modules specific to the Wildfly/JBoss EAP SAML Adapter within your Wildfly or JBoss EAP distro.
After adding the modules, you must then enable the Keycloak SAML Subsystem within your app server’s server configuration: domain.xml
or standalone.xml
.
There is a CLI script that will help you modify your server configuration. Start the server and run the script from the server’s bin directory:
$ ./bin/jboss-cli.sh --file=adapter-elytron-install-saml.cli
$ cd $JBOSS_HOME/bin
$ jboss-cli.sh -c --file=adapter-install-saml.cli
The script will add the extension, subsystem, and optional security-domain as described below.
<server xmlns="urn:jboss:domain:1.4">
<extensions>
<extension module="org.keycloak.keycloak-saml-adapter-subsystem"/>
...
</extensions>
<profile>
<subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1"/>
...
</profile>
The keycloak
security domain should be used with EJBs and other components when you need the security context created
in the secured web tier to be propagated to the EJBs (other EE component) you are invoking.
Otherwise this configuration is optional.
<server xmlns="urn:jboss:domain:1.4">
<subsystem xmlns="urn:jboss:domain:security:1.2">
<security-domains>
...
<security-domain name="keycloak">
<authentication>
<login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule"
flag="required"/>
</authentication>
</security-domain>
</security-domains>
For example, if you have a JAX-RS service that is an EJB within your WEB-INF/classes directory,
you’ll want to annotate it with the @SecurityDomain
annotation as follows:
import org.jboss.ejb3.annotation.SecurityDomain;
import org.jboss.resteasy.annotations.cache.NoCache;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import java.util.ArrayList;
import java.util.List;
@Path("customers")
@Stateless
@SecurityDomain("keycloak")
public class CustomerService {
@EJB
CustomerDB db;
@GET
@Produces("application/json")
@NoCache
@RolesAllowed("db_user")
public List<String> getCustomers() {
return db.getCustomers();
}
}
We hope to improve our integration in the future so that you don’t have to specify the
@SecurityDomain
annotation when you want to propagate a keycloak security context to the EJB tier.
Per WAR Configuration
This section describes how to secure a WAR directly by adding config and editing files within your WAR package.
The first thing you must do is create a keycloak-saml.xml
adapter config file within the WEB-INF
directory of your WAR.
The format of this config file is described in the General Adapter Config section.
Next you must set the auth-method
to KEYCLOAK-SAML
in web.xml
.
You also have to use standard servlet security to specify role-base constraints on your URLs.
Here’s an example web.xml file:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<module-name>customer-portal</module-name>
<security-constraint>
<web-resource-collection>
<web-resource-name>Admins</web-resource-name>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Customers</web-resource-name>
<url-pattern>/customers/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>KEYCLOAK-SAML</auth-method>
<realm-name>this is ignored currently</realm-name>
</login-config>
<security-role>
<role-name>admin</role-name>
</security-role>
<security-role>
<role-name>user</role-name>
</security-role>
</web-app>
All standard servlet settings except the auth-method
setting.
Securing WARs via Keycloak SAML Subsystem
You do not have to crack open a WAR to secure it with Keycloak.
Alternatively, you can externally secure it via the Keycloak SAML Adapter Subsystem.
While you don’t have to specify KEYCLOAK-SAML as an auth-method
, you still have to define the security-constraints
in web.xml
.
You do not, however, have to create a WEB-INF/keycloak-saml.xml
file.
This metadata is instead defined within the XML in your server’s domain.xml
or standalone.xml
subsystem configuration section.
<extensions>
<extension module="org.keycloak.keycloak-saml-adapter-subsystem"/>
</extensions>
<profile>
<subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1">
<secure-deployment name="WAR MODULE NAME.war">
<SP entityID="APPLICATION URL">
...
</SP>
</secure-deployment>
</subsystem>
</profile>
The secure-deployment
name
attribute identifies the WAR you want to secure.
Its value is the module-name
defined in web.xml
with .war
appended.
The rest of the configuration uses the same XML syntax as keycloak-saml.xml
configuration defined in General Adapter Config.
An example configuration:
<subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1">
<secure-deployment name="saml-post-encryption.war">
<SP entityID="http://localhost:8080/sales-post-enc/"
sslPolicy="EXTERNAL"
nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
logoutPage="/logout.jsp"
forceAuthentication="false">
<Keys>
<Key signing="true" encryption="true">
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
<PrivateKey alias="http://localhost:8080/sales-post-enc/" password="test123"/>
<Certificate alias="http://localhost:8080/sales-post-enc/"/>
</KeyStore>
</Key>
</Keys>
<PrincipalNameMapping policy="FROM_NAME_ID"/>
<RoleIdentifiers>
<Attribute name="Role"/>
</RoleIdentifiers>
<IDP entityID="idp">
<SingleSignOnService signRequest="true"
validateResponseSignature="true"
requestBinding="POST"
bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
<SingleLogoutService
validateRequestSignature="true"
validateResponseSignature="true"
signRequest="true"
signResponse="true"
requestBinding="POST"
responseBinding="POST"
postBindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"
redirectBindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
<Keys>
<Key signing="true" >
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
<Certificate alias="saml-demo"/>
</KeyStore>
</Key>
</Keys>
</IDP>
</SP>
</secure-deployment>
</subsystem>
3.1.3. Tomcat SAML adapters
To be able to secure WAR apps deployed on Tomcat 6, 7 and 8 you must install the Keycloak Tomcat 6, 7 or 8 SAML adapter into your Tomcat installation. You then have to provide some extra configuration in each WAR you deploy to Tomcat. Let’s go over these steps.
Adapter Installation
Adapters are no longer included with the appliance or war distribution. Each adapter is a separate download on the Keycloak download site. They are also available as a maven artifact.
You must unzip the adapter distro into Tomcat’s lib/
directory.
Including adapter’s jars within your WEB-INF/lib directory will not work! The Keycloak SAML adapter is implemented as
a Valve and valve code must reside in Tomcat’s main lib/ directory.
$ cd $TOMCAT_HOME/lib
$ unzip keycloak-saml-tomcat6-adapter-dist.zip
or
$ unzip keycloak-saml-tomcat7-adapter-dist.zip
or
$ unzip keycloak-saml-tomcat8-adapter-dist.zip
Per WAR Configuration
This section describes how to secure a WAR directly by adding config and editing files within your WAR package.
The first thing you must do is create a META-INF/context.xml
file in your WAR package.
This is a Tomcat specific config file and you must define a Keycloak specific Valve.
<Context path="/your-context-path">
<Valve className="org.keycloak.adapters.saml.tomcat.SamlAuthenticatorValve"/>
</Context>
Next you must create a keycloak-saml.xml
adapter config file within the WEB-INF
directory of your WAR.
The format of this config file is described in the General Adapter Config section.
Finally you must specify both a login-config
and use standard servlet security to specify role-base constraints on your URLs.
Here’s an example:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<module-name>customer-portal</module-name>
<security-constraint>
<web-resource-collection>
<web-resource-name>Customers</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>this is ignored currently</realm-name>
</login-config>
<security-role>
<role-name>admin</role-name>
</security-role>
<security-role>
<role-name>user</role-name>
</security-role>
</web-app>
3.1.4. Jetty SAML Adapters
To be able to secure WAR apps deployed on Jetty you must install the Keycloak Jetty 9.x or 8.x SAML adapter into your Jetty installation. You then have to provide some extra configuration in each WAR you deploy to Jetty. Let’s go over these steps.
Jetty 9 Adapter Installation
Keycloak has a separate SAML adapter for Jetty 9.x. You then have to provide some extra configuration in each WAR you deploy to Jetty. Let’s go over these steps.
Adapters are no longer included with the appliance or war distribution. Each adapter is a separate download on the Keycloak download site. They are also available as a maven artifact.
You must unzip the Jetty 9.x distro into Jetty 9.x’s root directory. Including adapter’s jars within your WEB-INF/lib directory will not work!
$ cd $JETTY_HOME
$ unzip keycloak-saml-jetty92-adapter-dist.zip
Next, you will have to enable the keycloak module for your jetty.base.
$ cd your-base
$ java -jar $JETTY_HOME/start.jar --add-to-startd=keycloak
Jetty 9 Per WAR Configuration
This section describes how to secure a WAR directly by adding config and editing files within your WAR package.
The first thing you must do is create a WEB-INF/jetty-web.xml
file in your WAR package.
This is a Jetty specific config file and you must define a Keycloak specific authenticator within it.
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Get name="securityHandler">
<Set name="authenticator">
<New class="org.keycloak.adapters.saml.jetty.KeycloakSamlAuthenticator">
</New>
</Set>
</Get>
</Configure>
Next you must create a keycloak-saml.xml
adapter config file within the WEB-INF
directory of your WAR.
The format of this config file is described in the General Adapter Config section.
Finally you must specify both a login-config
and use standard servlet security to specify role-base constraints on your URLs.
Here’s an example:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<module-name>customer-portal</module-name>
<security-constraint>
<web-resource-collection>
<web-resource-name>Customers</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>this is ignored currently</realm-name>
</login-config>
<security-role>
<role-name>admin</role-name>
</security-role>
<security-role>
<role-name>user</role-name>
</security-role>
</web-app>
Jetty 8 Adapter Installation
Keycloak has a separate SAML adapter for Jetty 8.1.x that you will have to install into your Jetty installation. You then have to provide some extra configuration in each WAR you deploy to Jetty. Let’s go over these steps.
Adapters are no longer included with the appliance or war distribution. Each adapter is a separate download on the Keycloak download site. They are also available as a maven artifact.
You must unzip the Jetty 8.1.x distro into Jetty 8.1.x’s root directory. Including adapter’s jars within your WEB-INF/lib directory will not work!
$ cd $JETTY_HOME
$ unzip keycloak-saml-jetty81-adapter-dist.zip
Next, you will have to enable the keycloak option. Edit start.ini and add keycloak to the options
#===========================================================
# Start classpath OPTIONS.
# These control what classes are on the classpath
# for a full listing do
# java -jar start.jar --list-options
#-----------------------------------------------------------
OPTIONS=Server,jsp,jmx,resources,websocket,ext,plus,annotations,keycloak
Jetty 8 Per WAR Configuration
Enabling Keycloak for your WARs is the same as the Jetty 9.x adapter. See Jetty 9 Per War Configuration
3.1.5. Java Servlet Filter Adapter
If you want to use SAML with a Java servlet application that doesn’t have an adapter for that servlet platform, you can
opt to use the servlet filter adapter that Keycloak has.
This adapter works a little differently than the other adapters.
You still have to specify a /WEB-INF/keycloak-saml.xml
file as defined in
the General Adapter Config section, but
you do not define security constraints in web.xml.
Instead you define a filter mapping using the Keycloak servlet filter adapter to secure the url patterns you want to secure.
| Backchannel logout works a bit differently than the standard adapters. Instead of invalidating the http session it instead marks the session ID as logged out. There’s just no way of arbitrarily invalidating an http session based on a session ID. |
| Backchannel logout does not currently work when you have a clustered application that uses the SAML filter. |
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<module-name>customer-portal</module-name>
<filter>
<filter-name>Keycloak Filter</filter-name>
<filter-class>org.keycloak.adapters.saml.servlet.SamlFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Keycloak Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
The Keycloak filter has the same configuration parameters available as the other adapters except you must define them as filter init params instead of context params.
You can define multiple filter mappings if you have various different secure and unsecure url patterns.
You must have a filter mapping that covers /saml .
This mapping covers all server callbacks.
|
When registering SPs with an IdP, you must register http[s]://hostname/{context-root}/saml
as your Assert Consumer Service URL and Single Logout Service URL.
To use this filter, include this maven artifact in your WAR poms:
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-servlet-filter-adapter</artifactId>
<version>3.4.1.CR1</version>
</dependency>
3.1.6. Registering with an Identity Provider
For each servlet-based adapter, the endpoint you register for the assert consumer service URL and and single logout service
must be the base URL of your servlet application with /saml
appended to it, that is, https://example.com/contextPath/saml
.
3.1.7. Logout
There are multiple ways you can logout from a web application.
For Java EE servlet containers, you can call HttpServletRequest.logout()
. For any other browser application, you can point
the browser at any url of your web application that has a security constraint and pass in a query parameter GLO, i.e. http://myapp?GLO=true
.
This will log you out if you have an SSO session with your browser.
Logout in Clustered Environment
Internally, the SAML adapter stores a mapping between the SAML session index, principal name (when known), and HTTP session ID.
This mapping can be maintained in JBoss application server family (Wildfly 10/11, EAP 6/7) across cluster for distributable
applications. As a precondition, the HTTP sessions need to be distributed across cluster (i.e. application is marked with
<distributable/>
tag in application’s web.xml
).
To enable the functionality, add the following section to your /WEB_INF/web.xml
file:
For EAP 7, Wildfly 10/11:
<context-param>
<param-name>keycloak.sessionIdMapperUpdater.classes</param-name>
<param-value>org.keycloak.adapters.saml.wildfly.infinispan.InfinispanSessionCacheIdMapperUpdater</param-value>
</context-param>
For EAP 6:
<context-param>
<param-name>keycloak.sessionIdMapperUpdater.classes</param-name>
<param-value>org.keycloak.adapters.saml.jbossweb.infinispan.InfinispanSessionCacheIdMapperUpdater</param-value>
</context-param>
If the session cache of the deployment is named deployment-cache
, the cache used for SAML mapping will be named
as deployment-cache.ssoCache
. The name of the cache can be overridden by a context parameter
keycloak.sessionIdMapperUpdater.infinispan.cacheName
. The cache container containing the cache will be the same as
the one containing the deployment session cache, but can be overridden by a context parameter
keycloak.sessionIdMapperUpdater.infinispan.containerName
.
By default, the configuration of the SAML mapping cache will be derived from session cache. The configuration can be manually overridden in cache configuration section of the server just the same as other caches.
Currently, to provide reliable service, it is recommended to use replicated cache for the SAML session cache. Using distributed cache may lead to results where the SAML logout request would land to a node with no access to SAML session index to HTTP session mapping which would lead to unsuccessful logout.
Logout in Cross DC Scenario
The cross DC scenario only applies to Wildfly 10 and higher, and EAP 7 and higher.
Special handling is needed for handling sessions that span multiple data centers. Imagine the following scenario:
-
Login requests are handled within cluster in data center 1.
-
Admin issues logout request for a particular SAML session, the request lands in data center 2.
The data center 2 has to log out all sessions that are present in data center 1 (and all other data centers that share HTTP sessions).
To cover this case, the SAML session cache described above needs to be replicated not only within individual clusters but across all the data centers e.g. via standalone Infinispan/JDG server:
-
A cache has to be added to the standalone Infinispan/JDG server.
-
The cache from previous item has to be added as a remote store for the respective SAML session cache.
Once remote store is found to be present on SAML session cache during deployment, it is watched for changes and the local SAML session cache is updated accordingly.
3.1.8. Obtaining Assertion Attributes
After a successful SAML login, your application code may want to obtain attribute values passed with the SAML assertion.
HttpServletRequest.getUserPrincipal()
returns a Principal
object that you can typecast into a Keycloak specific class
called org.keycloak.adapters.saml.SamlPrincipal
.
This object allows you to look at the raw assertion and also has convenience functions to look up attribute values.
package org.keycloak.adapters.saml;
public class SamlPrincipal implements Serializable, Principal {
/**
* Get full saml assertion
*
* @return
*/
public AssertionType getAssertion() {
...
}
/**
* Get SAML subject sent in assertion
*
* @return
*/
public String getSamlSubject() {
...
}
/**
* Subject nameID format
*
* @return
*/
public String getNameIDFormat() {
...
}
@Override
public String getName() {
...
}
/**
* Convenience function that gets Attribute value by attribute name
*
* @param name
* @return
*/
public List<String> getAttributes(String name) {
...
}
/**
* Convenience function that gets Attribute value by attribute friendly name
*
* @param friendlyName
* @return
*/
public List<String> getFriendlyAttributes(String friendlyName) {
...
}
/**
* Convenience function that gets first value of an attribute by attribute name
*
* @param name
* @return
*/
public String getAttribute(String name) {
...
}
/**
* Convenience function that gets first value of an attribute by attribute name
*
*
* @param friendlyName
* @return
*/
public String getFriendlyAttribute(String friendlyName) {
...
}
/**
* Get set of all assertion attribute names
*
* @return
*/
public Set<String> getAttributeNames() {
...
}
/**
* Get set of all assertion friendly attribute names
*
* @return
*/
public Set<String> getFriendlyNames() {
...
}
}
3.1.9. Error Handling
Keycloak has some error handling facilities for servlet based client adapters.
When an error is encountered in authentication, the client adapter will call HttpServletResponse.sendError()
.
You can set up an error-page
within your web.xml
file to handle the error however you want.
The client adapter can throw 400, 401, 403, and 500 errors.
<error-page>
<error-code>403</error-code>
<location>/ErrorHandler</location>
</error-page>
The client adapter also sets an HttpServletRequest
attribute that you can retrieve.
The attribute name is org.keycloak.adapters.spi.AuthenticationError
.
Typecast this object to: org.keycloak.adapters.saml.SamlAuthenticationError
.
This class can tell you exactly what happened.
If this attribute is not set, then the adapter was not responsible for the error code.
public class SamlAuthenticationError implements AuthenticationError {
public static enum Reason {
EXTRACTION_FAILURE,
INVALID_SIGNATURE,
ERROR_STATUS
}
public Reason getReason() {
return reason;
}
public StatusResponseType getStatus() {
return status;
}
}
3.1.10. Troubleshooting
The best way to troubleshoot problems is to turn on debugging for SAML in both the client adapter and Keycloak Server. Using your logging framework, set the log level to DEBUG
for the org.keycloak.saml
package. Turning this on allows you to see the SAML requests and response documents being sent to and from the server.
==== Migration from older versions
Migrating to 1.9.0
SAML SP Client Adapter Changes
Keycloak SAML SP Client Adapter now requires a specific endpoint, /saml
to be registered with your IdP.
The SamlFilter must also be bound to /saml in addition to any other binding it has.
This had to be done because SAML POST binding would eat the request input stream and this would be really bad for clients that relied on it.
3.2. mod_auth_mellon Apache HTTPD Module
The mod_auth_mellon module is an Apache HTTPD plugin for SAML. If your language/environment supports using Apache HTTPD as a proxy, then you can use mod_auth_mellon to secure your web application with SAML. For more details on this module see the mod_auth_mellon Github repo.
To configure mod_auth_mellon you’ll need:
-
An Identity Provider (IdP) entity descriptor XML file, which describes the connection to Keycloak or another SAML IdP
-
An SP entity descriptor XML file, which describes the SAML connections and configuration for the application you are securing.
-
A private key PEM file, which is a text file in the PEM format that defines the private key the application uses to sign documents.
-
A certificate PEM file, which is a text file that defines the certificate for your application.
-
mod_auth_mellon-specific Apache HTTPD module configuration.
If you have already defined and registered the client application within a realm on the Keycloak application server, Keycloak can generate all the files you need except the Apache HTTPD module configuration.
To generate the Apache HTTPD module configuration, complete the following steps:
-
Go to the Installation page of your SAML client and select the Mod Auth Mellon files option.
mod_auth_mellon config download -
Click Download to download a zip file that contains the XML descriptor and PEM files you need.
3.2.1. Configuring mod_auth_mellon with Keycloak
There are two hosts involved:
-
The host on which Keycloak is running, which will be referred to as $idp_host because Keycloak is a SAML identity provider (IdP).
-
The host on which the web application is running, which will be referred to as $sp_host. In SAML an application using an IdP is called a service provider (SP).
All of the following steps need to performed on $sp_host with root privileges.
Installing the Packages
To install the necessary packages, you will need:
-
Apache Web Server (httpd)
-
Mellon SAML SP add-on module for Apache
-
Tools to create X509 certificates
To install the necessary packages, run this command:
yum install httpd mod_auth_mellon mod_ssl openssl
Creating a Configuration Directory for Apache SAML
It is advisable to keep configuration files related to Apache’s use of SAML in one location.
Create a new directory named saml2 located under the Apache configuration root /etc/httpd:
mkdir /etc/httpd/saml2
Configuring the Mellon Service Provider
Configuration files for Apache add-on modules are located in the /etc/httpd/conf.d directory and have a file name extension of .conf. You need to create the /etc/httpd/conf.d/mellon.conf file and place Mellon’s configuration directives in it.
Mellon’s configuration directives can roughly be broken down into two classes of information:
-
Which URLs to protect with SAML authentication
-
What SAML parameters will be used when a protected URL is referenced.
Apache configuration directives typically follow a hierarchical tree structure in the URL space, which are known as locations. You need to specify one or more URL locations for Mellon to protect. You have flexibility in how you add the configuration parameters that apply to each location. You can either add all the necessary parameters to the location block or you can add Mellon parameters to a common location high up in the URL location hierarchy that specific protected locations inherit (or some combination of the two). Since it is common for an SP to operate in the same way no matter which location triggers SAML actions, the example configuration used here places common Mellon configuration directives in the root of the hierarchy and then specific locations to be protected by Mellon can be defined with minimal directives. This strategy avoids duplicating the same parameters for each protected location.
This example has just one protected location: https://$sp_host/protected.
To configure the Mellon service provider, complete the following steps:
-
Create the file /etc/httpd/conf.d/mellon.conf with this content:
<Location / >
MellonEnable info
MellonEndpointPath /mellon/
MellonSPMetadataFile /etc/httpd/saml2/mellon_metadata.xml
MellonSPPrivateKeyFile /etc/httpd/saml2/mellon.key
MellonSPCertFile /etc/httpd/saml2/mellon.crt
MellonIdPMetadataFile /etc/httpd/saml2/idp_metadata.xml
</Location>
<Location /private >
AuthType Mellon
MellonEnable auth
Require valid-user
</Location>
| Some of the files referenced in the code above are created in later steps. |
Creating the Service Provider Metadata
In SAML IdPs and SPs exchange SAML metadata, which is in XML format. The schema for the metadata is a standard, thus assuring participating SAML entities can consume each other’s metadata. You need:
-
Metadata for the IdP that the SP utilizes
-
Metadata describing the SP provided to the IdP
One of the components of SAML metadata is X509 certificates. These certificates are used for two purposes:
-
Sign SAML messages so the receiving end can prove the message originated from the expected party.
-
Encrypt the message during transport (seldom used because SAML messages typically occur on TLS-protected transports)
You can use your own certificates if you already have a Certificate Authority (CA) or you can generate a self-signed certificate. For simplicity in this example a self-signed certificate is used.
Because Mellon’s SP metadata must reflect the capabilities of the installed version of mod_auth_mellon, must be valid SP metadata XML, and must contain an X509 certificate (whose creation can be obtuse unless you are familiar with X509 certificate generation) the most expedient way to produce the SP metadata is to use a tool included in the mod_auth_mellon package (mellon_create_metadata.sh). The generated metadata can always be edited later because it is a text file. The tool also creates your X509 key and certificate.
SAML IdPs and SPs identify themselves using a unique name known as an EntityID. To use the Mellon metadata creation tool you need:
-
The EntityID, which is typically the URL of the SP, and often the URL of the SP where the SP metadata can be retrieved
-
The URL where SAML messages for the SP will be consumed, which Mellon calls the MellonEndPointPath.
To create the SP metadata, complete the following steps:
-
Create a few helper shell variables:
fqdn=`hostname` mellon_endpoint_url="https://${fqdn}/mellon" mellon_entity_id="${mellon_endpoint_url}/metadata" file_prefix="$(echo "$mellon_entity_id" | sed 's/[^A-Za-z.]/_/g' | sed 's/__*/_/g')"
-
Invoke the Mellon metadata creation tool by running this command:
/usr/libexec/mod_auth_mellon/mellon_create_metadata.sh $mellon_entity_id $mellon_endpoint_url
-
Move the generated files to their destination (referenced in the /etc/httpd/conf.d/mellon.conf file created above):
mv ${file_prefix}.cert /etc/httpd/saml2/mellon.crt mv ${file_prefix}.key /etc/httpd/saml2/mellon.key mv ${file_prefix}.xml /etc/httpd/saml2/mellon_metadata.xml
Adding the Mellon Service Provider to the Keycloak Identity Provider
Assumption: The Keycloak IdP has already been installed on the $idp_host.
Keycloak supports multiple tenancy where all users, clients, and so on are grouped in what is called a realm. Each realm is independent of other realms. You can use an existing realm in your Keycloak, but this example shows how to create a new realm called test_realm and use that realm.
All these operations are performed using the Keycloak administration web console. You must have the admin username and password for $idp_host.
To complete the following steps:
-
Open the Admin Console and log on by entering the admin username and password.
After logging into the administration console there will be an existing realm. When Keycloak is first set up a root realm, master, is created by default. Any previously created realms are listed in the upper left corner of the administration console in a drop-down list.
-
From the realm drop-down list select Add realm.
-
In the Name field type
test_realm
and click Create.
Adding the Mellon Service Provider as a Client of the Realm
In Keycloak SAML SPs are known as clients. To add the SP we must be in the Clients section of the realm.
-
Click the Clients menu item on the left and click Create in the upper right corner to create a new client.
Adding the Mellon SP Client
To add the Mellon SP client, complete the following steps:
-
Set the client protocol to SAML. From the Client Protocol drop down list, select saml.
-
Provide the Mellon SP metadata file created above (/etc/httpd/saml2/mellon_metadata.xml). Depending on where your browser is running you might have to copy the SP metadata from $sp_host to the machine on which your browser is running so the browser can find the file.
-
Click Save.
Editing the Mellon SP Client
There are several client configuration parameters we suggest setting:
-
Ensure "Force POST Binding" is On.
-
Add paosResponse to the Valid Redirect URIs list:
-
Copy the postResponse URL in "Valid Redirect URIs" and paste it into the empty add text fields just below the "+".
-
Change "postResponse" to "paosResponse". (The paosResponse URL is needed for SAML ECP.)
-
Click Save at the bottom.
-
Many SAML SPs determine authorization based on a user’s membership in a group. The Keycloak IdP can manage user group information but it does not supply the user’s groups unless the IdP is configured to supply it as a SAML attribute.
To configure the IdP to supply the user’s groups as as a SAML attribute, complete the following steps:
-
Click the Mappers tab of the client.
-
In the upper right corner of the Mappers page, click Create.
-
From the Mapper Type drop-down list select Group list.
-
Set Name to "group list."
-
Set the SAML attribute name to "groups."
-
Click Save.
The remaining steps are performed on $sp_host.
Retrieving the Identity Provider Metadata
Now that you have created the realm on the IdP you need to retrieve the IdP metadata associated with it so the Mellon SP recognizes it. In the /etc/httpd/conf.d/mellon.conf file created previously, the MellonIdPMetadataFile is specified as /etc/httpd/saml2/idp_metadata.xml but until now that file has not existed on $sp_host. To get that file we will retrieve it from the IdP.
-
Retrieve the file from the IdP by substituting $idp_host with the correct value:
curl -k -o /etc/httpd/saml2/idp_metadata.xml \ https://$idp_host/auth/realms/test_realm/protocol/saml/descriptor
Mellon is now fully configured.
-
To run a syntax check for Apache configuration files:
apachectl configtest
Configtest is equivalent to the -t argument to apachectl. If the configuration test shows any errors, correct them before proceeding. -
Restart the Apache server:
systemctl restart httpd.service
You have now set up both Keycloak as a SAML IdP in the test_realm and mod_auth_mellon as SAML SP protecting the URL $sp_host/protected (and everything beneath it) by authenticating against the $idp_host
IdP.
4. Docker Registry Configuration
| Docker authentication is disabled by default. To enable see Profiles. |
This section describes how you can configure a Docker registry to use Keycloak as its authentication server.
For more information on how to set up and configure a Docker registry, see the Docker Registry Configuration Guide.
4.1. Docker Registry Configuration File Installation
For users with more advanced docker registry configurations, it is generally recommended to provide your own registry configuration file. The Keycloak docker provider supports this mechanism via the Registry Config File Format Option. Choosing this option will generate output similar to the following:
auth: token: realm: http://localhost:8080/auth/auth/realms/master/protocol/docker-v2/auth service: docker-test issuer: http://localhost:8080/auth/auth/realms/master
This output can then be copied into any existing registry config file. See the registry config file specification for more information on how the file should be set up, or start with href:https://github.com/docker/distribution/blob/master/cmd/registry/config-example.yml[a basic example].
Don’t forget to configure the rootcertbundle field with the location of the Keycloak realm’s pulic certificate. The auth configuration will not work without this argument.
|
4.2. Docker Registry Environment Variable Override Installation
Often times it is appropriate to use a simple environment variable override for develop or POC Docker registries. While this approach is usually not recommended for production use, it can be helpful when one requires quick-and-dirty way to stand up a registry. Simply use the Variable Override Format Option from the client installation tab, and an output should appear like the one below:
REGISTRY_AUTH_TOKEN_REALM: http://localhost:8080/auth/auth/realms/master/protocol/docker-v2/auth REGISTRY_AUTH_TOKEN_SERVICE: docker-test REGISTRY_AUTH_TOKEN_ISSUER: http://localhost:8080/auth/auth/realms/master
Don’t forget to configure the REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE override with the location of the Keycloak realm’s pulic certificate. The auth configuration will not work without this argument.
|
4.3. Docker Compose YAML File
| This installation method is meant to be an easy way to get a docker registry authenticating against a keycloak server. It is intended for development purposes only and should never be used in a production or production-like environment. |
The zip file installation mechanism provides a quickstart for developers who want to understand how the keycloak server can interact with the docker registry. In order to configure:
-
From the desired realm, create a client configuration. At this point you won’t have a docker registry - the quickstart will take care of that part.
-
Choose the "Docker Compose YAML" option from the installation tab and download the .zip file
-
Unzip the archive to the desired location, and open the directory.
-
Start the docker registry with
docker-compose up
INFO: it is recommended that you configure the docker registry client in a realm other than 'master', since the HTTP Basic auth flow will not present forms.
Once the above configuration has taken place, and the keycloak server and docker registry are running, docker authentication should be successful:
[user ~]# docker login localhost:5000 -u $username Password: ******* Login Succeeded
5. Client Registration
In order for an application or service to utilize Keycloak it has to register a client in Keycloak. An admin can do this through the admin console (or admin REST endpoints), but clients can also register themselves through the Keycloak client registration service.
The Client Registration Service provides built-in support for Keycloak Client Representations, OpenID Connect Client Meta Data and SAML Entity Descriptors.
The Client Registration Service endpoint is /realms/<realm>/clients-registrations/<provider>
.
The built-in supported providers
are:
-
default - Keycloak Client Representation (JSON)
-
install - Keycloak Adapter Configuration (JSON)
-
openid-connect - OpenID Connect Client Metadata Description (JSON)
-
saml2-entity-descriptor - SAML Entity Descriptor (XML)
The following sections will describe how to use the different providers.
5.1. Authentication
To invoke the Client Registration Services you usually need a token. The token can be a bearer token, an initial access token or a registration access token. There is an alternative to register new client without any token as well, but then you need to configure Client Registration Policies (see below).
5.1.1. Bearer Token
The bearer token can be issued on behalf of a user or a Service Account. The following permissions are required to invoke the endpoints (see Server Administration Guide for more details):
-
create-client or manage-client - To create clients
-
view-client or manage-client - To view clients
-
manage-client - To update or delete client
If you are using a bearer token to create clients it’s recommend to use a token from a Service Account with only the create-client
role (see Server Administration Guide for more details).
5.1.2. Initial Access Token
The recommended approach to registering new clients is by using initial access tokens. An initial access token can only be used to create clients and has a configurable expiration as well as a configurable limit on how many clients can be created.
An initial access token can be created through the admin console.
To create a new initial access token first select the realm in the admin console, then click on Realm Settings
in the menu on the left, followed by
Client Registration
in the tabs displayed in the page. Then finally click on Initial Access Tokens
sub-tab.
You will now be able to see any existing initial access tokens. If you have access you can delete tokens that are no longer required. You can only retrieve the
value of the token when you are creating it. To create a new token click on Create
. You can now optionally add how long the token should be valid, also how
many clients can be created using the token. After you click on Save
the token value is displayed.
It is important that you copy/paste this token now as you won’t be able to retrieve it later. If you forget to copy/paste it, then delete the token and create another one.
The token value is used as a standard bearer token when invoking the Client Registration Services, by adding it to the Authorization header in the request. For example:
Authorization: bearer eyJhbGciOiJSUz...
5.1.3. Registration Access Token
When you create a client through the Client Registration Service the response will include a registration access token. The registration access token provides access to retrieve the client configuration later, but also to update or delete the client. The registration access token is included with the request in the same way as a bearer token or initial access token. Registration access tokens are only valid once when it’s used the response will include a new token.
If a client was created outside of the Client Registration Service it won’t have a registration access token associated with it.
You can create one through the admin console. This can also be useful if you loose the token for a particular client.
To create a new token find the client in the admin console and click on Credentials
. Then click on Generate registration access token
.
5.2. Keycloak Representations
The default
client registration provider can be used to create, retrieve, update and delete a client.
It uses Keycloak Client Representation format which provides support for configuring clients exactly as they can be configured through the admin
console, including for example configuring protocol mappers.
To create a client create a Client Representation (JSON) then perform an HTTP POST request to /realms/<realm>/clients-registrations/default
.
It will return a Client Representation that also includes the registration access token. You should save the registration access token somewhere if you want to retrieve the config, update or delete the client later.
To retrieve the Client Representation perform an HTTP GET request to /realms/<realm>/clients-registrations/default/<client id>
.
It will also return a new registration access token.
To update the Client Representation perform an HTTP PUT request with the updated Client Representation to:
/realms/<realm>/clients-registrations/default/<client id>
.
It will also return a new registration access token.
To delete the Client Representation perform an HTTP DELETE request to:
/realms/<realm>/clients-registrations/default/<client id>
5.3. Keycloak Adapter Configuration
The installation
client registration provider can be used to retrieve the adapter configuration for a client.
In addition to token authentication you can also authenticate with client credentials using HTTP basic authentication.
To do this include the following header in the request:
Authorization: basic BASE64(client-id + ':' + client-secret)
To retrieve the Adapter Configuration then perfrom an HTTP GET request to /realms/<realm>/clients-registrations/install/<client id>
.
No authentication is required for public clients. This means that for the JavaScript adapter you can load the client configuration directly from Keycloak using the above URL.
5.4. OpenID Connect Dynamic Client Registration
Keycloak implements OpenID Connect Dynamic Client Registration, which extends OAuth 2.0 Dynamic Client Registration Protocol and OAuth 2.0 Dynamic Client Registration Management Protocol.
The endpoint to use these specifications to register clients in Keycloak is /realms/<realm>/clients-registrations/openid-connect[/<client id>]
.
This endpoints can also be found in the OpenID Connect Discovery endpoint for the realm, /realms/<realm>/.well-known/openid-configuration
.
5.5. SAML Entity Descriptors
The SAML Entity Descriptor endpoint only supports using SAML v2 Entity Descriptors to create clients. It doesn’t support retrieving, updating or deleting clients. For those operations the Keycloak representation endpoints should be used. When creating a client a Keycloak Client Representation is returned with details about the created client, including a registration access token.
To create a client perform an HTTP POST request with the SAML Entity Descriptor to /realms/<realm>/clients-registrations/saml2-entity-descriptor
.
5.6. Example using CURL
The following example creates a client with the clientId myclient
using CURL. You need to replace eyJhbGciOiJSUz…
with a proper initial access token or
bearer token.
curl -X POST \
-d '{ "clientId": "myclient" }' \
-H "Content-Type:application/json" \
-H "Authorization: bearer eyJhbGciOiJSUz..." \
http://localhost:8080/auth/realms/master/clients-registrations/default
5.7. Example using Java Client Registration API
The Client Registration Java API makes it easy to use the Client Registration Service using Java.
To use include the dependency org.keycloak:keycloak-client-registration-api:>VERSION<
from Maven.
For full instructions on using the Client Registration refer to the JavaDocs.
Below is an example of creating a client. You need to replace eyJhbGciOiJSUz…
with a proper initial access token or bearer token.
String token = "eyJhbGciOiJSUz...";
ClientRepresentation client = new ClientRepresentation();
client.setClientId(CLIENT_ID);
ClientRegistration reg = ClientRegistration.create()
.url("http://localhost:8080/auth", "myrealm")
.build();
reg.auth(Auth.token(token));
client = reg.create(client);
String registrationAccessToken = client.getRegistrationAccessToken();
5.8. Client Registration Policies
Keycloak currently supports 2 ways how can be new clients registered through Client Registration Service.
-
Authenticated requests - Request to register new client must contain either
Initial Access Token
orBearer Token
as mentioned above. -
Anonymous requests - Request to register new client doesn’t need to contain any token at all
Anonymous client registration requests are very interesting and powerful feature, however you usually don’t want that anyone is able to register new
client without any limitations. Hence we have Client Registration Policy SPI
, which provide a way to limit who can register new clients and under which conditions.
In Keycloak admin console, you can click to Client Registration
tab and then Client Registration Policies
sub-tab. Here you will see what policies
are configured by default for anonymous requests and what policies are configured for authenticated requests.
The anonymous requests (requests without any token) are allowed just for creating (registration) of new clients. So when you register
new client through anonymous request, the response will contain Registration Access Token, which must be used for Read, Update or Delete request of particular client.
However using this Registration Access Token from anonymous registration will be then subject to Anonymous Policy too! This means that for example request for update
client also needs to come from Trusted Host if you have Trusted Hosts policy. Also for example it won’t be allowed to disable Consent Required when updating client and
when Consent Required policy is present etc.
|
Currently we have these policy implementations:
-
Trusted Hosts Policy - You can configure list of trusted hosts and trusted domains. Request to Client Registration Service can be sent just from those hosts or domains. Request sent from some untrusted IP will be rejected. URLs of newly registered client must also use just those trusted hosts or domains. For example it won’t be allowed to set
Redirect URI
of client pointing to some untrusted host. By default, there is not any whitelisted host, so anonymous client registration is de-facto disabled by default. -
Consent Required Policy - Newly registered clients will have
Consent Allowed
switch enabled. So after successful authentication, user will always see consent screen when he needs to approve personal info and permissions (protocol mappers and roles). It means that client won’t have access to any personal info or permission of user unless user approves it. -
Protocol Mappers Policy - Allows to configure list of whitelisted protocol mapper implementations. New client can’t be registered or updated if it contains some non-whitelisted protocol mapper. Note that this policy is used for authenticated requests as well, so even for authenticated request there are some limitations which protocol mappers can be used.
-
Client Template Policy - Allow to whitelist
Client Templates
, which can be used with newly registered or updated clients. There are no whitelisted templates by default. -
Full Scope Policy - Newly registered clients will have
Full Scope Allowed
switch disabled. This means they won’t have any scoped realm roles or client roles of other clients. -
Max Clients Policy - Rejects registration if current number of clients in the realm is same or bigger than specified limit. It’s 200 by default for anonymous registrations.
-
Client Disabled Policy - Newly registered client will be disabled. This means that admin needs to manually approve and enable all newly registered clients. This policy is not used by default even for anonymous registration.
6. Client Registration CLI
Client Registration CLI
is a command line interface tool for application developers to configure new clients in self-service manner
when integrating with Keycloak. It is specifically designed to interact with Keycloak Client Registration REST endpoints.
In order for any application to be able to use Keycloak it is necessary to create or obtain a client configuration. Usually a new client is configured for
each new application hosted on a unique hostname. When application interacts with Keycloak it needs to identify itself with a client_id
in order for Keycloak
to be able to provide login page, SSO session management, and other services.
Client Registration CLI
allows you to configure application clients from a command line, and can be used in shell scripts as well.
To allow a particular user to use Client Registration CLI
the Keycloak administrator will typically use Admin Console
to configure
a new user with proper roles, or configure a new client and client secret to grant access to Client Registration REST API
.
6.1. Configuring a new regular user for use with Client Registration CLI
Login as admin
into Admin Console
(e.g. http://localhost:8080/auth/admin
). Select a realm you want to administer.
If you want to use existing user, select that user for edit, otherwise create a new user. Go to Role Mappings
tab. Under
Client Roles
select realm-management
(if in master realm, select NAME-realm
where NAME is name of the target realm - users in master realm can have access to any other realms).
Under Available Roles
select manage-client
for full set of client management permissions. Alternatively you can choose
view-clients
for read-only or create-client
for ability to create new clients.
These permissions grant user the capability to perform operations without the use of Initial Access Token or
Registration Access Token.
It’s possible to not assign users any of realm-management
roles. In that case user can still login with Registration Client CLI
but will not be able to use it without being in possession of an Initial Access Token
. Trying to perform any operations
without it will result in 403 Forbidden
error.
Administrator can issue Initial Access Tokens
from Admin Console
by selecting Client Registration
tab under Realm Settings
, then Initial Access Token
sub-tab.
6.2. Configuring a client for use with Client Registration CLI
By default the Client Registration CLI
identifies to the server as admin-cli
client which is automatically configured for every new realm.
No additional client configuration is necessary when logging in with username. You may wish to strengthen security by
configuring the client Access Type
as Confidential
, and under Credentials
tab select ClientId and Secret
. When
running kcreg config credentials
you would then also have to provide a secret by using --secret
option.
If you want to use a separate client configuration for Registration Client CLI
then you can create a new client - you can call it reg-cli
for example. When running kcreg config credentials
you then need to specify which clientId
to use e.g. --client reg-cli
.
If you want to use a service account associated with the client, you first need to enable service accounts. In Admin Console
go to Clients
section, and select a client for edit. Then under Settings
change the Access Type
to Confidential
, and toggle
Service Accounts Enabled
setting to On
. Make sure to Save
the configuration.
Under Credentials
tab you can choose to configure either Client Id and Secret
, or Signed JWT
.
Having done that you can then omit specifying user during kcreg config credentials
, and only provide client secret or keystore info.
6.3. Installing Client Registration CLI
Client Registration CLI is packaged inside Keycloak Server distribution. You can find execution scripts inside bin
directory.
The Linux script is called kcreg.sh
, and the one for Windows is called kcreg.bat
.
In order to setup the client for use from any location on the filesystem you may want to add Keycloak server directory to your PATH.
On Linux:
$ export PATH=$PATH:$KEYCLOAK_HOME/bin
$ kcreg.sh
On Windows:
c:\> set PATH=%PATH%;%KEYCLOAK_HOME%\bin
c:\> kcreg
Where KEYCLOAK_HOME refers to a directory where Keycloak Server distribution was unpacked.
6.4. Using Client Registration CLI
First you need to start an authenticated session (i.e. logging in) by providing credentials. Then you perform operations on Client Registration REST endpoint.
For example on Linux:
$ kcreg.sh config credentials --server http://localhost:8080/auth --realm demo --user user --client reg-cli
$ kcreg.sh create -s clientId=my_client -s 'redirectUris=["http://localhost:8980/myapp/*"]'
$ kcreg.sh get my_client
Or on Windows:
c:\> kcreg config credentials --server http://localhost:8080/auth --realm demo --user user --client reg-cli
c:\> kcreg create -s clientId=my_client -s "redirectUris=[\"http://localhost:8980/myapp/*\"]"
c:\> kcreg get my_client
In a production environment Keycloak has to be accessed with https:
to avoid exposing tokens to network sniffers. If server’s
certificate is not issued by one of the trusted CAs that are included in Java’s default certificate truststore, you will
need to prepare a truststore.jks file, and instruct Client Registration CLI
to use it.
For example on Linux:
$ kcreg.sh config truststore --trustpass $PASSWORD ~/.keycloak/truststore.jks
Or on Windows:
c:\> kcreg config truststore --trustpass %PASSWORD% %HOMEPATH%\.keycloak\truststore.jks
6.4.1. Logging In
When logging in with Client Registration CLI
you specify a server endpoint url, and a realm. Then you specify a username
or, alternatively, a client id, which will result in special service account being used. In the first case,
a password for the specified user has to be used at login. In the latter case there is no user password - only client secret
or a Signed JWT
is used.
Regardless of the method, the account that logs in needs proper permissions to be able to perform client
registration operations. Keep in mind that any account in non-master realm can only have permissions to manage clients within the same realm.
If you need to manage different realms, you can either configure multiple users in different realms, or you can create a single user in master
realm and
add it roles for managing clients in different realms.
Client Registration CLI
by itself does not support configuring users, for that you would need to use Admin Console
web interface or Admin Client CLI command line tool (see Server Administration Guide for more details).
When kcreg
successfully logs in it receives authorization tokens and saves them into private config file so they can be
used for subsequent invocations. See next chapter for more info on configuration file.
See built-in help for more information on using Client Registration CLI
.
For example on Linux:
$ kcreg.sh help
Or on Windows:
c:\> kcreg help
See kcreg config credentials --help
for more information about starting an authenticated session.
6.4.2. Working with alternative configurations
By default, Client Registration CLI
automatically maintains a configuration file at a default location - ./.keycloak/kcreg.config
under user’s home directory.
You can always use --config
option to point to a different file / location. This way you can mantain multiple authenticated
sessions in parallel. It is safest to perform operations tied to a single config file from a single thread.
Make sure to not make the config file visible to other users on the system as it contains access tokens, and secrets that should be kept private.
You may want to avoid storing any secrets at all inside a config file for the price of less convenience and having to do more token requests.
In that case you can use --no-config
option with all your commands. You will have to specify all authentication info with each
kcreg
invocation.
6.4.3. Initial Access and Registration Access Tokens
Client Registration CLI
can be used by developers who don’t have an account configured at Keycloak server they want to use.
That’s possible when realm administrator issues developer an Initial Access Token
. It is up to realm administrator to decide
how to issue and distribute these tokens. Admin can limit Initial Access Token’s maximum age, and a total number of clients
that can be created with it. Many Initial Access Tokens can be created, and it’s up to realm administrator to distribute them
to application developers.
Once a developer is in possession of Initial Access Token they can use it to create new clients without authenticating
with kcreg config credentials
. Rather, Initial Access Token can be stored in configuration, or specified as part of kcreg create
command.
For example on Linux:
$ kcreg.sh config initial-token $TOKEN
$ kcreg.sh create -s clientId=myclient
or
$ kcreg.sh create -s clientId=myclient -t $TOKEN
On Windows:
c:\> kcreg config initial-token %TOKEN%
c:\> kcreg create -s clientId=myclient
or
c:\> kcreg create -s clientId=myclient -t %TOKEN%
When Initial Access Token is used, the server response will include a newly issued Registration Access Token. Any subsequent operation for that client needs to be performed by authenticating with that token which is only valid for that client.
Client Registration CLI
automatically uses its private configuration file to save, and use this token with its associated client.
As long as the same configuration file is used for all client operations, the developer will not need to
authenticate in order to read, update, or delete a client that was created this way.
You can read more about Initial Access and Registration Access Tokens in Client Registration chapter.
See kcreg config initial-token --help
and kcreg config registration-token --help
for more information on how to configure them with Client Registration CLI
.
6.4.4. Creating client configuration
After authenticating with credentials or configuring Initial Access Token, the first operation will usually be to create a new client.
We’ve seen the simplest create command already. Often we may want to use a prepared JSON file as a template and set / override
some of the attributes. For example, here is how you read a JSON file, override any clientId
it may contain,
set any other attributes as well, and after successful creation print the configuration to standard output.
On Linux:
$ kcreg.sh create -f client-template.json -s clientId=myclient -s baseUrl=/myclient -s 'redirectUris=["/myclient/*"]' -o
On Windows:
C:\> kcreg create -f client-template.json -s clientId=myclient -s baseUrl=/myclient -s "redirectUris=[\"/myclient/*\"]" -o
See kcreg create --help
for more information about kcreg create
.
You can use kcreg attrs
to list available attributes. Keep in mind that many configuration attributes are not checked for
validity or consistency. It is up to you to specify proper values. Also note that you should not have any id
fields in your
template and should not specify them as arguments to kcreg create
.
6.4.5. Retrieving client configuration
You can retrieve an existing client by using kcreg get
.
For example, on Linux:
$ kcreg.sh get myclient
On Windows:
C:\> kcreg get myclient
You can also get client configuration as adapter configuration file which you can package with your web application.
For example, on Linux:
$ kcreg.sh get myclient -e install > keycloak.json
On Windows:
C:\> kcreg get myclient -e install > keycloak.json
See kcreg get --help
for more information about kcreg get
.
6.4.6. Modifying client configuration
There are two modes of updating client configuration.
One is to submit a complete new state to the server after getting current configuration, saving it into a file, editing it, and posting it back.
On Linux:
$ kcreg.sh get myclient > myclient.json
$ vi myclient.json
$ kcreg.sh update myclient -f myclient.json
On Windows:
C:\> kcreg get myclient > myclient.json
C:\> notepad myclient.json
C:\> kcreg update myclient -f myclient.json
Another way is to fetch current client, set or delete fields on it, and post it back all in one single step.
For example, on Linux:
$ kcreg.sh update myclient -s enabled=false -d redirectUris
On Windows:
C:\> kcreg update myclient -s enabled=false -d redirectUris
You can even use a file that only contains changes to be applied so you don’t have to specify too many values as arguments.
In this case specify --merge
to tell Client Registration CLI
that rather than treating JSON file as full
new configuration, it should treat it as a set of attributes to be applied over existing configuration.
On Linux:
$ kcreg.sh update myclient --merge -d redirectUris -f mychanges.json
On Windows:
C:\> kcreg update myclient --merge -d redirectUris -f mychanges.json
See kcreg update --help
for more information about kcreg update
.
6.4.7. Deleting client configuration
You may sometimes also need to delete a client.
On Linux:
$ kcreg.sh delete myclient
On Windows:
C:\> kcreg delete myclient
See kcreg delete --help
for more information about kcreg delete
.
6.4.8. Refreshing Invalid Registration Access Tokens
When performing a CRUD operation using --no-config
mode, Client Registration CLI
can no longer handle Registration Access Tokens for you.
In that case it is possible to lose track of most recently issued Registration Access Token for a client, which makes it impossible to
perform any further CRUD operations on that client without authenticating with account that has 'manage-clients' permissions.
If you have permissions, you can issue a new Registration Access Token for the client, and have it printed to stdout or saved to a config
file of your choice. Otherwise you have to ask realm administrator to issue new Registration Access Token for your client, and send it
to you. You can then pass it to any CRUD command via --token
option. You can also use kcreg config registration-token
command to save the new token in configuration file, and have Client Registration CLI
automatically handle it for you from that point on.
See kcreg update-token --help
for more information about kcreg update-token
.
7. Token Exchange
In Keycloak, token exchange is the process of using a set of credentials or token to obtain an entirely different token. A client may want to invoke on a less trusted application so it may want to downgrade the current token it has. A client may want to exchange a {project_token} for a token stored for a linked social provider account. You may want to trust external tokens minted by other Keycloak realms or foreign IDPs. A client may have a need to impersonate a user. Here’s a short summary of the current capabilities of Keycloak around token exchange.
-
A client can exchange an existing Keycloak token created for a specific client for a new token targeted to a different client
-
A client can exchange an existing Keycloak token for an external token, i.e. a linked Facebook account
-
A client can exchange an external token for a Keycloak token.
-
A client can impersonate a user
Token exchange in Keycloak is a very loose implementation of the OAuth Token Exchange specification at the IETF. We have extended it a little, ignored some of it, and loosely interpreted other parts of the specification. It is a simple grant type invocation on a realm’s OpenID Connect token endpoint.
/realms/{realm}/protocol/openid-connect/token
It accepts form parameters (application/x-www-form-urlencoded
) as input and the output depends on the type of token you requested an exchange for.
Token exchange is a client endpoint so requests must provide authentication information for the calling client.
Public clients specify their client identifier as a form parameter. Confidential clients can also use form parameters
to pass their client id and secret, Basic Auth, or however your admin has configured the client authentication flow in your
realm. Here’s a list of form parameters
- client_id
-
REQUIRED MAYBE. This parameter is required for clients using form parameters for authentication. If you are using Basic Auth, a client JWT token, or client cert authentication, then do not specify this parameter.
- client_secret
-
REQUIRED MAYBE. This parameter is required for clients using form parameters for authentication and using a client secret as a credential. Do not specify this parameter if client invocations in your realm are authenticated by a different means.
- grant_type
-
REQUIRED. The value of the parameter must be
urn:ietf:params:oauth:grant-type:token-exchange
. - subject_token
-
OPTIONAL. A security token that represents the identity of the party on behalf of whom the request is being made. It is required if you are exchanging an existing token for a new one.
- subject_issuer
-
OPTIONAL. Identifies the issuer of the
subject_token
. It can be left blank if the token comes from the current realm or if the issuer can be determined from thesubject_token_type
. Otherwise it is required to be specified. Valid values are the alias of anIdentity Provider
configured for your realm. Or an issuer claim identifier configured by a specificIdentity Provider
. - subject_token_type
-
OPTIONAL. This parameter is the type of the token passed with the
subject_token
parameter. This defaults tourn:ietf:params:oauth:token-type:access_token
if thesubject_token
comes from the realm and is an access token. If it is an external token, this parameter may or may not have to be specified depending on the requirements of thesubject_issuer
. - requested_token_type
-
OPTIONAL. This parameter represents the type of token the client wants to exchange for. Currently only oauth and OpenID Connect token types are supported. The default value for this depends on whether the is
urn:ietf:params:oauth:token-type:refresh_token
in which case you will be returned both an access token and refresh token within the response. Other appropriate values areurn:ietf:params:oauth:token-type:access_token
andurn:ietf:params:oauth:token-type:id_token
- audience
-
OPTIONAL. This parameter specifies the target client you want the new token minted for.
- requested_issuer
-
OPTIONAL. This parameter specifies that the client wants a token minted by an external provider. It must be the alias of an
Identity Provider
configured within the realm. - requested_subject
-
OPTIONAL. This specifies a username or user id if your client wants to impersonate a different user.
- scope
-
NOT IMPLEMENTED. This parameter represents the target set of OAuth and OpenID Connect scopes the client is requesting. It is not implemented at this time but will be once Keycloak has better support for scopes in general.
| We currently only support OpenID Connect and OAuth exchanges. Support for SAML based clients and identity providers may be added in the future depending on user demand. |
A successful response from an exchange invocation will return the HTTP 200 response code with a content type that
depends on the requested-token-type
and requested_issuer
the client asks for. OAuth requested token types will return
a JSON document as described in the OAuth Token Exchange specification.
{ "access_token" : ".....", "refresh_token" : ".....", "expires_in" : "...." }
Clients requesting a refresh token will get back both an access and refresh token in the response. Clients requesting only access token type will only get an access token in the response. Expiration information may or may not be included for clients requesting a an external issuer through the `requested_issuer`paramater.
Error responses generally fall under the 400 HTTP response code category, but other error status codes may be returned
depending on the severity of the error. Error responses may include content depending on the requested_issuer
.
OAuth based exchanges may return a JSON document as follows:
{ "error" : "...." "error_description" : "...." }
Additional error claims may be returned depending on the exchange type. For example, OAuth Identity Providers may include
an additional account-link-url
claim if the user does not have a link to an identity provider. This link can be used
for a client initiated link request.
| Token exchange setup requires knowledge of fine grain admin permissions (See the Server Administration Guide for more information). You will need to grant clients permission to exchange. This is discussed more later in this chapter. |
The rest of this chapter discusses the setup requirements and provides examples for different exchange scenarios. For simplicity’s sake, let’s call a token minted by the current realm as an internal token and a token minted by an external realm or identity provider as an external token.
7.1. Internal Token to Internal Token Exchange
With an internal token to token exchange you have an existing token minted to a specific client and you want to exchange this token for a new one minted for a different target client. Why would you want to do this? This generally happens when a client has a token minted for itself, and needs to make additional requests to other applications that require different claims and permissions within the access token. Other reasons this type of exchange might be required is if you need to perform a "permission downgrade" where your app needs to invoke on a less trusted app and you don’t want to propagate your current access token.
7.1.1. Granting Permission for the Exchange
Clients that want to exchange tokens for a different client need to be authorized in the admin console to do so.
You’ll need to define a token-exchange
fine grain permission in the target client you want permission to exchange to.
Toggle the Permissions Enabled
switch to true.
You should see a token-exchange
link on the page. Click that to start defining the permission. It will bring you
to this page.
You’ll have to define a policy for this permission. Click the Authorization
link, go to the Policies
tab and create
a Client
Policy.
Here you enter in the starting client, that is the authenticated client that is requesting a token exchange. After you
create this policy, go back to the target client’s token-exchange
permission and add the client policy you just
defined.
Your client now has permission to invoke. If you do not do this correctly, you will get a 403 Forbidden response if you try to make an exchange.
7.1.2. Making the Request
When your client is exchanging an existing token for a token targeting another client, you must use the audience
parameter.
 \
--data-urlencode "requested_token_type=urn:ietf:params:oauth:token-type:refresh_token"
-d "audience=target-client" \
http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token
The subject_token
parameter must be an access token for the target realm. If your requested_token_type
parameter
is a refresh token type, then the response will contain both an access token, refresh token, and expiration. Here’s
an example JSON response you get back from this call.
{
"access_token" : "....",
"refresh_token" : "....",
"expires_in" : 3600
}
7.2. Internal Token to External Token Exchange
You can exchange a realm token for an externl token minted by an external identity provider. This external identity provider
must be configured within the Identity Provider
section of the admin console. Currently only OAuth/OpenID Connect based external
identity providers are supported, this includes all social providers. Keycloak does not perform a backchannel exchange to the external provider. So if the account
is not linked, you will not be able to get the external token. To be able to obtain an external token one of
these conditions must be met:
-
The user must have logged in with the external identity provider at least once
-
The user must have linked with the external identity provider through the User Account Service
-
The user account was linked through the external identity provider using Client Initiated Account Linking API.
Finally, the external identity provider must have been configured to store tokens, or, one of the above actions must have been performed with the same user session as the internal token you are exchanging.
If the account is not linked, the exchange response will contain a link you can use to establish it. This is discussed more in the Making the Request section.
7.2.1. Granting Permission for the Exchange
Internal to external token exchange requests will be denied with a 403, Forbidden response until you grant
permission for the calling client to exchange tokens with the external identity provider. To grant permission
to the client you must go to the identity provider’s configuration page to the Permissions
tab.
Toggle the Permissions Enabled
switch to true.
You should see a token-exchange
link on the page. Click that to start defining the permission. It will bring you
to this page.
You’ll have to define a policy for this permission. Click the Authorization
link, go to the Policies
tab and create
a Client
Policy.
Here you enter in the starting client, that is the authenticated client that is requesting a token exchange. After you
create this policy, go back to the identity providers’s token-exchange
permission and add the client policy you just
defined.
Your client now has permission to invoke. If you do not do this correctly, you will get a 403 Forbidden response if you try to make an exchange.
7.2.2. Making the Request
When your client is exchanging an existing internal token to an external one, you must provide the
requested_issuer
parameter.  \
--data-urlencode "requested_token_type=urn:ietf:params:oauth:token-type:refresh_token"
-d "requested_issuer=google" \
http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token
The subject_token
parameter must be an access token for the target realm. The requested_token_type
parameter
must be urn:ietf:params:oauth:token-type:access_token
or left blank. No other requested token type is supported
at this time. Here’s
an example successful JSON response you get back from this call.
{
"access_token" : "....",
"expires_in" : 3600
"account-link-url" : "https://...."
}
If the external identity provider is not linked for whatever reason, you will get an HTTP 400 response code with this JSON document:
{
"error" : "....",
"error_description" : "..."
"account-link-url" : "https://...."
}
The error
claim will be either token_expired
or not_linked
. The account-link-url
claim is provided
so that the client can perform Client Initiated Account Linking. Most (all?)
providers are requiring linking through browser OAuth protocol. With the account-link-url
just add a redirect_uri
query parameter to it and you can forward browsers to perform the link.
7.3. External Token to Internal Token Exchange
You can trust and exchange external tokens minted by external identity providers for internal tokens. This can be used to bridge between realms or just to trust tokens from your social provider. It works similarly to an identity provider browser login in that a new user is imported into your realm if it doesn’t exist.
| The current limitation on external token exchanges is that if the external token maps to an existing user an exchange will not be allowed unless the existing user already has an account link to the external identity provider. |
When the exchange is complete, a user session will be created within the realm, and you will receive an access
and or refresh token depending on the requested_toke_type
parameter value. You should note that this new
user session will remain active until it times out or until you call the logout endpoint of the realm passing this
new access token.
These types of changes required a configured identity provider in the admin console.
| SAML identity providers are not supported at this time. Twitter tokens cannot be exchanged either. |
7.3.1. Granting Permission for the Exchange
Before external token exchanges can be done, you must grant permission for the calling client to make the exchange. This permission is granted in the same manner as interal to external permission is granted.
If you also provide an audience
parameter whose value points to a different client other than the calling one, you
must also grant the calling client permission to exchange to the target client specific in the audience
parameter. How
to do this is discussed earlier in this section.
7.3.2. Making the Request
The subject_token_type
must either be urn:ietf:params:oauth:token-type:access_token
or urn:ietf:params:oauth:token-type:jwt
.
If the type is urn:ietf:params:oauth:token-type:access_token
you must specify the subject_issuer
parameter and it must be the
alias of the configured identity provider. If the type is urn:ietf:params:oauth:token-type:jwt
, the provider will be matched via
the issuer
claim within the JWT which must be the alias of the provider, or a registered issuer within the providers configuration.
For validation, if the token is an access token, the provider’s user info service will be invoked to validate the token. A successful call will mean that the access token is valid. If the subject token is a JWT and if the provider has signature validation enabled, that will be attempted, otherwise, it will default to also invoking on the user info service to validate the token.
By default, the internal token minted will use the calling client to determine what’s in the token using the protocol
mappers defined for the calling client. Alternatively, you can specify a different target client using the audience
parameter.
curl -X POST \
-d "client_id=starting-client" \
-d "client_secret=geheim" \
--data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
-d "subject_token=...." \
-d "subject_issuer=myOidcProvider" \
--data-urlencode "subject_token_type=urn:ietf:params:oauth:token-type:access_token"
-d "audience=target-client" \
http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token
If your requested_token_type
parameter
is a refresh token type, then the response will contain both an access token, refresh token, and expiration. Here’s
an example JSON response you get back from this call.
{
"access_token" : "....",
"refresh_token" : "....",
"expires_in" : 3600
}
7.4. Impersonation
For internal and external token exchanges, the client can request on behalf of a user to impersonate a different user. For example, you may have an admin application that needs to impersonate a user so that a support engineer can debug a problem.
7.4.1. Granting Permission for the Exchange
The user that the subject token represents must have permission to impersonate other users. See the Server Administration Guide on how to enable this permission. It can be done through a role or through fine grain admin permissions.
7.4.2. Making the Request
Make the request as described in other chapters except additionally specify the request_subject
parameter. The
value of this parameter must be a username or user id.
curl -X POST \
-d "client_id=starting-client" \
-d "client_secret=geheim" \
--data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
-d "subject_token=...." \
--data-urlencode "requested_token_type=urn:ietf:params:oauth:token-type:access_token" \
-d "audience=target-client" \
-d "requested_subject=wburke" \
http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token
7.5. Direct Naked Impersonation
You can make an internal token exchange request without providing a subject_token
. This is called a direct
naked impersonation because it places a lot of trust in a client as that client can impersonate any user in the realm.
You might need this to bridge for applications where it is impossible to obtain a subject token to exchange. For example,
you may be integrating a legacy application that performs login directly with LDAP. In that case, the legacy app
is able to authenticate users itself, but not able to obtain a token.
| It is very risky to enable direct naked impersonation for a client. If the client’s credentials are ever stolen, that client can impersonate any user in the system. |
7.5.1. Granting Permission for the Exchange
If the audience
parameter is provided, then the calling client must have permission to exchange to the client. How
to set this up is discussed earlier in this chapter.
Additionally, the calling client must be granted permission to impersonate users. In the admin console, go to the
Users
screen and click on the Permissions
tab.
Toggle the Permissions Enabled
switch to true.
You should see a impersonation
link on the page. Click that to start defining the permission. It will bring you
to this page.
You’ll have to define a policy for this permission. Click the Authorization
link, go to the Policies
tab and create
a Client
Policy.
Here you enter in the starting client, that is the authenticated client that is requesting a token exchange. After you
create this policy, go back to the users' impersonation
permission and add the client policy you just
defined.
Your client now has permission to impersonate users. If you do not do this correctly, you will get a 403 Forbidden response if you try to make this type of exchange.
| Public clients are not allowed to do direct naked impersonations. |
7.5.2. Making the Request
To make the request, simply specify the requested_subject
parameter. This must be the username or user id of
a valid user. You can also specify an audience
parameter if you wish.
curl -X POST \
-d "client_id=starting-client" \
-d "client_secret=geheim" \
--data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
-d "requested_subject=wburke" \
http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token
7.6. Expand Permission Model With Service Accounts
When granting clients permission to exchange, you don’t necessarily have to manually enable those permissions for each and every client.
If the client has a service account associated with it, you can use a role to group permissions together and assign exchange permissions
by assigning a role to the client’s service account. For example, you might define a naked-exchange
role and any service account that has that
role can do a naked exchange.
7.7. Exchange Vulnerabilities
When you start allowing token exchanges, there’s various things you have to both be aware of and careful of.
The first is public clients. Public clients do not have or require a client credential in order to perform an exchange. Anybody that has a valid token will be able to impersonate the public client and perform the exchanges that public client is allowed to perform. If there are any untrustworthy clients that are managed by your realm, public clients may open up vulnerabilities in your permission models. This is why direct naked exchanges do not allow public clients and will abort with an error if the calling client is public.
It is possible to exchange social tokens provided by Facebook, Google, etc. for a realm token. Be careful and vigilante on what the exchange token is allowed to do as its not hard to create fake accounts on these social websites. Use default roles, groups, and identity provider mappers to control what attributes and roles are assigned to the external social user.
Direct naked exchanges are quite dangerous. You are putting a lot of trust in the calling client that it will never leak out its client credentials. If those credentials are leaked, then the thief can impersonate anybody in your system. This is in direct contrast to confidential clients that have existing tokens. You have two factors of authentication, the access token and the client credentials, and you’re only dealing with one user. So use direct naked exchanges sparingly.