I have implemented shiro jwt token authentication using as reference  Shiro
json web token
<https://www.novatec-gmbh.de/en/blog/json-web-token-apache-shiro/>  .
Everything works fine besides that i have random disconnects with
SessionTimeOut Exception. Disconnects happen completely randomly. I might
have 3 disconnects in one Day or 1 Disconnect in one Week. The user logs in
with token authentication and token expiration of 1 Week period. However
while logged in suddenly and randomly gets logged out.

Has anyone faced a similar situation?
Can someone guide me where to look to isolate/find the problem?
Is my code correctly implemented?

Bellow is my code. To implement the functionality i have implemented one
*Realm* and one *Filter*.

I have tried to completely disable sessions completely using

*securityManager.subjectDAO.sessionStorageEvaluator.sessionStorageEnabled =
false*

in Shiro.ini but then Authentication Fails. No Subject Exists...

Any Example would be highly appreciated, shiro lacks of documentation...

*Shiro.ini File*

[main]
jwtg = gr.histopath.platform.lib.JWTGuard
jwtv =  gr.histopath.platform.lib.JWTVerifyingFilter

ds = com.mysql.cj.jdbc.MysqlDataSource
ds.serverName = 127.0.0.1
ds.port = 3306
ds.user = histopathUser
ds.password = H1s+0p@+h.U$er
ds.databaseName = histopath

jdbcRealm = gr.histopath.platform.lib.MyRealm
jdbcRealm.dataSource = $ds


credentialsMatcher =
org.apache.shiro.authc.credential.Sha512CredentialsMatcher
credentialsMatcher.hashIterations = 50000
credentialsMatcher.hashSalted = true
credentialsMatcher.storedCredentialsHexEncoded = false
jdbcRealm.credentialsMatcher = $credentialsMatcher

jdbcRealm.permissionsLookupEnabled = false

shiro.loginUrl = /authentication/login

#cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
cacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
securityManager.cacheManager = $cacheManager

sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager
securityManager.sessionManager.globalSessionTimeout = 172800000

# ssl.enabled = false

securityManager.realms = $jdbcRealm
[users]

[roles]

[urls]

/authentication/login = authc
# /authentication/logout = logout

/search/* = noSessionCreation, jwtv
/statistics/* = noSessionCreation, jwtv
/clinics/* = noSessionCreation, jwtv
/patients/* = noSessionCreation, jwtv
/incidents/* = noSessionCreation, jwtv
/doctors/* = noSessionCreation, jwtv

/users/new = noSessionCreation, anon
/users/details/* = noSessionCreation, anon
/users/* = noSessionCreation, jwtv

/* = anon

*MyRealm.java*

public class  MyRealm extends JdbcRealm {

    private UserDAO userDAO;
    private User user;
    private String password;
    private ByteSource salt;
    private static final Logger logger =
LoggerFactory.getLogger(MyRealm.class);


    public MyRealm() {
        this.userDAO = new UserDAO();
        setSaltStyle(SaltStyle.COLUMN);
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken
token) throws AuthenticationException {
        // identify account to log to
        UsernamePasswordToken userPassToken = (UsernamePasswordToken) token;
        String username = userPassToken.getUsername();

        logger.debug("GMOTO: " + userPassToken.getUsername());

        if (username.equals(null)) {
            logger.debug("Username is null.");
            return null;
        }

        // read password hash and salt from db
//        System.out.println("Username: " + username);

        if(!userDAO.isOpen()){
            userDAO = new UserDAO();
        }

        this.user = userDAO.getByUsername(username);
        this.userDAO.closeEntityManager();
        logger.debug("user's email: " + this.user.getUsername());

        if (this.user == null) {
            logger.debug("No account found for user [" + username + "]");
            return null;
        }
        this.password = this.user.getPassword();
        this.salt =
ByteSource.Util.bytes(Base64.decode(this.user.getSalt()));

        SaltedAuthenticationInfo info = new SimpleAuthenticationInfo(user,
password, salt, getName());

        return info;
    }

}

*JWTVerigyingFilter.java*


public class JWTVerifyingFilter extends AccessControlFilter {

    private static final Logger logger =
LoggerFactory.getLogger(JWTVerifyingFilter.class);

    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest,
ServletResponse servletResponse, Object o) {
        logger.debug("Verifying Filter Execution");

        HttpServletRequest httpRequest = (HttpServletRequest)
servletRequest;
        String jwt = httpRequest.getHeader("Authorization");

        if (jwt == null || !jwt.startsWith("Bearer ")) {
//            System.out.println("DEn  Brika Tipota: ");
            logger.debug("No Token Found...");
//           
servletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
        logger.debug("JWT Found");
        logger.debug("JWT Content: " + jwt);
        jwt = jwt.substring(jwt.indexOf(" "));
        Subject subject = SecurityUtils.getSubject();
        logger.debug("SecurityUtils Subject: " + subject.getPrincipal());

//        System.out.println("Token Found");
//        System.out.println("JWT: " + jwt);
//        System.out.println("Authenticated? " + subject.isAuthenticated());
//        System.out.println(" session " + subject.getSession().getId());
//        System.out.println(" salt " + ((User)
subject.getPrincipal()).getSalt());
//        System.out.println(" who-is " + ((User)
subject.getPrincipal()).getUsername());

        User user = null;
        logger.debug("Is Subject Authenticated: " +
subject.isAuthenticated());
        if (subject.isAuthenticated()) {

            user = (User) subject.getPrincipal();
            String username = null;

            try {
                Jws<Claims> claimsJws = Jwts.parser()
                       
.setSigningKey(DatatypeConverter.parseBase64Binary(user.getSalt()))
                        .parseClaimsJws(jwt);

//                System.out.println("Claims: " + claimsJws);
                logger.debug("Expiration: " +
claimsJws.getBody().getExpiration());
                username = claimsJws.getBody().getSubject();
            } catch (ExpiredJwtException expiredException) {
                logger.error("Token Is Expired....");
                logger.error(expiredException.getMessage(),
expiredException);
//                System.out.println("Token IS Expired.....");
//                expiredException.printStackTrace();
                logger.debug("Logging out the user...");
//                System.out.println("Logging out the user...");
                SecurityUtils.getSubject().logout();
//                System.out.println("mmmnnnnn: " +
SecurityUtils.getSubject().isAuthenticated());
                return false;
//                throw expiredException;
            } catch (SignatureException signatureException) {
                logger.error(signatureException.getMessage(),
signatureException);
//                signatureException.printStackTrace();
                return false;
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
//                e.printStackTrace();
                return false;
            }
            System.out.println("Subject: " + user.getUsername());

            return username.equals(user.getUsername());

        }
//        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        return false;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest,
ServletResponse servletResponse) {
        HttpServletResponse response = (HttpServletResponse)
servletResponse;
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        return false;
    }
}

I have also posted the question in stack overflow  Question
<https://stackoverflow.com/questions/56576654/apache-shiro-jwt-token-authentication-random-disconnects-problem-with-sessiontim>
  



--
Sent from: http://shiro-user.582556.n2.nabble.com/

Reply via email to