MySQL & Apache Derby as jdbcRealm for Apache Shiro

In this post I’d like to show you, how you could use Apache Derby or MySQL as Security Realm for Apache Shiro.

Apache Shiro is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management

Step 1 creating a simple WebApp

First we need to create a simple WebApp using maven

mvn archetype:generate -DgroupId=dev.nabil -DartifactId=ShiroDemo -DarchetypeArtifactId=maven-archetype-webapp

Generate eclipse configuration files (if you want to import as Eclipse project)

mvn eclipse:eclipse 

Added jetty Plugin into your pom.xml, in order to be able to run the WebApp

<build>
	<plugins>
		<plugin>
			<groupId>org.mortbay.jetty</groupId>
			<artifactId>maven-jetty-plugin</artifactId>
		</plugin>
	</plugins>
    <finalName>ShiroDemo</finalName>
  </build>

At this point if you start jetty

mvn jetty:run

You should be able to access the WebApp at http://localhost:8080/ShiroDemo/

Step 2 securing some content

Now we’re going to use Apache Shiro to secure access to a JSP page.

Create a new directory “auth” and add a new JSP under it, let’s call it “BackOffice.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@page import="org.apache.shiro.SecurityUtils"%>
<html>
<body>
<h2>Master <%= SecurityUtils.getSubject().getPrincipal() %> I'm Here To Serve You :)</h2>
</body>
</html>

This acquire and display the current authenticated user.

Now we have to create a database that will hold the list of the authorized users along with their password
I use Apache Derby for my staging environment (we’ll see later how we could use MySQL)

CREATE TABLE T_CUSTOMER
(
   IDCUSTOMER varchar(255) PRIMARY KEY NOT NULL,
   PINCODE varchar(255) NOT NULL
)
INSERT INTO T_CUSTOMER (IDCUSTOMER,PINCODE) VALUES ('nabil','changeit');

