Я реализовал собственный LoginModule для пользовательского процесса аутентификации из-за необходимости поиска детального контроля доступа.Модуль LoginModule выглядит следующим образом:
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;
}
}
Я добавляю эту конфигурацию LoginModule с компонентом @Singleton для @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;
}
}
Форма входа должна быть основана на собственной странице JSF 2.0,Я положил все в композит: реализация для последующего повторного использования.Соответствующая часть выглядит следующим образом:
<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>
Когда я пытаюсь все протестировать, я вижу в журналах (журналы удалены из кода выше), что конфигурация была добавлена и что мой собственный модуль входа был запущен (инициализироватьи войти).Но как только CallbackHandler запущен, обработчик обратного вызова выдает исключение 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)
[...]
Что здесь происходит?Почему существует исключение NullPointerException?Я ожидаю, что CallbackHandler, который я получаю, происходит из базовой реализации JAAS и возвращает мне предоставленные имя пользователя и пароль.Почему этого не происходит?
Я попробовал альтернативный способ.Я позволил форме JSF поместить имя пользователя и пароль в @ManagedBean и вызвал процедуру входа в систему через HttpServletRequest:
FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) context
.getExternalContext().getRequest();
request.login(login.getEmail(), login.getPassword());
Когда я это делаю, я также получаю исключение 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)
[...]
Мой собственный LoginModule вызывался снова и снова. ServerLoginCallbackHandler генерирует исключение NullPointerException в той же позиции.Хорошо, это воспроизводимо и повторяется.Но в этом варианте я проверил, что ненулевые значения были введены в login () для имени пользователя и пароля.
Где я могу посмотреть сейчас?В чем проблема?Любой клей поможет.Я уже три дня ломаю голову над этим вопросом, и в Интернете нет полезной информации.По крайней мере, с ключевыми словами я использую ...