2

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.

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
dermoritz
  • 12,519
  • 25
  • 97
  • 185

2 Answers2

2

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

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • i am trying to strictly rely on Java EE standards. But as i said with implementing "ContextResolver" it is working fine. – dermoritz Jun 03 '15 at 08:55
0

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).

dermoritz
  • 12,519
  • 25
  • 97
  • 185
  • Interesting solution. I've never thought of doing this. Have you tried this injection of `User` to see it it works? – Paul Samsotha Jun 03 '15 at 09:00
  • no i didn't tried yet - i would have to refactor seome code (including tests). But at least all Context stuff will be injected in a class annotated with @Provider (need to implement some jax-rs interface) – dermoritz Jun 03 '15 at 11:37