【问题标题】:Websphere Role Based WS-Security with UsernameToken带有 UsernameToken 的基于 Websphere 角色的 WS-Security
【发布时间】:2023-03-10 22:00:01
【问题描述】:

通过 Websphere 控制台,我设置了策略集和策略集绑定,以支持 Web 服务上的 UsernameToken 身份验证。正如预期的那样,它拒绝没有正确用户名和密码的 Web 服务调用。但是,它现在接受连接的 LDAP 中的每个用户。

我希望能够只允许特定 LDAP 组中的用户访问。我觉得我需要在 Caller 设置中创建一个自定义 JAAS 登录,但我不完全确定。

有人对此有解决方案,或者我应该寻找的方向吗?

编辑:我这样做是为了公开 IBM BPM Web 服务。

【问题讨论】:

  • 我看到了您的 ibm-bpm 标签,这是 IBM BPM 应用程序中的 Web 服务的问题吗?您使用的是哪个版本的 IBM BPM?
  • 我使用的是 IBM BPM 8.5.6。
  • 您能否附加一个(审查的)LDAP 配置示例?您应该能够在那里实现组过滤器。

标签: web-services authentication websphere usernametoken ibm-bpm


【解决方案1】:

基于 EJB 而不是 POJO 创建您的 Web 服务,然后使用 @RolesAllowed 注释来指定允许从您的服务调用特定方法的角色。使用 adminconsole、脚本或绑定文件将定义的角色映射到 LDAP 服务器中的用户或组。

这可能比使用登录模块更容易,更灵活。

【讨论】:

  • 不幸的是,这不是一个简单的选项,因为我将它用于 IBM BPM Web 服务。之后我可能能够在内部将其路由到 BPM,但我更希望能够附加策略和绑定并使其正常工作。
【解决方案2】:

您可以创建自定义 JAAS 登录模块以在使用用户名令牌时使用。您可以使用一个 JAAS 配置,它首先调用内置令牌使用者,然后是您的自定义使用者。这样做意味着您可以使用内置的消费者来解析令牌并进行时间戳和随机数处理,您只需在自己的登录模块中进行用户名/密码验证。

说明可以在这里找到:http://www14.software.ibm.com/webapp/wsbroker/redirect?version=phil&product=was-nd-dist&topic=twbs_replace_authmethod_usernametoken

(请原谅格式。我正在尽我所能使用这里可用的内容。)

使用堆叠的 JAAS 登录模块替换 UsernameToken 消费者的身份验证方法

默认情况下,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 而没有随附的登录模块将令牌返回到共享状态。

程序

  1. 开发一个 JAAS 登录模块来进行身份验证并使其可用于您的应用程序代码。这个新的登录模块堆栈在 com.ibm.ws.wssecurity.wssapi.token.impl.UNTConsumeLoginModule 下。

    此登录模块必须:

    • 使用如下方法获取UNTConsumeLoginModule消费的UsernameToken。

    用户名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
}
  1. 创建一个新的 JAAS 登录配置。

    • 在管理控制台中,选择安全性 > 全局安全性。
    • 在身份验证下,选择 Java 身份验证和授权服务。
    • 选择系统登录。
    • 单击新建,然后指定别名 = test.consume.unt。
    • 单击新建,然后指定模块类名 = com.ibm.ws.wssecurity.wssapi.token.impl.UNTConsumeLoginModule
    • 点击确定。
    • 点击新建,然后指定模块类名 = test.tokens.MyUntAuthenticator
    • 选择使用登录模块代理。
    • 单击“确定”,然后单击“保存”。
  2. 配置您的 UsernameToken 令牌使用者以使用新的 JAAS 配置。

    • 打开您要更改的绑定配置。
    • 在管理控制台中,选择 WS-Security > 身份验证和保护。
    • 在身份验证令牌下,选择您要更改的 UsernameToken 入站令牌。
    • 选择 JAAS 登录 = test.consume.unt。
  3. 在为 UsernameToken 使用者配置的回调处理程序上设置所需的属性。

    • 单击回调处理程序。
    • 添加 com.ibm.wsspi.wssecurity.token.UsernameToken.authDeferred=true 自定义属性。
    • 点击确定。
  4. 点击保存。

  5. 重新启动应用程序服务器以应用 JAAS 配置更改。
  6. 测试您的服务。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-18
    • 2019-09-24
    • 1970-01-01
    • 1970-01-01
    • 2017-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多