В течение многих месяцев я занимался реализацией прокси-сервера веб-службы с использованием Mule ESB CE . Хотя для его настройки потребовалась определенная работа, сейчас она работает хорошо. В этом посте я покажу вам результат. Давайте начнем с конфигурации входящего запроса, который подписан и должен быть проверен. Кстати, я знаю, что в Mule есть также шаблон webservice-proxy-pattern, но я не мог использовать его в сочетании с подписью / проверкой, что мне нужно было сделать. Итак, вот поток, который проверяет входящий SOAP-запрос:
<flow name="order-status-update">
        <https:inbound-endpoint address="${my.incoming.url}" connector-ref="httpsConnector">
            <cxf:proxy-service>
                <cxf:inInterceptors>
                    <spring:bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
                    <spring:bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
                        <spring:constructor-arg>
                            <spring:map>
                                <spring:entry key="action" value="Signature" />
                                <spring:entry key="signaturePropFile" value="ws-validate-security.properties" />
                            </spring:map>
                        </spring:constructor-arg>
                    </spring:bean>
                </cxf:inInterceptors>
            </cxf:proxy-service>
        </https:inbound-endpoint>
        <https:outbound-endpoint address="${my.internal.url}" connector-ref="httpsConnector">
            <cxf:proxy-client />
        </https:outbound-endpoint>
    </flow>
Примечание: обратите внимание, что значения ‘$ {}’ являются свойствами, считанными из файла свойств, как описано в этой статье.
Как вы можете видеть, я определил прокси-сервер CXF с двумя перехватчиками: один для ведения журнала и один для выполнения действий безопасности с использованием библиотеки Apache WSS4J . Я поставляю два параметра для WSS4JInInterceptor:
- «действие»: описывает, какое действие должно быть выполнено перехватчиком. Возможные значения: «Подпись», «Метка времени», «Зашифровать» и другие.
- ‘signaturePropFile’: параметр ссылается на файл свойств, который будет использоваться перехватчиком.
Содержимое файла ‘ws-validate-security.properties’, размещенного на пути к классам Mule, гласит следующее:
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin org.apache.ws.security.crypto.merlin.keystore.type=JKS org.apache.ws.security.crypto.merlin.file=/usr/local/keystores/myKeystore.jks org.apache.ws.security.crypto.merlin.keystore.password=myPassword
Для более подробного описания этих свойств и используемой технологии см.
 Эту статью .
Но это все, чтобы настроить эту часть. В этом случае я использовал Mule CE 3.2. Конфигурация mule использует следующие пространства имен:
<mule xmlns="http://www.mulesoft.org/schema/mule/core"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:cxf="http://www.mulesoft.org/schema/mule/cxf"
      xmlns:spring="http://www.springframework.org/schema/beans"
      xmlns:https="http://www.mulesoft.org/schema/mule/https"
      xsi:schemaLocation="
        http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/3.2/mule.xsd
        http://www.mulesoft.org/schema/mule/cxf http://www.mulesoft.org/schema/mule/cxf/3.2/mule-cxf.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.mulesoft.org/schema/mule/https http://www.mulesoft.org/schema/mule/https/3.2/mule-https.xsd">
Для полноты используются следующие зависимости в pom.xml:
<dependency> <groupId>org.mule</groupId> <artifactId>mule-core</artifactId> <version>3.2.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.mule.modules</groupId> <artifactId>mule-module-spring-config</artifactId> <version>3.2.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.mule.transports</groupId> <artifactId>mule-transport-http</artifactId> <version>3.2.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.mule.modules</groupId> <artifactId>mule-module-cxf</artifactId> <version>3.2.1</version> <scope>provided</scope> </dependency>
А вот конфигурация для подписи исходящих запросов:
<flow name="place-order">
  <https:inbound-endpoint address="${my.internal.url}" connector-ref="httpsConnector" responseTimeout="0">
    <cxf:proxy-service enableMuleSoapHeaders="false" payload="envelope" />
  </https:inbound-endpoint>
  <https:outbound-endpoint address="${my.outgoing.url}" connector-ref="httpsConnector" responseTimeout="0" >
    <cxf:proxy-client payload="envelope">
      <cxf:outInterceptors>
        <spring:bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
          <spring:constructor-arg>
            <spring:map>
              <spring:entry key="action" value="Signature" />
              <spring:entry key="user" value="${signature.user}" />
              <spring:entry key="signaturePropFile" value="ws-sign-security.properties" />
              <spring:entry key="passwordCallbackClass" value="net.pascalalma.MyKeystorePasswordCallback"/>
              <spring:entry key="signatureKeyIdentifier" value="DirectReference" />
            </spring:map>
          </spring:constructor-arg>
        </spring:bean>
        <spring:bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
      </cxf:outInterceptors>
    </cxf:proxy-client>
  </https:outbound-endpoint> 
</flow>
Важным перехватчиком здесь, конечно же, является
 WSS4JOutInterceptor . Свойства, настроенные здесь:
- «действие»: описывает, какое действие должно быть выполнено перехватчиком
- ‘user’: псевдоним сертификата в криптоконфигурации подписи, которым нужно подписать сообщение. Пароль извлекается из обработчика обратного вызова.
- ‘signaturePropFile’: определяет имя файла, содержащего свойства с желаемыми настройками в нем.
- ‘passwordCallbackClass’: ссылка на обработчик обратного вызова для получения паролей для закрытых ключей в криптографических конфигурациях подписи и шифрования.
- ‘signatureKeyIdentifier’: метод вложения ключа подписи. Я хочу поместить токен непосредственно в заголовок и не использовать ссылку.
«SignaturePropFile» содержит следующую информацию:
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin org.apache.ws.security.crypto.merlin.keystore.type=JKS org.apache.ws.security.crypto.merlin.file=/usr/local/keystores/myKeystore.jks org.apache.ws.security.crypto.merlin.keystore.password=myPassword
Как вы видите, я добавил пароль, который используется для открытия хранилища ключей здесь в виде простого текста. Конечно, это не способ сделать это в производственной системе, но для разработки это довольно удобно. Я использую MyKeystorePasswordCallback для получения этого пароля, как показано в следующей реализации этого класса:
package net.pascalalma;
import java.io.IOException;
import java.util.ResourceBundle;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
/**
 *
 * @author Pascal Alma
 */
public class MyKeystorePasswordCallback implements CallbackHandler {
    private static final String BUNDLE_LOCATION = "ws-sign-security";
    private static final String PASSWORD_PROPERTY_NAME = "org.apache.ws.security.crypto.merlin.keystore.password";	
    private static String password;
    static {
        final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_LOCATION);
        password = bundle.getString(PASSWORD_PROPERTY_NAME);
    }	
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
        // set the password for our message.
        pc.setPassword(password);
    }
}
На этом завершается пример полной конфигурации для подписания и проверки запросов SOAP с помощью Mule ESB. Хотя это не ракетостроение, потребовалось довольно много времени, чтобы собрать полную конфигурацию и работать. И еще есть возможности для улучшения, в основном для обработки ошибок, но я оставлю это в другой раз
