Websphere基于角色的WS-Security与UsernameToken

时间:2015-12-09 15:46:36

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

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

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

有没有人有这方面的解决方案,或者我应该寻找的方向?

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

2 个答案:

答案 0 :(得分:0)

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

这可能比使用Login模块更轻松,更灵活。

答案 1 :(得分:0)

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

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

(请原谅格式化。我在这里尽我所能做到最好。)

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

默认情况下,Web服务安全性UsernameToken使用者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);

    在此代码示例中,factory是com.ibm.websphere.wssecurity.wssapi.token.GenericSecurityTokenFactory的实例。

    • 以您选择的方式检查用户名和密码。

      您可以调用unt.getUsername()和unt.getPassword()来获取用户名和密码。

      如果出现身份验证错误,您的登录模块应抛出LoginException。

    • 将在前一个子步骤中获得的UsernameToken放回共享状态。

      使用以下方法将UsernameToken重新置于共享状态。

      factory.putAuthenticatedTokenToSharedState(sharedState,unt);

  2. 以下是一个示例登录模块:

    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登录配置。

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

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

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

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