Sunday, June 15, 2014

JAAS Revisited (Using Database and Tomcat)

I have wrote a blog post about JAAS application using database on this post. Now we will expand it by writing those knowledge for a web application. First of all we will see our database structure. Since we will use the same database structure as previous post, there is no need to repeat it here. Also, we will use the same data but the application name and login module in table APP_CONFIGURATION. Below is the script to insert data to table APP_CONFIGURATION.


As we can see, instead of using DBLoginModule as previous post, we have a new login module class, TomcatLoginModule. Below is the code of our TomcatLoginModule.


As shown above, TomcatLoginModule extends DBLoginModule and overrides its commit() and logout() methods. This is done since we will introduce a new principal, RolePrincipal. We will visit the RolePrincipal class later and explain why we need this. In the code above, we add "admin" RolePrincipal to a user that has SysAdminPrincipal principal or "user" RolePrincipal to a user that has UserPrincipal principal. In the logout() method, we simply remove the RolePrincipal that was assigned.

Next we will visit the web.xml file. In this file, we define a servlet named StartupServlet to initialize JAAS configuration and policy as shown below:


Since its load-on-startup value is positive, which is set to zero, it is loaded by servlet container when the application is deployed. The servlet container executes servlet's init() method when it is deployed just once for the servlet lifetime; and since there is only one instance for each servlet on the container, it is save to put JAAS configuration initialization in the init() method. Below is our code to configure JAAS on StartupServlet.


In the code above, we set JAAS configuration, populate permissions, set JAAS policy, and set the security manager. We already see the JAAS configuration and policy in previous post so we won't repeat them again here. Next we will see how to populate permissions.


In the code above we have a static variable permissionMap which is used to save mapping of principal class and its permissions. It is populated from table PERMISSION and PRINCIPAL_PERMISSION. The static permissionMap is then used to get permissions based on principal class name in DBPolicy as shown below.



Let's go back to the web.xml to see how security is implemented to protect pages. In this simple web application we have two roles, admin role and user role. Each role has access to its own pages. Below is the folder structure where those pages are placed in Eclipse project.


All admin pages are put inside admins folder while all ordinary user pages are put inside customers folder. Other JSP files are self-descriptive. Below is the web.xml file that contains security configuration.


First, we have login configuration. We configure it to use html form based configuration and JAAS realm which we will configure later on Tomcat. We also set the login and login error page.


Next we set up the security constraint and security role. We have two roles, admin role and user role. All pages under admins folder can only be accessed by admin role while all pages under customers folder can only be accessed by user role.


We also set the welcome page to be index.jsp for web context, admins, and customers. If a user accesses a page that is not intended for him/her, for example if a user that has user role tries to access admin page, security error code 403 access denied is thrown by security manager. We will forward the user to the access-denied.jsp.



As we can see from the flow above, index.jsp is our entry point and from there we can go to admin page, user page, or logout page. If a user clicks the link to go to admin page, the security manager will check if he/she has already logged in. If yes, it will check if he/she has admin role. If he/she doesn't have admin role, he/she will be redirected to access-denied.jsp. If he/she has not logged in, he/she will be redirected to login.jsp. If the login process fails, he/she will be redirected to login-error.jsp. If he/she has logged in as admin, he/she will be redirected to admin page. The same logic applies to user role as well. Below are the jsp files involved in these scenario.








The login.jsp is the user interface we need to gather credentials. We have a form with action value j_security_check. We also have two textfields to input username and password. The textfields must be named j_username and j_password. Those names are mandatory if we want to take advantage of JAAS.

As mentioned before, we configure JAAS to use html form and JAAS realm. We have seen the html form on login.jsp, so now it's time to see the JAAS realm configuration on Tomcat as explained below.


Above is the default Tomcat configuration on its server.xml which is located in its conf folder.


The Tomcat configuration above is added automatically when we deploy our web app on Tomcat from Eclipse. The docBase and path properties point to our project name on Eclipse which is usually also our war file name and context name. The source property is internally used by Eclipse.


Then we need to add JAAS realm as shown above. The className property refers to internal Tomcat JAAS realm implementation. The appName refers to our package/application name in database. The roleClassNames is a class that is used by JAAS realm to decide what role that a user is assigned as configured on security constraint part of web.xml. We will see the RolePrincipal class later. useContextClassLoader is used to tell Tomcat that the RolePrincipal class should be loaded from context classpath, that is from /JAASWeb.

Below is the RolePrincipal class. It has the same structure as other principal classes. The name variable is set by TomcatLoginModule.commit() method and it has value either admin or user.


Once we have done with authentication, we can start authorization process. Unfortunately, we can't get the logging in Subject from authentication process that was done by JAAS realm before. We can overcome this by repeating the authentication process in a servlet Filter. Let's see how this is done below:


First, we declare two filters in the web.xml, Authentication-Filter and Authorization-Filter. The first is used to repeat the authentication process until we get the Subject. The second is used to simulate authorization process by checking the Subject privilege against an input file. We will visit them one by one.


For Authentication-Filter we create AuthenticationFilter class and pass "ted" as its app-name parameter. Our AuthenticationFilter class implements servlet's Filter interface. In the init() method we get the app-name parameter from web.xml. In the doFilter() method we get username and query his/her password from database. If the authentication process success, we put the Subject in to a session attribute "loggedInSubject".


For Authorization-Filter we create AuthorizationFilter class. In the code above we test the Subject against an input file.

Below is the folder structure of our project:


Running this project on Tomcat produces the following results:








0 comments:

 

©2009 Stay the Same | by TNB