-
Notifications
You must be signed in to change notification settings - Fork 55
Description
Feature epic details
- For the title of this issue, type: Development epic name
- Link to development epic: Support Jakarta Security 4.0 #25090
- Target GA release: same release as GA of Jakarta EE 11 in Open Liberty
Operating systems
Does the documentation apply to all operating systems?
- Yes
- No; specify operating systems: ______
Main page
Application Security (Jakarta Security) 6.0
Overview of Jakarta Security
This feature enables support for securing the server runtime environment and applications using Jakarta Security 4.0.
If you are updating your application from using the appSecurity-5.0 feature to using the appSecurity-6.0 feature, removal of a single, previously deprecated Jakarta class might require you to update your application code. For more information, see the "Removals, Additions and Updates" notice below.
Overview of the Main Features of Jakarta Security
Jakarta Security 4.0 contains two main new features and API change notices for application developers.
In-memory identity store
The Application Security 6.0 feature supports the new InMemoryIdentityStoreDefinition annotation to configure an in-memory only store of user, password and group information which can be used to validate API credentials during an HTTP authentication work flow in the container.
This is a convenience-only provision to be used for testing, debugging, development, demos, etc, and its use in a production environment is strongly discouraged. Although it is already possible to provide similar functionality using a bespoke identity store handler, this customised functionality cannot be detected by the container and externally disabled, therefore the use of the InMemoryIdentityStore is preferred in these situations.
Note: the in-memory identity store must be explicitly enabled for usage within the server configuration, by default, it is disabled.
Basic API (handler) for Multiple authentication mechanisms
Applications can now specify multiple authentication mechanisms to logically act as a single HttpAuthenticationMechanism to the container. Previously, the container only allowed for a single HttpAuthenticationMechanism per application, and application start-up would be halted if multiple authentication mechanisms were encountered.
Access to the HttpAuthenticationMechanism is now abstracted by the new, Jakarta defined HttpAuthenticationMechanismHandler interface which provides a similar interface. The container provides a default implementation of the HttpAuthenticationMechanismHandler interface, adhering to a simple logical flow which - when encountering multiple authentication mechanisms specified within an application - chooses a single one to be used by the authentication work-flow based on a prioritization algorithm.
The developer can also deploy their own implementation of the HttpAuthenticationMechanismHandler to provide a bespoke prioritization algorithm which overrides the internal one. As the internal prioritization algorithm cannot be configured by external parameters, it is expected that a developer will provide their own implementation if multiple authentication mechanisms are required.
Removals, Additions and Updates
-
jakarta.security.enterprise.identitystore.IdentityStorePermissionwas removed as its usage was only encouraged to optionally validate identity store permission for thegetCallers()API. Its implementation was always in conjunction with theSecurityManagerwhich is not supported and has been removed for Jakarta EE. -
jakarta.security.enterprise.SecurityContexthas a new method added:Set<String> getAllDeclaredCallerRoles() -
HTTP authentication mechanisms now have a qualifier by default (which can be overridden within the application), whereas before they were unqualified.
Main Feature Examples
In-memory identity store
NOTE: The usage of an application defined in memory identity store must be explicitly enabled in the server.xml via the new configuration attribute allowInMemoryIdentityStores as shown below. By default, this attribute is set to false, which explicitly instructs the Liberty authentication work flows to not use in memory identity stores, even if a custom identity store handler has been defined.
<server description = "Liberty server">
. . .
<featureManager>
<feature>appSecurity-6.0</feature>
</featureManager>
<webAppSecurity allowInMemoryIdentityStores="true"/>
. . .
Once enabled, a single in-memory identity store can be configured through the new application level annotation @InMemoryIdentityStoreDefinition, an example of which is shown below:
@InMemoryIdentityStoreDefinition(
priority = 10,
useFor = {VALIDATE, PROVIDE_GROUPS},
value = {
@Credentials(callerName = "jasmine", password = "secret1", groups = { "caller", "user" } ),
@Credentials(callerName = "bill", password = "{xor}LDo8LTorbg==", groups = { "foo", "bar" }),
@Credentials(callerName = "frank", groups = { "user" },
password = "{hash}ARAAAAAUUEJLREYyV _<sequence shortened>_ x2w=="),
@Credentials(callerName = "sally", groups = { "user" },
password = "{aes}ARAFCrWIYJCL7ZBNjN+ _<sequence shortened>_ EFA==")
}
)
The password specification has the same support for encryption and encoding as does the basic user registry: hash, aes and xor (along with plain text passwords which are supported but not encouraged to use).
The annotation also supports attributes priority, priorityExpression, useFor and useForExpression - an explanation can be found within the Jakarta EE specification - 3.2.3. Declaring Capabilities.
It should be noted that if this annotation is found within an application, then upon application start up, a clear warning about its use in a production environment is output in the main log files.
Basic API (handler) for Multiple authentication mechanisms
It is now possible be able to specify multiple HTTP authentication mechanisms of different types and have an internal Liberty handler choose a mechanism for the authentication process given documented, consistent rules.
Specification via existing mechanisms - different HTTP authentication mechanism types
Multiple mechanisms can be specified within the same application code using the existing mechanism definition annotations.
For example, shown below are three annotation defined mechanisms contained within the same code block, all of a different type:
. . .
@BasicAuthenticationMechanismDefinition(realmName = "basicAuth")
@OpenIdAuthenticationMechanismDefinition(
providerURI = "https://samples.auth0.com/authorize",
clientId="_<removed>_",
redirectURI= "https://openidconnect.net/callback",
scope="openid profile email phone address",
responseType="code")
@FormAuthenticationMechanismDefinition(
loginToContinue = @LoginToContinue(errorPage = "/login-error.html",
loginPage = "/login.html"))
public class MyClass extends Application {
}
Prior to appSecurity-6.0, the above specification would have caused the container to fail the application's start-up with a clear error in the console and log files.
Specification via existing in-built mechanisms - the same HTTP authentication mechanism types
Http authentication mechanisms (both annotation defined and custom defined) can also have an optional class name qualifier if an application needs to define the same authentication mechanism type multiple times. For example, if you wanted to define three Basic Http Authentication Mechanisms (using in-built annotations), you would first define qualifiers in separate files such as:
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Admin {
}
and
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface User {
}
Then, use the qualifier in your specifications, such as:
// no explicit qualifier, so "BasicAuthenticationMechanism" (the specification default) is assigned
@BasicAuthenticationMechanismDefinition(realmName="my-realm")
// explicit qualifiers Admin and User
@BasicAuthenticationMechanismDefinition(realmName="admin-realm", qualifiers={Admin.class})
@BasicAuthenticationMechanismDefinition(realmName="user-realm", qualifiers={User.class})
In the above, three unique Basic Http Authentication Mechanisms would be available for injection (shown below) based on unique qualifier names, with a default one - BasicAuthenticationMechanism given to any specification without an explicit one.
Below is a table showing the four Http authentication mechanisms and their default qualifiers (if not explicitly defined):
| HttpAuthenticationMechanism definition | Default Qualifier |
|---|---|
| BasicAuthenticationMechanismDefinition | BasicAuthenticationMechanism |
| FormAuthenticationMechanismDefinition | FormAuthenticationMechanism |
| CustomFormAuthenticationMechanismDefinition | CustomFormAuthenticationMechanism |
| OpenIdAuthenticationMechanismDefinition | OpenIdAuthenticationMechanismDefinition |
IMPORTANT: If qualifiers are use, then a custom Http authentication mechanism handler must be defined, else an error is thrown. Custom handlers are discussed below.
Specification via custom Httpauthentication mechanisms
An application an also specify multiple Http authentication mechanisms using customized classes as shown below:
CustomHAMOne.java:
@ApplicationScoped
@Priority(100)
public class CustomHAMOne implements HttpAuthenticationMechanism {
@Override
public AuthenticationStatus validateRequest(
// custom logic
}
}
CustomHAMTwo.java:
@ApplicationScoped
@Priority(200)
public class CustomHAMTwo implements HttpAuthenticationMechanism {
@Override
public AuthenticationStatus validateRequest(
// custom logic
}
}
Note: If @Priority is not specified, a default value is assigned which is higher than all of the annotation defined authentication mechanisms (i.e. @Form, @Basic, etc ...) but not unique, so if more than one custom authentication mechanism is specified, then @Priority must be set to avoid an application start up error due to the inability to determine a single, prioritised authentication mechanism.
And customised classes can also be annotated with qualifiers to be used during injection as shown below (Note: this is core CDI functionality and not new for Jakarta Security 4.0):
CustomHAMThree.java:
@ApplicationScoped
@Priority(300)
@User
public class CustomHAMThree implements HttpAuthenticationMechanism {
@Override
public AuthenticationStatus validateRequest(
// custom logic
}
}
Specification via existing and custom mechanisms
It is possible to mix both existing mechanism definitions specified by annotations and also custom mechanisms, there are no restrictions in this respect.
For example, the main application may contain:
. . .
@BasicAuthenticationMechanismDefinition(realmName = "my-realm")
@BasicAuthenticationMechanismDefinition(realmName = "admin-realm", qualifiers={Admin.class})
. . .
and another application class can exist which implements the HttpAuthenticationMechanism interface:
. . .
@User
@ApplicationScoped
public class CustomHttpAuthenticationMechanism implements HttpAuthenticationMechanism {
. . .
}
In the above, the CustomHttpAuthenticationMechanism also adds the optional @User qualifier which can be used for injection into the custom Http authentication mechanism handler, discussed below.
Note: as mentioned previously, if any in-built Http authentication mechanism explicitly specifies a qualifier, then a custom Http authentication mechanism handler must be defined.
Managing the authentication mechanisms
The HttpAuthenticationMechanismHandler interface is new to Jakarta 4.0 and defines a mechanism for invoking methods on HttpAuthenticationMechanism implementations, thus abstracting the authentication mechanism from the authentication module, providing a bridge between.
The main purpose of implementations of the HttpAuthenticationMechanismHandler interface is to select a single authentication mechanism (should multiple ones be found) to be used within the authentication work flow based on a documented prioritization algorithm.
The internal implementation
The container contains an implementation of the HttpAuthenticationMechanismHandler interface which implements the following algorithm:
- Resolve multiple Http authentication mechanisms ("HAM") – remembering the one resulting HAM – with a documented algorithm prioritizing:
1/ Developer provided (using@Priorityannotation values if multiple developer HAMs found) and then
2/ HAM types in the order: OpenId, Custom Form, Form, Basic. - throw an
AmbiguousResolutionExceptionat application start-up if a single mechanism cannot be selected:- For example, if only two Developer provided HAMs are found, both with equal
@Priorityvalues.
- For example, if only two Developer provided HAMs are found, both with equal
- Implement specification defined interfaces.
- Log HAM resolution details to assist debugging.
Custom implementations
A custom implementation of the HttpAuthenticationMechanismHandler interface can also be specified to implement a custom multiple-authentication-mechanism prioritization algorithm. This custom algorithm may aggregate the results of multiple authentication mechanism implementations, order multiple mechanisms with any priority, or implement some other arbitrary selection criteria.
Any custom implementations take priority over the internal implementation, so it is expected that custom implementations will be frequently used as the internal implementation does not allow for configuration.
It should be re-iterated that if you specify qualified Http authentication mechanisms in your application, then your application must also contain a custom Http authentication mechanism handler, otherwise an application start-up error will occur.
Shown below is an example of a custom implementation which injects Http authentication mechanisms which have been differentiated with qualifiers:
. . .
@Default
@ApplicationScoped
public class CustomHttpAuthenticationMechanismHandler implements HttpAuthenticationMechanismHandler {
@Inject @Admin
private HttpAuthenticationMechanism adminHAM;
@Inject @User
private HttpAuthenticationMechanism userHAM;
@Inject @BasicAuthenticationMechanism // the default qualifier if not specified in the main application
private HttpAuthenticationMechanism defaultHAM;
@Override
AuthenticationStatus validateRequest(HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) throws AuthenticationExceString
path = request.getRequestURI();
// route to appropriate mechanism based on path
if (path.startsWith("/admin")) {
return adminHAM.validateRequest(request, response, context);
} else if (path.startsWith("/user")) {
return userHAM.validateRequest(request, response, context);
}
// Default behavior
return defaultHAM.validateRequest(request, response, context);
}
@Override
AuthenticationStatus secureResponse(HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) throws AuthenticationException {
// custom implementation
// note, the interface has a custom definition, so this method does not have to be overridden if not required to be
}
@Override
void cleanSubject(HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) {
// custom implementation
// note, the interface has a custom definition, so this method does not have to be overridden if not required to be
}
Note that although the HttpAuthenticationMechanismHandler abstracts HttpAuthenticationMechanism implementations by providing the very same methods, it is otherwise not related in type (i.e. it does not inherit from HttpAuthenticationMechanism).
It should also be noted that qualified beans within the CDI is not a Jakarta Security implementation, but a CDI one - and the functionality for qualified bean injection, along with errors from ambiguous or missing beans at injection time, is part of core Jakarta and Liberty functionality. For example, if you specified in your main application, a single, qualified Basic http authentication mechanism as shown below:
// explicit qualifiers Admin
@BasicAuthenticationMechanismDefinition(realmName="admin-realm", qualifiers={Admin.class})
but tried to inject @user CDI bean into your custom Http authentication mechanism handler such as:
@Inject @User
private HttpAuthenticationMechanism userHAM;
the CDI would produce an error at start-up indicating that there are no matching CDI beans, and the application will fail to start.
Qualifiers for Http authentication mechanism definitions are actually a list, so the following is valid:
// explicit qualifiers Admin and User
@BasicAuthenticationMechanismDefinition(realmName="admin-realm", qualifiers={Admin.class, User.class})
And CDI injection would set two unique variables both to the same Http authentication mechanism.
@Inject @User
private HttpAuthenticationMechanism userHAM;
@Inject @Admin
private HttpAuthenticationMechanism adminHAM;
// userHAM and adminHAM are equal to the same Http authentication mechanism CDI bean
Logging
Explicit new entries to the log files in relation to multiple authentication mechanisms are:
- Log in order the name and prioritization of all authentication mechanisms found during the authentication flow (just once) to aid debugging of which mechanism was used and why. For example:
Order of HttpAuthenticationMechanisms found (the first one will be used if its prioritization is unique - @Priority for application HAMs and HAM type - Oidc/CustomForm/Form/Basic - for in-built HAMs): CustomHAMThree Priority = 300, CustomHAMTwo Priority = 200, CustomHAMOne Priority = 100, OidcHttpAuthenticationMechanism, FormAuthenticationMechanism, BasicHttpAuthenticationMechanism
- Log the name of the authentication mechanism handler to explicitly show if a custom handler was used. For example:
HttpAuthenticationMechanismHandler is [CustomAuthenticationMechanismHandler]
Error handling
Explicit new errors to the log files include:
- Unable to find a unique authentication mechanism:
CWWKS2605E: Unable to determine which HttpAuthenticationMechanism to handle request. The following HttpAuthenticationMechanisms have the same priority or Http Authentication Mechanism Type: CustomHAMOne Priority = 100, CustomHAMTwo Priority = 100.
- Missing custom Http authentication mechanism handler if qualified authentication mechanism definitions are found:
- CWWKS2610E: Missing a custom handler that uses qualified HttpAuthenticationMechanisms.
Removals, Additions and Updates
The following removals, additions and updates should be noted by the application developer:
- Classes using
jakarta.security.enterprise.identitystore.IdentityStorePermissionhave been updated to have this removed.- Its implementation has always been in conjunction with the SecurityManager which is not supported and has been removed for Jakarta EE11.
jakarta.security.enterprise.SecurityContexthas a new method added:Set<String> getAllDeclaredCallerRoles().- This is not used within the Liberty container.
- All
HttpAuthenticationMechanisminterfaces have a newqualifiersmember with default values, therefore not requiring an explicit application update. For example,BasicAuthenticationMechanismDefinitionis now defined as follows:
public @interface BasicAuthenticationMechanismDefinition {
String realmName() default "";
// this is new
Class<?>[] qualifiers() default { BasicAuthenticationMechanism.class };
}
Note: "Basic" in the qualfiers() value above would be replaced by "Form", "CustomForm" and "OpenId" for the three other interface definitions.
- Because it is allowed to use multiple *AuthenticationMechanismDefinition annotations of the same type (e.g. two instances of
BasicAuthenticationMechanismDefinition), they should differ in their qualifiers. If they do not, as shown below:
// explicit qualifier
@BasicAuthenticationMechanismDefinition(realmName="my-realm", qualifiers={Admin.class})
@BasicAuthenticationMechanismDefinition(realmName="admin-realm", qualifiers={Admin.class})
and you tried to inject @Admin CDI bean into your custom Http authentication mechanism handler such as:
@Inject @Admin
private HttpAuthenticationMechanism adminHAM;
the CDI would produce an error at start-up indicating that there are multiple matching CDI beans with the same type and qualifier(s).
Note to documentation team:
Configuration
No configuration updates
Updates to existing topics
No update to existing topics
Create a new topic
To create a topic, specify a first draft of the topic that you want added and the section in the navigation where the topic should go. - Apologies, not sure what this means?