-
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 InMemoryIdentityStoreDefinition annotation to configure an in-memory only store of user, password and group information, 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. It is already possible to provide custom, similar functionality, but this functionality cannot be detected by the container as generally unwanted, therefore the use of the InMemoryIdentityStore is preferred in these situations.
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 the application - chooses a single one to be used by the authentication work-flow based on a documented prioritization algorithm.
The developer can also deploy their own implementation of the HttpAuthenticationMechanismHandler to provide a custom prioritization algorithm which overrides the internal one. As the internal prioritization algorithm cannot be influenced by external configuration or parameters, it is expected that a developer will generally 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, whereas before they were unqualified.
Main Feature Examples
In-memory identity store
The in-memory identity store is 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 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 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 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 @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 qualifier names.
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.
Specifying via custom mechanisms
Multiple mechanisms can also be specified within the same application code using custom implementations of the Jakarta HttpAuthenticationMechanism interface.
For example, shown below is a skeleton implementation of this interface, with the developer able to write their own method logic:
. . .
@ApplicationScoped
public class CustomHttpAuthenticationMechanism implements HttpAuthenticationMechanism {
@Override
AuthenticationStatus validateRequest(HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) throws AuthenticationException {
// custom implementation
}
@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
}
}
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 = "basicAuth")
@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.
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.
To set the @Priority value within custom authentication mechanisms within the same application, the following can be used:
. . .
@ApplicationScoped
@Priority(100)
public class CustomOneHttpAuthenticationMechanism implements HttpAuthenticationMechanism {
. . .
}
and
. . .
@ApplicationScoped
@Priority(200)
public class CustomTwoHttpAuthenticationMechanism implements HttpAuthenticationMechanism {
. . .
}
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.
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
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, only two Basic http authentication mechanisms, both qualified, as shown below:
// explicit qualifiers Admin and User
@BasicAuthenticationMechanismDefinition(realmName="admin-realm", qualifiers={Admin.class})
@BasicAuthenticationMechanismDefinition(realmName="user-realm", qualifiers={User.class})
but tried to inject an unqualified http authentication mechanism in your custom Http authentication mechanism handler such as:
@Inject
private HttpAuthenticationMechanism defaultHAM;
the CDI would produce an error at start-up indicating that there are no matching CDI beans, and the application will fail to start.
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:
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.
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?
HAMs (both annotation defined and custom defined) can also have an optional class name qualifier if an application needs to define the same HAM multiple times. For example, if you wanted to define four Basic HAMs, you would first define qualifiers in separate files such as:
@qualifier
@retention(RUNTIME)
@target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Admin {
}
(Not shown is the above for User and Operator as used below).
Then, use the qualifier in your HAM specifications, such as:
// no explicit qualifier, so @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})
and
@operator // qualifier
@ApplicationScoped
@priority(100)
public class CustomHAMOne implements HttpAuthenticationMechanism {
// implementation
}
In the above, four unique Basic HAMs would be available for injection (shown below) based on qualifier names.
IMPORTANT: If qualifiers, then a custom HAM handler must be specified, else an error is thrown. Custom HAM Handlers are discussed below.