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

Introduction

NOTE: Updated in November 2013.

I recently took over a project that used Apache Shiro for web application security. Shiro was previously known as JSecurity (and briefly also called Ki). Not having used Shiro before, I needed to do some research and learn the basics. This blog entry is designed to assist other developers in applying Shiro to a web application. Please understand that I'm just a beginner in using Shiro. Any mistakes in my explanations or code are my responsibility. If you do notice that something is wrong, please post a comment.

From the Shiro web site:

Apache Shiro is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management.
(http://shiro.apache.org - accessed January 2011)

In March 2009, JSecurity's developers changed the JSecurity name to Ki and then to Shiro for various reasons. So you may hear/read about reference to all three names. According to the Apache Software Foundation: "Ki entered the Apache Incubator in June, 2008" (http://incubator.apache.org/projects/ki.html, accessed on April 5, 2009). In September 2010, Shiro became a Apache Top Level Project. The current release (January 2011) of Shiro is 1.1.0.

Shiro provides powerful capabilities with minimal setup--if you're able to use Shiro's configuration defaults in your project. But even if you're not able to use the defaults, you can provide your configuration to Shiro or you can extend one or more of the Shiro classes to customize how it works.

Tutorial Description and Setup

Part 1 of this tutorial starts with a basic web application that has no security. You can download an archived Maven web project here. The project uses Maven to manage dependencies. If you're not familiar with Maven, see the references below. Eclipse has an excellent Maven plugin (see: http://www.sonatype.com/books/m2eclipse-book/reference/index.html ). You should be able to unzip the download and then import the Maven project directly into Eclipse. The project's name is nosecurity. If you don't use Eclipse, just unzip the downloaded file (nosecurity.zip) and copy the source code to your own Java IDE.

You must also download the separate Apache Derby database as I'm going to show you how to use Shiro when your web application is storing usernames and passwords in a database. Note that Shiro comes with support for many other kinds of storage mechanisms. Unzip this download on your computer and make a note of the path to the folder securityDB.

The no security web application includes an index.jsp page and a separate folder (named secure) that has two web pages (users.jsp and index.jsp). The pages under the secure folder are supposed to be available only to logged in (authenticated) users. Under the src/main/java folder are packages with the data access, model, and Servlet classes.

Testing The Database Connection

After you've got everything setup you can test the application's connection to Derby by running the TestConnectionFactory class that is in the dao package. This class is just a standard Java class with a main method. In the main method, it uses the ConnectionFactory class to get a connection to the Derby database, then displays some information about Derby, and shows the results of querying the users table. The users table is where the project is storing the usernames and passwords for the tutorial. Note you will need to change the path to securityDB in class ConnectionFactory, method getConnection and in the context.xml file under the META-INF folder.

Running The Tutorial

After confirming that the project can connect to the Derby database, you can build and deploy the web application to a Java Servlet container and web server such as Tomcat. The tutorial was tested on Tomcat version 7. Remember if you're using Eclipse, you'll need the Maven Eclipse plugin so that all the dependent jars will be provided to the project. See the reference below for how to get the Maven Eclipse plugin.

You can also 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 nosecurity.zip download. Make sure you're in the nosecurity directory. Then do the following:

mvn clean tomcat7:run-war

Once you see INFO: Starting Servlet Engine: Apache Tomcat/7.0.47 in the command window, open your web browser and go to this URL: http://localhost:8080/nosecurity/. 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 no security you should be able to click on all the links and all the web pages should display, including the secure/users.jsp which displays the records from the users table that is the Derby database.

What's Next?

I realize this seems like a lot of setup just to get a simple web application to run. But I want to ensure that you can run this web application that uses a Derby database to store user information. In future tutorials, I'll be adding to this web application features from Shiro to enable security. So it's important that you get the basic web application working correctly in your development environment so that if you run into problems in the future tutorials you'll be able to more easily determine the cause.

In part 2 of this tutorial, I'll add basic security using Shiro to the web application to prevent users who have not logged in from viewing the pages in the secure folder.

References

  1. No Security Example Application, http://www.brucephillips.name/jsecurity_examples/nosecurity_mvn.zip
  2. Apache Shiro http://shiro.apache.org/
  3. Apache Shiro API, http://shiro.apache.org/static/current/apidocs/
  4. Apache Shiro Mailing Lists, http://shiro.apache.org/mailing-lists.html
  5. Apache Derby, http://db.apache.org/derby/
  6. Apache Tomcat, http://tomcat.apache.org/
  7. Jetty, http://jetty.mortbay.org/jetty5/index.html
  8. Maven: The Definitive Guide, http://www.sonatype.com/books/maven-book/reference/public-book.html
  9. 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.)
Any suggestions on running the example on glassfish v.3? i was unable to view the user list page (it throws null pointer exception), when the app was run. the home page is displayed correctly.
# Posted By Umair Ishaq | 3/14/10 4:33 PM
Hi Bruce,

I am working on implemneting Shiro and was looking at your tutorial. I may be missing something but when I run the TestConnectionFactory I get an exception stating that the USERS schema does not exist.

I connected to the DB supplied and noticed that this is correct - the USERS schema doesn't exist. I did unzip securityDB to c:\derby as instructed.

Any possiblility the uploaded data did not contain this table?
# Posted By Keith | 2/20/12 7:11 PM
Keith:

This line in class ConnectionFactory:


String sourceURL = "jdbc:derby:/derby/" + dbName + ";create=true";

needs to be changed to


String sourceURL = "jdbc:derby:c:/derby/" + dbName + ";create=true";

if you are running this on a Windows computer and have copied the no security database to c:/derby.

When I first built this example app I was on Windows, but when I updated two years later I was on a Mac.

