gb.
gb.

Reputation: 190

WebSphere Liberty JSR-250 implementation (RolesAllowed)

In order to use the security annotations of JSR-250 (RolesAllowed, PermitAll, DenyAll):

Both of these rely on the implementation of SecurityContext.isUserInRole(), but it seems that WebSphere Liberty Profile does not.

How do we get this to work in WebSphere Liberty Profile (WLP)?

I used a minimal example:

  1. Create a resource class/method with @RolesAllowed:

    @Path("/rest")
    public class HelloWorld {
        @GET
        @RolesAllowed("ANYTHING")
        public Response hello() {
            return Response.ok("Hello World").build();
        }
    }
    
  2. Set your SecurityContextImpl in a filter, overriding isUserInRole() to always returns true;
  3. Enable "role-based security" for the JAX-RS implementation. (Jersey or RESTeasy, etc as above. For WLP, I had to add the appSecurity-2.0 feature)
  4. And you should have a working example.

However, it appears that WebSphere Liberty Profile returns 403 Forbidden even though isUserInRole returns true.

Does anyone know how to properly use the @RolesAllowed annotation in Liberty and what I might be missing?

Code

@ApplicationPath("/")
public class MyApplication extends Application {
    public MyApplication() {}
}

@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthFilter implements ContainerRequestFilter {
    @Override
    public void filter(ContainerRequestContext ctx) throws IOException {
        System.out.println("Setting SecurityContext..");
        ctx.setSecurityContext(new MySecurityContext("someuser", "anyrole"));
    }
}

public class MySecurityContext implements SecurityContext {

    private String user;
    private String role;

    public static class MyPrincipal implements Principal {
        private String name;

        public MyPrincipal(String name) { this.name = name; }
        @Override public String getName() { return name; }
    }

    public MySecurityContext(String user, String role) {
        this.user = user;
        this.role = role;
    }

    @Override public String getAuthenticationScheme() { return "BASIC"; }
    @Override public Principal getUserPrincipal() { return new MyPrincipal(user); }
    @Override public boolean isSecure() { return true; }

    @Override
    public boolean isUserInRole(String role) {
        return true;
    }
}

@Path("/test")
public class HelloWorld {
    @GET
    @RolesAllowed("doesntmatter")
    public Response hello() {
        return Response.ok("Hello World").build();
    }
}

pom.xml (dependencies only)

<dependencies>
    <dependency>
        <groupId>javax.ws.rs</groupId>
        <artifactId>javax.ws.rs-api</artifactId>
        <version>2.0.1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.annotation</groupId>
        <artifactId>javax.annotation-api</artifactId>
        <version>1.2</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

server.xml

Code works with the appSecurity feature disabled. Does not work with it enabled.

<server description="test">
    <featureManager>
        <feature>jaxrs-2.0</feature>
        <feature>localConnector-1.0</feature>
        <!--  <feature>appSecurity-2.0</feature> -->
    </featureManager>

    <webApplication id="RoleTest" location="RoleTest.war" name="RoleTest"/>
    <httpEndpoint httpPort="9081" httpsPort="9444" id="defaultHttpEndpoint"/>

    <!-- below lines are required when appSecurity feature is loaded -->
    <!--  
    <keyStore id="defaultKeyStore" password="{xor}Lz4sLCgwLTtu"/>
    <basicRegistry id="basic" realm="BasicRegistry"> 
        <user name="username" password="password" />
    </basicRegistry>
    -->
</server>

Upvotes: 2

Views: 1253

Answers (1)

Qian Du
Qian Du

Reputation: 11

May be you can try this:

1 server.xml

<server description="test">
    <featureManager>
        <feature>jaxrs-2.0</feature>
        <feature>appSecurity-2.0</feature>
    </featureManager>

    <webApplication id="RoleTest" location="RoleTest.war" name="RoleTest">
        <application-bnd>
            <security-role name="ANYTHING">
                <user name="username" />
            </security-role>
            <security-role name="AuthenticationRole">
                <user name="username" />
            </security-role>
            <security-role name="AllAuthenticated">
                <special-subject type="ALL_AUTHENTICATED_USERS" />
            </security-role>
        </application-bnd>
    </webApplication>

    <httpEndpoint httpPort="9081" httpsPort="9444" id="defaultHttpEndpoint" />

    <basicRegistry id="basic" realm="BasicRegistry">
        <user name="username" password="password" />
    </basicRegistry>
</server>

2 Java Code Create a MyApplication class and a resource class/method with @RolesAllowed:

@ApplicationPath("/")
public class MyApplication extends Application {
    public MyApplication() {}
    public Set<Class<?>> getClasses(){
      Set<Class<?>> classes = new HashSet();
      classes.add(HelloWorld.class);

      return classes;
   }
}


@Path("/rest")
public class HelloWorld {
    @GET
    @RolesAllowed("ANYTHING")
    public Response hello() {
        return Response.ok("Hello World").build();
    }
}

3 web.xml

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

  <display-name>Test Application</display-name>
  <description>blablabla</description>

    <servlet>
        <servlet-name>MyApplication</servlet-name>
        <servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
        <init-param>
            <param-name>requestProcessorAttribute</param-name>
            <param-value>requestProcessorAttribute_webcontainer</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet>
        <servlet-name>com.xxx.MyApplication</servlet-name>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>SecurityContextApp</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>com.xxx.MyApplication</servlet-name>
        <url-pattern>/xxx/*</url-pattern>
    </servlet-mapping>


    <security-constraint id="SecurityConstraint_2">
        <web-resource-collection id="WebResourceCollection_2">
            <web-resource-name>com.xxx.MyApplication
            </web-resource-name>
            <description>Protection area for Rest Servlet</description>
            <url-pattern>/xxx/rest</url-pattern>
            <http-method>GET</http-method>
            <http-method>POST</http-method>
        </web-resource-collection>
        <user-data-constraint id="UserDataConstraint_2">
            <transport-guarantee>NONE</transport-guarantee>
        </user-data-constraint>
        <auth-constraint id="AuthConstraint_2">
            <role-name>AuthenticationRole</role-name>
        </auth-constraint>
    </security-constraint>    


    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>test</realm-name>
    </login-config>
    <security-role id="SecurityRole_1">
        <description>blabla</description>
        <role-name>ANYTHING</role-name>
    </security-role>

    <security-role id="SecurityRole_2">
        <role-name>AuthenticationRole</role-name>
    </security-role>

</web-app>

Any other issues, leave me a message.

Upvotes: 1

Related Questions