Skip to content
This repository was archived by the owner on May 31, 2022. It is now read-only.
This repository was archived by the owner on May 31, 2022. It is now read-only.

[SECOAUTH-432] Support automatically destroying session on OAuth2 authorization server as soon as user redirected to client app #140

@dsyer

Description

@dsyer

Priority: Minor
Original Assignee: Dave Syer
Reporter: Harleen Sahni
Created At: Wed, 18 Dec 2013 02:41:26 +0000
Last Updated on Jira: Mon, 30 Dec 2013 14:52:48 +0000

It'd be a nice feature to only maintain the session on the authorization server as long the user is granting approval to an oauth2 client, and no longer. This is useful for when your authorization server's sole role is for authorizing oauth2 clients, and nothing else. In this case, a longer lived session has no real value.

Also, if an oauth2 client wants to switch users for oauth2 access, it can't do so easily today. As long as the user's session is alive on the authorization server what will happen is as the client sends the user to /oauth/authorize, the client will be using the user's old session, and the client will be auto approved since it has a current access token for that user.

This feature should be configurable.

Currently I've accomplished this with use of aspects:

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;

@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();
        }
    }

}

Comments:

david_syer on Mon, 30 Dec 2013 10:57:23 +0000

I'm not really sure what the use case is for a "client switching users". Maybe you could be a bit more specific about that?

In any case I would prefer not to have explicit HttpSession-specific code in Spring OAuth if we can avoid it. A short session timeout in the server is definitely a good idea, but that's better left to the server setup.

If the client is a webapp (I think that's the only scenario that makes sense in your description), then the user's session will be tied to their browser, and they can control sessions by logging out and logging back in again (as long as the server provides that feature, which isn't really anything to do with OAuth)?

harleen on Mon, 30 Dec 2013 14:52:48 +0000

A short lived session on the authorization server would help accomplish about the same thing, but not as effectively.

When talking about the client that's being authorized for oauth2 access, it's true that the session on that client is tied to the browser. We do provide a logout out of the client session. However, in our case, the client's sole means of authenticating the user is via being redirected to login to the oauth2 authorization server, and be redirected back the client web app. The client has no user store of its own and no login of its own. So when the the client web app logs out of it's session, the user is asked to log back in by being redirected to the authorization server to login again. If the authorization server's session is still active, the user would be automatically logged back in. This isn't desirable for us, and that's why we're killing the authorization server's session immediately after authorization.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions