Search code examples
shiro

Shiro in distributed environment - auto authenticating/white listing internal calls


I am developing a distributed system with shiro for RBAC. I am not using shiro-web , but have custom filtering in my SecurityFilter attached to the Servlet.

My question is, Is there a way to white-list(auto-authenticate) requests coming from certain nodes ( in my case, peers in the distributed system) without having to go through the entire authentication process.


Solution

  • We use an approach when we have some code that is started by the system, not a user and we use the idea of a system user token, which we couple to a user that has all permissions. You could take a similar approach. We have a custom realm implementation to check for those cases as we have multiple realms, we need to register this with the token. If you don't have that, you can just remove the realmName stuff.

    public class SystemAuthenticationToken implements AuthenticationToken {
    
        private String realmName;
    
        public SystemAuthenticationToken(String realmName) {
            this.realmName = realmName;
        }
    
        public String getRealmName() {
            return realmName;
        }
    
        @Override
        public Object getPrincipal() {
            return null;
        }
    
        @Override
        public Object getCredentials() {
            return null;
        }
    }
    

    In our custom realm implementation:

    public class OurRealmImpl extends AuthorizingRealm {
    
    
        @Override
        public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
            if (token instanceof SystemAuthenticationToken) {
                login = //..get the special login
            } else {
                login = //..get normal login
            }
            SimplePrincipalCollection principalCollection = new SimplePrincipalCollection(login, realmName);
            if (token instanceof SystemAuthenticationToken) {
                principalCollection.add(token, realmName);
            }
    
           return new SimpleAuthenticationInfo(principalCollection, login.getPasswordHash());
        }
    

    We extend a passwordmatcher which you need to set on the security manager:

    public class PasswordAndSystemCredentialsMatcher extends PasswordMatcher {
    
    
        @Override
        public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
            if (token instanceof SystemAuthenticationToken){
                return true;
            }
            return super.doCredentialsMatch(token, info);
        }
    

    Then the security filter would call the login to set the token:

        Subject currentUser = SecurityUtils.getSubject();
        SystemAuthenticationToken token = new SystemAuthenticationToken(realmName);
        currentUser.login(token);
    

    Is it is not so simple as you hoped it would be, but for us it gets the job done.