In order to use the security annotations of JSR-250 (RolesAllowed, PermitAll, DenyAll):
- In Jersey, you would register the RolesAllowedDynamicFeature class.
In RESTeasy, you would use the web.xml config:
<context-param> <param-name>resteasy.role.based.security</param-name> <param-value>true</param-value> </context-param>
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:
Create a resource class/method with @RolesAllowed:
@Path("/rest") public class HelloWorld { @GET @RolesAllowed("ANYTHING") public Response hello() { return Response.ok("Hello World").build(); } }
- Set your SecurityContextImpl in a filter, overriding isUserInRole() to always returns true;
- 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)
- 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>