Search code examples
facebookapacheauthenticationauthorizationshiro

Apache Shiro Authentication with Facebook OAuth


I am stucked in authenticating my application running on Shiro with Facebook OAuth. I really don't know what am I doing wrong. Bascially, my problem is when I get a "code" from Facebook. I want shiro to authenticate it using that code. This is my authentication code.

FacebookToken token = null;
        try{
                org.apache.shiro.subject.Subject currentUser = SecurityUtils.getSubject();
                //currentUser.logout(); 
                //This is done to avoid temporary multiple url hit.., when the user is not logged out

                token = new FacebookToken(code);
                currentUser.login(token);  //returns true if valid 
               result =  true;
            }catch (UnknownAccountException uae) {
                log.info("There is no user with username of " + token.getPrincipal());
            } catch (IncorrectCredentialsException ice) {
                log.info("Password for account " + token.getPrincipal() + " was incorrect!");
            } catch (LockedAccountException lae) {
                log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                        "Please contact your administrator to unlock it.");
            }
            // ... catch more exceptions here (maybe custom ones specific to your application?
            catch (AuthenticationException ae) {
                log.info("Authentication exception Here.");
            }

Here is my facebook token class:

public class FacebookToken implements AuthenticationToken {

    private static final long serialVersionUID = 1L;
    private String code;
    public FacebookToken(){

    }

    public FacebookToken(String code){
        this.code = code;
    }

    public Object getCredentials() {

        return null; //Credentials are handled by facebook 
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public Object getPrincipal() {
        return null; //Not known facebook does the login
    }

I have the realm for facebook that is extending authorization realms.

public class FacebookRealm extends AuthorizingRealm {
    }

and finally here is my shiro.ini file:

[main]  
#authc.loginUrl = /login
#authc.successUrl  = /hello
#logout.redirectUrl = /hello

# ------------------------  
# Database  

# Own Realm  
jdbcRealm = com.shiro.common.controller.MyCustomRealm
facebookRealm = com.facebook.login.FacebookRealm


# Sha256  
sha256Matcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
# base64 encoding, not hex in this example:  
sha256Matcher.storedCredentialsHexEncoded = false  
sha256Matcher.hashIterations = 1024  

#Facebook Credential matcher
fbCredentialsMatcher = com.facebook.login.FacebookCredentialsMatcher 


jdbcRealm.credentialsMatcher = $sha256Matcher
facebookRealm.credentialsMatcher = $fbCredentialsMatcher


# User Query  
# default is "select password from users where username = ?"  
jdbcRealm.authenticationQuery = SELECT password, salt FROM User WHERE email = ?

# permissions  
jdbcRealm.permissionsLookupEnabled = true
jdbcRealm.userRolesQuery = select roleName from UserRole where email = ?
jdbcRealm.permissionsQuery = select permission from RolesPermission where roleName = ?

# Connection   
ds = com.mysql.jdbc.jdbc2.optional.MysqlDataSource
ds.serverName = localhost
ds.user = root
ds.password = root123
ds.databaseName = testdb
jdbcRealm.dataSource=$ds

#authc.usernameParam = email
#authc.passwordParam = password
#authc.failureKeyAttribute = shiroLoginFailure

# Use Built-in Chache Manager
builtInCacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $builtInCacheManager

#securityManager.realms = $facebookRealm,$jdbcRealm
securityManager.realms = $facebookRealm


# -----------------------------------------------------------------------------  
[urls]  
#/hello = authc
#/login = authc
#/admin.jsp = authc, perms["admin:access"]

Now when do i debug and reach at currentuser.login methods and go inside, it throws an exception saying Realm [FacebookRealm@52039826] does not support authentication token [FacebookToken@132d9844]. Please ensure that the appropriate Realm implementation is configured correctly or that the realm accepts AuthenticationTokens of this type.

Please suggest me whether am I doing correct, or not !! Am i missing any configuration or any thing else. Thank you !!


Solution

  • You should extend your FacebookRealm with the following method:

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof FacebookToken;
    }
    

    or add the following line to your ini:

    facebookRealm.authenticationTokenClass=<realpackage>.FacebookToken