4

我正在尝试编写自己的以CustomLoginModuleWildfly 8.0.0.CR1 命名的 LoginModule,它在以下位置注册了一个安全域standalone.xml

<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="com.someExample.CustomLoginModule" flag="required">  
      <module-option name="password-stacking" value="useFirstPass"/>  
    </login-module>  
  </authentication>  
</security-domain>

在我的远程客户端中,我使用以下 jboss-ejb-client.properties:

endpoint.name=client-endpoint  
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false  
remote.connections=default  
remote.connection.default.host=[...]  
remote.connection.default.port=[...]  
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false  
remote.connection.default.username=myUserName  
remote.connection.default.password=abcde  

在客户端获取 InitialContext 如下所示:

Properties props = new Properties();  
props.put(Context.URL_PKG_PREFIXES,  "org.jboss.ejb.client.naming");  
InitialContext ctx = new InitialContext(props);  

基本上这工作正常,并且在通过带有正确注释的远程接口访问 EJB 时调用我的登录模块@SecurityDomain

在登录模块中,我可以使用回调或sharedState传递给initialize方法的方法读取用户名。但我无法获得提供的密码(在这个例子中,我希望得到字符串的位置abcde)。

我已经尝试了几件事来获取密码。通过回调(就像我在 JBoss 5 上所做的那样),通过给定的 sharedState,... 即使我从org.jboss.security.auth.spi.UsernamePasswordLoginModule或使用 JBoss-Quickstart 示例中的代码派生,我也看不到在客户端设置的密码。相反,我总是将以下字符串作为密码返回org.jboss.as.security.remoting.RemotingConnectionCredential@...

编辑:这是我的LoginModule(或至少一个版本)的代码:

import javax.security.auth.callback.*;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;

public class CustomLoginModule implements LoginModule
{
    private CallbackHandler callbackHandler;

    public void initialize(Subject subject, CallbackHandler callbackHandler,
      Map<String, ?> sharedState, Map<String, ?> options)
    {
        this.callbackHandler = callbackHandler;
    }

    public boolean login() throws LoginException
    {
        NameCallback namecallback = new NameCallback("Username");
        PasswordCallback passwordcallback = new PasswordCallback("Password", false);
        CallbackHandler handler = this.callbackHandler;
        try {
            handler.handle(new Callback[] { namecallback, passwordcallback });
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        String username = namecallback.getName();
        char[] password2 = passwordcallback.getPassword();
        String password = new String(password2);
        System.out.println(username + " / " + password);
        if (username == null || password == null) {
            return false;
        }
        // do authentication...
        return true;
    }

    public boolean commit() throws LoginException
    { ... }

    public boolean abort() throws LoginException
    { ... }

    public boolean logout() throws LoginException
    { ... }
}
4

1 回答 1

-1

我现在创建了一个小型测试项目,以了解如何使其工作。而且我认为值得分享。

我们在第一阶段(用于保护远程连接)循环通过ClientLoginModule(由 Wildfly 提供)。ApplicationRealm该模块存储凭据(在某个地方?),然后它们可用于我的其他登录模块。

<security-realm name="ApplicationRealm">
    <authentication>
        <jaas name="AppRealmLoopThrough"/>
    </authentication>
</security-realm>

当然,这个安全域必须在之后定义:

<security-domain name="AppRealmLoopThrough" cache-type="default">
    <authentication>
        <login-module code="Client" flag="required">
            <module-option name="multi-threaded" value="true"/>
        </login-module>
    </authentication>
</security-domain>
<security-domain name="other" cache-type="default">
    <authentication>
        <login-module code="com.someExample.CustomLoginModule" flag="required"/>
    </authentication>
</security-domain>

CustomLoginModule(其中扩展UsernamePasswordLoginModule)中,我可以执行以下操作来检索用户名和密码:

final String[] usernameAndPassword = getUsernameAndPassword();
System.out.println("received username: " + usernameAndPassword[0] + " and password " + usernameAndPassword[1]);

getUsernameAndPassword()是基类提供的方法UsernamePasswordLoginModule

当然,必须使用@SecurityDomain("other")(或通过部署描述符)对受保护的 EJB 进行注释才能CustomLoginModule调用我。

顺便说一句:我知道安全域other有一些特殊含义,不应该用于应用程序 - 这只是为了测试......;)

当我试图为此找到解释时,我并不是很成功。对我来说,登录模块似乎分两步调用:首先,当AppRealmLoopThrough用于时,ApplicationRealm这是http-remoting-connector. 在此“步骤”中,用户名和密码可用。第二个“步骤”是CustomLoginModule容器检查 EJB 权限时的调用。在此阶段,默认情况下无法获取密码(如最初尝试的那样)。这听起来合理吗?

于 2014-02-04T15:13:57.397 回答