Merge pull request #8 from stianst/master

Misc
This commit is contained in:
Stian Thorgersen 2016-06-03 12:36:04 +02:00
commit 6c76260d06
16 changed files with 324 additions and 317 deletions

View file

@ -20,7 +20,7 @@
{% endif %} {% endif %}
... link:topics/oidc/java/servlet-filter-adapter.adoc[Java Servlet Filter Adapter] ... link:topics/oidc/java/servlet-filter-adapter.adoc[Java Servlet Filter Adapter]
... link:topics/oidc/java/jaas.adoc[JAAS plugin] ... link:topics/oidc/java/jaas.adoc[JAAS plugin]
... link:topics/oidc/java/adapter-context.adoc[Keycloak Security Context] ... link:topics/oidc/java/adapter-context.adoc[Security Context]
... link:topics/oidc/java/adapter_error_handling.adoc[Error Handling] ... link:topics/oidc/java/adapter_error_handling.adoc[Error Handling]
... link:topics/oidc/java/logout.adoc[Logout] ... link:topics/oidc/java/logout.adoc[Logout]
... link:topics/oidc/java/multi-tenancy.adoc[Multi Tenancy] ... link:topics/oidc/java/multi-tenancy.adoc[Multi Tenancy]

View file

@ -1,12 +1,19 @@
=== Keycloak Security Context === Security Context
The `KeycloakSecurityContext` interface is available if you need to look at the access token directly. The `KeycloakSecurityContext` interface is available if you need to access to the tokens directly. This could be useful if you want to retrieve additional
This context is also useful if you need to get the encoded access token so you can make additional REST invocations. details from the token (such as user profile information) or you want to invoke a RESTful service that is protected by {{book.project.title}}.
In servlet environments it is available in secured invocations as an attribute in HttpServletRequest.
Or, it is available in secure and insecure requests in the HttpSession for browser apps.
[source] In servlet environments it is available in secured invocations as an attribute in HttpServletRequest:
[source,java]
---- ----
httpServletRequest.getAttribute(KeycloakSecurityContext.class.getName()); httpServletRequest
httpServletRequest.getSession().getAttribute(KeycloakSecurityContext.class.getName()); .getAttribute(KeycloakSecurityContext.class.getName());
----
Or, it is available in secure and insecure requests in the HttpSession:
[source,java]
----
httpServletRequest.getSession()
.getAttribute(KeycloakSecurityContext.class.getName());
---- ----

View file

@ -2,59 +2,33 @@
[[_adapter_error_handling]] [[_adapter_error_handling]]
=== Error Handling === Error Handling
Keycloak has some error handling facilities for servlet based client adapters. {{book.project.name}} has some error handling facilities for servlet based client adapters.
When an error is encountered in authentication, keycloak will call `HttpServletResponse.sendError()`. When an error is encountered in authentication, {{book.project.title}} will call `HttpServletResponse.sendError()`.
You can set up an error-page within your `web.xml` file to handle the error however you want. You can set up an error-page within your `web.xml` file to handle the error however you want.
Keycloak may throw 400, 401, 403, and 500 errors. {{book.project.title}} may throw 400, 401, 403, and 500 errors.
[source,xml]
[source]
---- ----
<error-page> <error-page>
<error-code>404</error-code> <error-code>404</error-code>
<location>/ErrorHandler</location> <location>/ErrorHandler</location>
</error-page> </error-page>
---- ----
Keycloak also sets an `HttpServletRequest` attribute that you can retrieve. {{book.project.name}} also sets a `HttpServletRequest` attribute that you can retrieve.
The attribute name is `org.keycloak.adapters.spi.AuthenticationError`. The attribute name is `org.keycloak.adapters.spi.AuthenticationError`, which should be casted to to `org.keycloak.adapters.OIDCAuthenticationError`.
Typecast this object to: `org.keycloak.adapters.OIDCAuthenticationError`.
This class can tell you exactly what happened.
If this attribute is not set, then the adapter was not responsible for the error code.
For example:
[source] [source,java]
---- ----
import org.keycloak.adapters.OIDCAuthenticationError;
import org.keycloak.adapters.OIDCAuthenticationError.Reason;
...
public class OIDCAuthenticationError implements AuthenticationError { OIDCAuthenticationError error = (OIDCAuthenticationError) httpServletRequest
public static enum Reason { .getAttribute('org.keycloak.adapters.spi.AuthenticationError');
NO_BEARER_TOKEN,
NO_REDIRECT_URI,
INVALID_STATE_COOKIE,
OAUTH_ERROR,
SSL_REQUIRED,
CODE_TO_TOKEN_FAILURE,
INVALID_TOKEN,
STALE_TOKEN,
NO_AUTHORIZATION_HEADER
}
private Reason reason; Reason reason = error.getReason();
private String description; System.out.println(reason.name());
public OIDCAuthenticationError(Reason reason, String description) {
this.reason = reason;
this.description = description;
}
public Reason getReason() {
return reason;
}
public String getDescription() {
return description;
}
}
---- ----

View file