Now that we have our database ready, we will enable Shiro into our project by adding a ServletFilter into our Web.xml

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
	<filter>
	    <filter-name>ShiroFilter</filter-name>
	    <filter-class>
	        org.apache.shiro.web.servlet.IniShiroFilter
	    </filter-class>
	    <!-- no init-param means load the INI config
	        from classpath:shiro.ini --> 
	</filter>
	<filter-mapping>
	     <filter-name>ShiroFilter</filter-name>
	     <url-pattern>/*</url-pattern>
	</filter-mapping>
	
  <display-name>Archetype Created Web Application</display-name>
</web-app>

Don’t forget to added Shiro’s dependencies into pom.xml

       <dependency>
		<groupId>org.apache.shiro</groupId>
		<artifactId>shiro-core</artifactId>
		<version>1.1.0</version>
	</dependency>

	<dependency>
		<groupId>org.apache.shiro</groupId>
		<artifactId>shiro-web</artifactId>
		<version>1.1.0</version>
	</dependency>

        <dependency>
		<groupId>commons-logging</groupId>
		<artifactId>commons-logging</artifactId>
		<version>1.1.1</version>
	</dependency>

        <dependency>
	        <groupId>org.apache.derby</groupId>
                <artifactId>derbyclient</artifactId>
	        <version>10.4.2.0</version>	
 	</dependency>

        <dependency>
		<groupId>com.jolbox</groupId>
		<artifactId>bonecp</artifactId>
		<version>0.7.1.RELEASE</version>
	</dependency>

Finally create shiro.ini under resource dir, it’s the configuration file.

[main]
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.authenticationQuery = select pincode from t_customer where idcustomer = ?

ds = com.jolbox.bonecp.BoneCPDataSource
ds.driverClass=org.apache.derby.jdbc.ClientDriver
ds.jdbcUrl=jdbc:derby://localhost:1527/shiro_schema
ds.username = APP
ds.password = APP
jdbcRealm.dataSource=$ds

[users]
[roles]
[urls]
/auth/** = authcBasic
/** = anon

As you can see the configuration is pretty straightforward.
First we setup the jdbc realm, this is where Shiro will find the authorized users.
Then, we map the URLs to be protected, all the url under /auth should be authenticated with basic HTTP authentication
All the other URLs should be accessed without authentication.

Note: The mapping order matter.

Now we’re ready to restart jetty

mvn clean jetty:run

Try to access http://localhost:8080/ShiroDemo/auth/secured.jsp you should be prompted to login.

What about MySQL?

In this project I wanted to use two different Databases, let’s say Apache Derby for Dev/staging environment and MySQL for production.

To achieve this, we will use Maven profile and filter.

First Add a new directory under src let’s call it production we will create a new shiro configuration file compatible with MySQL.

[main]
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.authenticationQuery = select pincode from t_customer where idcustomer = ?

ds = com.mysql.jdbc.jdbc2.optional.MysqlDataSource
ds.serverName = localhost
ds.user = ADM
ds.password = secret123
ds.databaseName = shiro_schema
jdbcRealm.dataSource = $ds

[users]
[roles]
[urls]
/auth/** = authcBasic
/** = anon

As you can see, the configuration is almost the same especially the mapping part, what’s different indeed is the jdbcRealm which use a MySQL driver
This is why we need to added the appropriate dependency to maven pom.xml

<dependency>
        <groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.6</version>
</dependency>

Putting it all together

<profiles>
  <!-- STAGING ENV (default) -->
        <profile>
            <id>staging</id>
            <activation>
                <activeByDefault>true</activeByDefault>
                <property>
                    <name>environment.type</name>
                    <value>staging</value>
                </property>
            </activation>
            <properties>
                <jdbc.user>APP</jdbc.user>
                <jdbc.passwd>APP</jdbc.passwd>
                <jdbc.url>jdbc:derby://localhost:1527/shiro_schema</jdbc.url>
                <jdbc.driver>org.apache.derby.jdbc.ClientDriver</jdbc.driver>
            </properties>
            <build>
	            <resources>
					<resource>
						<directory>src/main/resources</directory>
						<filtering>true</filtering>
					</resource>
				</resources>
			</build>
			<dependencies>
                <dependency>
						<groupId>org.apache.derby</groupId>
						<artifactId>derbyclient</artifactId>
						<version>10.4.2.0</version>						
			  	</dependency>
            </dependencies>
        </profile>
        
        <!-- PRODUCTION ENV -->
        <profile>
            <id>production</id>
            <activation>
                <property>
                    <name>environment.type</name>
                    <value>prod</value>
                </property>
            </activation>
            <properties>
                <jdbc.user>ADM</jdbc.user>
                <jdbc.passwd>secret123</jdbc.passwd>
                <jdbc.ds>com.mysql.jdbc.jdbc2.optional.MysqlDataSource</jdbc.ds>
                <jdbc.serverName>localhost</jdbc.serverName>
                <jdbc.databaseName>shiro_schema</jdbc.databaseName>
            </properties>
            <build>
	            <resources>
					<resource>
						<directory>src/production/resources</directory>
						<filtering>true</filtering>
					</resource>
				</resources>
			</build>
			<dependencies>
				<dependency>
		            <groupId>mysql</groupId>
		            <artifactId>mysql-connector-java</artifactId>
		            <version>5.1.6</version>
		        </dependency>
	        </dependencies>
        </profile>
        
  </profiles>

We separate here the staging conf (Apache Derby) from the production configuration that include MySQL driver and some specific properties. This allow us to change environment/conf easily while maintaining a single pom.xml

  • To build and run for staging
mvn clean jetty:run

this will use staging’s profile as it’s the default.

  • To build for production
mvn clean jetty:run -Denvironment.type=prod

This project is available on GitHub

Resources

Advertisements

About nhachicha

Android Developer, share experience about Java, System and Android
This entry was posted in Java and tagged , , , , , . Bookmark the permalink.

One Response to MySQL & Apache Derby as jdbcRealm for Apache Shiro

  1. Hi.
    This is a very helpful post on configuring Apache Shiro with databases, but it leaves me with a couple basic questions on password security. You appear to have the database password (and whole configuration) in both the shiro.ini files and in the pom.xml. Why the redundancy? Is there a way to avoid having the password in the shiro.ini files? Ideally, I think it would be best to have the password stored outside of both shiro.ini and pom.xml, which would generally be checked into version control. Is there a good way of separating out the password into a separate file or keystore?
    Thanks again for a very informative post.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s