Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring security OAuth2 - invalidate session after authentication

We are securing out REST services using spring security OAuth2. Applications can call into either the /oauth/authorize, /oauth/token or /rest-api endpoints. The token and rest-api endpoints are stateless and do not need a session.

Can we invalidate the session after the user is authenticated? If so, what is the best approach. We want the user to sign-in always whenever a call to /oauth/authorize is made. Currently, calls to /oauth/authorize are skipping authentication whenever a session exists.

like image 336
mpusarla Avatar asked Oct 08 '15 03:10

mpusarla


2 Answers

Understanding that the question is a bit old, I hope that the following could be helpful for those who search for the correct answer for the question

OP asked not about tokens invalidation, but how to invalidate httpSession on Spring OAuth2 server right after user authentication successfully passed and a valid access_token or authorization_code (for subsequent getting of access_token) returned to a client.

There is no out-of-the-box solution for this use-case still. But working workaround from the most active contributor of spring-security-oauth, Dave Syer, could be found here on GitHub

Just copy of the code from there:

@Service
@Aspect
public class SessionInvalidationOauth2GrantAspect {

    private static final String FORWARD_OAUTH_CONFIRM_ACCESS = "forward:/oauth/confirm_access";
    private static final Logger logger = Logger.getLogger(SessionInvalidationOauth2GrantAspect.class);

    @AfterReturning(value = "within(org.springframework.security.oauth2.provider.endpoint..*) && @annotation(org.springframework.web.bind.annotation.RequestMapping)", returning = "result")
    public void authorizationAdvice(JoinPoint joinpoint, ModelAndView result) throws Throwable {

        // If we're not going to the confirm_access page, it means approval has been skipped due to existing access
        // token or something else and they'll be being sent back to app. Time to end session.
        if (!FORWARD_OAUTH_CONFIRM_ACCESS.equals(result.getViewName())) {
            invalidateSession();
        }
    }

    @AfterReturning(value = "within(org.springframework.security.oauth2.provider.endpoint..*) && @annotation(org.springframework.web.bind.annotation.RequestMapping)", returning = "result")
    public void authorizationAdvice(JoinPoint joinpoint, View result) throws Throwable {
        // Anything returning a view and not a ModelView is going to be redirecting outside of the app (I think). 
        // This happens after the authorize approve / deny page with the POST to /oauth/authorize. This is the time
        // to kill the session since they'll be being sent back to the requesting app.
        invalidateSession();
    }

    @AfterThrowing(value = "within(org.springframework.security.oauth2.provider.endpoint..*) &&  @annotation(org.springframework.web.bind.annotation.RequestMapping)", throwing = "error")
    public void authorizationErrorAdvice(JoinPoint joinpoint) throws Throwable {
        invalidateSession();
    }

    private void invalidateSession() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                .getRequest();
        HttpSession session = request.getSession(false);
        if (session != null) {
            logger.warn(String.format("As part of OAuth application grant processing, invalidating session for request %s", request.getRequestURI()));

            session.invalidate();
            SecurityContextHolder.clearContext();
        }
    }

}

add pom.xml

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
</dependency>

Another solution could be to set session time out to some very small value. The simplest way to achieve that is put the following to application.yml config:

server:
  session:
    timeout: 1

But it's not ideal solution as the minimum value could be provider is 1 (zero is reserved for infinite sessions) and it is in minutes not in seconds

like image 111
AlexK Avatar answered Nov 03 '22 06:11

AlexK


From what I understand, you are trying to programmatically logout after you have undertaken certain set of actions. Probably you should look into the SecurityContextLogoutHandler and see how it works. There is a method for logout there. I think calling it as an advice will solve your problem.

public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
      Assert.notNull(request, "HttpServletRequest required");
      if (invalidateHttpSession) {
          HttpSession session = request.getSession(false);
          if (session != null) {
              session.invalidate();
          }
      }

      SecurityContextHolder.clearContext();
  }
like image 2
de_xtr Avatar answered Nov 03 '22 08:11

de_xtr