package org.ros.chatto.security; import java.io.IOException; import java.time.Duration; import java.time.Instant; import java.util.ArrayList; import java.util.List; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.ros.chatto.logged.TokenCacheUtil; import org.ros.chatto.model.UserToken; import org.ros.chatto.service.UserTokenService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.token.Token; import org.springframework.security.core.token.TokenService; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; @Component public class TokenAuthenticationFilter extends OncePerRequestFilter { @Autowired private UserTokenService userTokenService; @Autowired private TokenService tokenService; private final Logger logger = LoggerFactory.getLogger(TokenAuthenticationFilter.class); private final int tokenTimeoutDuration; public TokenAuthenticationFilter(@Value("${chatto.token.timeout-duration}") String tokenTimeoutDuration) { // super(); this.tokenTimeoutDuration = Integer.parseInt(tokenTimeoutDuration); } private boolean isTokenExpired(UserToken userToken) { Duration duration = Duration.between(userToken.getCreationTime(), Instant.now()); long minutes = Math.abs(duration.toMinutes()); if (minutes > tokenTimeoutDuration) { return true; } return false; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { try { final String accessToken = request.getHeader("X-AUTH-TOKEN"); if (null != accessToken) { // get and check whether token is valid ( from DB or file wherever you are // storing the token) Token token = tokenService.verifyToken(accessToken); if (token == null) { throw new BadCredentialsException("Token not issued by us"); } UserToken userToken = userTokenService.getTokenByTokenString(accessToken); if (userToken == null) { throw new BadCredentialsException("Token not found"); } String userName = userToken.getUserName(); if (userName == null) { throw new BadCredentialsException("User not found"); } logger.info("Timeout duration = " + tokenTimeoutDuration); boolean isTokenExpired = isTokenExpired(userToken); logger.info(String.format("Token for %s is expired? %s", userToken.getUserName(), isTokenExpired)); if (!isTokenExpired) { userToken.setCreationTime(Instant.now()); userTokenService.saveToken(userToken); SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(userToken.getRole()); List updatedAuthorities = new ArrayList(); updatedAuthorities.add(simpleGrantedAuthority); final UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( userName, token.getKey(), updatedAuthorities); SecurityContextHolder.getContext().setAuthentication(authentication); } else { userTokenService.deleteToken(userToken.getUserName()); TokenCacheUtil.evictSingleTokenValue(userToken.getTokenContent()); response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE); response.setStatus(440); // response.sendError(440, "Token authentication error: Token has expired"); response.getWriter().write("Token authentication error: Token has expired"); logger.warn("Token authentication error: Token has expired"); // return; } } filterChain.doFilter(request, response); } catch (BadCredentialsException e) { response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE); response.setStatus(HttpServletResponse.SC_BAD_REQUEST); // response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage()); response.getWriter().write("Token authentication error"); logger.warn("Token authentication error: " + e.getMessage()); } } }