@RolesAllowed cannot be resolved with Jersey

2019-06-14 09:23发布

I am using JAX-RS using jersey implementation. I am trying to authenticate my service using BASIC authentication using Tomcat 6.

This is the code:

@Path("/authenticate")
@RolesAllowed({"Admin","Guest"})
public class BasicAuthenticationSecurity {

@GET
@Path("/wbiPing")
@Produces(MediaType.TEXT_PLAIN) 
@RolesAllowed("Admin")
public Response wbiPing(){

System.out.println("Pinged!!!");
return Response.ok("Pinged!!!").build();
}

}

When I try to annotate my method using @RolesAllows, I am getting an compilation error:

@RolesAllows cannot be resolved to a type

Please let me know how to resolve this? Any specific jars/API required for this?

EDIT:

web.xml

<servlet>
    <servlet-name>jersey-serlvet</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>
            com.security;
            com.exception
        </param-value>
    </init-param>       
    <init-param>
        <param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>
        <param-value>com.sun.jersey.api.container.filter.RolesAllowedResourceFilterFactory</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>jersey-serlvet</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

<security-constraint>      
  <web-resource-collection>
      <web-resource-name>BasicDemo</web-resource-name>          
      <url-pattern>/*</url-pattern>
      <http-method>GET</http-method>
  </web-resource-collection>
  <auth-constraint>
      <role-name>Admin</role-name>
  </auth-constraint>
</security-constraint>
  <login-config>
  <auth-method>BASIC</auth-method>
  <!-- The realm name is typically displayed by the browser in the login dialog box. -->
  <realm-name>Login</realm-name>      
  </login-config>

Please let me know about the issue.

5条回答
【Aperson】
2楼-- · 2019-06-14 09:57

Finally made it work!

Here are the steps to make it work in Tomcat and Jersey.

Let's assume we have the following contents in TOMCAT_HOME/conf/tomcat-users.xml, where we define 2 roles - editor and member.

We also define three users - gavin, julie, and admin.

<?xml version="1.0" encoding="UTF-8"?>
  <role rolename="editor"/>
  <role rolename="member"/>

  <user username="admin" password="qwerty" roles="editor,member"/>
  <user username="gavin" password="qwerty" roles="editor"/>
  <user username="julie" password="qwerty" roles="member"/>
</tomcat-users>

Step 1. Make sure you use Servlet 3.0 spec in web.xml

Security annotations do not work with Servlet 2.5 and below.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">

</web-app>

Step 2. Create your Application Class to enable Security Annotations

NOTE: The code below is specific to Jersey.

package ph.activelearning.rest.security;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;

public class MyApplication extends ResourceConfig {
    public MyApplication() {
        super(TestResource.class);
        register(RolesAllowedDynamicFeature.class);
    }
}

Step 3. Specify your Application Class in web.xml

Make sure that the Application class you created in Step 2 is recognized by Jersey.

<servlet>
    <servlet-name>Jersey Web Application</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>ph.activelearning.rest.security</param-value>
    </init-param>

    <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <param-value>ph.activelearning.rest.security.MyApplication</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

Step 4. Create security-constraint in web.xml

Ironically, even though we want to use security annotations, we still need to define a security constraint in web.xml.

In the example below, we try to secure access to /test/*. It's important that you don't specify any HTTP methods. (ex. <http-method>GET</http-method>) This means that you're denying access to all HTTP methods.

Still, you need to define all roles that can have access to the URL regardless of the method, through the <auth-constraint> element.

<web-app …>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>test</web-resource-name>
            <url-pattern>/test/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>editor</role-name>
            <role-name>member</role-name>
        </auth-constraint>
    </security-constraint>
</web-app>

Step 5. Specify authentication method in web.xml

The example below illustrates BASIC authentication.

<web-app …>
    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>test</realm-name>
    </login-config>
</web-app>

Step 6. Define Security Roles

The security roles should correspond to the same roles defined in tomcat-users.xml. In this example, we define the roles editor and member.

NOTE: It seems that this step is optional since authentication / authorization still works even without it.

<web-app ...>
    <security-role>
         <description>This is editor</description>
         <role-name>editor</role-name>
    </security-role>

     <security-role>
         <description>This is member</description>
         <role-name>member</role-name>
    </security-role>
</web-app>

Step 7. Annotate your resources

package ph.activelearning.rest.security;

import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.SecurityContext;

@Path("test")
@PermitAll
public class TestResource {

    @GET
    @Path("editor")
    @Produces(MediaType.TEXT_PLAIN)
    @RolesAllowed("editor")
    public String editorOnly() {
        return "Got to editor path!";
    }

    @GET
    @Path("member")
    @Produces(MediaType.TEXT_PLAIN)
    @RolesAllowed("member")
    public String memberOnly() {
        return "Got to member path!";
    }

    @GET 
    @Path("open")
    @Produces(MediaType.TEXT_PLAIN)
    public String open(@Context SecurityContext context) {
        return "Open to all! - " + context.getUserPrincipal().getName();
    }
}

That's it. Here's the complete web.xml for your programming pleasure.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">
    <servlet>
        <servlet-name>Jersey Web Application</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>ph.activelearning.rest.security</param-value>
        </init-param>

        <!-- Define the Application class where we enable security annotations -->
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>ph.activelearning.rest.security.MyApplication</param-value>
        </init-param>

        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey Web Application</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

    <!-- Required even though we use annotations -->
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>test</web-resource-name>
            <url-pattern>/test/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>editor</role-name>
            <role-name>member</role-name>
        </auth-constraint>
    </security-constraint>

    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>test</realm-name>
    </login-config>

    <!-- Optional: Define security roles that are defined in your app server -->
    <!--  
    <security-role>
        <description>This is editor</description>
        <role-name>editor</role-name>
    </security-role>

    <security-role>
        <description>This is member</description>
        <role-name>member</role-name>
    </security-role>
    -->

</web-app>
查看更多
放我归山
3楼-- · 2019-06-14 10:13

I don't know any java library that declare @RolesAllows. The Java6 EE API docs declare only 5 annotations to security use.

@DeclareRoles
@DenyAll
@PermitAll
@RolesAllowed
@RunAs

If you are trying to override the class roles, you cant simply put @RolesAllowed in your method, just like you did, I'm sure that will work.

查看更多
Deceive 欺骗
4楼-- · 2019-06-14 10:17

I struggled with a similar issue for hours before one line from this IBM article opened my eyes. Surprisingly, not a single book or user guide mentions this critical fact, without which, authentication can't succeed.

When using annotation-based security, web.xml is not optional; quite on the contrary, <security-constraint> element must be present; the web container checks for security before JAX-RS does and without a <security-constraint>, the proper security context is not set. Thus when JAX-RS invokes isUserInRole(role), it always returns false.

In addition, either <security-role> element(s) in web.xml or @DeclareRoles annotation must be present.

Lastly, if using Jersey, RolesAllowedDynamicFeature needs to be registered in the Application class to enable annotation-based security.

HTH others who struggle with the pathetic documentation, or lack of it, thereof, that's out there.

查看更多
来,给爷笑一个
5楼-- · 2019-06-14 10:19

Do you have the import in your code?

import javax.annotation.security.RolesAllowed;

Also make sure annotations-api.jar is in your classpath. The jar can be found at Tomcat installation lib folder.

查看更多
放我归山
6楼-- · 2019-06-14 10:20

I think you should add the jsr250-api-1.0.jar. If you use Maven you can add this:

    <dependency>
        <!-- Annotations for role management -->
        <groupId>javax.annotation</groupId>
        <artifactId>jsr250-api</artifactId>
        <version>1.0</version>
    </dependency>
查看更多
登录 后发表回答