@ -1,131 +1,113 @@
[[_applicationclustering]] [[_applicationclustering]]
=== Application Clustering === Application Clustering
This chapter is focused on clustering support for your own AS7, EAP6 or Wildfly applications, which are secured by Keycloak. This chapter is related to supporting clustered applications deployed to JBoss EAP{% if book.community %}, WildFly and JBoss AS{% endif %}.
We support various deployment scenarios according if your application is:
* stateless or stateful There are several options depending on if your application is:
* distributable (replicated http session) or non-distributable and just relying on sticky sessions provided by loadbalancer
* deployed on same or different cluster hosts where keycloak servers are deployed
The situation is a bit tricky as application communicates with Keycloak directly within user's browser (for example redirecting to login screen), but there is also backend (out-of-bound) communication between keycloak and application, which is hidden from end-user and his browser and hence can't rely on sticky sessions. * Stateless or stateful
* Distributable (replicated http session) or non-distributable
* Relying on sticky sessions provided by load balancer
* Hosted on same domain as {{book.project.name}}
NOTE: To enable distributable (replicated) HTTP Sessions in your application, you may need to do some additional steps. Dealing with clustering is not quite as simple as for a regular application. Mainly due to the fact that both the browser and the server-side application
Usually you need to put tag into `WEB-INF/web.xml` file of your application and possibly do some additional steps to configure underlying cluster cache (In case of Wildfly, the implementation of cluster cache is based on Infinispan). These steps are server specific, so consult documentation of your application server for more details. sends requests to {{book.project.name}}, so it's not as simple as enabling sticky sessions on your load balancer.
==== Stateless token store ==== Stateless token store
By default, the servlet web application secured by Keycloak uses HTTP session to store information about authenticated user account. By default, the web application secured by {{book.project.name}} uses the HTTP session to store security context. This means that you either have to
This means that this info could be replicated across cluster and your application will safely survive failover of some cluster node. enable sticky sessions or replicate the HTTP session.
However if you don't need or don't want to use HTTP Session, you may alternatively save all info about authenticated account into cookie. As an alternative to storing the security context in the HTTP session the adapter can be configured to store this in a cookie instead. This is useful if you want
This is useful especially if your application is: to make your application stateless or if you don't want to store the security context in the HTTP session.
* stateless application without need of HTTP Session, but with requirement to be safe to failover of some cluster node To use the cookie store for saving the security context, edit your applications `WEB-INF/keycloak.json` and add:
* stateful application, but you don't want sensitive token data to be saved in HTTP session [source,json]
* stateless application relying on loadbalancer, which is not aware of sticky sessions (in this case cookie is your only way)
To configure this, you can add this line to configuration of your adapter in `WEB-INF/keycloak.json` of your application:
[source]
---- ----
"token-store": "cookie" "token-store": "cookie"
---- ----
Default value of `token-store` is `session`, hence saving data in HTTP session. NOTE: The default value for `token-store` is `session`, which stores the security context in the HTTP session.
One limitation of cookie store is, that whole info about account is passed in cookie KEYCLOAK_ADAPTER_STATE in each HTTP request. One limitation of using the cookie store is that the whole security context is passed in the cookie for every HTTP request. This may impact performance.
Hence it's not the best for network performance.
Another small limitation is limited support for Single-Sign out. Another small limitation is limited support for Single-Sign Out. It works without issues if you init servlet logout (HttpServletRequest.logout) from the
It works without issues if you init servlet logout (HttpServletRequest.logout) from this application itself as the adapter will delete the KEYCLOAK_ADAPTER_STATE cookie. application itself as the adapter will delete the KEYCLOAK_ADAPTER_STATE cookie. However, back-channel logout initialized from a different application isn't
But back-channel logout initialized from different application can't be propagated by Keycloak to this application with cookie store. propagated by {{book.project.name}} to applications using cookie store. Hence it's recommended to use a short value for the access token timeout (for example 1 minute).
Hence it's recommended to use very short value of access token timeout (1 minute for example).
==== Relative URI optimization ==== Relative URI optimization
In many deployment scenarios will be Keycloak and secured applications deployed on same cluster hosts. In deployment scenarios where {{book.project.name}} and the application is hosted on the same domain (through a reverse proxy or load balancer) it can be
For this case Keycloak already provides option to use relative URI as value of option _auth-server-url_ in `WEB-INF/keycloak.json` . In this case, the URI of Keycloak server is resolved from the URI of current request. convenient to use relative URI options in your client configuration.
For example if your loadbalancer is on _https://loadbalancer.com/myapp_ and auth-server-url is _/auth_, then relative URI of Keycloak is resolved to be _https://loadbalancer.com/auth_ . With relative URIs the URI is resolved as relative to the URL of the URL used to access {{book.project.name}}.
For cluster setup, it may be even better to use option _auth-server-url-for-backend-request_ . This allows to configure that backend requests between Keycloak and your application will be sent directly to same cluster host without additional round-trip through loadbalancer. For example if the URL to your application is `https://acme.org/myapp` and the URL to {{book.project.name}} is `https://acme.org/auth`, then you can use
So for this, it's good to configure values in `WEB-INF/keycloak.json` like this: the redirect-uri `/myapp` instead of `https://acme.org/myapp`.
[source]
----
"auth-server-url": "/auth",
"auth-server-url-for-backend-requests": "http://${jboss.host.name}:8080/auth"
----
This would mean that browser requests (like redirecting to Keycloak login screen) will be still resolved relatively to current request URI like _https://loadbalancer.com/myapp_, but backend (out-of-bound) requests between keycloak and your app are sent always to same cluster host with application .
Note that additionally to network optimization, you may not need "https" in this case as application and keycloak are communicating directly within same cluster host.
==== Admin URL configuration ==== Admin URL configuration
Admin URL for particular application can be configured in Keycloak admin console. Admin URL for a particular application can be configured in the {{book.project.name}} Administration Console.
It's used by Keycloak server to send backend requests to application for various tasks, like logout users or push revocation policies. It's used by the {{book.project.name}} server to send backend requests to the application for various tasks, like logout users or push revocation policies.
For example logout of user from Keycloak works like this: For example the way backchannel logout works is:
. User sends logout request from one of applications where he is logged. . User sends logout request from one application
. Then application will send logout request to Keycloak . The application sends logout request to {{book.project.name}}
. Keycloak server logout user in itself, and then it re-sends logout request by backend channel to all applications where user is logged. . The {{book.project.name}} server invalidates the user session
Keycloak is using admin URL for this. . The {{book.project.name}} server then sends a backchannel request to application with a admin url that are associated with the session
So logout is propagated to all apps. . When an application receives the logout request it invalidates the corresponding HTTP session
You may again use relative values for admin URL, but in cluster it may not be the best similarly like in <<_relative_uri_optimization,previous section>> .
Some examples of possible values of admin URL are: Some examples of possible values of admin URL are:
http://${jboss.host.name}:8080/myapp::
This is best choice if "myapp" is deployed on same cluster hosts like Keycloak and is distributable.
In this case Keycloak server sends logout request to itself, hence no communication with loadbalancer or other cluster nodes and no additional network traffic.
http://${application.session.host}:8080/myapp:: http://${application.session.host}:8080/myapp::
Keycloak will track hosts where is particular HTTP Session served and it will send session invalidation message to proper cluster node. {{book.project.name}} tracks hosts associated with the HTTP Session and will send session invalidation message to the associated node.
[[_registration_app_nodes]] [[_registration_app_nodes]]
==== Registration of application nodes to Keycloak ==== Registration of application nodes
Previous section describes how can Keycloak send logout request to proper application node. The previous describes how {{book.project.name}} can send logout request to node associated with a specific HTTP session.
However in some cases admin may want to propagate admin tasks to all registered cluster nodes, not just one of them. However, in some cases admin may want to propagate admin tasks to all registered cluster nodes, not just one of them.
For example push new notBefore for realm or application, or logout all users from all applications on all cluster nodes. For example to push a new not before policy to the application or to logout all users from the application.
In this case Keycloak should be aware of all application cluster nodes, so it could send event to all of them. In this case {{book.project.name}} needs to be aware of all application cluster nodes, so it can send the event to all of them.
To achieve this, we support auto-discovery mechanism: To achieve this, we support auto-discovery mechanism:
. Once new application node joins cluster, it sends registration request to Keycloak server . When a new application node joins the cluster, it sends a registration request to the {{book.project.name}} server
. The request may be re-sent to Keycloak in configured periodic intervals . The request may be re-sent to {{book.project.name}} in configured periodic intervals
. If Keycloak won't receive re-registration request within specified timeout (should be greater than period from point 2) then it automatically unregister particular node . If the {{book.project.name}} server doesn't receive a re-registration request within a specified timeout then it automatically unregisters the specific node
. Node is also unregistered in Keycloak when it sends unregistration request, which is usually during node shutdown or application undeployment. . The node is also unregistered in {{book.project.name}} when it sends an unregistration request, which is usually during node shutdown or application undeployment.
This may not work properly for forced shutdown when undeployment listeners are not invoked, so here you need to rely on automatic unregistration from point 3 . This may not work properly for forced shutdown when undeployment listeners are not invoked, which results in the need for automatic unregistration
Sending startup registrations and periodic re-registration is disabled by default, as it's main usecase is just cluster deployment. Sending startup registrations and periodic re-registration is disabled by default as it's only required for some clustered applications.
In `WEB-INF/keycloak.json` of your application, you can specify:
To enable the feature edit the `WEB-INF/keycloak.json` file for your application and add:
[source] [source]
---- ----
"register-node-at-startup": true, "register-node-at-startup": true,
"register-node-period": 600, "register-node-period": 600,
---- ----
which means that registration is sent at startup (accurately when 1st request is served by the application node) and then it's resent each 10 minutes.
In Keycloak admin console you can specify the maximum node re-registration timeout (makes sense to have it bigger than _register-node-period_ from adapter configuration for particular application). Also you can manually add and remove cluster nodes in admin console, which is useful if you don't want to rely on adapter's automatic registration or if you want to remove stale application nodes, which weren't unregistered (for example due to forced shutdown). This means the adapter will send the registration request on startup and re-register every 10 minutes.
In the {{book.project.name}} Administration Console you can specify the maximum node re-registration timeout (should be larger than _register-node-period_ from
the adapter configuration). You can also manually add and remove cluster nodes in through the Adminstration Console, which is useful if you don't want to rely
on the automatic registration feature or if you want to remove stale application nodes in the event your not using the automatic unregistration feature.
[[_refresh_token_each_req]] [[_refresh_token_each_req]]
==== Refresh token in each request ==== Refresh token in each request
By default, application adapter tries to refresh access token when it's expired (period can be specified as <<_token_timeouts,Access Token Lifespan>>) . However if you don't want to rely on the fact, that Keycloak is able to successfully propagate admin events like logout to your application nodes, then you have possibility to configure adapter to refresh access token in each HTTP request. By default the application adapter will only refresh the access token when it's expired. However, you can also configure the adapter to refresh the token on every
request. This may have a performance impact as your application will send more requests to the {{book.project.name}} server.
In `WEB-INF/keycloak.json` you can configure: To enable the feature edit the `WEB-INF/keycloak.json` file for your application and add:
[source] [source]
---- ----
"always-refresh-token": true "always-refresh-token": true
---- ----
Note that this has big performance impact. NOTE: This may have a significant impact on performance. Only enable this feature if you can't rely on backchannel messages to propagate logout and not before
It's useful just if performance is not priority, but security is critical and you can't rely on logout and push notBefore propagation from Keycloak to applications. policies. Another thing to consider is that by default access tokens has a short expiration so even if logout is not propagated the token will expire within
minutes of the logout.

