2

我在 WSO2 ESB 中创建了一个代理服务并设置了 UsernameToken 身份验证。但是,使用捆绑在 JDK 中的 JAX-WS 配置 UsernameToken 似乎并不容易(如此所述),必须对 JDK 进行修补等等。有没有办法使用带有 ESB 凭据的基本 HTTP 身份验证,就像 UsernameToken 一样?

4

1 回答 1

2

根据 Amila Suriarachchi 的文章“Securing Web Service Integration”,“WSO2 carbon 通过转换 POX 消息支持 UT,即使使用 HTTP 基本身份验证”,但我不确定这是否与您的兴趣相关。

然而,使用 JAX-WS 客户端配置 UsernameToken 授权并不像看起来那么难。您所要做的就是创建一个实现 javax.xml.ws.handler.soap.SOAPHandler 的类,并通过覆盖 handleMessage(SOAPMessageContext messageContext) 方法在出站消息中添加安全标头。

我的 java 版本是 1.6.0_26(没有应用上述补丁),并且 Web 服务客户端存根类是由 JAX-WS RI 2.1.7 根据 Web 服务的 wsdl 生成的,由 UsernameToken 场景保护并公开通过 WSO2 Carbon Server(即 Data Services Server-2.6.3)

我使用Apache WSS4J创建安全标头——在本例中,只需实例化一个 org.apache.ws.security.message.WSSecUsernameToken 对象并通过 setUserInfo(String user, String password) 方法设置用户名和密码。此外,还应将时间戳元素添加到传出 SOAP 消息的安全标头中。示例实现可能如下所示:

public boolean handleMessage(SOAPMessageContext messageContext) {
    Boolean isOutboundMessage = (Boolean) messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

    if (isOutboundMessage) {
        SOAPPart messageSoapPart = messageContext.getMessage().getSOAPPart();

        WSSecHeader securityHeader = new WSSecHeader();
        securityHeader.insertSecurityHeader(messageSoapPart);
        WSSecUsernameToken usernameToken = new WSSecUsernameToken();

        usernameToken.setPasswordType(WSConstants.PASSWORD_TEXT);
        usernameToken.setUserInfo("root", "top_secret");

        WSSecTimestamp timestamp = new WSSecTimestamp();

        usernameToken.build(messageSoapPart, securityHeader);
        timestamp.build(messageSoapPart, securityHeader);
    }

    return true;
}

另一件重要的事情是 SOAP 标头元素可能带有 mustUnderstand 全局 SOAP 属性。参考 Jim White 的文章Working with Headers in JAX-WS SOAPHandlers,此属性用于指示 Web 服务接收者或中介是否需要在处理消息之前理解 header 元素。

如果 mustUnderstand 元素设置为 true (soapenv:mustUnderstand="1"),则应该对 getHeaders() 方法进行编码,以告诉运行时环境 SOAP 处理程序将通过返回一组来处理 mustUnderstand 标头元素与 mustUnderstand 标头元素匹配的 QName(限定名称)对象。下面是处理 Security 标头的 getHeaders() 方法。

public Set<QName> getHeaders() {
    final String NAMESPACE_URI = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
    final String LOCAL_PART = "Security";
    final String PREFIX = "wsse";

    final QName wssecurity = new QName(NAMESPACE_URI, LOCAL_PART, PREFIX);  
    final Set<QName> headers = new HashSet<QName>();
    headers.add(wssecurity);  

    return headers;  
}

最后,在获取服务端口并调用其任何方法之前,您应该将上述类的一个实例(比如说 - UsernameTokenSecuritySoapHandler)注册到您的 Web 服务客户端的处理程序链中。这可以通过使用以下代码来完成:

    Service service = new Service();
    service.setHandlerResolver(new HandlerResolver() {
        public List<Handler> getHandlerChain(PortInfo portInfo) {
            List<Handler> handlers = new ArrayList<Handler>();
            handlers.add(new UsernameTokenSecuritySoapHandler());
            return handlers;
        }
    });

此外,您可以在此处找到Young Yang 撰写的一篇关于 JAX-WS API 处理程序框架的优秀文章。

希望这可以帮助。

于 2012-08-20T14:07:25.800 回答