7.3. 提供客户端凭证

概述

基本上有两种提供 UsernameToken 客户端凭证的方法:您可以在客户端的 Blueprint XML 配置中直接设置用户名和密码;或者,您可以在客户端的配置中设置用户名并实施回调处理程序来以编程方式提供密码。后一种方法(通过编程)具有从视图中隐藏密码更容易的优势。

客户端凭证属性

表 7.1 “客户端凭证属性” 显示您可以在 Blueprint XML 中的客户端请求上下文中指定 WS-Security 用户名/密码凭证的属性。

表 7.1. 客户端凭证属性

Properties描述

security.username

指定 UsernameToken 策略断言的用户名。

security.password

指定 UsernameToken 策略断言的密码。如果没有指定,则通过调用回调处理程序来获取密码。

security.callback-handler

指定用于检索 UsernameToken 策略断言密码的 WSS4J 回调处理程序的类名称。请注意,回调处理程序也可以处理其他类型的安全事件。

在蓝图 XML 中配置客户端凭证

要在蓝图 XML 中的客户端请求上下文中配置用户名/密码凭证,请设置 security.usernamesecurity.password 属性,如下所示:

<beans ... >
    <jaxws:client name="{NamespaceName}LocalPortName"
                  createdFromAPI="true">
        <jaxws:properties>
            <entry key="security.username" value="Alice"/>
            <entry key="security.password" value="abcd!1234"/>
        </jaxws:properties>
    </jaxws:client>
    ...
</beans>

如果您不希望将密码直接存储在 Blueprint XML 中(这可能是安全 hazard),您可以使用回调处理程序提供密码。

为密码编程回调处理器

如果要使用回调处理器为 UsernameToken 标头提供密码,您必须首先在 Blueprint XML 中修改客户端配置,将 security.password 设置替换为 security.callback-handler 设置,如下所示:

<beans ... >
    <jaxws:client name="{NamespaceName}LocalPortName"
                  createdFromAPI="true">
        <jaxws:properties>
            <entry key="security.username" value="Alice"/>
            <entry key="security.callback-handler" value="interop.client.UTPasswordCallback"/>
        </jaxws:properties>
    </jaxws:client>
    ...
</beans>

在上例中,回调处理程序由 UTPasswordCallback 类实施。您可以通过实施 javax.security.auth.callback.CallbackHandler 接口来编写回调处理器,如 例 7.2 “UsernameToken Passwords 的回调处理程序” 所示。

例 7.2. UsernameToken Passwords 的回调处理程序

package interop.client;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

import org.apache.ws.security.WSPasswordCallback;

public class UTPasswordCallback implements CallbackHandler {

    private Map<String, String> passwords =
        new HashMap<String, String>();

    public UTPasswordCallback() {
        passwords.put("Alice", "ecilA");
        passwords.put("Frank", "invalid-password");
        //for MS clients
        passwords.put("abcd", "dcba");
    }

    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        for (int i = 0; i < callbacks.length; i++) {
            WSPasswordCallback pc = (WSPasswordCallback)callbacks[i];

            String pass = passwords.get(pc.getIdentifier());
            if (pass != null) {
                pc.setPassword(pass);
                return;
            }
        }

        throw new IOException();
    }

    // Add an alias/password pair to the callback mechanism.
    public void setAliasPassword(String alias, String password) {
        passwords.put(alias, password);
    }
}

回调功能由 CallbackHandler.handle () 方法实现。在本例中,假设传递给 handle () 方法的回调对象都是 org.apache.ws.security.WSPasswordCallback 类型(在更真实的示例中,您要检查回调对象的类型)。

客户端回调处理程序的更真实的实现可能包括提示用户输入其密码。

WSPasswordCallback 类

当 Apache CXF 客户端中针对设置 UsernameToken 密码调用 CallbackHandler 时,对应的 WSPasswordCallback 对象具有 USERNAME_TOKEN 使用代码。

有关 WSPasswordCallback 类的详情,请参阅 org.apache.ws.security.WSPasswordCallback

WSPasswordCallback 类定义了几个不同的使用代码,如下所示:

USERNAME_TOKEN

获取 UsernameToken 凭证的密码。这个使用代码在客户端(获取发送到服务器的密码)和服务器端使用(获取密码以便与从客户端收到的密码进行比较)。

在服务器端,在以下情况下设定这个代码:

  • 摘要密码- 如果 UsernameToken 包含摘要密码,回调必须返回给定用户名的对应密码(由 WSPasswordCallback.getIdentifier ()提供)。密码验证(与摘要密码进行比较)由 WSS4J 运行时进行。
  • plaintext password- 实现的方式与摘要密码案例相同(自 Apache CXF 2.4.0 起)。
  • 自定义密码类型-if getHandleCustomPasswordTypes ()org.apache.ws.security.WSSConfig 上为 true,则这个情况与摘要密码案例相同(自 Apache CXF 2.4.0 起)。否则,会抛出异常。

    如果没有在服务器端接收的 UsernameToken 中包含 Password 元素,则回调处理程序不会调用(自 Apache CXF 2.4.0 起)。

DECRYPT
需要密码从 Java 密钥存储检索私钥,其中 WSPasswordCallback.getIdentifier () 提供密钥存储条目的别名。WSS4J 使用这个私钥解密会话(symmetric)密钥。
签名
需要密码从 Java 密钥存储检索私钥,其中 WSPasswordCallback.getIdentifier () 提供密钥存储条目的别名。WSS4J 使用这个私钥生成签名。
SECRET_KEY
在出站端需要加密或签名的 secret 密钥,或者在入站端进行解密或验证。回调处理器必须使用 setKey (byte[]) 方法设置密钥。
SECURITY_CONTEXT_TOKEN
需要 wsc:SecurityContextToken 的键,您可以通过调用 setKey (byte[]) 方法来提供它。
CUSTOM_TOKEN
需要令牌作为 DOM 元素。例如,这用于对消息中没有的 SAML Assertion 或 SecurityContextToken 的引用。回调处理器必须使用 setCustomToken (Element) 方法设置令牌。
KEY_NAME
(obsolete) 由于 Apache CXF 2.4.0,这个使用代码已过时。
USERNAME_TOKEN_UNKNOWN
(obsolete) 由于 Apache CXF 2.4.0,这个使用代码已过时。
UNKNOWN
WSS4J 不使用.