You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@shiro.apache.org by Ankit <mr...@gmail.com> on 2014/07/03 08:31:47 UTC

Multiple realms to handle authentication for different sets of urls in Spring MVC and shiro

I am trying to find a best practice solution for my situation. I have two
different sets of urls in my webapp that need to be secured/authenticated
against two different sets of user bases.

For example, the /foo/* urls are to be accessible only to a certain set of
users based on username/pwd tokens. And another set /bar/* urls are to be
accessible only to a set of users (stored in a different database table from
the first set) via username/pwd token mechanism.

I want to understand how to structure the shiro filter(s) in my web.xml and
the corresponding shiro filter bean definition in my applicationContext.xml.
Should I be using two different shiro filters (one for each url pattern),
mapping to two different bean in the context file, where each bean has its
own security manager that is configured with its own realm (each realm
responsible for authenticating against the corresponding user base table).

Here I am following this two links: 
http://stackoverflow.com/questions/9268523/multi-tenancy-in-shiro/24545588#24545588
http://shiro-user.582556.n2.nabble.com/Multiple-security-managers-and-realms-to-handle-authentication-for-different-sets-of-urls-td7445068.html#a7579763

but I am getting errors in my application. Here I am pasting some sample
code.

ApplicationContext-shiro.xml

    
    <property name="realms">
        <util:list>
            <ref bean="adminAuthRealm" />
            <ref bean="vendorAuthRealm" />              
        </util:list>
    </property>

    

    <property name="cacheManager" ref="cacheManager" />
    
</bean>`<bean id="shiroFilter"
class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager" />
    <property name="unauthorizedUrl" value="/permissionDenied.do" />

    

    <property name="filters">
        <util:map>
            <entry key="adminAuthc" value-ref="adminAuthc" />
            <entry key="vendorAuthc" value-ref="vendorAuthc" />
            <entry key="adminUser" value-ref="adminUser" />
        </util:map>
    </property>
    <property name="filterChainDefinitions">
        <value>
            /admin/welcome.do = anon
            /vendor/welcome.do = anon
            /vendor/signup.do = anon
            /admin/signup.do = anon
            /assets/** = anon
            /admin/** = adminAuthc
            /vendor/** = vendorAuthc
        </value>
    </property>
</bean>
<bean id="adminAuthc"
    class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter">
    <property name="loginUrl" value="/admin/login.do" />
    <property name="successUrl" value="/admin/home.do" />
</bean>
<bean id="vendorAuthc"
    class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter">
    <property name="loginUrl" value="/vendor/login.do" />
    <property name="successUrl" value="/vendor/home.do" />
</bean>
<bean id="adminUser" class="org.apache.shiro.web.filter.authc.UserFilter">
    <property name="loginUrl" value="/admin/login.do" />
</bean>

<bean id="vendorUser" class="org.apache.shiro.web.filter.authc.UserFilter">
    <property name="loginUrl" value="/vendor/login.do" />
</bean>`

MultiLoginAuthenticator.java

public class MultiLoginAuthenticator extends ModularRealmAuthenticator {

@Override
protected AuthenticationInfo doAuthenticate(AuthenticationToken
authenticationToken) throws AuthenticationException {
    assertRealmsConfigured();   <------- Here I am getting null getRealms().
So I am getting exceptions
    MultiLoginAuthenticationToken mlat = null;
    Realm loginRealm = null;

    if (!(authenticationToken instanceof MultiLoginAuthenticationToken)) {
        throw new AuthenticationException("Unrecognized token , not a typeof
MultiLoginAuthenticationToken ");
    } else {
        mlat = (MultiLoginAuthenticationToken) authenticationToken;
        loginRealm = lookupRealm(mlat.getRealmName());
    }

    return doSingleRealmAuthentication(loginRealm, mlat);

}

protected Realm lookupRealm(String realmName) throws AuthenticationException
{
    Collection<Realm> realms = getRealms();
    for (Realm realm : realms) {
        if (realm.getName().equalsIgnoreCase(realmName)) {
            return realm;
        }
    }
    throw new AuthenticationException("No realm configured for Client " +
realmName);
}

}

while i am configuring MultiLoginAuthenticator, i am getting null in
getReamls() method. So it is throwing IllegalStateException.

If I remove this Authenticator configuration from applicationContext.xml
file, then it is able to login correctly but it is calling different Realm
for "doGetAuthorizationInfo" method. So It is not assigning any role and
permission to that current Subject.

This is my Realm file (both Realms are same. Difference is both are calling
different datasource.)

@Override
public boolean supports(AuthenticationToken token) {
    if (token instanceof MultiLoginAuthenticationToken) {
        return
((MultiLoginAuthenticationToken)token).getRealmName().equalsIgnoreCase("VendorAuthRealm");
    }
    return false;
}

@Override
protected AuthorizationInfo doGetAuthorizationInfo(
        PrincipalCollection principals) {
    logger.debug("authorization info.....");
    logger.debug("realm size is : {}",
principals.fromRealm(getName()).size());
    logger.debug("realm name is : {}", principals.fromRealm(getName()));

    int userId = (Integer)
principals.fromRealm(getName()).iterator().next();

    VendorUser vendorUser = vendorUserService.getVendorUser(userId);
    if(vendorUser != null) {
        logger.debug("vendor user first name is : {}",
vendorUser.getFirstName());
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        if(vendorUser.getVendorProducts() != null){
            logger.debug("vendor users products and rate types...");
           
info.addRoles(VendorYatraUtil.getProductSet(vendorUser.getVendorProducts()));
           
info.addStringPermissions(VendorYatraUtil.getCarRateTypeSet(vendorUser.getVendorCarRateTypes()));
        }
        return info;
    }
    return null;
}

@Override
protected AuthenticationInfo doGetAuthenticationInfo(
        AuthenticationToken authcToken) throws AuthenticationException {
    MultiLoginAuthenticationToken token = (MultiLoginAuthenticationToken)
authcToken;
    logger.debug("username is : {}", token.getUsername());

    if(vendorUserService.findVendorUser(token.getUsername()) != null){
        VendorUser vendorUser =
vendorUserService.findVendorUser(token.getUsername()); 
        if (vendorUser != null){
            return new SimpleAuthenticationInfo(vendorUser.getId(),
                    vendorUser.getPassword(), getName());
        }
    }

    return null;
}

Thanks, Ankit




--
View this message in context: http://shiro-user.582556.n2.nabble.com/Multiple-realms-to-handle-authentication-for-different-sets-of-urls-in-Spring-MVC-and-shiro-tp7580059.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Multiple realms to handle authentication for different sets of urls in Spring MVC and shiro

Posted by Ankit <mr...@gmail.com>.
I have solved this problem now. 

Here in applicationContext.xml file is having order misplace for Custom
authenticator class. I wrote authenticator property first and then define
Realms.

It is authenticating successfully...



--
View this message in context: http://shiro-user.582556.n2.nabble.com/Multiple-realms-to-handle-authentication-for-different-sets-of-urls-in-Spring-MVC-and-shiro-tp7580059p7580068.html
Sent from the Shiro User mailing list archive at Nabble.com.