dermoritz
dermoritz

Reputation: 13038

Context injected SecurityContext is null

I have created a Javae EE app using JAX-RS 2.0 and JPA. I created a special provider of my User entity (using Qualifiers) to provide the current user (logged in) as entity from applications user database. To get current user i use

@Context
private SecurityContext secContext;

The problem is that this is null. The security is setup fine (Wildfly 8.2) - the app asks for Authentication (basic) but SecurityContext is null. Here is the code:

@RequestScoped
public class CurrentUserProducer implements Serializable {

    /**
     * Default
     */
    private static final long serialVersionUID = 1L;

    @Context
    private SecurityContext secContext;

    /**
     * Tries to find logged in user in user db (by name) and returns it. If not
     * found a new user with role {@link UserRole#USER} is created.
     * 
     * @return found user a new user with role user
     */
    @Produces
    @CurrentUser
    public User getCurrentUser() {
        if (secContext == null) {
            throw new IllegalStateException("Can't inject security context - security context is null.");
        //... code to retrieve or create new user
        return user;
    }

}

As you see I check secContext for null and i see my exception as soon as i try to reach a resource that injects @CurrentUser.

So how to fix this? Why is SecurityContext null.

Upvotes: 2

Views: 12144

Answers (2)

Paul Samsotha
Paul Samsotha

Reputation: 209092

As stated in my comment

SecurityContext is a JAX-RS component and can only be injected into other JAX-RS component. All you have is a CDI bean. You can try to make it an EJB and inject SessionContext. See Securing an Enterprise Bean Programmatically

Haven't tested but seems to work for the OP. This is a EE stack solution.

Another JAX-RS (Resteasy specific) way to allow for injection is with the help of the ResteasyProviderFactory (found with help from this answer). You could use this in a ContainerRequestFilter, which has access to the SecurityContext. We can use the RESTeasy utility class to push the User into the context. This allows for injection with the @Context annotation. Not sure how/if it would work with a custom annotation though. Here's an example

@Provider
public class UserContextFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext context) throws IOException {
        SecurityContext securityContext = context.getSecurityContext();
        String username = securityContext.getUserPrincipal().getName();

        ResteasyProviderFactory.pushContext(User.class, new User(username));
    }  
}

Note: this is a JAX-RS 2.0 solution (i.e. RESTeasy 3.x.x). Prior to 2.0, there is no ContainerRequestFilter

Upvotes: 2

dermoritz
dermoritz

Reputation: 13038

I found another way to get the class recognized by Jax-Rs: Implementing ContextResolver and annotating the class with provider.

To implement the interface i added:

@Override
public User getContext(Class<?> type) {
    if (type.equals(User.class)){
        return getCurrentUser();
    }
    return null;
}

I am not sure but probably with this i can do

@Context private User currentUser;

But i didn't try. But the injection via qualifier is working now (security context is injected).

Upvotes: 0

Related Questions