1

I have following jax-rs Restful API which works fine if I won't add following Annotation line

@RolesAllowed("AdminRole")

above GET Annotation

package service;

import entities.Booking;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.annotation.security.DeclareRoles;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;


@PermitAll
@Stateless
@Path("entities.booking")
public class BookingFacadeREST extends AbstractFacade<Booking> {
    @PersistenceContext(unitName = "ofserverDBPU")

    private EntityManager em;

    public BookingFacadeREST() {
        super(Booking.class);
    }

    @POST
    @Override
    @Consumes({"application/xml", "application/json"})
    public void create(Booking entity) {
        super.create(entity);
    }

    @PUT
    @Override
    @Consumes({"application/xml", "application/json"})
    public void edit(Booking entity) {
        super.edit(entity);
    }

    @DELETE
    @Path("{id}")
    public void remove(@PathParam("id") Integer id) {
        super.remove(super.find(id));
    }

    @GET
    @Path("{id}")
    @Produces({"application/xml", "application/json"})
    public Booking find(@PathParam("id") Integer id) {
        return super.find(id);
    }

    @RolesAllowed("AdminRole")
    @GET
    @Override
    @Produces({"application/xml", "application/json"})        
    public List<Booking> findAll() {
        return super.findAll();
    }

    @GET
    @Path("{from}/{to}")
    @Produces({"application/xml", "application/json"})
    public List<Booking> findRange(@PathParam("from") Integer from, @PathParam("to") Integer to) {
        return super.findRange(new int[]{from, to});
    }

    @GET
    @Path("count")
    @Produces("text/plain")
    public String countREST() {
        return String.valueOf(super.count());
    }

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

}

By placing above annotation gives following error.

HTTP Status 500 - Internal Server Error

type Exception report

messageInternal Server Error

descriptionThe server encountered an internal error that prevented it from fulfilling this request.

exception

javax.servlet.ServletException: javax.ejb.EJBAccessException
root cause

javax.ejb.EJBAccessException
root cause

javax.ejb.AccessLocalException: Client not authorized for this invocation
note The full stack traces of the exception and its root causes are available in the GlassFish Server Open Source Edition 4.0 logs.

GlassFish Server Open Source Edition 4.0

Where am I doing wrong?

Developer
  • 25,073
  • 20
  • 81
  • 128
  • I am using localhost http://localhost:8080/ofserverDB/webresources/entities.booking without RoleAllow Annotation it returns xml file from db. which is correct. but with annotation, it suppose to ask basic Authentication to verify username and password, rather it return exception. – Developer Nov 08 '13 at 16:13
  • I have done configuration in web.xml and glassfish-web.xml and test them on Basic Web Application and those worked fine for http basic authentication. So I don't think there is something wrong in those file. I must be missing something(i.e. annotation) in java services file – Developer Nov 08 '13 at 16:16
  • Hello @Developer, I realize that your question is almost a year old, but I have a similar issue, can't seem to get the RolesAllowed annotation to work.. Could you tell me if you found a solution to your problem? – PJvG Sep 15 '14 at 12:58

1 Answers1

0

It is a bit old, but I still have the same problem (note that I also have a custom SecurityContext. After wandering around a while, I finally made it work by writing my own "@RolesAllowed annotation.

Here is how I proceeded:

First, create a new annotation:

@NameBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Secured {
    String role() default "all";
}

Then, use a ContainerRequestFilter running at the authentication phase and checking the permissions:

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

    @Context
    private ResourceInfo resourceInfo;

     @Override
     public void filter(ContainerRequestContext crc) throws IOException {
         // get annotation (only for secured method)
        Secured security = resourceInfo.getResourceMethod().getAnnotation(Secured.class);
        if(security == null){
            // no security on method: check the class 
            security = resourceInfo.getResourceClass().getAnnotation(Secured.class);
            if(security == null) return;
        }

        // check the security, for example through the header:
        //   crc.getHeaderString("token") 
        // You can also inject a PersistenceContext and query your db

        // if the security check fails, use crc.abort() method
        // else, set the security context
        crc.setSecurityContext(new AppSecurityContext(userId, security.role()));
     }
 }

This filter must be registered either through web.xml or using the register method in your Application constructor.

For the AppSecurityContext, have a look at this tutorial . It can be accessed later in your service with:

@Context
SecurityContext sctx;

Finally, annotate either your class or your method (or both), with @Secure(role = "somerole").

Derlin
  • 9,572
  • 2
  • 32
  • 53