I implemented a custom loginModule that is accessed via a web service and checks a username and password infront of a JPA accessed DB. I ran it on jboss 7.1 and it worked fine, but after moving it to Wildfly (and adding what i think is the right configuration) i get a NullPointerException stemming from way inside the wildfly classes. any ideas?
18:48:21,417 ERROR [io.undertow.request] (default task-3) UT005023: Exception handling request to /jass.ws/jaas/verifier/authenticateWithBasicUsernamePasswordAuth: java.lang.RuntimeException: java.lang.NullPointerException
at org.wildfly.extension.undertow.security.JAASIdentityManagerImpl.verifyCredential(JAASIdentityManagerImpl.java:126)
at org.wildfly.extension.undertow.security.JAASIdentityManagerImpl.verify(JAASIdentityManagerImpl.java:82)
at io.undertow.security.impl.BasicAuthenticationMechanism.authenticate(BasicAuthenticationMechanism.java:110) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.security.impl.SecurityContextImpl$AuthAttempter.transition(SecurityContextImpl.java:281) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.security.impl.SecurityContextImpl$AuthAttempter.transition(SecurityContextImpl.java:298) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.security.impl.SecurityContextImpl$AuthAttempter.access$100(SecurityContextImpl.java:268) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.security.impl.SecurityContextImpl.attemptAuthentication(SecurityContextImpl.java:131) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.security.impl.SecurityContextImpl.authTransition(SecurityContextImpl.java:106) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.security.impl.SecurityContextImpl.authenticate(SecurityContextImpl.java:99) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.security.handlers.AuthenticationCallHandler.handleRequest(AuthenticationCallHandler.java:50) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.security.handlers.AuthenticationConstraintHandler.handleRequest(AuthenticationConstraintHandler.java:51) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:45) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:61) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.servlet.handlers.security.ServletSecurityConstraintHandler.handleRequest(ServletSecurityConstraintHandler.java:56) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:58) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:70) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:240) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:73) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:146) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:168) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:687) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_51]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_51]
at java.lang.Thread.run(Thread.java:744) [rt.jar:1.7.0_51]
Caused by: java.lang.NullPointerException
at org.wildfly.extension.undertow.security.AccountImpl.<init>(AccountImpl.java:61)
at org.wildfly.extension.undertow.security.JAASIdentityManagerImpl.verifyCredential(JAASIdentityManagerImpl.java:123)
... 29 more
This is my custom login module:
public class JPALoginModule implements LoginModule {
CallbackHandler callbackHandler;
Subject subject;
Map sharedState;
Map options;
boolean success;
LoginVerifier loginVerifier;
@Override
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map<String, ?> sharedState, Map<String, ?> options) {
System.out.println("JPALoginModule.initialize()");
this.callbackHandler = callbackHandler;
this.subject = subject;
this.sharedState = sharedState;
this.options = options;
InitialContext context = null;
try {
context = new InitialContext();
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
this.loginVerifier = (LoginVerifier) context.lookup("java:global/jaas.ear/jaas.ejb/LoginVerifierBean!beans.LoginVerifier");
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public boolean login() throws LoginException {
System.out.println("JPALoginModule.login()");
try {
// Setup default callback handlers.
Callback[] callbacks = new Callback[] {
new NameCallback("Username: "),
new PasswordCallback("Password: ", false) };
callbackHandler.handle(callbacks);
String username = ((NameCallback) callbacks[0]).getName();
String password = new String(
((PasswordCallback) callbacks[1]).getPassword());
success = loginVerifier.verify(username, password);
if (!success) {
throw new LoginException(
"Authentication Failed: Wrong Password");
} else if (success) {
return true;
}
} catch (IOException e) {
e.printStackTrace();
} catch (UnsupportedCallbackException e) {
e.printStackTrace();
}
catch (NullPointerException e) {
System.out.println(e.getMessage()+" "+e.getLocalizedMessage());
}
return false;
}
@Override
public boolean commit() throws LoginException {
if (success) {
if (subject.isReadOnly()) {
throw new LoginException("subject is read only");
}
if (callbackHandler instanceof PassiveCallBackHandler) {
((PassiveCallBackHandler) callbackHandler).clearPassword();
}
return true;
}
else {
return true;
}
}
@Override
public boolean abort() throws LoginException {
logout();
return true;
}
@Override
public boolean logout() throws LoginException {
if (callbackHandler instanceof PassiveCallBackHandler) {
((PassiveCallBackHandler) callbackHandler).clearPassword();
}
return true;
}
my jboss-web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<security-domain>java:/jaas/jpa-login-module</security-domain>
</jboss-web>
my web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>jass.ws</display-name>
<security-constraint>
<web-resource-collection>
<web-resource-name></web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>jpa-login-module</realm-name>
</login-config>
and my standalone.xml relevant configuration:
<security-domains>
<security-domain name="jpa-login-module" cache-type="default">
<authentication>
<login-module code="com.jaas.JPALoginModule" flag="required"/>
</authentication>
</security-domain>
<security-domain name="jpa-password-username" cache-type="default">
<authentication>
<login-module code="com.jaas.JPAUsernamePasswordLoginModule" flag="required"/>
</authentication>
</security-domain>
<security-domain name="other" cache-type="default">
<authentication>
<login-module code="Remoting" flag="optional">
<module-option name="password-stacking" value="useFirstPass"/>
</login-module>
<login-module code="RealmDirect" flag="required">
<module-option name="password-stacking" value="useFirstPass"/>
</login-module>
</authentication>
</security-domain>
<security-domain name="jboss-web-policy" cache-type="default">
<authorization>
<policy-module code="Delegating" flag="required"/>
</authorization>
</security-domain>
<security-domain name="jboss-ejb-policy" cache-type="default">
<authorization>
<policy-module code="Delegating" flag="required"/>
</authorization>
</security-domain>
</security-domains>
Ok I figured out the reason, it's because I didn't add principals after authentication.
So I added this:
if (!success) {
throw new LoginException(
"Authentication Failed: Wrong Password");
} else if (success) {
Principal passPrincipal = new UsernamePrincpal(username);
subject.getPrincipals().add(passPrincipal);
subject.getPrivateCredentials().add(password);
return true;
}
and it works