Java EE 6 on Glassfish 3.1 CallbackHandler throws NullPointerException
I implemented an own LoginModule for a custom authentication process due to the need for find granular access control. The LoginModule looks like that:
public class PasswordSafeLoginModule implements LoginModule {
private Subject subject;
private CallbackHandler callbackHandler;
private Object sharedState;
private Object options;
private Set<Principal> principalsAdded;
private boolean authenticated;
private String username;
private String password;
@Override
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map<String, ?> sharedState, Map<String, ?> options) {
this.subject = subject;
this.callbackHandler = callbackHandler;
this.sharedState = sharedState;
this.options = options;
}
@Override
public boolean abort() throws LoginException {
// TODO
return true;
}
@Override
public boolean commit() throws LoginException {
// TODO
return false;
}
@Override
public boolean login() throws LoginException {
NameCallback nameCB = new NameCallback("Username");
PasswordCallback passwordCB = new PasswordCallback("Password", true);
Callback[] callbacks = new Callback[] { nameCB, passwordCB };
try {
callbackHandler.handle(callbacks);
// Authenticate username/password
username = nameCB.getName();
password = String.valueOf(passwordCB.getPassword());
//
// lookup credentials
//
// TODO...
return true;
} catch (IOException e) {
throw new LoginException(e.getMessage());
} catch (UnsupportedCallbackException e) {
throw new LoginException(e.getMessage());
}
}
@Override
public boolean logout() throws LoginException {
logger.info("Logging out '" + username + "'...");
return false;
}
}
I add this LoginModule configuration with a @Singleton bean on @Startup:
@Singleton
@Startup
public class PasswordSafeJAASConfiguration extends Configuration {
/**
* This method just registers the configuration after the construction.
*/
@PostConstruct
void init() {
Configuration.setConfiguration(this);
}
@Override
public AppConfigurationEntry[] getAppConfigurationEntry(
String applicationName) {
AppConfigurationEntry[] entries = new AppConfigurationEntry[1];
entries[0] = new AppConfigurationEntry(
PasswordSafeLoginModule.class.getName(),
LoginModuleControlFlag.REQUIRED, new HashMap<String, Object>());
return entries;
}
}
The login shall be form based on an own JSF 2.0 page. I put everything into a composite:implementation for later reuse. The relevant part look like:
<form method="POST" action="j_security_check">
<h:messages />
<h:panelGrid columns="2" columnClasses="rightAlign,leftAlign">
<h:outputText value="Email address:" />
<h:inputText id="j_username" required="true" size="8">
<f:validator validatorId="emailAddressValidator" />
<f:validateLength minimum="5" maximum="128" />
</h:inputText>
<h:outputText value="Password:" />
<h:inputText id="j_password" required="true" size="8" />
</h:panelGrid>
<h:commandButton value="Login..." />
</form>
When I try to test everything, I see in the logs (logging removed from the code above) that the configuration was added and that my own login module was started (initialize and login). But as soon as the CallbackHandler is started the callback handler throws a NullPointerException:
Caused by: javax.security.auth.login.LoginException: java.lang.NullPointerException
at com.sun.enterprise.security.auth.login.common.ServerLoginCallbackHandler.handle(ServerLoginCallbackHandler.java:109)
at javax.security.auth.login.LoginContext$SecureCallbackHandler$1.run(LoginContext.java:955)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.login.LoginContext$SecureCallbackHandler.handle(LoginContext.java:951)
at com.puresol.passwordsafe.jaas.PasswordSafeLoginModule.login(PasswordSafeLoginModule.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[...]
What is happening here? Why is there a NullPointerException? I ex开发者_开发技巧pect, that the CallbackHandler I get is from the underlying JAAS implementation and gives me the provided username and password back. Why is this not happening?
I tried an alternative way. I let the JSF form put the username and password into a @ManagedBean and called the login procedure via HttpServletRequest:
FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) context
.getExternalContext().getRequest();
request.login(login.getEmail(), login.getPassword());
When I do this, I get an NullPointerException, too:
Caused by: javax.security.auth.login.LoginException: java.lang.NullPointerException
at com.sun.enterprise.security.auth.login.common.ServerLoginCallbackHandler.handle(ServerLoginCallbackHandler.java:109)
at javax.security.auth.login.LoginContext$SecureCallbackHandler$1.run(LoginContext.java:955)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.login.LoginContext$SecureCallbackHandler.handle(LoginContext.java:951)
at com.puresol.passwordsafe.jaas.PasswordSafeLoginModule.login(PasswordSafeLoginModule.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[...]
My own LoginModule was called again and again the ServerLoginCallbackHandler throws a NullPointerException at the same position. Ok, that's reproducable and repeatable. But, in this variant I checked, that non-null values were put into login() for username and password.
Where can I look now? What is the issue? Any glue will help. I puzzle on this issue for three days now and the web is not providing useful information on that. At least with the key words, I use...
精彩评论