how to configure a shiro Realm to connect to an oracle database within a struts2 application

jahndatcam picture jahndatcam · May 29, 2013 · Viewed 7.1k times · Source

I have been working with shiro (ki, jsecurity) now for a few days and have been able to create a test application. I am working with struts2, off JBoss. I have been able create a shiro.ini file with a few hard-coded users, and i have gotten that to work. It seems like the API within JAVA is extremely easy to get a grasp of, so integrating shiro to my application and making it functional hasnt been the real problem. My real issue is that i have not been able to find any form of documentation on how to create/tie a REALM to an oracle database using this set up. I have found several examples and tried aimlessly to adapt it to my situation. but i have been unable.

I have an oracle database with a USERS table, it simply holds a username, password, and role. If i am able to make the connection, it seems as though it should simply fit right into my current login/logoff app.

I added the following lines to my web.xml

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
        <filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher> 
    <dispatcher>FORWARD</dispatcher> 
    <dispatcher>INCLUDE</dispatcher> 
    <dispatcher>ERROR</dispatcher>
</filter-mapping>
<listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>

I then added shiro.ini to my WEB-INF:

[main]

[users]
bruins = boston, admin, super, worker
rangers = newyork, super, worker
leafs = toronto, worker

[urls]
/authoring/logout = logout
/authoring/** = authc

after that it was simply calling the java code from within my loginAction.java:

Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();   
SecurityUtils.setSecurityManager(securityManager);   
Subject currentUser = SecurityUtils.getSubject();   
UsernamePasswordToken token = new UsernamePasswordToken(this.username, this.password);
try {   
    currentUser.login(token);   
    Session session = currentUser.getSession();   
    session.setAttribute("user", this.username);   
} catch (UnknownAccountException uae) {   
  ... 
} catch (IncorrectCredentialsException iae) {   
 ...
} catch (LockedAccountException lae) {   
 ... 
} catch (AuthenticationException ae) {   
  ...         
} catch (Exception e) {   
 ...
}   
ActionMessages messages = new ActionMessages();
if (currentUser.isAuthenticated()) {   
    System.out.println("user is authenticated!!!!!");

    if (currentUser.hasRole("admin")){
        System.out.println(this.username + " can access admin functions");
    }
    if(currentUser.hasRole("super")){
        System.out.println(this.username + " can access supervisor functions");
    }
    if(currentUser.hasRole("worker")){
        System.out.println(this.username + " can only perform worker functions");
    }
    addActionMessage(getText("success.valid.user", this.username));
    return SUCCESS;
} else {   
    System.out.println("user was not authenticated!!!!!!");
    addActionError(getText("error.login"));
    return ERROR;
}

so all in all, i have the application working with hard-coded users: my question is what is the best way for me to set up the REALM to connect to my oracle database? I have seen it online done in several different ways, and i have been unable to adapt any of them to my set up, and i would love to get this going to that i can continue to familiarize myself with the API.

thanks - John

Answer

Les Hazlewood picture Les Hazlewood · May 30, 2013

You could use Shiro's JdbcRealm using a connection-pooling DataSource configured in shiro.ini, e.g. with BoneCP:

[main]
ds = com.jolbox.bonecp.BoneCPDataSource
ds.driverClass = oracle.jdbc.driver.OracleDriver
ds.jdbcUrl = dbc:oracle:thin:@localhost:1521:myschema
ds.username = scott
ds.password = tiger
# other BoneCP connection pool settings as desired

jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.dataSource = $ds
# you can customize the authenticationQuery, userRolesQuery and permissionsQuery
# if needed.

securityManager.realms = $jdbcRealm

We use BoneCP in production and are quite happy with it.

You can look at the JdbcRealm's source code to see how it works. You can customize the queries to match your database schema.

Also, you could of course subclass JdbcRealm to customize to your needs if the default settings/queries won't work. Here's an example of a custom JdbcRealm (it also uses JNDI to look up the datasource if you want to do that instead of configure the datasource in shiro.ini).