Search code examples
javahibernateangularauthenticationshiro

Java hibernate with Apache Shiro login authentication returning false after "successfully" logging in


I'm using Java Hibernate with Apache Shiro for user login and authentication. I use this code to authenticate the user and it works as intended (as far as I can tell).

 try {
        AuthenticationToken token = new UsernamePasswordToken(user.getUsername().toUpperCase(), user.getPassword());


        Subject currentUser = SecurityUtils.getSubject();

        Session session = currentUser.getSession();
        session.setAttribute( "username", user.getUsername());
        System.out.println("USER: " + session.getAttribute("username"));

        currentUser.login(token);

        System.out.println( "User [" + currentUser.getPrincipal() + "] logged in successfully." );
        System.out.println( "Is user authenticated? " + currentUser.isAuthenticated());
    }
    catch (ExcessiveAttemptsException eae ) { 
         eae.getStackTrace();
         eae.printStackTrace();
    } 
    catch (AuthenticationException e) {
        throw new ForbiddenException();
    }

This works if the correct credentials are provided or return forbidden exception if they're incorrect.

After I use another method to check if the user is authorised, But it ALWAYS returns false (when it should be true). I'm not sure what's causing this.

   try {
        Subject currentUser = SecurityUtils.getSubject();

        return SecurityUtils.getSubject().isAuthenticated();

    } catch (AuthenticationException e) {
        throw new ForbiddenException();
    }

The currentUser is null when checking in debug mode.

I can also use another approach but it returns a nullPointerException in the second line.

try {

        sessionFactory.getCurrentSession().getTransaction().begin();

        User user = userDAO.find(securityContext.getUserPrincipal().getName());

        if (user == null) {
            sessionFactory.getCurrentSession().getTransaction().rollback();
            throw new NotFoundException();
        }

        UserModel result = new UserModel(user);

        sessionFactory.getCurrentSession().getTransaction().commit();

        return result;
}
    } catch (HibernateException e) {
        e.printStackTrace();
        sessionFactory.getCurrentSession().getTransaction().rollback();
    }
    return null;

I use shiro.ini to connect to a local database.
[Update] I've added a debug login filter that can log in automatically when it's enabled (using a Servlet) and it works as intended.

I've added a URL section and it works when I use authcBasic but not when I use authc in Shiro. I can check by calling the method isAuthenticated() or getCurrentUser(). Using authcBasic returns all the correct information but authc returns false/null. I also cannot logout when using authcBasic unless I clean the web browser. The method SecurityUtils.getSubject().logout(); sets the isAuthenticated boolean to false (when I debug) but doesn't seem to have any actual effect on the session.

# =======================
# Shiro INI configuration
# =======================

[main]
# Debug filter to automatically login
debugLogin = util.DebugLoginFilter
debugLogin.enabled = false
debugLogin.username = ADMIN
debugLogin.password = ADMIN

jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.authenticationQuery = select password from user where username = ?
jdbcRealm.userRolesQuery = select role from user_role INNER JOIN user ON     user_role.id = user.user_role_id where user.username = ?

# Datasource for the jdbc realm
ds = com.mysql.jdbc.jdbc2.optional.MysqlDataSource
ds.serverName = localhost
ds.user = root
ds.databaseName = database
jdbcRealm.dataSource = $ds

authc.usernameParam = username
authc.passwordParam = password
authc.failureKeyAttribute = shiroLoginFailure

sha256Matcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
jdbcRealm.credentialsMatcher = $sha256Matcher

[roles]
admin = *

[urls]
/ = debugLogin, authcBasic
/index.html = debugLogin, authcBasic
/api/login = anon
/api/login/me = authcBasic
/api/login/logout = authcBasic
/api/** = debugLogin, authcBasic

My pom.xml

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-web</artifactId>
    <version>1.3.2</version>
</dependency>

My web.xml

<listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

Apologies if I made any mistakes, I'm new here! Any help would be greatly appreciated.

Edit: This message displays in the console when running the Apache server:

[localhost-startStop-1] INFO org.apache.shiro.config.IniSecurityManagerFactory - Realms have been explicitly set on the SecurityManager instance - auto-setting of realms will not occur.

Solution

  • I have found a solution. The problem was not the code but rather the approach I used.

    I'm using Angular 2 for the front-end and Java Hibernate for the back-end. Shiro cannot communicate with the front-end because it's in a different directory. But it works as it should after building the angular app and copying the dist content into the WebContent in the back-end.

    I will use the debug login filter to manually login when I'm developing (then disable it in Shiro once it's ready for production).

    I will keep the code snippets in case someone else has this problem.