I'm still playin with Wildfly-9.0.1.Final and JAAS (see my previous question Wildfly and JAAS login module) in a web application that use a BASIC auth-method
. While my custom login module works I got some problems about authorization. I use a RESTeasy RESTFul web service with annotation to test, here is the code:
package it.bytebear.web.mongo;
import it.bytebear.web.mongo.jaas.MongoModuleCallbackHandler;
import it.bytebear.web.mongo.model.User;
import java.security.Principal;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ejb.Stateless;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.SecurityContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Path("/service")
Stateless
ublic class UserServices {
private Logger log = LoggerFactory.getLogger(UserServices.class);
@GET
@Path("/userA")
@RolesAllowed({ "userA" })
public Response postUserA() {
return Response.ok("You're user A.", MediaType.TEXT_HTML).build();
}
@GET
@Path("/userB")
@RolesAllowed({ "userB" })
public Response postUserB() {
return Response.ok("You're user B.", MediaType.TEXT_HTML).build();
}
@GET
@Path("/userC")
@RolesAllowed({ "userC" })
public Response postUserC() {
return Response.ok("You're user C.", MediaType.TEXT_HTML).build();
}
@POST
@Path("/login")
@PermitAll
@Consumes(MediaType.APPLICATION_JSON)
// @Consumes("application/x-authc-username-password+json")
public Response login(User userCredentials) {
log.info("logging in.");
try {
MongoModuleCallbackHandler handler = new MongoModuleCallbackHandler();
handler.setUsername(userCredentials.getUserName());
handler.setPassword(userCredentials.getPassword().toCharArray());
LoginContext loginContext = new LoginContext("MongoLoginRealm", handler);
loginContext.login();
Subject subject = loginContext.getSubject();
List<String> roles = new ArrayList<String>();
for (Principal p : subject.getPrincipals()) {
roles.add(p.getName());
}
String[] userCredentialsRoles = new String[roles.size()];
roles.toArray(userCredentialsRoles);
userCredentials.setRoles(userCredentialsRoles);
return Response.ok().entity(userCredentials)
.type(MediaType.APPLICATION_JSON_TYPE).build();
} catch (Exception e) {
log.error("login fails.", e);
return Response.status(Status.FORBIDDEN).entity("Not logged")
.type(MediaType.APPLICATION_JSON_TYPE).build();
}
}
@GET
@Path("/logout")
@PermitAll
public Response logout(Request req) {
return Response.ok().build();
}
@POST
@Path("/test")
@PermitAll
public Response test(@Context SecurityContext ctx) {
Principal p = ctx.getUserPrincipal();
return Response.status(Status.OK).entity(p).build();
}
}
My login module is correctly invoked and generate a subjec with a Group
named Roles
containing a Principal
named userA
, but when I try to access .../service/userA
I always get a 403
error. I use test
method to check subject
but ctx.getUserPrincipal()
always return null
. I miss how LoginModule
and SecurityContext
works, how SecurityContext
knows about a Subject? More important: I'd like to learn more, link to resources and docs will be appreciated.
UPDATE:
In my web.xml
I'm using RESTEasy security:
...
<context-param>
<param-name>resteasy.role.based.security</param-name>
<param-value>true</param-value>
</context-param>
...
Am I messing up EJB security with RESTEasy security?