Wildfly JAAS authorization
fpezzati Oct 25, 2015 7:43 AMHello,
I'm trying to understand how Wildfly and JAAS works together. I made a simple pure JAAS custom LoginModule using some custom Principals too. I can login succesfully but I can't get Subject Roles working as expected. When I check for SecurityContext getUserPrincipal I always get back a null value. I'm using BASIC authentication. Here is my custom login module:
package it.bytebear.jaas.mongo.module;
import java.io.IOException;
import java.security.Principal;
import java.util.Map;
import javax.inject.Inject;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import org.bson.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.mongodb.client.FindIterable;
public class MongoLoginModule implements LoginModule {
@Inject
protected MongoDB mongoDb;
protected Subject subject;
protected Principal identity;
protected boolean loginOk;
private CallbackHandler callbackHandler;
private Map sharedState;
private Map options;
private Logger log = LoggerFactory.getLogger(MongoLoginModule.class);
public boolean abort() throws LoginException {
log.info("abort!");
subject = null;
return true;
}
public boolean commit() throws LoginException {
// TODO Auto-generated method stub
log.info("commit!");
try {
if(loginOk) {
UserGroup userGroup = new UserGroup("Roles");
userGroup.addMember(new RolePrincipal("userA"));
subject.getPrincipals().add(userGroup);
subject.getPublicCredentials().add(userGroup);
return true;
}
} catch (Throwable e) {
log.error("Error while committing.", e);
}
return false;
}
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map<String, ?> sharedState, Map<String, ?> options) {
log.info("Initializing MongoLoginModule.");
this.subject = subject;
this.callbackHandler = callbackHandler;
this.sharedState = sharedState;
this.options = options;
}
public boolean login() throws LoginException {
log.info("login requested.");
NameCallback nameCallback = new NameCallback("username:");
PasswordCallback passwordCallback = new PasswordCallback("password:", false);
try {
callbackHandler.handle(new Callback[]{nameCallback, passwordCallback});
String username = nameCallback.getName();
String password = new String(passwordCallback.getPassword());
log.info("check credentials for: "+username);
if(username.equals("jim") && password.equals("jim")) {
loginOk = true;
identity = new UserPrincipal(username);
subject.getPrincipals().add(identity);
subject.getPublicCredentials().add(identity);
return true;
}
} catch (IOException e) {
e.printStackTrace();
} catch (UnsupportedCallbackException e) {
e.printStackTrace();
}
return false;
}
public boolean logout() throws LoginException {
if(subject != null && identity != null) {
subject.getPrincipals().remove(identity);
return true;
}
return false;
}
public Document getUserByName(String userName) {
FindIterable<Document> results = mongoDb.getCollection().find(new Document("username", userName));
return results.iterator().next();
}
public void getRoles() {
// FindIterable<Document> results = mongoDb.getCollection().find(new Document("username", userName));
// results.iterator().next().get
}
}
And here is the RESTFul service I use to test my login module:
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.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Path("/service")
@Stateless
public 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();
}
}
As I succesfull login (I can debug my login module), I can't get resource at URL http://localhost:8080/MongoWebTest/services/service/userA I always get a 403 error. That URL is allowed to users who got the role "userA" and I put a Principal named "userA" into the "Roles" group of the subject. What am I missing? Do you have some docs where I can learn more about authentication and authorization with JAAS and Wildfly? Thanks.