Let me know if that fixes your issue.
# Posted By Bruce | 2/20/12 8:31 PM
Thanks Bruce - I figured it out 5 minutes after I posted - I missed that there is a separate download for the derby DB data!

It's working fine now and I'm moving on to part two.

Thanks Again.

Keith
# Posted By Keith | 2/20/12 8:48 PM
Hi Bruce,
I am a new comer in the programming world,When I first built this example app I also made mistake like this friend--Keith,I spent half-hour to find and fixed it ,and just because the "String sourceURL" is not the correct path.Then,I think you should draw a red line in the sentence “you will need to change the parth to securityDB in class ConnectionFactory, method getConnection, in the context.xml file under the META-INF folder, and in jetty-env.xml in WEB-INF folder.”, in order to avoid the newcomers like me to make the same mistake.
Thanks.
# Posted By jackpan | 11/15/12 8:41 PM
HI Bruce!
On windows,I have added "c:" into the path in "method getConnection", "context.xml under META-INF folder", "jetty-env.xml in WEB-INF folder".

When I run TestConnectionFactory.java, which throw the excetion "java.sql.SQLSyntaxErrorException: Schema 'USERS' does not exist"

I think that may lost some step to setup the data into derby database!

Can you help me?
# Posted By willson | 11/30/12 1:48 AM
Wilson - Review the section headed Testing the Database Connection and the comments others have made. Double check all the paths to ensure they match where you have put the Derby database.
# Posted By Bruce | 11/30/12 6:48 AM
Hi Bruce?
I've changed the line :
"jdbc:derby:/derby/" + dbName + ";create=true"
to:
"jdbc:derby:c:/derby/" + dbName + ";create=true"
on a Windows,but when i debug this application on a eclipse,and i found that the connection object was still print the "jdbc:derby:/derby/" one?
I can't find what wrong with that, can you help me?
# Posted By leoxu | 1/20/13 8:45 PM
<Configure id="wac" class="org.eclipse.jetty.webapp.WebAppContext">

<New id="security" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg><Ref id="wac"/></Arg>
<Arg>jdbc/security</Arg>
<Arg>
<New class="org.apache.commons.dbcp.BasicDataSource">
<Set name="driverClassName">org.apache.derby.jdbc.EmbeddedDriver</Set>
<Set name="url">jdbc:derby:/Unix or Mac location/securityDB;create=false</Set>
<Set name="username">users</Set>
<Set name="password">password</Set>
</New>
</Arg>
</New>

</Configure>

Based on the latest version of Jetty Server (as of 2013), i have to change the package of jetty to have org.eclipse for WebAppContext as well as Resource. Used Configure id in Ref id as per some other reference. Also please use create=true only for tutorial 1 and rest all other 2,3 and 4th tutorials should say create=false.

Similarly modify the changes in ConnectionFactory.java.

regards,
raj
# Posted By Raj | 8/4/13 1:00 PM
I think, the change suggested by Raj is mandatory for newer versions of jetty. thanks bruce and raj for the nice post.

there were some hickup's though in setting up part-1. especially the JNDI lokup. ( 2 problems i could see here is Run as jetty web-app doesnt work on WAR file rather maven target folder classes, which makes META-INF invisible to the container).

finally i had to use mvn jetty:run to run the nosecurity web-app, after updating jetty-web.xml as per jetty 8 syntax.
# Posted By Shravan | 11/11/13 7:38 AM
Shravan and Raj

Thanks for the feedback. I updated all the Shiro example projects to use the Tomcat 7 Maven plugin instead of Jetty. That way I did not need to different configurations.
# Posted By Bruce | 11/12/13 11:39 AM
I unzipped the DB (securityDB) under "c:\..\nosecurity\Derby\" folder, then changed the path in code lines to-->

- content.xml : line29
url="jdbc:derby:C:/Users/Administrator/workspace for Shiro/nosecurity/Derby/securityDB;create=true"

- ConnectionFactory.java : line71
String sourceURL = "jdbc:derby:/C:/Users/Administrator/workspace for Shiro/nosecurity/Derby/" + dbName + ";create=true";

After cleaning, building and running with Maven, I run accross "NullPointerException" on "http://localhost:8080/nosecurity/GetAllUsers";.
Here is the page:

HTTP Status 500 -

--------------------------------------------------------------------------------

type Exception report

message

description The server encountered an internal error that prevented it from fulfilling this request.

exception

java.lang.NullPointerException
   name.brucephillips.nosecurity.dao.UserDAO.getAllUsers(UserDAO.java:73)
   name.brucephillips.nosecurity.servlet.GetAllUsers.doPost(GetAllUsers.java:45)
   name.brucephillips.nosecurity.servlet.GetAllUsers.doGet(GetAllUsers.java:33)
   javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
   javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
   org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)


note The full stack trace of the root cause is available in the Apache Tomcat/7.0.47 logs.


I think the problem is concerned with connection to the derby DB.
# Posted By Ça?r? | 11/30/13 11:06 AM
Try putting securityDB in a folder where there are no spaces in the path (e.g. (c:/Users/Adminstrators/workspace/shiro/noSecurity)

Bruce
# Posted By Bruce | 11/30/13 11:36 AM
Thanks. It worked.
I figured also that the issue was about eclipse derby plugins: simply, I copied the "db-derby-10.9.1.0-bin" distribution folder into local "C:\eclipse\plugins\" and restarted eclipse, built it.

Secure Area Users Page

Since our web site doesn't have any security anyone can visit this web page even though it's in our secure area.

Here is information on our users from the data store:

User ID: 1
Username: bruce@hotmail.com
Password: bruce

User ID: 2
Username: sue@hotmail.com
Password: sue

User ID: 3
Username: jack@hotmail.com
Password: jack
# Posted By Ça?r? | 11/30/13 12:33 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.1.002. Contact Blog Owner