Few days ago, I was asked to write this article by my friend and classmate Ali Almutawakel. Thanks for this request, I got a lot of fun digging into JAAS.
JAAS stands for Java Authentication and Authorization Service, which is a JVM level security solution for Java applications. That means, in practice, it requires some setups with the platform to get it works. In this article, I will use WildFly as an example application server to demonstrate how it works. The source code that will be using in this article can be found on my github. There is a project I created few days ago called “demo“.
About the Demo Project
Regarding to this project, I want to thank my instructors, Aaron Warsylewicz, John O’Loughlin and Nicole Berard. They contributed their time to inspire me even though this project was not covered by my current program. Without them, I can’t start this article or get the project to work. In my opinion, JAAS by itself, is one of the toughest concept to understand. However, in this article, I’ll skip all the lower level details*, and directly jump into the practice.
To run this project, you need to download and import the source code to Eclipse, and run it on a WildFly application server along with a database (scripts for MySQL and Oracle are provided). You can download some tools to test against the RESTful Web Services, or you can just run the JUnit tests.
If you check my database script in the project, you will find 3 tables. They are a User table, a Group table, and a bridging table. This structure is very common and works well with JAAS. Notice that, although I have a persistence layer and all the entities, JAAS will not use them in this particular project with my settings.
There are 3 steps to get JAAS working properly:
- configure the Application Server
- configure the project
- add annotations to your code (or you can do it in a programmatic way)
Configure the Application Server
To configure the security settings on WildFly in order to read credentials from database, you need to setup a data source for your database connection first. You can set all the configurations through the web console, or by changing the configuration file.
Web console solution:
- Login to WildFly web console (localhost:9990)
- Go to Configuration / Subsystem / Security
- Add a security domain. The name of the security domain will be used later in jboss-web.xml
- Open the security domain. Within the Authentication view, click Add to add an authentication module
- Click on Edit to edit the properties of this module (module option key value pairs).
<security-domain name="demo" cache-type="default"> <authentication> <login-module code="Database" flag="required"> <module-option name="dsJndiName" value="java:/DemoDS" /> <module-option name="principalsQuery" value="select password from demo_user where name=?" /> <module-option name="rolesQuery" value="select g.name, 'Roles' from demo_user u, demo_group g, demo_user_group ug where u.name=? and u.id=ug.user_id and g.id=ug.group_id" /> <module-option name="hashAlgorithm" value="SHA-256"/> <module-option name="hashEncoding" value="BASE64"/> <module-option name="ignorePasswordCase" value="true"/> <module-option name="hashStorePassword" value="false"/> <module-option name="hashUserPassword" value="true"/> </login-module> </authentication> </security-domain>
This is the only section that really depends on the which application server you are using. However, most of them shares similar concepts. In addition, you can also create your own authentication mechanism, and setup in the application server.
Configure the Project
This tag allows you to apply authentication process by specifying which web resource you want to constraint with what roles. A more general constraint will be overridden by the more specific constraints. For example: in the web.xml file of my project, the constraint “protected” will be applied to all urls with a pattern of
/rest/*, except the put method for
/rest/user/*, which is using the constraint “public”. In addition, if you don’t specify a role, then everyone can access.
I had a project which the roles and constraints were constantly changing. For example, the accessibility of each level admin changed every few months, new roles were added, old roles were removed. In that case, since we didn’t predict this requirement, the web.xml configurations locked down all the roles and constraints, we lost the flexibility to change them within java code. To fix it (and meet the deadline), we actually made the program to rewrite the web.xml file. Because of that, every time the system applied new roles and constraints, the server had to restart to apply the changes. That was a disaster in my opinion. So, to know what the clients really need (not only what they say), and choose an appropriate approach is always critical to a complex system.
jboss-web.xml is an JBoss/WildFly extension of web.xml file. If you see this file in my project, you’ll find it’s very straight forward, which only contains the name of the security domain.
The Java security annotations are fairly simple. You add them to method level (code example) in different layers. It means, you don’t only take control of the security in your RESTful Web Services, but also the business logic layer or even persistent layer (code example).
There are 3 annotations being used mostly:
javax.annotation.security.RolesAllowed. You can find them in the code examples.