View file

@ -1,27 +1,30 @@
[[_jaas_adapter]] [[_jaas_adapter]]
=== JAAS plugin === JAAS plugin
It's generally not needed to use JAAS for most of the applications, especially if they are HTTP based, but directly choose one of our adapters. It's generally not needed to use JAAS for most of the applications, especially if they are HTTP based, and you should most likely choose one of our other adapters.
However some applications and systems may still rely on pure legacy JAAS solution. However, some applications and systems may still rely on pure legacy JAAS solution.
Keycloak provides couple of login modules to help with such use cases. {{book.project.title}} provides two login modules to help in these situations.
Some login modules provided by Keycloak are:
The provided login modules are:
org.keycloak.adapters.jaas.DirectAccessGrantsLoginModule:: org.keycloak.adapters.jaas.DirectAccessGrantsLoginModule::
This login module allows to authenticate with username/password from Keycloak database. This login module allows to authenticate with username/password from {{book.project.title}}.
It's using <<_direct_access_grants,Direct Access Grants>> Keycloak endpoint to validate on Keycloak side if provided username/password is valid. It's using <<fake/../../oidc-generic.adoc#_resource_owner_password_credentials_flow,Resource Owner Password Credentials>> flow to validate if the provided
It's useful especially for non-web based systems, which need to rely on JAAS and want to use Keycloak credentials, but can't use classic browser based authentication flow due to their non-web nature. username/password is valid. It's useful for non-web based systems, which need to rely on JAAS and want to use Keycloak, but can't use the standard browser
Example of such application could be messaging application or SSH system. based flows due to their non-web nature. Example of such application could be messaging or SSH.
org.keycloak.adapters.jaas.BearerTokenLoginModule:: org.keycloak.adapters.jaas.BearerTokenLoginModule::
This login module allows to authenticate with Keycloak access token passed to it through CallbackHandler as password. This login module allows to authenticate with {{book.project.title}} access token passed to it through CallbackHandler as password.
It may be useful for example in case, when you have Keycloak access token from classic web based authentication flow and your web application then needs to talk to external non-web based system, which rely on JAAS. It may be useful for example in case, when you have {{book.project.title}} access token from standard based authentication flow and your web application then
For example to JMS/messaging system. needs to talk to external non-web based system, which rely on JAAS. For example a messaging system.
Both login modules have configuration property `keycloak-config-file` where you need to provide location of keycloak.json configuration file. Both modules use the following configuration properties:
It could be either provided from filesystem or from classpath (in that case you may need value like `classpath:/folder-on-classpath/keycloak.json` ).
Second property `role-principal-class` allows to specify alternative class for Role principals attached to JAAS Subject. keycloak-config-file::
Default value for Role principal is `org.keycloak.adapters.jaas.RolePrincipal` . Note that class should have constructor with single String argument. The location of the `keycloak.json` configuration file. The configuration file can either be located on the filesystem or on the classpath. If it's located
on the classpath you need to prefix the location with `classpath:` (for example `classpath:/path/keycloak.json`).
This is _REQUIRED._
`role-principal-class`::
Configure alternative class for Role principals attached to JAAS Subject.
Default value is `org.keycloak.adapters.jaas.RolePrincipal`. Note: The class is required to have a constructor with a single `String` argument.

