JAX-WS Использование веб-службы с WS-Security и WS-Addressing - PullRequest
10 голосов
/ 31 марта 2009

Я пытаюсь разработать автономный клиент веб-службы Java с JAX-WS (Metro), который использует WS-Security с аутентификацией по токену имени пользователя (дайджест пароля, одноразовые и временные метки) и проверку временной метки наряду с WS-адресацией по SSL.

WSDL, с которым мне приходится работать, не определяет никакой информации о политике безопасности. Мне не удалось выяснить, как именно добавить эту информацию заголовка (правильный способ сделать это), когда WSDL не содержит эту информацию. Большинство примеров, которые я обнаружил, используя Metro, вращаются вокруг использования Netbeans для автоматической генерации этого из WSDL, что мне совсем не помогает. Я изучил WSIT, XWSS и т. Д. Без особой ясности или направления. Метро JBoss WS выглядело многообещающе, но пока еще много.

У кого-нибудь есть опыт в этом деле или есть предложения по выполнению этой задачи? Даже направление меня в правильном направлении было бы полезно. Я не ограничен определенной технологией, за исключением того, что она должна быть основана на Java.

Ответы [ 3 ]

8 голосов
/ 06 мая 2009

В конце концов я решил эту проблему, но пошел в другом направлении, чтобы сделать это. Мое решение состояло в том, чтобы использовать CXF 2.1 и его реализацию JAX-WS, сочетая мощь CXF с существующей инфраструктурой Spring, которую я уже использовал. Сначала я скептически относился к многочисленным банкам, которые требовались для CXF, но в конце концов это было лучшее и простое решение.

Адаптируя пример с веб-сайта CXF для конфигурации клиента , я использовал собственное пространство имен CXF JAXWS внутри Spring и использовал Out Interceptor для аутентификации токена имени пользователя (дайджест пароля, одноразовые и временные метки) и проверки меток времени. Единственным другим шагом для выполнения этой работы было создание моего собственного обработчика обратного вызова пароля, который выполняется для каждого исходящего SOAP-запроса.

Для конфигурации SSL я снова обратился к CXF и его поддержке SSL через каналы , хотя я никогда не мог заставить SSL работать с определенным именем http: номер канала, мне пришлось использовать универсальное, то есть не рекомендуется для производственных сред.

Ниже приведен пример моего конфигурационного файла.

Файл конфигурации Spring

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jaxws="http://cxf.apache.org/jaxws"
    xmlns:sec="http://cxf.apache.org/configuration/security"
    xmlns:http="http://cxf.apache.org/transports/http/configuration"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:cxf="http://cxf.apache.org/core"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
    http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
    http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
    http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd">

    <context:property-placeholder location="meta/my.properties" />
    <context:component-scan base-package="com.foo" />

    <import resource="remoting.xml" />
    <jaxws:client id="myWebService" address="${my.endpointAddress}"
                  serviceClass="com.foo.my.ServicePortType">

<!-- Testing only, adds logging of entire message in and out -->
<jaxws:outInterceptors>
    <ref bean="TimestampUsernameToken_Request" />
    <ref bean="logOutbound" />
</jaxws:outInterceptors>
<jaxws:inInterceptors>
        <ref bean="logInbound" />
    </jaxws:inInterceptors>
    <jaxws:inFaultInterceptors>
        <ref bean="logOutbound" />
    </jaxws:inFaultInterceptors>

<!-- Production settings -->
<!--
    <jaxws:outInterceptors> <ref bean="TimestampUsernameToken_Request" />
    </jaxws:outInterceptors>
    -->
</jaxws:client >



<!--
    CXF Interceptors for Inbound and Outbound messages
    Used for logging and adding Username token / Timestamp Security Header to SOAP message
-->
<bean id="logInbound" class="org.apache.cxf.interceptor.LoggingInInterceptor" />
<bean id="logOutbound" class="org.apache.cxf.interceptor.LoggingOutInterceptor" />

<bean id="TimestampUsernameToken_Request" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
    <constructor-arg>
        <map>
            <entry key="action" value="UsernameToken Timestamp" />
            <entry key="user" value="${my.group}.${my.userId}" />
            <entry key="passwordType" value="PasswordDigest" />
            <entry key="passwordCallbackClass" value="com.foo.my.ClientPasswordHandler" />
        </map>
    </constructor-arg>
