-
Notifications
You must be signed in to change notification settings - Fork 626
Description
The information you provide here will be included in the Open Liberty beta blog post (example), which will be published on openliberty.io/blog/, and potentially elsewhere, to promote this beta feature/function of Open Liberty. For this post to be included in the beta issue please make sure that this is completed by the end of Friday following the GM (Tuesday). The beta and release blogs are created using automation and rely on you following the template's structure. DO NOT REMOVE/ALTER THE <GHA> TAGS THROUGHOUT THIS TEMPLATE.
This blog post details the feature in the epic Support Jakarta Security 4.0.
<GHA-BLOG-SUMMARY>
Please provide a summary of the update, including the following points:
-
A sentence or two that introduces the update to someone new to the general technology/concept.
-
An In-memory Identity Store is a developer defined store of credential information used during the Open Liberty authentication and authorization work flow. It provides a quick, simple and convenient authentication mechanism for the purpose of Liberty application testing, debugging, demos, etc.
-
Multiple Http Authentication Mechanisms (HAMs) can now be defined within the same application whether specified via built-in Jakarta annotations - such as
@FormAuthenticationMechanismDefinition- or by custom implementations of theHttpAuthentiationMechanisminterface. If multiple HAMs are present, a single HAM is chosen for use during the authentication workflow by an internal HAM handler (NEW!), or a custom implementation (!NEW) which takes priority. Multiple HAMs can optionally be qualified for ease of selection in a custom HAM handler. -
A new method has been added to the interface
SecurityContextcalledgetAllDeclaredCallerRoles()which returns a list of all static (declared) application roles that the authenticated caller is in. -
References to the
IdentityStorePermissionclass has been removed as it was previously deprecated.
-
-
The Human-readable name and short feature name for your feature- eg WebSockets feature (websockets-1.0).
All features are available as part of appSecurity-6.0.
- Who is the target persona? Who do you expect to use the update? eg application developer, operations.
All feature use cases are targeted towards Jakarta EE web application developers who want to move to a modern Jakarta version and use implementations of the Jakarta Security 4.0 specification.
- What was the problem before and how does your update make their life better? (Why should they care?)
in-memory identity store
Prior to the new identity store specification, only two identity stores - database and LDAP - were natively supported for credential validation by the Jakarta, and both were considered heavy-weight for testing, debugging and demo purposes. A developer could also write a custom identity store, but this requires bespoke coding to gather, validate and store credential information, reducing developer focus from core activities. A built-in in-memory identity store alleviates this burden for the non-production deployment use cases.
Shown below is an example of an application with a single authentication mechanism, and three identity stores (including the new in-memory identity store) all controlled by the existing IdentityStoreHandler internal implementation. The internal implementation will cycle through all three identity stores to validate results. The identity store handler can be overridden by a user defined implementation also (existing functionality).
multiple hams
It is now possible for multiple authentication mechanisms to logically act as a single Http Authentication Mechanism (HAM) to the container, allowing for a more flexible, dynamic and configurable approach towards the authentication work flow. Access to the HttpAuthenticationMechanism is now abstracted by an internal implementation of the new Jakarta HttpAuthenticationMechanismHandler interface which prioritises the use of custom defined HAMs and then by the in-built (annotation defined) HAMs, the order being: openId, custom form, form and basic authentication mechanisms. Developers are free to provide their own implementation of the HttpAuthenticationMechanismHandler which can implement a customised prioritisation of HAMs, and must do so if in-built HAMs are defined with the optional qualifiers attribute set.
Shown below is an example of an application with three HAMs (abbreviated as Basic, Form and Custom) with the internal implementation of the Jakarta HttpAuthenticationMechanismHandler interface selecting Custom as it takes priority over built-in HAMs such as Basic and Form (of course, a custom implementation of the HttpAuthenticationMechanismHandler interface could have selected any HAM based on a bespoke selection algorithm). Note the HAM hand-off to the identity store handler is still in place.
- Briefly explain how to make your update work. Include screenshots, diagrams, and/or code snippets, and provide a
server.xmlsnippet.
getAllDeclaredCallerRoles()
The SecurityContext interface implementation has been updated to include a new method: getAllDeclaredCallerRoles(), which returns a list declared application roles for an authentiated caller. An empty list is returned if the caller is not authenticated or does not have any declared roles.
How to use
Enable Jakarta Security 4.0 features within server.xml by adding the appSecurity-6.0 feature as shown below:
<server description = "Liberty server">
. . .
<featureManager>
<feature>appSecurity-6.0</feature>
</featureManager>
<webAppSecurity allowInMemoryIdentityStores="true"/>
. . .
NOTE: As shown above, the usage of an application (in code) defined in-memory identity store must be explicitly enabled in the server.xml. By default, allowInMemoryIdentityStores 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. For multiple HAMs, the allowInMemoryIdentityStore is not required.
in-memory identity store
The [Jakarta Security Specification 4.0(https://jakarta.ee/specifications/security/4.0/jakarta-security-spec-4.0#in-memory-annotation) provides details for specifying credential information to be used during the authentication workflow via a new @InMemoryIdentityStoreDefinition annotation as shown below:
. . .
@InMemoryIdentityStoreDefinition (
priority = 10,
priorityExpression = "${80/20}",
useFor = {VALIDATE, PROVIDE_GROUPS},
useForExpression = "#{'VALIDATE'}",
value = {
@Credentials(callerName = "jasmine", password = "secret1", groups = { "caller", "user" } )
}
)
In the above, all attributes for the @InMemoryIdentityStoreDefinition are shown, with priority, priorityExpression, useFor and useForExpression being optional and having sensible defaults.
@Credentials maps 1-N caller names to a password and optional group values. callerName and password are mandatory, and if they are missing, a complication error occurs.
Shown above is a single caller and credential information using a plain text password, but it is highly recommended that passwords are given using an Open Liberty supported encoding mechanism as shown below:
@InMemoryIdentityStoreDefinition (
value = {
@Credentials(callerName = "jasmine", password = "{xor}LDo8LTorbg==", groups = { "caller", "user" } ),
@Credentials(callerName = "frank", groups = { "user" }, password = "{hash}ARAAA <sequence shortened> Fyyw=="),
@Credentials(callerName = "sally", groups = { "user" }, password = "{aes}ARAFIYJ <sequence shortened> WRQNA==")
}
)
Encrypted and encoded passwords can be created using the Open Liberty application securityUtility found under wlp/bin/securityUtility. Encoding a text string using xor is shown below:
wlp/bin/securityUtility encode --encoding=xor
Enter text: <enter text to encode>
Re-enter text:
{xor}PTA9Lyg
multiple hams
application specification
The Jakarta Security Specification 4.0 allows multiple HAMs to be be implemented within a single application by specifying their details as shown below:
@BasicAuthenticationMechanismDefinition(realmName="basicAuth")
@FormAuthenticationMechanismDefinition(
loginToContinue = @LoginToContinue(errorPage = "/form-login-error.html",
loginPage = "/form-login.html"))
@CustomFormAuthenticationMechanismDefinition(
loginToContinue = @LoginToContinue(errorPage = "/custom-login-error.html",
loginPage = "/custom-login.html"))
which allows for three HAMs to be defined for the application.
Custom HAMs can also be defined within the same application by having one or more classes which implement the HttpAuthenticationMechanism interface as shown below:
@ApplicationScoped
// @Priority is optional and used to control selection priority if multiple custom definitions exist
@Priority(100)
public class CustomHAM implements HttpAuthenticationMechanism {
@Override
public AuthenticationStatus validateRequest(
HttpServletRequest request,
HttpServletResponse response,
HttpMessageContext httpMessageContext) throws AuthenticationException {
// implement custom logic here, and return an AuthenticationStatus
return AuthenticationStatus.NOT_DONE;
}
}
So a single application can have a mix of both annotation defined HAMs and custom ones, meaning that given the above two snippets of code, a total of four HAMs will be defined (three by annotation and one custom one).
IMPORTANT: @Priority should be used to raise or lower the priority of one custom HAM over another. If not specified, then a default priority is assigned. If more than one custom HAM is defined, their priorities should be explicitly set to unique values, else if they are set to the same value or not set at all (and inherit the same default value), an error occurs.
ham resolution
An internal implementation of the Jakarta Security 4.0 (NEW!) interface HttpAuthenticationMechanismHandler ("internal HAM handler") exists which - when presented with multiple HAMs within a single application - will select the a single HAM to be used in the authentication flow.
The order of HAMs used (if found) are:
- Custom (developer) HAMs (further resolved by
@Priorityif multiple ones are found) OpenIdAuthenticationMechanismDefinitionCustomFormAuthenticationMechanismDefinitionFormAuthenticationMechanismDefinitionBasicAuthenticationMechanismDefinition
Therefore given the previous snippets of code, the Custom HAM will always be used in the authentication work flow if all four HAMs were defined.
IMPORTANT: A developer should also provide a custom implementation of the HttpAuthenticationMechanismHandler interface ("custom HAM handler") if the internal HAM handler does not satisify their requirements - this will take priority over the internal implementation, allowing for any customised algorithm to select a single HAM from multiple choices. Information about the custom HAM handler is shown further below.
qualifiers
HAMs (both annotation defined and custom defined) can also have an optional class name qualifier to ease HAM injection into a custom HAM handler. For example, if you wanted to define qualified HAMs, you would first define qualifier interfaces such as:
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Admin {
}
(Not shown is the qualifier definitions for User , Fallback which follow an identical pattern, and are used below).
Then, import and use the qualifiers in your in-built or custom HAM specifications, such as:
@CustomFormAuthenticationMechanismDefinition(<existing details not shown>, qualifiers={Admin.class})
@BasicAuthenticationMechanismDefinition(<existing details not shown>, qualifiers={User.class})
and
@ApplicationScoped
@Fallback // add custom qualifier to be used during injection
public class CustomHAM implements HttpAuthenticationMechanism {
@Override
public AuthenticationStatus validateRequest (. . .) {
. . .
}
}
The three HAMs defined above would be available for injection within a custom HAM handler based on their qualifier names - this is the anticipated use case for multiple HAMs.
IMPORTANT: If qualifiers have been specified in the in-built HAM definitions, then a custom HAM handler must be specified, else an error is thrown - this is a Jakarta specification requirement. Custom HAM Handlers are discussed directly below.
To implement a custom HAM Handler, a public, @ApplicationScoped class which implements the HttpAuthenticationMechanismHandler interface (!NEW) can must be defined, and qualified HAMs injected using standard CDI syntax, as shown below:
@Default
@ApplicationScoped
public class CustomHAMHandler implements HttpAuthenticationMechanismHandler {
@Inject @Admin // this will be the FormHAM
private HttpAuthenticationMechanism adminHAM;
@Inject @User // this will be the BasicHAM
private HttpAuthenticationMechanism userHAM;
@Inject @Fallback // this will be the Custom HAM
private HttpAuthenticationMechanism fallbackHAM;
public AuthenticationStatus validateRequest(HttpServletRequest request,
HttpServletResponse response,
HttpMessageContext context) throws AuthenticationException {
String path = request.getRequestURI();
// route to appropriate mechanism based on path, default to my-realm
if (path.startsWith("/admin")) { // FormHAM
return adminHAM.validateRequest(request, response, context);
} else if (path.startsWith("/user")) { // BasicHAM
return userHAM.validateRequest(request, response, context);
} else { // Custom HAM
return fallbackHAM.validateRequest(request, response, context);
}
}
This custom HAM handler will take priority over the internal HAM handler allowing a different prioritisation algorithm to be implemented.
getAllDeclaredCallerRoles()
To use the new SecurityContext method, simply inject the SecurityContext implemenation into your application and call the method directly, as shown below:
@Inject
private SecurityContext securityContext;
. . .
Set<String> allDeclaredCallerRoles = securityContext.getAllDeclaredCallerRoles();
System.out.println("All declared caller roles for caller ["
+ securityContext.getCallerPrincipal().getName()
+ "] are "
+ allDeclaredCallerRoles.toString());
- Where can they find out more about this specific update (eg Open Liberty docs, Javadoc) and/or the wider technology?
Further information can be found in the Jakarta Security Specification 4.0
Information about the securityUtility can be found in the WAS Liberty topic base.
</GHA-BLOG-SUMMARY>
What happens next?
- Add the label to the blog issue for the beta you're targeting (e.g.
target:YY00X-beta). - Make sure this blog post is linked back to the Epic for this feature/function.
- Your paragraph will be included in the beta blog post. It might be edited for style and consistency.
- You will be asked to review a draft before publication.
- Once you've approved the code review, close this issue.
- If you would also like to write a standalone blog post about your update (highly recommended), raise an issue on the Open Liberty blogs repo. State in the issue that the blog post relates to a specific release so that we can ensure it is published on an appropriate date (it won't be the same day as the beta blog post).