View file

@ -2,7 +2,7 @@
[[_java_adapter_config]] [[_java_adapter_config]]
=== Java Adapter Config === Java Adapter Config
Each Java adapter supported by Keycloak can be configured by a simple JSON file. Each Java adapter supported by {{book.project.name}} can be configured by a simple JSON file.
This is what one might look like: This is what one might look like:
[source,json] [source,json]
@ -71,7 +71,7 @@ use-resource-role-mappings::
The default value is _false_. The default value is _false_.
public-client:: public-client::
If set to true, the adapter will not send credentials for the client to Keycloak. If set to true, the adapter will not send credentials for the client to {{book.project.name}}.
This is _OPTIONAL_. This is _OPTIONAL_.
The default value is _false_. The default value is _false_.
@ -118,8 +118,8 @@ credentials::
This is _REQUIRED_. This is _REQUIRED_.
connection-pool-size:: connection-pool-size::
Adapters will make separate HTTP invocations to the Keycloak Server to turn an access code into an access token. Adapters will make separate HTTP invocations to the {{book.project.name}} 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 config option defines how many connections to the {{book.project.name}} server should be pooled.
This is _OPTIONAL_. This is _OPTIONAL_.
The default value is `20`. The default value is `20`.
@ -130,7 +130,7 @@ disable-trust-manager::
The default value is `false`. The default value is `false`.
allow-any-hostname:: allow-any-hostname::
If the {{book.project.name}} server requires HTTPS and this config option is set to `true` the Keycloak Server's certificate is validated via the truststore, If the {{book.project.name}} server requires HTTPS and this config option is set to `true` the {{book.project.name}} server's certificate is validated via the truststore,
but host name validation is not done. but host name validation is not done.
This setting should only be used during development and *never* in production as it will disable verification of SSL certificates. This setting should only be used during development and *never* in production as it will disable verification of SSL certificates.
This seting may be useful in test environments This is _OPTIONAL_. This seting may be useful in test environments This is _OPTIONAL_.
@ -143,7 +143,7 @@ truststore::
Client making HTTPS requests need a way to verify the host of the server they are talking to. Client making HTTPS requests need a way to verify the host of the server they are talking to.
This is what the trustore does. This is what the trustore does.
The keystore contains one or more trusted host certificates or certificate authorities. 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. You can create this truststore by extracting the public certificate of the {{book.project.name}} server's SSL keystore.
This is _OPTIONAL_ if `ssl-required` is `none` or `disable-trust-manager` is `true`. This is _OPTIONAL_ if `ssl-required` is `none` or `disable-trust-manager` is `true`.
truststore-password:: truststore-password::
@ -167,20 +167,20 @@ always-refresh-token::
If _true_, the adapter will refresh token in every request. If _true_, the adapter will refresh token in every request.
register-node-at-startup:: register-node-at-startup::
If _true_, then adapter will send registration request to Keycloak. If _true_, then adapter will send registration request to {{book.project.name}}.
It's _false_ by default and useful only when application is clustered. It's _false_ by default and useful only when application is clustered.
See link:application-clustering.html[Application Clustering] for details See <<fake/../../oid/java/application-clustering.adoc#_applicationclustering,Application Clustering>> for details
register-node-period:: register-node-period::
Period for re-registration adapter to Keycloak. Period for re-registration adapter to {{book.project.name}}.
Useful when application is clustered. Useful when application is clustered.
See link:application-clustering.html[Application Clustering] for details See <<fake/../../oid/java/application-clustering.adoc#_applicationclustering,Application Clustering>> for details
token-store:: token-store::
Possible values are _session_ and _cookie_. Possible values are _session_ and _cookie_.
Default is _session_, which means that adapter stores account info in HTTP Session. Default is _session_, which means that adapter stores account info in HTTP Session.
Alternative _cookie_ means storage of info in cookie. Alternative _cookie_ means storage of info in cookie.
See link:application-clustering.html[Application Clustering] for details See <<fake/../../oid/java/application-clustering.adoc#_applicationclustering,Application Clustering>> for details
principal-attribute:: principal-attribute::
OpenID Connection ID Token attribute to populate the UserPrincipal name with. OpenID Connection ID Token attribute to populate the UserPrincipal name with.

View file

@ -2,5 +2,5 @@
{{book.project.name}} comes with a range of different adapters for Java application. Selecting the correct adapter depends on the target platform. {{book.project.name}} comes with a range of different adapters for Java application. Selecting the correct adapter depends on the target platform.
All Java adapters share a set of common configuration options described in the link:java-adapter-config.html[Java Adapters Config] chapter. There are also All Java adapters share a set of common configuration options described in the <<fake/../java-adapter-config.adoc#_java_adapter_config,Java Adapters Config>> chapter. There are also
a few more chapters that are relevant to all Java adapters. a few more chapters that are relevant to all Java adapters.

View file

@ -1,103 +1,129 @@
[[_jboss_adapter]] [[_jboss_adapter]]
=== JBoss/Wildfly Adapter {% if book.community %}
=== JBoss EAP/Wildfly Adapter
{% endif %}
{% if book.product %}
=== JBoss EAP Adapter
{% endif %}
To be able to secure WAR apps deployed on JBoss AS 7.1.1, JBoss EAP 6.x, or Wildfly, you must install and configure the Keycloak Subsystem. To be able to secure WAR apps deployed on JBoss EAP {% if book.community %}, WildFly or JBoss AS{% endif %}, you must install and configure the
You then have two options to secure your WARs. {{book.project.name}} adapter subsystem. You then have two options to secure your WARs.
You can provide a keycloak config file in your WAR and change the auth-method to KEYCLOAK within web.xml.
Alternatively, you don't have to crack open your WARs at all and can apply Keycloak via the Keycloak Subsystem configuration in standalone.xml. You can provide an adapter config file in your WAR and change the auth-method to KEYCLOAK within web.xml.
Alternatively, you don't have to modify your WAR at all and you can secure it via the {{book.project.name}} adapter subsystem configuration in `standalone.xml`.
Both methods are described in this section. Both methods are described in this section.
[[_jboss_adapter_installation]] [[_jboss_adapter_installation]]
==== Adapter Installation ==== Adapter Installation
Adapters are no longer included with the appliance or war distribution. Adapters are available as a separate archive and are also available as Maven artifacts.
Each adapter is a separate download on the Keycloak download site.
They are also available as a maven artifact.
{% if book.community %}
Install on Wildfly 9 or 10: Install on Wildfly 9 or 10:
[source] [source,bash]
----
$ cd $WILDFLY_HOME
$ unzip keycloak-wildfly-adapter-dist-{{book.project.version}}.zip
---- ----
$ cd $WILDFLY_HOME
$ unzip keycloak-wildfly-adapter-dist.zip
----
Install on Wildfly 8: Install on Wildfly 8:
[source] [source,bash]
---- ----
$ cd $WILDFLY_HOME $ cd $WILDFLY_HOME
$ unzip keycloak-wf8-adapter-dist.zip $ unzip keycloak-wf8-adapter-dist-{{book.project.version}}.zip
---- ----
Install on JBoss EAP 6.x:
Install on JBoss EAP 7:
[source] [source]
---- ----
$ cd $EAP_HOME
$ unzip keycloak-eap7-adapter-dist-{{book.project.version}}.zip
----
Install on JBoss EAP 6:
[source]
----
$ cd $EAP_HOME
$ unzip keycloak-eap6-adapter-dist-{{book.project.version}}.zip
----
Install on JBoss AS 7.1:
[source]
----
$ cd $JBOSS_HOME $ cd $JBOSS_HOME
$ unzip keycloak-eap6-adapter-dist.zip $ unzip keycloak-as7-adapter-dist-{{book.project.version}}.zip
---- ----
Install on JBoss AS 7.1.1: {% endif %}
{% if book.product %}
Install on JBoss EAP 7:
[source] [source]
---- ----
$ cd $EAP_HOME
$ cd $JBOSS_HOME $ unzip RH-SSO-{{book.project.version}}-eap7-adapter.zip
$ unzip keycloak-as7-adapter-dist.zip
---- ----
This zip file creates new JBoss Modules specific to the Wildfly Keycloak Adapter within your Wildfly distro. Install on JBoss EAP 6:
After adding the Keycloak modules, you must then enable the Keycloak 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:
[source] [source]
---- ----
$ cd $EAP_HOME
$ cd $JBOSS_HOME/bin $ unzip RH-SSO-{{book.project.version}}-eap6-adapter.zip
$ jboss-cli.sh -c --file=adapter-install.cli
---- ----
The script will add the extension, subsystem, and optional security-domain as described below. {% endif %}
For more recent versions of WildFly there's also a offline CLI script that can be used to install the adapter while the server is not running: This ZIP archive contains JBoss Modules specific to the {{book.project.name}} adapter. It also contains JBoss CLI scripts to install and configure the adapter.
Once the ZIP archive is extracted you have to enable the {{book.project.name}} subystem in the server configuration (i.e. `standalone.xml`). The easiest way to
do this is to use the supplied JBoss CLI scripts.
To install and configure the adapter, first start the server and then run the JBoss CLI installation script :
[source] [source]
---- ----
$ ./bin/jboss-cli.sh -c --file=adapter-install.cli
$ cd $JBOSS_HOME/bin
$ jboss-cli.sh -c --file=adapter-install-offline.cli
---- ----
The script will add the required configuration to the server configuration file.
For JBoss EAP 7 {% if book.community %} and WildFly 9+{% endif %} there is also an offline CLI script that can be used to install the adapter while the server
is not running:
[source] [source]
---- ----
$ ./bin/jboss-cli.sh -c --file=adapter-install-offline.cli
----
<server xmlns="urn:jboss:domain:1.4"> If you are planning to add it manually you need to add the extension and subsystem definition to the server configuration:
<extensions> [source,xml]
----
<extensions>
<extension module="org.keycloak.keycloak-adapter-subsystem"/> <extension module="org.keycloak.keycloak-adapter-subsystem"/>
... ...
</extensions> </extensions>
<profile> <profile>
<subsystem xmlns="urn:jboss:domain:keycloak:1.1"/> <subsystem xmlns="urn:jboss:domain:keycloak:1.1"/>
... ...
</profile> </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. If you need to be able to propagate the security context from the web tier to the EJB tier you also need to add the `keycloak` security domain:
Otherwise this configuration is optional.
[source] [source,xml]
---- ----
<subsystem xmlns="urn:jboss:domain:security:...">
<server xmlns="urn:jboss:domain:1.4">
<subsystem xmlns="urn:jboss:domain:security:1.2">
<security-domains> <security-domains>
... ...
<security-domain name="keycloak"> <security-domain name="keycloak">
<authentication> <authentication>
<login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule" <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule"
@ -105,6 +131,7 @@ Otherwise this configuration is optional.
</authentication> </authentication>
</security-domain> </security-domain>
</security-domains> </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: 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:
@ -142,8 +169,6 @@ public class CustomerService {
} }
---- ----
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.
==== Required Per WAR Configuration ==== Required Per WAR Configuration
This section describes how to secure a WAR directly by adding config and editing files within your WAR package. This section describes how to secure a WAR directly by adding config and editing files within your WAR package.
@ -153,19 +178,18 @@ The format of this config file is describe in the <<_adapter_config,general adap
Next you must set the `auth-method` to `KEYCLOAK` in `web.xml`. Next you must set the `auth-method` to `KEYCLOAK` in `web.xml`.
You also have to use standard servlet security to specify role-base constraints on your URLs. You also have to use standard servlet security to specify role-base constraints on your URLs.
Here's an example pulled from one of the examples that comes distributed with Keycloak.
Here's an example:
[source] [source,xml]
---- ----
<web-app xmlns="http://java.sun.com/xml/ns/javaee" <web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"> version="3.0">
<module-name>customer-portal</module-name> <module-name>application</module-name>
<security-constraint> <security-constraint>
<web-resource-collection> <web-resource-collection>
@ -208,16 +232,13 @@ Here's an example pulled from one of the examples that comes distributed with Ke
==== Securing WARs via Keycloak Subsystem ==== Securing WARs via Keycloak Subsystem
You do not have to crack open a WAR to secure it with Keycloak. You do not have to modify your WAR to secure it with {{book.project.title}}. Instead you can externally secure it via the {{book.project.title}} Adapter Subsystem.
Alternatively, you can externally secure it via the Keycloak Adapter Subsystem.
While you don't have to specify KEYCLOAK as an `auth-method`, you still have to define the `security-constraints` in `web.xml`. While you don't have to specify KEYCLOAK 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.json` file. You do not, however, have to create a `WEB-INF/keycloak.json` file.
This metadata is instead defined within XML in your server's `domain.xml` or `standalone.xml` subsystem configuration section. This metadata is instead defined within server configuration (i.e. `standalone.xml`) in the {{book.project.title}} subsystem definition.
[source,xml]
[source]
---- ----
<extensions> <extensions>
<extension module="org.keycloak.keycloak-adapter-subsystem"/> <extension module="org.keycloak.keycloak-adapter-subsystem"/>
</extensions> </extensions>
@ -236,25 +257,22 @@ This metadata is instead defined within XML in your server's `domain.xml` or `st
</profile> </profile>
---- ----
The `secure-deployment` `name` attribute identifies the WAR you want to secure. 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. Its value is the `module-name` defined in `web.xml` with `.war` appended.
The rest of the configuration corresponds pretty much one to one with the `keycloak.json` configuration options defined in <<_adapter_config,general adapter configuration>>. The rest of the configuration corresponds pretty much one to one with the `keycloak.json` configuration options defined in <<_adapter_config,general adapter configuration>>.
The exception is the `credential` element. The exception is the `credential` element.
To make it easier for you, you can go to the Keycloak Adminstration Console and go to the Application/Installation tab of the application this WAR is aligned with. To make it easier for you, you can go to the {{book.project.title}} Administration Console and go to the Application/Installation tab of the application this WAR is aligned with.
It provides an example XML file you can cut and paste. It provides an example XML file you can cut and paste.
There is an additional convenience format for this XML if you have multiple WARs you are deployment that are secured by the same domain. There is an additional convenience format for this XML if you have multiple WARs you are deployment that are secured by the same domain.
This format allows you to define common configuration items in one place under the `realm` element. This format allows you to define common configuration items in one place under the `realm` element.
[source,xml]
[source]
---- ----
<subsystem xmlns="urn:jboss:domain:keycloak:1.1"> <subsystem xmlns="urn:jboss:domain:keycloak:1.1">
<realm name="demo"> <realm name="demo">
<realm-public-key>MIGfMA0GCSqGSIb3DQEBA</realm-public-key> <realm-public-key>MIGfMA0GCSqGSIb3DQEBA...</realm-public-key>
<auth-server-url>http://localhost:8080/auth</auth-server-url> <auth-server-url>http://localhost:8080/auth</auth-server-url>
<ssl-required>external</ssl-required> <ssl-required>external</ssl-required>
</realm> </realm>

