An Introduction to Shiro (formerly JSecurity) – A Beginner’s Tutorial Part 3

Introduction

NOTE: Updated in November 2013.

In part 2 of this tutorial, I demonstrated how to use Apache Shiro (formerly JSecurity and also called Ki) to add basic security to a web application. In part 3, I show how to configure Shiro to secure different parts of the web application based on a user's role.

One of Shiro's many features is an ability to restrict areas of a web application to be available not just to authenticated (logged in) users but to authenticated users that have a specific role such as admin.

Part 3 Example Application

You can download the part 3 example project, which is an archived Maven project. This example is based on the example project built in the tutorial parts 1 and 2. Be sure you read parts 1 and 2 of the tutorial (links at the bottom of this page) and that you've successfully configured the Derby database (see part 1).

In part 3's example project, I reconfigured the web folders into a secure folder (secure/index.jsp) and an admin folder (admin/index.jsp and admin/users.jsp). Users who are logged in and have a role of user can access the JSPs in the secure folder, but cannot access the JSPs in the admin folder. Only users logged in and have a role of admin can view the pages in the admin folder.

Unzip the downloaded role security file and then import the Maven project into Eclipse.

Be sure to update the path to the securityDB in context.xml before building the .war file or running the Maven goal mentioned below.

You can use the Maven Tomcat plugin (see reference below for how to install Maven if you've don't already have Maven) to run the web application. Just open a command window and navigate to where you unzipped the rolesecurity.zip download. Make sure you're in the rolesecurity directory. Then do the following:

mvn -e clean tomcat7:run-war

Once you see [INFO] Started Servlet Engine in the command window, open your web browser and go to this URL: http://localhost:8080/rolesecurity/ . You should see the contents of the index.jsp. To stop the Tomcat server type control-c in the command window.

Since this web application has security based on user roles you should NOT be able to open the web pages that are in the admin folder (admin/index.jsp and admin/users.jsp) without first logging in as user bruce@hotmail.com and bruce (password). If you log in using user sue@hotmail.com and sue (password), you can only view the pages in the secure folder.

If you try to visit a web page for which you don't have the correct role, you'll be redirected to /unauthorized.jsp.

Configuring Shiro To Use Role Security

To add security based on roles, I did the following:

Add a database table named user_roles with columns named username and role_name to the Derby database. I inserted records into this table for my two users (bruce@hotmail.com and sue@hotmail.com). Bruce has a role of admin and a role of user. Sue only has a role of user. Giving Bruce both roles enables him to log in and visit pages located in both the secure and admin folders.

Because I'm following Shiro's defaults for where it looks for user roles when using a realm based on a database, my table had to be named user_roles and the columns in the table had to be named username and role_name. If your project cannot follow Shiro's defaults, you can configure Shiro to use your projects conventions (see the Shiro references below).

Note Shiro will automatically query the user_roles table when a a user logs in to determine what roles to associate with the authenticated user.

Then I had to change the configuration for IniShiroFilter (see part 2) in web.xml. Here's the code that changed:

[filters]
roles.unauthorizedUrl = /unauthorized.jsp

[urls]
/secure/** = authc, roles[user]
/admin/** = authc, roles[admin]

The changes to part 2's web.xml are in red.

The roles.unauthorizedUrl filter specifies where the IniShiroFilter should forward the user to if he tries to access a web page but doesn't have the correct role.

The line /secure/** = authc, roles[admin] tell the IniShiroFilter to restrict the JSPs in the /secure/ folder to only users logged and that have a role of user. The line after that one does the same for the admin folder, but a logged in user must have a role of admin to visit those pages. Note you CANNOT do: /secure/** = authc, roles[user,admin] to indicate that users with either the admin or the user role can view pages in the secure folder.

In my Servlet GetAllUsers, I now needed to verify that the user making the request is logged in and has the role of admin. If you examine the code in the doPost method of GetAllUsers you'll see that I just needed to call the Subject class's hasRole method. This method returns true if the Subject has the role passed in as a parameter, otherwise it returns false.

Summary

It was simple to refactor the part 2 web application to use Shiro's role security. Please note that I'm only scratching the surface of Shiro's capabilities. Consult the references below for much more information. When you download Shiro, you'll receive several sample applications that use more advanced features. Also be sure to review the JavaDoc for the Shiro classes as they contain much useful information.

What's Next?

In part 4 of the tutorial, I'll explain how to use some of the custom tags provided by Shiro.

References:

  1. An Introduction to Shiro (formerly JSecurity) – A Beginner's Tutorial Part 2, http://www.brucephillips.name/blog/index.cfm/2009/4/5/An-Introduction-to-Ki-formerly-JSecurity--A-Beginners--Tutorial-Part-2
  2. Role Security Example Application, http://www.brucephillips.name/jsecurity_examples/rolesecurity_mvn.zip
  3. Apache Shiro http://shiro.apache.org/
  4. Apache Shiro API, http://shiro.apache.org/static/current/apidocs/
  5. Apache Shiro Mailing Lists, http://shiro.apache.org/mailing-lists.html
  6. Presentation on JSecurity to the Charlotte Java Users Group, http://www.jsecurity.org/files/JSecurity.pdf
  7. Apache Derby, http://db.apache.org/derby/
  8. Apache Tomcat, http://tomcat.apache.org/
  9. Jetty, http://jetty.mortbay.org/jetty5/index.html
  10. Apache Software Foundation, Apache incubator, http://incubator.apache.org/projects/ki.html
  11. Maven: The Definitive Guide, http://www.sonatype.com/books/maven-book/reference/public-book.html
  12. Developing with Eclipse and Maven, http://www.sonatype.com/books/m2eclipse-book/reference/index.html

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
It seems Shiro need another table - ROLES_PERMISSIONS - in the DerbyDB in order to make the role based authorization. This table should have the following two columns:
ROLE_NAME
PERMISSION
# Posted By Richard | 9/18/09 3:38 PM
Richard:

Did the example application from part 3 not work for you?

In part 5 I discuss using permissions and describe the changes needed for the database.

For part 3 you don't need the roles_permissions table.
# Posted By Bruce | 9/18/09 3:46 PM
Bruce,

Thanks for the blog.

I believe the following statement in Part 3 is incorrect: "The line /secure/** = authc, roles[admin] tell the IniShiroFilter to restrict the JSPs in the /secure/ folder to only users logged and that have a role of user"

It should have been: "The line /secure/** = authc, roles[user] tell the IniShiroFilter to restrict the JSPs in the /secure/ folder to only users logged and that have a role of user"
# Posted By David | 5/30/13 8:14 AM
Bruce,

Thanks for the blog.

I believe the following statement in Part 3 is incorrect: "The line /secure/** = authc, roles[admin] tell the IniShiroFilter to restrict the JSPs in the /secure/ folder to only users logged and that have a role of user"

It should have been: "The line /secure/** = authc, roles[user] tell the IniShiroFilter to restrict the JSPs in the /secure/ folder to only users logged and that have a role of user"
# Posted By David | 5/30/13 8:14 AM
I had to add the maven dependency : commons-logging to deploy on tomcat 7.0.45
# Posted By korena | 11/19/13 2:18 AM
Exactly so!
To deploy third part on Tomcat7, commons-logging dependency needs to be specified in pom.xml as:
--------------------------------------------
<dependency>
       <groupId>commons-logging</groupId>
       <artifactId>commons-logging</artifactId>
       <version>1.1.3</version>
</dependency>
-----------------------------------------------
Thanks to Bruce.
# Posted By Ça?r? | 12/9/13 11:18 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.1.002. Contact Blog Owner