Search code examples
java-ee-6shiro

Apache Shiro with JdbcRealm and JndiObjectFactory throws IllegalArgumentException


I'm trying to use Apache Shiro (v1.2) in a JavaEE6 web application on a GlassFish v3.1.2 application server.

In GlassFish I've set up a datasource (jdbc/myds) which I have tested to work through JPA2.

I would like to use the same datasource for authenticating users using the Shiro JDBC realm.

I've got the following in shiro.ini:

# DataSource config
ds                = org.apache.shiro.jndi.JndiObjectFactory 
ds.requiredType   = javax.sql.DataSource
ds.resourceName   = jdbc/myds

# JDBC realm config
jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.permissionsLookupEnabled = false
jdbcRealm.authenticationQuery = SELECT password FROM user_account WHERE email = ?
jdbcRealm.userRolesQuery = SELECT role_name FROM user_group_membership WHERE email = ?
jdbcRealm.dataSource = $ds

When I deploy the application I get the following Exception (summarised):

FINE: Encountered object reference '$ds'.  Looking up object with id 'ds'
FINEST: Applying property [dataSource] value [org.apache.shiro.jndi.JndiObjectFactory@2ca061] on object of type [org.apache.shiro.realm.jdbc.JdbcRealm]
SEVERE: Unable to start Filter: [Unable to set property 'dataSource' with value [$ds] on object of type org.apache.shiro.realm.jdbc.JdbcRealm.  If '$ds' is a reference to another (previously defined) object, prefix it with '$' to indicate that the referenced object should be used as the actual value.  For example, $$ds].
org.apache.shiro.config.ConfigurationException: Unable to set property 'dataSource' with value [$ds] on object of type org.apache.shiro.realm.jdbc.JdbcRealm.  If '$ds' is a reference to another (previously defined) object, prefix it with '$' to indicate that the referenced object should be used as the actual value.  For example, $$ds
at org.apache.shiro.config.ReflectionBuilder.applyProperty(ReflectionBuilder.java:373)
at org.apache.shiro.config.ReflectionBuilder.applySingleProperty(ReflectionBuilder.java:198)
at org.apache.shiro.config.ReflectionBuilder.applyProperty(ReflectionBuilder.java:159)
at org.apache.shiro.config.ReflectionBuilder.buildObjects(ReflectionBuilder.java:119)
...
...
Caused by: java.lang.IllegalArgumentException: Cannot invokeorg.apache.shiro.realm.jdbc.JdbcRealm.setDataSource on bean class 'class org.apache.shiro.realm.jdbc.JdbcRealm' - argument type mismatch - had objects of type "org.apache.shiro.jndi.JndiObjectFactory" but expected signature "javax.sql.DataSource"
at org.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(PropertyUtilsBean.java:2235)
at org.apache.commons.beanutils.PropertyUtilsBean.setSimpleProperty(PropertyUtilsBean.java:2151)
at org.apache.commons.beanutils.PropertyUtilsBean.setNestedProperty(PropertyUtilsBean.java:1957)
...

If instead I define an actual MySQL data source it works fine, e.g.

ds = com.mysql.jdbc.jdbc2.optional.MysqlDataSource 
ds.serverName = localhost
ds.user = root
ds.password = root
ds.databaseName = mydb

Any help is much appreciated.


Solution

  • This looks like it is likely a classpath issue. The stack trace references line numbers for ReflectionBuilder that make sense in shiro 1.1.0. However, they don't make sense in shiro 1.2.0. However, since JndiObjectFactory is new in shiro 1.2.0, and both classes are in shiro-core, it seems likely that you have both jars on the classpath.

    You should first look in your war file, make sure that both jars aren't in there. If they are, you can fix your war file by removing the 1.1.0 version. If not, I would begin looking to see if you are inheriting an old version of shiro through the glassfish infrastructure somehow.