سؤال

I'm using Jersey (1.18.1) with RolesAllowedResourceFilterFactory enabled. Suppose that I have the following resource:

@RolesAllowed("SuperUser")
@Path("/resource")
class Resource{
  //some code here
}

On access to this resource when the session has timed out the server throws a WebApplicationException with no message whatsoever, but it also does this if a user without the necessary role tries to access the given resource. So: How can I differentiate between the session timeout and the lack of the necessary role ?

I need to do that because I want to send an appropriate message (from an ExceptionMapper) to the frontend and take appropriate measures there.

هل كانت مفيدة؟

المحلول 2

I've solved the problem by injecting the SecurityContext into the ExceptionMapper and checking if the the user has any roles assigned. If it has and the webAppException.getResponse().getStatus() status code is equal to FORBIDDEN(403) then the cause of the exception is lack of authorization (the user doesn't have the necessary role). If the user doesn't have any assigned roles and again the status code of the response is 403 - it means that the session has expired, else something else is the cause of the exception.

This approach has one big downside - it requires all users to have at least one assigned role else it won't work;

نصائح أخرى

I don't think there is a build in way to do this because then the container needed to remember expired sessionIds and their associated users. As far as I know the container will just delete this information on session-timeout. But you could try to do this on your own:

Implement a HttpSessionListener and store expired SessionIDs in some kind of cache. Most likely you want to show this "your session expired" message only to authorized users but a HTTP-Session may also be created for non-authorized users. So you need to check if the user was authorized. As you don't have access to the UserPrincipal in the SessionListener you need to store some information in the session on your own.

@WebListener
public class HttpSessionChecker implements HttpSessionListener {

    @Inject
    private SessionIdCache cache;

    public void sessionCreated(HttpSessionEvent event) {}

    public void sessionDestroyed(HttpSessionEvent event) {
        if (event.getSession().getAttribute("someAuthInformation") != null) { // whatever you've stored
            cache.put(event.getSession().getId(), new Date());
        }
    }

}

In Your ExceptionMapper you can now check if a JSESSIONID-Cookie was part of the request-headers and if the passed sessionID is found in your cache.

@Provider
public class ExMapper implements ExceptionMapper<Exception> { 

    @Inject
    private SessionIdCache cache;

    @Context 
    private HttpServletRequest request;

    @Override 
    public Response toResponse(Exception ex) { 
        for (Cookie cookie : request.getCookies()) {
            if ("JSESSIONID".equals(cookie.getName())) {
                String sessionId = cookie.getValue().substring(0, cookie.getValue().lastIndexOf('.')); // ignore .hostname
                if (cache.contains(sessionId)) {
                    return Response.serverError().entity("Your session timed out").build();
                }
            }
        }
        return Response.serverError().build();
    } 

}

You should think of cleaning up your cache from time to time.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top