-
Language:
English
-
Language:
English
Chapter 16. Java Authentication SPI for Containers (JASPI)
16.1. About Java Authentication SPI for Containers (JASPI) Security
Java Authentication SPI for Containers (JASPI or JASPIC) is a pluggable interface for Java applications. It is defined in JSR-196 of the Java Community Process. Refer to http://www.jcp.org/en/jsr/detail?id=196 for details about the specification.
16.2. Configure Java Authentication SPI for Containers (JASPI) Security
You can authenticate a JASPI provider by adding <authentication-jaspi>
element to your security domain. The configuration is similar to that of a standard authentication module, but login module elements are enclosed in a <login-module-stack>
element. The structure of the configuration is:
Example: Structure of the authentication-jaspi
Element
<authentication-jaspi> <login-module-stack name="..."> <login-module code="..." flag="..."> <module-option name="..." value="..."/> </login-module> </login-module-stack> <auth-module code="..." login-module-stack-ref="..."> <module-option name="..." value="..."/> </auth-module> </authentication-jaspi>
The login module itself is configured the same way as a standard authentication module.
The web-based management console does not expose the configuration of JASPI authentication modules. You must stop the JBoss EAP running instance completely before adding the configuration directly to the EAP_HOME/domain/configuration/domain.xml
file or the EAP_HOME/standalone/configuration/standalone.xml
file.
16.3. Configure Java Authentication SPI for Containers (JASPI) Security Using Elytron
Starting in JBoss EAP 7.3, the elytron
subsystem provides an implementation of the Servlet
profile from the Java Authentication SPI for Containers (JASPI). This allows tighter integration with the security features provided by Elytron.
Enabling JASPI for a Web Application
For the JASPI integration to be enabled for a web application, the web application needs to be associated with either an Elytron http-authentication-factory
or a security-domain
. By doing this, the Elytron security handlers get installed for the deployment and the Elytron security framework gets activated for the deployment.
When the Elytron security framework is activated for a deployment, the globally registered AuthConfigFactory
is queried when requests are handled. It will identify if an AuthConfigProvider
, which should be used for that deployment, has been registered. If an AuthConfigProvider
is found, then JASPI authentication will be used instead of the deployment’s authentication configuration. If no AuthConfigProvider
is found, then the authentication configuration for the deployment will be used instead. This could result in one of the three possibilities:
-
Use of authentication mechanisms from an
http-authentication-factory
. -
Use of mechanisms specified in the
web.xml
. - No authentication is performed if the application does not have any mechanisms defined.
Any updates made to the AuthConfigFactory
are immediately available. This means if an AuthConfigProvider
is registered and is a match for an existing application, it will start to be used immediately without requiring redeployment of the application.
All web applications deployed to JBoss EAP have a security domain, which will be resolved in the following order:
- From the deployment descriptors or annotations of the deployment.
-
The value defined on the
default-security-domain
attribute on theundertow
subsystem. -
Default to
other
.
It is assumed that this security domain is a reference to the PicketBox
security domain, so the final step in activation is ensuring this is mapped to Elytron using an application-security-domain
resource in the undertow
subsystem.
This mapping can do one of the following:
Reference an
elytron
security domain directly, for example:/subsystem=undertow/application-security-domain=MyAppSecurity:add(security-domain=ApplicationDomain)
Reference a
http-authentication-factory
resource to obtain instances of authentication mechanisms, for example:/subsystem=undertow/application-security-domain=MyAppSecurity:add(http-authentication-factory=application-http-authentication)
The minimal steps to enable the JASPI integration are:
-
Leave the
default-security-domain
attribute on theundertow
subsystem undefined so that it defaults toother
. -
Add an
application-security-domain
mapping fromother
to an Elytron security domain.
The security domain associated with a deployment in these steps is the security domain that will be wrapped in a CallbackHandler
to be passed into the ServerAuthModule
instances used for authentication.
Additional Options
Two additional attributes have been added to the application-security-domain
resource to allow some further control of the JASPI behavior.
Table 16.1. Attributes Added to the application-security-domain
Resource
Attribute | Description |
---|---|
|
Can be set to |
|
By default, all identities are loaded from the security domain. If set to |
Subsystem Configuration
One way to register a configuration that will result in an AuthConfigProvider
being returned for a deployment is to register a jaspi-configuration
in the elytron
subsystem.
The following command demonstrates how to add a configuration containing two ServerAuthModule
definitions.
/subsystem=elytron/jaspi-configuration=simple-configuration:add(layer=HttpServlet, application-context="default-host /webctx", description="Elytron Test Configuration", server-auth-modules=[{class-name=org.wildfly.security.examples.jaspi.SimpleServerAuthModule, module=org.wildfly.security.examples.jaspi, flag=OPTIONAL, options={a=b, c=d}}, {class-name=org.wildfly.security.examples.jaspi.SecondServerAuthModule, module=org.wildfly.security.examples.jaspi}])
This results in the following configuration being persisted.
<jaspi> <jaspi-configuration name="simple-configuration" layer="HttpServlet" application-context="default-host /webctx" description="Elytron Test Configuration"> <server-auth-modules> <server-auth-module class-name="org.wildfly.security.examples.jaspi.SimpleServerAuthModule" module="org.wildfly.security.examples.jaspi" flag="OPTIONAL"> <options> <property name="a" value="b"/> <property name="c" value="d"/> </options> </server-auth-module> <server-auth-module class-name="org.wildfly.security.examples.jaspi.SecondServerAuthModule" module="org.wildfly.security.examples.jaspi"/> </server-auth-modules> </jaspi-configuration> </jaspi>
The name
attribute is just a name that allows the resource to be referenced in the management model.
The layer
and application-context
attributes are used when registering this configuration with the AuthConfigFactory
. Both of these attributes can be omitted allowing wildcard matching. The description
attribute is also optional and is used to provide a description to the AuthConfigFactory
.
Within the configuration, one or more server-auth-module
instances can be defined with the following attributes.
-
class-name - The fully qualified class name of the
ServerAuthModule
. -
module - The module to load the
ServerAuthModule
from. - flag - The control flag to indicate how this module operates in relation to the other modules.
-
options - Configuration options to be passed into the
ServerAuthModule
on initialization.
Configuration defined in this way is immediately registered with the AuthConfigFactory
. Any existing deployments using the Elytron security framework, that matches the layer
and application-context
, will immediately start making use of this configuration.
Programmatic Configuration
The APIs defined within the JASPI specification allow for applications to dynamically register custom AuthConfigProvider
instances. However, the specification does not provide the actual implementations to be used or any standard way to create instances of the implementations. The Elytron project contains a simple utility that deployments can use to help with this.
The following code example demonstrates how to use this API to register a configuration similar to the one illustrated in the Subsystem Configuration above.
String registrationId = org.wildfly.security.auth.jaspi.JaspiConfigurationBuilder.builder("HttpServlet", servletContext.getVirtualServerName() + " " + servletContext.getContextPath()) .addAuthModuleFactory(SimpleServerAuthModule::new, Flag.OPTIONAL, Collections.singletonMap("a", "b")) .addAuthModuleFactory(SecondServerAuthModule::new) .register();
As an example, this code could be executed within the init()
method of a Servlet to register the AuthConfigProvider
specific for that deployment. In this code example, the application context has also been assembled by consulting the ServletContext
.
The register()
method returns the resulting registration ID that can also be used to subsequently remove this registration directly from the AuthConfigFactory
.
As with the Subsystem Configuration, this call also has an immediate effect and will be live for all web applications using the Elytron security framework.
Authentication Process
Based on the configuration of the application-security-domain
resource in the undertow
subsystem, the CallbackHandler
passed to the ServerAuthModule
can operate in either of the following modes:
Integrated Mode
When operating in the integrated mode, although the ServerAuthModule
instances will be handling the actual authentication, the resulting identity will be loaded from the referenced SecurityDomain
using the SecurityRealms
referenced by that SecurityDomain
. In this mode, it is still possible to override the roles that will be assigned within the servlet container.
The advantage of this mode is that ServerAuthModules
are able to take advantage of the Elytron configuration for the loading of identities, so that the identities stored in the usual locations, such as databases and LDAP, can be loaded without the ServerAuthModule
needing to be aware of these locations. In addition, other Elytron configuration can be applied, such as role and permission mapping. The referenced SecurityDomain
can also be referenced in other places, such as for SASL authentication or other non JASPI applications, all backed by a common repository of identities.
Table 16.2. Operations of the CallbackHandlers
method in the integrated mode.
Operation | Description |
---|---|
|
The username and password will be used with the |
|
This Note
If an authenticated identity has already been established via the
If a
Where authorization of the anonymous identity is performed, the |
|
In this mode, the attribute loading, role decoding, and role mapping configured on the security domain are used to establish the identity. If this |
Non-Integrated Mode
When operating in non-integrated mode, the ServerAuthModules
are completely responsible for all authentication and identity management. The specified Callbacks
can be used to establish an identity. The resulting identity will be created on the SecurityDomain
but it will be independent of any identities stored in referenced SecurityRealms
.
The advantage of this mode is that JASPI configurations that are able to completely handle the identities can be deployed to the application server without requiring anything beyond a simple SecurityDomain
definitions. There is no need for this SecurityDomain
to actually contain the identities that will be used at runtime. The disadvantage of this mode is that the ServerAuthModule
is now responsible for all identity handling, potentially making the implementation much more complex.
Table 16.3. Operations of the CallbackHandlers
method in the non-integrated mode.
Operation | Description |
---|---|
|
The |
|
This
If a |
|
As the identity is created in this mode without loading from the |
validateRequest
During the call to validateRequest
on the ServerAuthContext
, the individual ServerAuthModule
instances will be called in the order in which they are defined. A control flag can also be specified for each module. This flag defines how the response should be interpreted and if processing should continue to the next server authentication module or return immediately.
Control Flags
Whether the configuration is provided within the elytron
subsystem or using the JaspiConfigurationBuilder
API, it is possible to associate a control flag with each ServerAuthModule
. If one is not specified, it defaults to REQUIRED
. The flags have the following meanings depending on their result.
Flag | AuthStatus.SEND_SUCCESS | AuthStatus.SEND_FAILURE, AuthStatus.SEND_CONTINUE |
---|---|---|
Required | Validation will continue to the remaining modules. Provided the requirements of the remaining modules are satisfied, the request will be allowed to proceed to authorization. | Validation will continue to the remaining modules; however, regardless of their outcomes, the validation will not be successful and control will return to the client. |
Requisite | Validation will continue to the remaining modules. Provided the requirements of the remaining modules are satisfied, the request will be allowed to proceed to authorization. | The request will return immediately to the client. |
Sufficient |
Validation is deemed successful and complete, provided no previous |
Validation will continue down the list of remaining modules. This status will only affect the decision if there are no |
Optional |
Validation will continue to the remaining modules, provided any |
Validation will continue down the list of remaining modules. This status will only affect the decision if there are no |
For all ServerAuthModule
instances, if they throw an AuthException
, an error will be immediately reported to the client with no further module calls.
secureResponse
During the call to secureResponse
, each ServerAuthModule
is called, but this time in reverse order where a module only undertakes an action in secureResponse
. If the module undertook an action in validateResponse
, it is the responsibility of the module to track this.
The control flag has no effect on secureResponse
processing. Processing ends when one of the following is true:
-
All of the
ServerAuthModule
instances have been called. -
A module returns
AuthStatus.SEND_FAILURE
. -
A module throws an
AuthException
.
SecurityIdentity Creation
Once the authentication process has completed, the org.wildfly.security.auth.server.SecurityIdentity
for the deployment’s SecurityDomain
will have been created as a result of the Callbacks
to the CallbackHandler
. Depending on the Callbacks
, this will either be an identity loaded directly from the SecurityDomain
, or it will be an ad-hoc identity described by the callbacks. This SecurityIdentity
will be associated with the request, in the same way it is done for other authentication mechanisms.