JBoss Programmatic Login, non-password authentication
pgib Dec 10, 2009 3:50 PMHello. I am having difficulty determining how to perform programmatic login in JBoss where the credentials is more complex than a simple username + password pair.
In our system, users are identified by UserName (String), AuthAgentId (long), and VerificationCode (String). Basically, AuthAgentId is the "domain"; each one is an independent namespace of UserNames. VerificationCode is a SHA-256 signature that we use to verify the authenticity of the user.
Therefore we have a custom LoginModule:
import org.jboss.security.auth.spi.AbstractServerLoginModule; public class VhmDbServerLoginModule extends AbstractServerLoginModule { public void initialize(...) { ... } public boolean login () throws LoginException { ... } ... }
Also, we have a custom CallbackHandler to actually feed the LoginModule:
public class UsernameAuthAgentHandler implements CallbackHandler { private transient final String username; private transient final String verificationCode; private transient final long authAgentId; public UsernameAuthAgentHandler ( String username, long authAgentId, String verificationCode) { ... } public void handle (Callback[] callbacks) throws UnsupportedCallbackException { for (Callback c : callbacks) { if (c instanceof NameCallback) { NameCallback nc = (NameCallback) c; nc.setName(username); } else if (c instanceof TextInputCallback) { TextInputCallback tc = (TextInputCallback) c; if (tc.getPrompt().equals("VerificationCode")) { tc.setText(verificationCode); } } else if (c instanceof LongInputCallback) { LongInputCallback lc = (LongInputCallback) c; if (lc.getPrompt().equals("AuthAgent")) { lc.setValue(authAgentId); } } else { throw new UnsupportedCallbackException(c, "Unrecognized Callback"); } } } }
Good so far - We use LoginContext to perform the login:
Request request = SecurityAssociationValve.activeRequest.get(); if (request == null) { throw new IllegalStateException("request is null"); } UsernameAuthAgentHandler uaah = new UsernameAuthAgentHandler(username, agentId, credential); String realm = request.getContext().getLoginConfig().getRealmName(); LoginContext lc = null; try { lc = new LoginContext(realm, uaah); lc.login(); } catch (LoginException le) { return false; } ...
This works, it results in a subject that looks like:
Subject: Principals: Principal: com.vhm.security.auth.UserPrincipal@65824b9 Principal: Roles(members:OWNER,SUBSCRIBER,ACCESS_FULL) Principal: CallerPrincipal(members:com.vhm.security.auth.UserPrincipal@65824b9) pubCredentials: size = 0 privCredentials: size = 0
I can share the exact LoginModule code incase this output looks invalid, but it seems correct to me.
I then call the WebAuthentication.register(Request request, Principal principal, String s, Object o) method. I created a subclass of WebAuthentication in order to make the method public.
Principal p = lc.getSubject().getPrincipals(UserPrincipal.class).iterator().next(); wad.register(request, p, username, credential);
After all this, I make another request to a servlet. I call request.getUserPrincipal() and it returns my custom UserPrincipal! However, when I call request.isUserInRole("OWNER") I get false. I expect this since I never had a chance to register the roles.
My question is - How do I actually register the roles with the request/session? Some people in #jboss tell me to "Create a SAR". I know how to do this, but I have absolutely no clue what this Service should do. I have no existing services I know to fork. So - I'm at a total loss.
If someone could please help me register the roles with the catalina session, I would be eternally grateful!