我正在尝试为Wildfly 8.0.0.CR1编写我自己的名为CustomLoginModule
的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时会调用我的login-module,该接口使用正确的@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
{ ... }
}
答案 0 :(得分:-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权限时调用{{1}}。在此阶段,默认情况下无法获取密码(最初尝试过)。这听起来合理吗?