View file

@ -1,6 +1,5 @@
=== Logout === Logout
There are multiple ways you can logout from a web application. 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 the url `http://auth-server/auth/realms/{realm-name}/tokens/logout?redirect_uri=encodedRedirectUri`. For Java EE servlet containers, you can call HttpServletRequest.logout(). For any other browser application, you can redirect the browser to
This will log you out if you have an SSO session with your browser. `http://auth-server/auth/realms/{realm-name}/tokens/logout?redirect_uri=encodedRedirectUri`. This will log you out if you have a SSO session with your browser.

View file

@ -1,28 +1,54 @@
=== Multi Tenancy === Multi Tenancy
Multi Tenancy, in our context, means that one single target application (WAR) can be secured by a single (or clustered) Keycloak server, authenticating its users against different realms. Multi Tenancy, in our context, means that a single target application (WAR) can be secured with multiple {{book.project.name}} realms. The realms can be located
In practice, this means that one application needs to use different `keycloak.json` files. one the same {{book.project.name}} instance or on different instances.
For this case, there are two possible solutions:
* The same WAR file deployed under two different names, each with its own Keycloak configuration (probably via the Keycloak Subsystem). In practice, this means that the application needs to have multiple `keycloak.json` adapter configuration files.
This scenario is suitable when the number of realms is known in advance or when there's a dynamic provision of application instances.
One example would be a service provider that dynamically creates servers/deployments for their clients, like a PaaS.
* client1.acme.com
+`client2.acme.com`
+`/app/client1/`
+`/app/client2/` This chapter of the reference guide focus on this second scenario.
Keycloak provides an extension point for applications that need to evaluate the realm on a request basis. You could have multiple instances of your WAR with different adapter configuration files deployed to different context-paths. However, this may be inconvenient
During the authentication and authorization phase of the incoming request, Keycloak queries the application via this extension point and expects the application to return a complete representation of the realm. and you may also want to select the realm based on something else than context-path.
With this, Keycloak then proceeds the authentication and authorization process, accepting or refusing the request based on the incoming credentials and on the returned realm.
For this scenario, an application needs to:
* web.xml {{book.project.name}} makes it possible to have a custom config resolver so you can choose what adapter config is used for each request.
+`keycloak.config.resolver`
+`org.keycloak.adapters.KeycloakConfigResolver`
* org.keycloak.adapters.KeycloakConfigResolver
+`resolve(org.keycloak.adapters.spi.HttpFacade.Request)`
+`org.keycloak.adapters.KeycloakDeployment`
An implementation of this feature can be found in the examples. To achieve this first you need to create an implementation of `org.keycloak.adapters.KeycloakConfigResolver`. For example:
[source,java]
----
package example;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
public class PathBasedKeycloakConfigResolver implements KeycloakConfigResolver {
@Override
public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
if (path.startsWith("alternative")) {
KeycloakDeployment deployment = cache.get(realm);
if (null == deployment) {
InputStream is = getClass().getResourceAsStream("/tenant1-keycloak.json");
return KeycloakDeploymentBuilder.build(is);
}
} else {
InputStream is = getClass().getResourceAsStream("/default-keycloak.json");
return KeycloakDeploymentBuilder.build(is);
}
}
}
----
You also need to configure which `KeycloakConfigResolver` implementation to use with the `keycloak.config.resolver` context-param in your `web.xml`:
[source,xml]
----
<web-app>
...
<context-param>
<param-name>keycloak.config.resolver</param-name>
<param-value>example.PathBasedKeycloakConfigResolver</param-value>
</context-param>
</web-app>
----