</bean>

<!--
    http:conduit namespace is used to configure SSL using keystores, etc
    *.http-conduit works but CXF says its only supposed to be for temporary use (not production),
    well until the correct way works, we're going to use it.
-->
<http:conduit name="*.http-conduit">
    <http:tlsClientParameters   
                  secureSocketProtocol="SSL">
                  <!--
          <sec:trustManagers>
        <sec:keyStore type="JKS"
                         password="${my.truststore.password}"
                         file="${my.truststore.file}" />
                  </sec:trustManagers>
                  -->
                  <sec:keyManagers keyPassword="${my.keystore.password}">
                    <sec:keyStore type="JKS"
                         password="${my.keystore.password}"
                         file="${my.keystore.file}" />
                  </sec:keyManagers>

                  <!-- Cipher suites filters specify the cipher suite to allow/disallow in SSL communcation  -->
                  <sec:cipherSuitesFilter>
                    <sec:include>.*_WITH_3DES_.*</sec:include>
                    <sec:include>.*_EXPORT_.*</sec:include>
                    <sec:include>.*_EXPORT1024_.*</sec:include
                    <sec:include>.*_WITH_DES_.*</sec:include
                    <sec:exclude>.*_WITH_NULL_.*</sec:exclude
                    <sec:exclude>.*_DH_anon_.*</sec:exclude>
                  </sec:cipherSuitesFilter>
    </http:tlsClientParameters>
</http:conduit>
</beans>

Обработчик пароля клиента Java :

import java.io.IOException;

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

import org.apache.log4j.Logger;
import org.apache.ws.security.WSPasswordCallback;


/**
 * <p>
 * Provides a callback handler for use processing outbound/inbound SOAP messages.
 * ClientPasswordHandler sets the password used in the WS-Security UsernameToken 
 * SOAP header.
 * 
 * </p>
 * 
 * Created: Apr 1, 2009
 * @author Jared Knipp
 * 
 */
public final class ClientPasswordHandler implements CallbackHandler {
    protected static Logger log = Logger.getLogger(ClientPasswordHandler.class);

    private static final PropertyManager PROPS = PropertyManager.getInstance();
    private static String PASSWORD = PROPS.getPassword();
    private static boolean IS_PASSWORD_CLEAR = PROPS.getIsClearPassword();

    /**
     * Client password handler call back.  This method is used to provide
     * additional outbound (or could be inbound also) message processing.
     * 
     * Here the method sets the password used in the UsernameToken SOAP security header
     * element in the SOAP header of the outbound message.  For our purposes the clear 
     * text password is SHA1 hashed first before it is hashed again along with the nonce and 
     * current timestamp in the security header.
     */
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        if(log.isDebugEnabled()) { log.debug("Setting password for UsernameToken"); }
        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];


        // Check to see if the password is already Hashed via SHA1, if not then hash it first
        if(IS_PASSWORD_CLEAR) {
            synchronized(this) {
                PASSWORD = PasswordDigestUtil.doPasswordDigest(PASSWORD);
                IS_PASSWORD_CLEAR = false;
                PROPS.setIsClearPassword(IS_PASSWORD_CLEAR);
                PROPS.setPassword(PASSWORD);
                PROPS.saveProperties();
            }
        }

        pc.setPassword(PASSWORD);
    }
}
0 голосов
/ 29 ноября 2011

Здесь есть пост, объясняющий, как настроить Клиент и Сервер в CXF с WS-Security: Веб-сервисы JAX-WS с Spring и CXF

0 голосов
/ 31 марта 2009

Если информация отсутствует в WSDL, вы уверены, что она находится в службе, описанной WSDL? WSDL предназначен для предоставления всей информации, необходимой для описания сервиса, включая политики безопасности, необходимые для использования сервиса.

На какой платформе появился WSDL? Возможно ли, что WSDL не является полным описанием? Например, это может быть WSDL, который включает d в другой WSDL, который предоставляет информацию о безопасности.

...