Introduction
The Java EE Security API (JSR-375) goal is to enhance the security features of the Java EE platform and to make sure that no custom configuration of the application server must be updated anymore when you want to use for example hashed passwords stored in a database table.
It was released together with Java EE 8 in September 2017 and one of the main concepts which are defined is the IdentityStore which validates the user credentials (like username and password) and retrieves the groups (the authorization grants) the user has.
The Octopus framework is mainly targeted to authorization features like declarative permissions useable for JSF components (with a custom tag) or annotations (to protect EJB methods for example). There are many authentication integrations available like OAuth2, OpenId Connect, KeyCloak, CAS server and custom integrations for database usage to name a few.
Since v 0.9.7.1, released on 27 December 2017, it is possible to integrate the IdentityStores from JSR-375 within Octopus and most of all, it runs also on Java EE 7.
The demo code can be found in the Octopus demo repository.
Project setup
The JSR-375 integration is defined within a Maven artifact specifically created for this purpose,
<dependency> <groupId>be.c4j.ee.security.octopus.authentication</groupId> <artifactId>security-api</artifactId> <version>${octopus.version}</version> </dependency>
Together with the dependency for JSF on a Java EE 7 server,
<dependency> <groupId>be.c4j.ee.security.octopus</groupId> <artifactId>octopus-javaee7-jsf</artifactId> <version>${octopus.version}</version> </dependency>
they can be found in the Bintray repository
<repository> <id>Bintray_JCenter</id> <url>https://jcenter.bintray.com</url> </repository>
These are the other dependencies which we need
- Java EE 7 (Provided) all the features of the Java EE 7 platform
- PrimeFaces (Compile) The JSF Component library
- Deltaspike (Compile/Runtime) Required dependency of Octopus but set as provided within Octopus so it is easier to specify the version you want to use within your application
- Soteria (Compile) JSR-375 implementation and required since we are using a Java EE 7 server.
- H2 database (Runtime) Our database where we want to store hashed passwords.
Security config
In this example, I want to show you the usage of a JSR-375 defined IdentityStore and a custom one.
The default defined IdentityStore is the Database one which stores the passwords hashed. It can be configured by putting an annotation on a CDI bean.
@DatabaseIdentityStoreDefinition( dataSourceLookup = "java:global/MyDS", callerQuery = "select password from caller where name = ?", groupsQuery = "select group_name from caller_groups where caller_name = ?", hashAlgorithmParameters = { "Pbkdf2PasswordHash.Iterations=3072", "Pbkdf2PasswordHash.Algorithm=PBKDF2WithHmacSHA512", "Pbkdf2PasswordHash.SaltSizeBytes=64" } )
The datasource is defined within the DatabaseSetup class, which ensures the correct tables are created and filled with a few credentials.
This @DatabaseIdentityStoreDefinition is placed in our demo on the CDI bean which defines the second IdentityStore which is consulted when the database store didn’t contain the username we specified.
This custom store is created by implementing the interface javax.security.enterprise.identitystore.IdentityStore and override the validate() method.
Here we check if it is a certain fixed user and if the correct password is supplied. If so, it returns a few groups. Of course, you can write any kind of logic in these custom stores when the default ones don’t fit your needs.
Authorization
JSR-375 and Java EE in general, expect that each user has some groups defined in the external system which are then converted in roles of your application.
Octopus can also work with roles but one should use permissions because they are far more powerful. It has very powerful permission support like named, wildcard and domain permissions.
The groups of the user are interpreted as follows:
– The group is converted to a role with the same name (for the case you want to work with roles within Octopus)
– The group is converted to a named permission.
– The group is converted to a set of permissions by a CDI bean implementing the RolePermissionResolver which needs to be supplied by the developer.
This last option is probably the best and most powerful way to convert a group to a set of permissions and thus getting the maximum out of the features of Octopus.
No full integration
The described solution here is to integrate the IdentityStores of Java EE 8 (JSR-375) into the Octopus framework. It does not use the JASPIC as the underlying mechanism as JSR-375 describes, nor is there any integration with the other security features of Java EE like @RolesAllowed.
Java EE 8
And your application, like the demo, will be ready to convert to Java EE 8 with a minimal amount of effort. The only thing you need to do is take the Java EE 8 dependency (instead of the Java EE 7 one) and remove the Soteria dependency.
There will be no other changes required to make your application run on Java EE 8 and make use of all the features in that latest release.
Conclusion
With the Octopus framework, you have today already the most powerful authorization features available. And by using you are preparing yourself for the future when Java EE also has the authorization features available which are planned within the Java EE Security API.
Have fun.