Introduction
Since the release of Java EE Security API (JSR-375) specification, there is an easy, uniform API to define authentication and to some extend authorization.
With this specification inplace, there will be no need anymore to change Application server specific configuration files within any Java EE 8 compliant server.
Another good thing is that Soteria, the RI of this JSR-375 specification can also be used on most of the Java EE 7 servers.
The downside is that only the ‘classic’ mechanisms using Basic, Digest and Form authentication using LDAP or Database based validation is standardized.
The reasons for this were time (specification was under time pressure since it needed to be included in Java EE 8) and usage of external libraries (and license issues)
The usage of tokens is not standardized but can be created since the API is already available within the specification.
JWT based extension
The above observations lead me to create such an extension which is able to retrieve a JWT from the header within a JAX-RS call and authenticate/authorize the ‘remote user’ using the JSR-375 defined APIs.
If you want to skip the (longer) explanation in this blog entry, you can go straight to the GitHub repository with the compact instructions to get started.
When you are not familiar with JSON Web Tokens (JWT), have a look at the site jwt.io which explains it to you very nicely.
Since the JWT specification only defines the ‘structure’, as a developer, you are free to specify the content of the JWT Payload.
This variability leads to the following implemented flow:
– Extension is responsible for retrieving the token defined with the authorization header (through a custom HttpAuthenticationMechanism)
– Control is handed over to a JWTTokenHandler which needs to be implemented by the developer to verify if the JWT is valid (signature, timings, … check) and extract authentication and authorization information.
– This information is communicated to the low-level layers of the security API so that ‘request’ is now considered as authenticated and that roles can be verified.
JWT payload structure
The JWT token is expected as part of the authorization header with the bearer marker as in the following example:
Authorization:Bearer eyJraWQiOiI3NGYyNDYxOS1kNzIwLTQ1YWQtOTk2Yy0zNWNkNzNiNDdmZmQiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9.eyJzdWIiOiJTb3RlcmlhIFJJIiwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbInVzZXIiLCJtYW5hZ2VyIl19LCJleHAiOjE1MTAzNDgxMTMsImlhdCI6MTUxMDM0ODA4M30.Bk37fPLgymuLZfLq_hdxt94PDRwNAkPkoajegaLLMrsuCCeKEb5DRXcpT9kUyrwEzSFamg_19Y7IT-0utDw4yd_rEzq7lIG8UFc8qnoYi9692Es_sqzwu64x0dM1ODOAHYEPFhIXPo2-nxquYyayMJI5PN4WlTPrRgoFCkY6saxJGzAGlfQIqH3ozaMvEJn1GK3uj1_zglv2HHK1t8lliazRkmRI-p1k9A_HCnnpChb9czpUP_wXRN4HxbADldS5sM7lgsFeLZDB4oewAh9sTXiseH7HnbPfmQKF18vb9Vejc9XzIGf0CrSOf6yVTyYDChYhI1eB5z6Wv33ofFgbPg
If you decode the payload from the above example (yes payload is unprotected but safe due to the signature) you have the following information:
{"sub":"Soteria RI", "realm_access":{"roles":["user","manager"]}, "exp":1510348113, "iat":1510348083 }
The sub claim defines the authentication information (who is it), the realm_access defines the groups/roles the ‘user’ has (what is he allowed) and exp and iat can be used to have a token which expires and thus replay attacks are excluded.
As I already mentioned, the payload structure is not defined by JWT, nor by Java EE Security API (as tokens are not tackled yet).
But another organization, Eclipse MicroProfile, also created their specification around authentication within micro-services. Have a look at this post which goes deeper into the subject.
So why not using their recommended claims as it will become probably the (defacto) standard.
The example in the GitHub repository implements such an MP JWT payload (also using RSA keys as mentioned within the specification).
Setup
Have a look at the readme for all the details on how you can use the extension.
In short, this is all that you need to do
Add the dependency
You need to add the Maven dependency to include the code for the JWT extension for jsr375
<dependency> <groupId>be.atbash.ee.security.jsr375</groupId> <artifactId>soteria-jwt</artifactId> <version>0.9</version> </dependency>
Implement the be.atbash.ee.security.soteria.jwt.JWTTokenHandler.
It is responsible for loading the RSA keys and verifying if the JWT is valid (Signing and time restriction for example)
The implementation is also responsible for retrieving the user name and the groups from the JWT payload and supply them to the system. They are used to construct the required principal and role info.
Conclusion
Usage of tokens, like JWT and OAuth2 tokens, is not included in the Java EE Security API specification for the moment. But the interfaces are already in place to extend to the system in any way you like. Those are used to create these extensions so that you can start using them already today, On Java EE 8 and Java EE 7!
Have fun.