[KEYCLOAK-7264] Add documentation for the new RoleMappingsProvider SPI

This commit is contained in:
Stefan Guilhen 2019-08-01 01:42:11 -03:00 committed by Hynek Mlnařík
parent 538cbc433f
commit b1e487ec39
6 changed files with 139 additions and 0 deletions

View file

@ -12,3 +12,16 @@ of extensions to access secrets from custom vaults.
== Messages in theme resources
Message bundles in theme resources enables internationalization of custom providers such as authenticators. They are also shared between all theme types, making it possible to for example share messages between the login and account console. Thanks to https://github.com/micedre[micedre].
== RoleMappingsProvider SPI for the SAML adapters
We have added a new SPI that allows for the configuration of custom role mappers that are used by the SAML adapters to map
the roles extracted from the SAML assertion into roles that exist in the SP application environment. This is particularly useful
when the adapters need to communicate with third party IDPs and the roles set by the IDP in the assertion do not correspond to
the roles that were defined for the SP application. The provider to be used can configured in the `keycloak-saml.xml`
file or in the `keycloak-saml` subsystem. An implementation that performs the role mappings based on the contents of a properties
file was also provided.
Notice that when {project_name} acts as the IDP we can use the built-in role mappers to perform any necessary mappings
before setting the roles into the assertion, so this SPI will probably be redundant in this case. The `RoleMappingsProvider`
SPI was designed for situations when the IDP offer no way to map roles before adding them to the assertion.

View file

@ -70,6 +70,7 @@ include::topics/saml/java/general-config/sp-keys/keystore_element.adoc[]
include::topics/saml/java/general-config/sp-keys/key_pems.adoc[]
include::topics/saml/java/general-config/sp_principalname_mapping_element.adoc[]
include::topics/saml/java/general-config/roleidentifiers_element.adoc[]
include::topics/saml/java/general-config/sp_role_mappings_provider_element.adoc[]
include::topics/saml/java/general-config/idp_element.adoc[]
include::topics/saml/java/general-config/idp_allowedclockskew_subelement.adoc[]
include::topics/saml/java/general-config/idp_singlesignonservice_subelement.adoc[]

View file

@ -30,6 +30,9 @@ This is what one might look like:
<RoleIdentifiers>
<Attribute name="Role"/>
</RoleIdentifiers>
<RoleMappingsProvider id="properties-based-role-mapper">
<Property name="properties.resource.location" value="/WEB-INF/role-mappings.properties"/>
</RoleMappingsProvider>
<IDP entityID="idp"
signaturesRequired="true">
<SingleSignOnService requestBinding="POST"

View file

