Glassfish 3.1 CallbackHandler 上的 Java EE 6 抛出 NullPointerException

发布于 2024-12-09 06:57:26 字数 5760 浏览 0 评论 0原文

由于需要找到精细的访问控制,我为自定义身份验证过程实现了自己的 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;
    }
}

我在 @Startup 上添加了带有 @Singleton bean 的 LoginModule 配置:

@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)
[...]

这里发生了什么?为什么会出现空指针异常?我希望我得到的 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位置。好的,这是可重现和可重复的。但是,在我检查的这个变体中,非空值被放入登录()中作为用户名和密码。

我现在可以在哪里查看?有什么问题吗?任何胶水都会有所帮助。我对这个问题困惑了三天,网络上没有提供这方面的有用信息。至少对于关键词,我使用...

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 expect, 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...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文