通过 Websphere 控制台,我设置了策略集和策略集绑定,以支持 Web 服务上的 UsernameToken 身份验证。正如预期的那样,它拒绝没有正确用户名和密码的 Web 服务调用。但是,它现在接受连接的 LDAP 中的每个用户。
我希望能够只允许访问特定 LDAP 组中的用户。我觉得我需要在呼叫者设置中创建自定义 JAAS 登录,但我不完全确定。
有人对此有解决方案,或者我应该寻找的方向吗?
编辑:我这样做是为了公开 IBM BPM Web 服务。
通过 Websphere 控制台,我设置了策略集和策略集绑定,以支持 Web 服务上的 UsernameToken 身份验证。正如预期的那样,它拒绝没有正确用户名和密码的 Web 服务调用。但是,它现在接受连接的 LDAP 中的每个用户。
我希望能够只允许访问特定 LDAP 组中的用户。我觉得我需要在呼叫者设置中创建自定义 JAAS 登录,但我不完全确定。
有人对此有解决方案,或者我应该寻找的方向吗?
编辑:我这样做是为了公开 IBM BPM Web 服务。
您可以创建自定义 JAAS 登录模块以在使用用户名令牌时使用。您可以使用一个 JAAS 配置,它首先调用内置令牌使用者,然后是您的自定义使用者。这样做意味着您可以使用内置的使用者来解析令牌并进行时间戳和随机数处理,您只需在自己的登录模块中进行用户名/密码验证。
(请原谅格式。我正在尽我所能在这里提供的东西。)
默认情况下,Web 服务安全用户名令牌使用者 UNTConsumeLoginModule 始终根据 WebSphere 注册表验证令牌中包含的用户名和密码。您可以使用 GenericSecurityTokenFactory 提供的 SPI 绕过此身份验证方法。
如果要替换 UNTConsumeLoginModule 使用的身份验证方法,则必须提供自己的自定义 JAAS 登录模块来进行身份验证。自定义登录模块堆叠在自定义 JAAS 配置中的 UNTConsumeLoginModule 下。UNTConsumeLoginModule 使用并验证令牌 XML。为用户名和密码提供的值的验证推迟到自定义堆叠登录模块。
因为 UNTConsumeLoginModule 的使用带有用户名和密码将被验证的假设,所以对旨在执行此功能的堆叠登录模块的要求比对仅旨在提供动态令牌功能的登录模块的要求更多。
要向 UNTConsumeLoginModule 指示它不应验证用户名和密码,您必须在配置的回调处理程序上设置以下属性:
com.ibm.wsspi.wssecurity.token.UsernameToken.authDeferred=true
与大多数 WS-Security 登录模块一样,UNTConsumeLoginModule 始终将使用的令牌放在堆栈中所有登录模块都可以访问的共享状态映射中。当指定 authDeferred=true 时,在提交阶段,UNTConsumeLoginModule 确保原来被置于共享状态的同一个 UsernameToken 对象已被置于处于共享状态的另一个位置。如果找不到此 UsernameToken 对象,则会发生 LoginException。因此,您不能只在回调处理程序上设置 authDeferred=true 而没有伴随的登录模块将令牌返回到共享状态。
开发一个 JAAS 登录模块来进行身份验证并使其可用于您的应用程序代码。这个新的登录模块堆叠在 com.ibm.ws.wssecurity.wssapi.token.impl.UNTConsumeLoginModule 下。
此登录模块必须:
用户名Token unt = UsernameToken)factory.getConsumerTokenFromSharedState(sharedState,UsernameToken.ValueType);
在此代码示例中,工厂是 com.ibm.websphere.wssecurity.wssapi.token.GenericSecurityTokenFactory 的一个实例。
以您选择的方式检查用户名和密码。
您可以调用 unt.getUsername() 和 unt.getPassword() 来获取用户名和密码。
如果出现身份验证错误,您的登录模块应该抛出 LoginException。
将在上一个子步骤中获得的 UsernameToken 放回共享状态。
使用以下方法将 UsernameToken 重新置于共享状态。
factory.putAuthenticatedTokenToSharedState(sharedState, unt);
以下是一个示例登录模块:
package test.tokens;
import com.ibm.websphere.wssecurity.wssapi.token.GenericSecurityTokenFactory;
import com.ibm.websphere.wssecurity.wssapi.WSSUtilFactory;
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import com.ibm.websphere.wssecurity.wssapi.token.UsernameToken;
import java.util.ArrayList;
import com.ibm.wsspi.security.registry.RegistryHelper;
import com.ibm.websphere.security.UserRegistry;
public class MyUntAuthenticator implements LoginModule {
private Map _sharedState;
private Map _options;
private CallbackHandler _handler;
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map<String, ?> sharedState, Map<String, ?> options) {
this._handler = callbackHandler;
this._sharedState = sharedState;
this._options = options;
}
public boolean login() throws LoginException {
//For the sake of readability, this login module does not
//protect against all NPE's
GenericSecurityTokenFactory factory = null;
WSSUtilFactory utilFactory = null;
try {
factory = GenericSecurityTokenFactory.getInstance();
utilFactory = WSSUtilFactory.getInstance();
} catch (Exception e) {
throw new LoginException(e.toString());
}
if (factory == null) {
throw new LoginException("GenericSecurityTokenFactory.getInstance() returned null");
}
UsernameToken unt = (UsernameToken)factory.getConsumerTokenFromSharedState(this._sharedState,UsernameToken.ValueType);
String username = unt.getUsername();
char [] password = unt.getPassword();
//authenticate the username and password
//to validate a PasswordDigest password (fixpack 8.5.5.8 and later)
//String pw = yourCodeToLookUpPasswordForUsername(username);
//boolean match = utilFactory.verifyDigestedPassword(unt, pw.toCharArray());
//if (!match) throw new LoginException("Digested passwords do not match");
//Example:
try {
simpleUserGroupCheck(username, password, "cn=group1,o=ibm,c=us");
} catch (Exception e) {
LoginException le = new LoginException(e.getMessage());
le.initCause(e);
throw le;
}
//Put the authenticated token to the shared state
factory.putAuthenticatedTokenToSharedState(this._sharedState, unt);
return true;
}
private boolean simpleUserGroupCheck(String username, char [] password, String group) throws Exception {
String allowedGroup = null;
//get the default user registry
UserRegistry user_reg = RegistryHelper.getUserRegistry(null);
//authenticate the user against the user registry
user_reg.checkPassword(username, new String(password));
//get the list of groups that the user belongs to
java.util.List<String> groupList = user_reg.getGroupsForUser(username);
//you can either use a hard-coded group
allowedGroup = group;
//or get the value from your own custom property on the callback handler
//WSSUtilFactory util = WSSUtilFactory.getInstance();
//Map map = util.getCallbackHandlerProperties(this._handler);
//allowedGroup = (String) map.get("MY_ALLOWED_GROUP_1");
//check if the user belongs to an allowed group
if (!groupList.contains(allowedGroup)) {
throw new LoginException("user ["+username+"] is not in allowed group ["+allowedGroup+"]");
}
return true;
}
//implement the rest of the methods required by the
//LoginModule interface
}
创建一个新的 JAAS 登录配置。
配置您的 UsernameToken 令牌使用者以使用新的 JAAS 配置。
在为 UsernameToken 使用者配置的回调处理程序上设置所需的属性。
单击保存。
基于 EJB 而不是 POJO 创建您的 Web 服务,然后使用@RolesAllowed
注释来指定允许从您的服务调用特定方法的角色。使用 adminconsole、scirpt 或绑定文件将定义的角色映射到 LDAP 服务器中的用户或组。
这可能比使用登录模块更容易,更灵活。