Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAX-RS: Custom SecurityContext has unexpected type when injected into resource method

I have implemented a ContainerRequestFilter that performs JWT-based authentication:

@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        AuthenticationResult authResult = ...
        if (authResult.isSuccessful()) {
            // Client successfully authenticated.
            // Now update the security context to be the augmented security context that contains information read from the JWT.
            requestContext.setSecurityContext(new JwtSecurityContect(...));
        } else {
            // Client provided no or an invalid authentication token.
            // Deny request by sending a 401 response.
            requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
        }
    }
}

As you can see, I update the SecurityContext of the request, setting it to be an instance of my own custom implementation (JwtSecurityContext) if authentication succeeds. This implementation adds extra authentication and authorization data, which I would like to later access in my subsequent filter(s) and my resource methods.

I have also implemented an AuthorizationFilter that is invoked immediately after the AuthenticationFilter. Here, I can access the updated JwtSecurityContext just fine.

However, I am having problems when I try to inject the JwtSecurityContext into a resource (method).

I am currently using Jersey, and I've read the following in its documentation:

The SecurityContext can be directly retrieved from ContainerRequestContext via getSecurityContext() method. You can also replace the default SecurityContext in a request context with a custom one using the setSecurityContext(SecurityContext) method. If you set a custom SecurityContext instance in your ContainerRequestFilter, this security context instance will be used for injection into JAX-RS resource class fields. This way you can implement a custom authentication filter that may setup your own SecurityContext to be used. To ensure the early execution of your custom authentication request filter, set the filter priority to AUTHENTICATION using constants from Priorities. An early execution of you authentication filter will ensure that all other filters, resources, resource methods and sub-resource locators will execute with your custom SecurityContext instance.

I try to inject the JwtSecurityContext into a resource method like so:

@Path("/somepath")
public class SomeResource {
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<SomeItem> getItems(@Context SecurityContext securityContext) {
        // securityContext is of type 'SecurityContextInjectee'
    }
}

As the comment indicates, the runtime type of the securityContext variable becomes SecurityContextInjectee. From debugging, I've observed that this wraps a ContainerRequest which in turn wraps my JwtSecurityContext. However, there are no getters, and I do not want to use reflection to drill down this object hierarchy, so I don't know how to get a hold on my JwtSecurityContext.

I have tried changing @Context SecurityContext securityContext to @Context JwtSecurityContext jwtSecurityContext, but if I do this, the variable becomes null. I have also tried field injection, but this behaves the same way.

Am I heading down a wrong path? Should I not be accessing my custom SecurityContext in my resource method? One alternative could be to wrap all my data in the Principal implementation I return from getUserPrincipal in my JwtSecurityContext. I suppose the proxy (SecurityContextInjectee) would forward the call to its underlying JwtSecurityContext and hence return my Principal, but I am not sure, and ultimately I would prefer to use my JwtSecurityContext instead of wrapping these values in a Principal implementation.

like image 344
Janus Varmarken Avatar asked Sep 14 '16 10:09

Janus Varmarken


1 Answers

You can inject the ContainerRequestContext (as mentioned in this post) and just get the SecurityContext from there.

public List<SomeItem> getItems(@Context ContainerRequestContext context) {
    JwtSecurityContext sec = (JwtSecurityContext)context.getSecurityContext();
}
like image 171
Paul Samsotha Avatar answered Nov 18 '22 03:11

Paul Samsotha