View file

@ -1,25 +1,22 @@
[[_servlet_filter_adapter]]
=== Java Servlet Filter Adapter === Java Servlet Filter Adapter
If you want to use Keycloak 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. If you are deploying your Java Servlet application on a platform where there is no {{book.project.title}} adapter you opt to use the the servlet filter adapter.
This adapter works a little differently than the other adapters. This adapter works a bit differently than the other adapters. You do not define security constraints in web.xml.
You do not define security constraints in web.xml. Instead you define a filter mapping using the {{book.project.title}} servlet filter adapter to secure the url patterns you want to secure.
Instead you define a filter mapping using the Keycloak servlet filter adapter to secure the url patterns you want to secure.
WARNING: Backchannel logout works a bit differently than the standard adapters. WARNING: 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. Instead of invalidating the HTTP session it marks the session id as logged out.
There's just no way of arbitrarily invalidating an http session based on a session id. There's no way standard way to invalidate an HTTP session based on a session id.
[source] [source,xml]
---- ----
<web-app xmlns="http://java.sun.com/xml/ns/javaee" <web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"> version="3.0">
<module-name>customer-portal</module-name> <module-name>application</module-name>
<filter> <filter>
<filter-name>Keycloak Filter</filter-name> <filter-name>Keycloak Filter</filter-name>
@ -33,23 +30,23 @@ There's just no way of arbitrarily invalidating an http session based on a sessi
</web-app> </web-app>
---- ----
If you notice above, there are two url-patterns. In the snippet above there are two url-patterns.
`/protected/*` are just the files we want protected. `/keycloak/*` url-pattern will handle callback from the keycloak server. `/protected/*` are the files we want protected, while the `/keycloak/*` url-pattern handles callbacks from the {{book.project.title}} server.
Note that you should configure your client in the Keycloak Admin Console with an Admin URL that points to a secured section covered by the filter's url-pattern.
Note that you should configure your client in the {{book.project.title}} Admin Console with an Admin URL that points to a secured section covered by the filter's url-pattern.
The Admin URL will make callbacks to the Admin URL to do things like backchannel logout. The Admin URL will make callbacks to the Admin URL to do things like backchannel logout.
So, the Admin URL in this example should be `http[s]://hostname/{context-root}/keycloak`. So, the Admin URL in this example should be `http[s]://hostname/{context-root}/keycloak`.
There is an example of this in the distribution.
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. The {{book.project.title}} filter has the same configuration parameters as the other adapters except you must define them as filter init params instead of context params.
To use this filter, include this maven artifact in your WAR poms To use this filter, include this maven artifact in your WAR poms:
[source] [source,xml]
---- ----
<dependency>
<dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-servlet-filter-adapter</artifactId> <artifactId>keycloak-servlet-filter-adapter</artifactId>
<version>&project.version;</version> <version>&project.version;</version>
</dependency> </dependency>
---- ----

View file

@ -1,4 +1,4 @@
[[_spring_boot_adapter]]
=== Spring Boot Adapter === Spring Boot Adapter
To be able to secure Spring Boot apps you must add the Keycloak Spring Boot adapter JAR to your app. To be able to secure Spring Boot apps you must add the Keycloak Spring Boot adapter JAR to your app.

View file

@ -1,4 +1,4 @@
[[_spring_security_adapter]]
=== Spring Security Adapter === Spring Security Adapter
To secure an application with Spring Security and Keycloak, add this adapter as a dependency to your project. To secure an application with Spring Security and Keycloak, add this adapter as a dependency to your project.

View file

@ -1,4 +1,4 @@
[[_javascript_adapter]]
== Javascript Adapter == Javascript Adapter
The Keycloak Server comes with a Javascript library you can use to secure HTML/Javascript applications. The Keycloak Server comes with a Javascript library you can use to secure HTML/Javascript applications.

View file

@ -14,6 +14,7 @@ TODO
==== Implicit ==== Implicit
[[_resource_owner_password_credentials_flow]]
==== Resource Owner Password Credentials ==== Resource Owner Password Credentials
==== Client Credentials ==== Client Credentials

View file

@ -3,26 +3,26 @@
=== OpenID Connect === OpenID Connect
==== Java ==== Java
* link:oidc/java/jboss-adapters.html[JBoss EAP] * <<fake/../../oidc/java/jboss-adapter.adoc#_jboss_adapter,JBoss EAP>>
{% if book.community %} {% if book.community %}
* link:oidc/java/jboss-adapters.html[WildFly] * <<fake/../../oidc/java/jboss-adapter.adoc#_jboss_adapter,WildFly>>
{% endif %} {% endif %}
* link:oidc/java/fuse-adapter.html[Fuse] * <<fake/../../oidc/java/fuse-adapter.adoc#_fuse_adapter,Fuse>>
{% if book.community %} {% if book.community %}
* link:oidc/java/tomcat-adapter.html[Tomcat] * <<fake/../../oidc/java/tomcat-adapter.adoc#_tomcat_adapter,Tomcat>>
* link:oidc/java/jetty-adapter.html[Jetty] * <<fake/../../oidc/java/jetty9-adapter.adoc#_jetty9_adapter,Jetty 9>>, <<fake/../../oidc/java/jetty8-adapter.adoc#_jetty8_adapter,Jetty 8>>
{% endif %} {% endif %}
* link:oidc/java/servlet-filter-adapter.html[Servlet Filter] * <<fake/../../oidc/java/servlet-filter-adapter.adoc#_servlet_filter_adapter,Servlet Filter>>
{% if book.community %} {% if book.community %}
* link:oidc/java/spring-adapter.html[Spring Security] (community) * <<fake/../../oidc/java/spring-security-adapter.adoc#_spring_security_adapter,Spring Security>> (community)
* link:oidc/java/spring-boot-adapter.html[Spring Boot] (community) * <<fake/../../oidc/java/spring-boot-adapter.adoc#_spring_boot_adapter,Spring Boot>> (community)
{% endif %} {% endif %}
==== JavaScript (client-side) ==== JavaScript (client-side)
* link:oidc/javascript-adapter.html[JavaScript] * <<fake/../../oidc/javascript-adapter.adoc#_javascript_adapter,JavaScript>>
=== Apache Cordova === Apache Cordova
* link:oidc/javascript-adapter.html[JavaScript] * <<fake/../../oidc/javascript-adapter.adoc#_javascript_adapter,JavaScript>>
{% if book.community %} {% if book.community %}
==== Node.js ==== Node.js
@ -61,11 +61,11 @@
==== Java ==== Java
* link:oidc/java/jboss-adapters.html[JBoss EAP] * <<fake/../../saml/java/jboss-adapter.adoc#_jboss_adapter,JBoss EAP>>
{% if book.community %} {% if book.community %}
* link:oidc/java/jboss-adapters.html[WildFly] * <<fake/../../saml/java/jboss-adapter.adoc#_jboss_adapter,WildFly>>
* link:oidc/java/tomcat-adapter.html[Tomcat] * <<fake/../../saml/java/tomcat-adapter.adoc#_tomcat_adapter,Tomcat>>
* link:oidc/java/jetty-adapter.html[Jetty] * <<fake/../../saml/java/jetty-adapter.adoc#_jetty_adapter,Jetty>>
{% endif %} {% endif %}
==== Apache HTTP Server ==== Apache HTTP Server