@ -0,0 +1,92 @@
===== RoleMappingsProvider Element
The `RoleMappingsProvider` is an optional element that allows for the specification of the id and configuration of the
`org.keycloak.adapters.saml.RoleMappingsProvider` SPI implementation that is to be used by the SAML adapter.
When {project_name} is used as the IDP, it is possible to use the built in role mappers to map any roles before adding them to the
SAML assertion. However, the SAML adapters can be used to send SAML requests to third party IDPs and in this case it might be
necessary to map the roles extracted from the assertion into a different set of roles as required by the SP. The
`RoleMappingsProvider` SPI allows for the configuration of pluggable role mappers that can be used to perform the necessary
mappings.
The configuration of the provider looks as follows:
[source,xml]
----
...
<RoleIdentifiers>
...
</RoleIdentifiers>
<RoleMappingsProvider id="properties-based-role-mapper">
<Property name="properties.resource.location" value="/WEB-INF/role-mappings.properties"/>
</RoleMappingsProvider>
<IDP>
...
</IDP>
----
The `id` attribute identifies which of the installed providers is to be used. The `Property` sub-element can be used multiple times
to specify configuration properties for the provider.
====== Properties Based Role Mappings Provider
{project_name} includes a `RoleMappingsProvider` implementation that performs the role mappings using a `properties` file. This
provider is identified by the id `properties-based-role-mapper` and is implemented by the `org.keycloak.adapters.saml.PropertiesBasedRoleMapper`
class.
This provider relies on two configuration properties that can be used to specify the location of the `properties` file
that will be used. First, it checks if the `properties.file.location` property has been specified, using the configured
value to locate the `properties` file in the filesystem. If the configured file is not located, the provider throws a
`RuntimeException`. The following snippet shows an example of provider using the `properties.file.configuration`
option to load the `roles.properties` file from the `/opt/mappers/` directory in the filesystem:
[source,xml,subs="attributes+"]
----
<RoleMappingsProvider id="properties-based-role-mapper">
<Property name="properties.file.location" value="/opt/mappers/roles.properties"/>
</RoleMappingsProvider>
----
If the `properties.file.location` configuration has not been set, the provider checks the `properties.resource.location`
property, using the configured value to load the `properties` file from the `WAR` resource. If this configuration property is
also not present, the provider attempts to load the file from `/WEB-INF/role-mappings.properties` by default. Failure to load the file
from the resource will result in the provider throwing a `RuntimeException`. The following snippet shows an example of provider
using the `properties.resource.location` to load the `roles.properties` file from the application's `/WEB-INF/conf/` directory:
[source,xml,subs="attributes+"]
----
<RoleMappingsProvider id="properties-based-role-mapper">
<Property name="properties.resource.location" value="/WEB-INF/conf/roles.properties"/>
</RoleMappingsProvider>
----
The `properties` file can contain both roles and principals as keys, and a list of zero or more roles separated by comma
as values. When invoked, the implementation iterates through the set of roles that were extracted from the assertion and checks,
for each role, if a mapping exists. If the role maps to an empty role, it is discarded. If it maps to a set of one ore more
different roles, then these roles are set in the result set. If no mapping is found for the role then it is included as is
in the result set.
Once the roles have been processed, the implementation checks if the principal extracted from the assertion contains an entry
`properties` file. If a mapping for the principal exists, any roles listed as value are added to the result set. This
allows the assignment of extra roles to a principal.
As an example, let's assume the provider has been configured with the following properties file:
[source]
----
roleA=roleX,roleY
roleB=
kc_user=roleZ
----
If the principal `kc_user` is extracted from the assertion with roles `roleA`, `roleB` and `roleC`, the final set of roles
assigned to the principal will be `roleC`, `roleX`, `roleY` and `roleZ` because `roleA` is being mapped into both `roleX`
and `roleY`, `roleB` was mapped into an empty role - thus being discarded, `roleC` is used as is and finally an additional role
was added to the `kc_user` principal (`roleZ`).
====== Adding Your Own Role Mappings Provider
To add a custom role mappings provider one simply needs to implement the `org.keycloak.adapters.saml.RoleMappingsProvider` SPI.
For more details see the `SAML Role Mappings SPI` section in link:{developerguide_link}[{developerguide_name}].

View file

@ -14,6 +14,7 @@ include::topics/extensions.adoc[]
include::topics/auth-spi.adoc[]
include::topics/action-token-spi.adoc[]
include::topics/events.adoc[]
include::topics/saml-role-mappings-spi.adoc[]
endif::[]
include::topics/user-storage.adoc[]
include::topics/user-storage/provider-interfaces.adoc[]

View file

@ -0,0 +1,29 @@
[[_saml_role_mappings_spi]]
== SAML Role Mappings SPI
{project_name} defines a SPI for mapping SAML roles into roles that exist in the SP environment. The roles returned by
a third-party IDP might not always correspond to the roles that were defined for the SP application so there is a need for a
mechanism that allows mapping the SAML roles into different roles. It is used by the SAML adapter after it extracts the roles
from the SAML assertion to set up the container's security context.
The `org.keycloak.adapters.saml.RoleMappingsProvider` SPI doesn't impose any restrictions on the mappings that can be performed.
Implementations can not only map roles into other roles but also add or remove roles (and thus augment or reduce the set of
roles assigned to the SAML principal) depending on the use case.
For details about the configuration of the role mappings provider for the SAML adapter as well as a description of the default
implementations available see the link:{adapterguide_link}[{adapterguide_name}].
=== Implementing a Custom Role Mappings Provider
To implement a custom role mappings provider one first needs to implement the `org.keycloak.adapters.saml.RoleMappingsProvider`
interface. Then, a `META-INF/services/org.keycloak.adapters.saml.RoleMappingsProvider` file containing the fully qualified name
of the custom implementation must be added to the archive that also contains the implementation class. This archive can be:
* The SP application WAR file where the provider class is included in WEB-INF/classes;
* A custom JAR file which will be added into WEB-INF/lib of the SP application WAR;
* (WildFly/JBoss EAP only) A custom JAR file configured as a `jboss module` and referenced in `jboss-deployment-structure.xml`
of the SP application WAR.
When the SP application is deployed, the role mappings provider that will be used is selected by the id that was set in
`keycloak-saml.xml` or in the `keycloak-saml` subsystem. So to enable your custom provider simply make sure that its id is
properly set in the adapter configuration.