We are evaluating Shiro for a custom Saas app that we are building. Seems like a great framework does does 90% of what we want, out of the box. My understanding of Shiro is basi
You will probably need a ServletFilter that sits in front of all requests and resolves a tenantId pertaining to the request. You can store that resolved tenantId as a request attribute or a threadlocal so it is available anywhere for the duration of the request.
The next step is to probably create a sub-interface of AuthenticationToken, e.g. TenantAuthenticationToken
that has a method: getTenantId()
, which is populated by your request attribute or threadlocal. (e.g. getTenantId() == 'client1' or 'client2', etc).
Then, your Realm implementations can inspect the Token and in their supports(AuthenticationToken)
implementation, and return true
only if the token is a TenantAuthenticationToken
instance and the Realm is communicating with the datastore for that particular tenant.
This implies one realm per client database. Beware though - if you do this in a cluster, and any cluster node can perform an authentication request, every client node will need to be able to connect to every client database. The same would be true for authorization if authorization data (roles, groups, permissions, etc) is also partitioned across databases.
Depending on your environment, this might not scale well depending on the number of clients - you'll need to judge accordingly.
As for JNDI resources, yes, you can reference them in Shiro INI via Shiro's JndiObjectFactory:
[main]
datasource = org.apache.shiro.jndi.JndiObjectFactory
datasource.resourceName = jdbc/mydatasource
# if the JNDI name is prefixed with java:comp/env (like a Java EE environment),
# uncomment this line:
#datasource.resourceRef = true
jdbcRealm = com.foo.my.JdbcRealm
jdbcRealm.datasource = $datasource
The factory will look up the datasource and make it available to other beans as if it were declared in the INI directly.