Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

WSO2: Настройка прокси к сервису с аутентификацией по логину и паролю

Anna | 2.06.2014 | нет комментариев

Задача

Есть приложение, которое может запрашивать данные по определённому протоколу и есть сервис, тот, что может отдавать данные, но по иному протоколу и требует авторизации по логину и паролю.
В приложении нет учётных данных нужных для доступа к сервису. Нужно подружить приложение и сервис.

Решение

Применять шину: WSO2 Enterprise Service Bus, на которой настроить прокси-сервис.

Используем WSO2 ESB версии 4.7.0.

Создаём политики

Так как целевой сервис защищён по эталону WS-Security, то и доступ к нему будем настраивать по каждой строгости эталона.
Политики создаются как источники в локальном репозитории, в интерфейсе: Manage — Service Bus — Local Entries — Add Local Entries — Add In-lined XML Entry.

Политика для исходящих сообщений

Тут и в последующем имена могут даваться произвольные, но буду акцентировать на них внимание, потому что через них будут связываться все артефакты в одно целое
Указываем имя: service-policy
Указываем политику:

<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
            xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
            wsu:Id="UTOverTransport">
    <wsp:ExactlyOne>
        <wsp:All>
            <sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
                <wsp:Policy>
                    <sp:TransportToken>
                        <wsp:Policy>
                            <sp:HttpsToken RequireClientCertificate="false"/>
                        </wsp:Policy>
                    </sp:TransportToken>
                    <sp:AlgorithmSuite>
                        <wsp:Policy>
                            <sp:Basic128/>
                        </wsp:Policy>
                    </sp:AlgorithmSuite>
                    <sp:Layout>
                        <wsp:Policy>
                            <sp:Lax/>
                        </wsp:Policy>
                    </sp:Layout>
                    <sp:IncludeTimestamp/>
                </wsp:Policy>
            </sp:TransportBinding>
            <sp:SignedSupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
                <wsp:Policy>
                    <sp:UsernameToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"/>
                </wsp:Policy>
            </sp:SignedSupportingTokens>
            <ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">
                <ramp:user>MyUsername</ramp:user>
                <ramp:passwordCallbackClass>s.e.r.PasswordCallbackHandler</ramp:passwordCallbackClass>
            </ramp:RampartConfig>
        </wsp:All>
    </wsp:ExactlyOne>
</wsp:Policy>

Стержневой частью в этой политике является указание имени пользователя целевого обслуживания и класса, тот, что в нашем случае легко подставит нужный пароль, класс s.e.r.PasswordCallBackHandler:

package s.e.r;

import org.apache.ws.security.WSPasswordCallback;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;

public class PasswordCallBackHandler implements CallbackHandler
{
    private static final String PASSWORD = "MyPassword";
    @Override
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
    {
        for (Callback callback : callbacks)
        {
            if (callback instanceof WSPasswordCallback)
            {
                WSPasswordCallback pc = (WSPasswordCallback) callback;
                if (pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN_UNKNOWN)
                {
                    if (pc.getPassword().equals(PASSWORD))
                        return;
                    throw new UnsupportedCallbackException(callback, "Check failed");
                }
                pc.setPassword(PASSWORD);
            } else
            {
                throw new UnsupportedCallbackException(callback, "Unrecognized Callback");
            }
        }
    }
}

Пакуем в jar и кладём в WSO2_HOME/repository/components/lib/.
Рестартуем WSO2.

Политика для входящих сообщений

Указываем имя: empty-policy.
Указываем политику:

<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
            wsu:Id="UTOverTransport">
    <wsp:ExactlyOne>
        <wsp:All>
            <sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
                <wsp:Policy/>
            </sp:TransportBinding>
            <sp:SignedSupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
                <wsp:Policy/>
            </sp:SignedSupportingTokens>
        </wsp:All>
    </wsp:ExactlyOne>
</wsp:Policy>
Создаём Address Endpoint

Указываем имя: my-endpoint.
Указываем адрес обслуживания.
В добавочный опциях подмечаем применение WS-Security и указываем политики для исходящих и входящих сообщений сделанные ранее.
Исходник Endpoint’а:

<endpoint name="my-endpoint">
  <address uri="http://service/soap/">
    <enableSec inboundPolicy="empty-policy" outboundPolicy="service-policy"/>
  </address>
</endpoint>
Создаём XSLT-реформирование сообщений

XSLT-реформирования создаются там же где и политики: Manage — Service Bus — Local Entries — Add Local Entries — Add In-lined XML Entry.

Реформирование входящего сообщения

Нам нужно привести запрос нашего приложения к виду, тот, что понимает сервис:
Указываем имя: in-xslt
Указываем реформирование:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="/">
        <!--здесь само реформирование-->
    </xsl:template>
</xsl:stylesheet>
Реформирование в исходящее сообщение

Нам необходимо результат обслуживания привести к виду, внятному для приложения. Шаг одинаков шагу для входящего сообщения, только имя: out-xslt.

Создаём Proxy Service

В UI: Manage — Service — Add — Proxy Service — Custom Proxy
Указываем имя: external-service. По этому имени будет доступен ваш сервис на шине, скажем:localhost:8280/services/external-service.
В нашем случае снимаем отметку с протокола https.
Дальше переключаемся в режим начально кода (switch to source view) и приводим содержимое примерно к дальнейшему:

<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="external-service"
       transports="http"
       statistics="disable"
       trace="disable"
       startOnLoad="true">
    <target faultSequence="fault" endpoint="my-endpoint">
        <inSequence>
            <xslt key="in-xslt"/>
            <send>
                <endpoint key="my-endpoint"/>
            </send>
        </inSequence>
        <outSequence>
            <xslt key="out-xslt"/>
            <send/>
        </outSequence>
    </target>
    <description/>
</proxy>                   

Здесь указаны две последовательности для входящего и исходящего сообщения, обе начинаются с соответствующего реформирования и после этого посылают сообщение в необходимом направлении.

Готово!

Добавочно

Дабы следить за тем, во что трансформирует наша прокси сообщения, применял fiddler

Потому что не нашёл как настроить и где глядеть финальные сообщения.
Подробнее про fiddler:

Прокси пробрасывает заголовок Action пришедшие из приложения, а сервис ругается?

Добавляем медиаторы в последовательность прокси обслуживания, удаляем заголовок Action:

<inSequence>
    <xslt key="in-xslt"/>
    <header name="Action" value=""/>
    <property name="SOAPAction" value="" scope="transport"/>
    <send>
        <endpoint key="my-endpoint"/>
    </send>
</inSequence>
Прокси возвращает данные в некорректной кодировке?

Указываем кодировку, в которой возвращаем сообщения:

<outSequence>
    <xslt key="out-xslt"/>
    <property name="messageType"
              value="text/xml;charset=windows-1251"
              scope="axis2"
              type="STRING"/>
    <send/>
</outSequence>
Результат обслуживания состоит из нескольких частей?

Скажем:

<soapenv:Envelope>
    <soapenv:Body>
        <part1/>
        <part2/>
    </soapenv:Body>
</soapenv:Envelope> 

WSO2 по умолчанию считает что результат должен состоять из одной части, следственно передают на реформирование то что находится по пути: s11:Body/child::*[position()=1] | s12:Body/child::*[position()=1], как итог мы можем трансформировать только первую часть, Дабы это поправить меняем вызов преобразователя в сервисе:

<outSequence>
    <xslt xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
          key="stav-out-xslt"
          source="SOAP-ENV:Body"/>
    <send/>
</outSequence>

… и рассматриваем это в преобразователе:

<xsl:stylesheet>
    <xsl:template match=".">
        <xsl:apply-templates select="/part1"/>
        <xsl:apply-templates select="/part2"/>
    </xsl:template>
    <!--в нашем случае part1 необходимо было проигнорировать-->
    <xsl:template match="part1"/>
    <xsl:template match="part2">
        <forbody>
            <!--здесь трансформации обёрнутые в произвольный тег, он нужен, чтоб в финальном итоге не пропал корневой элемент результата-->
        </forbody>
    </xsl:template>
</xsl:stylesheet>

Нерешённые вопросы

Пришлось настраивать две политики безопасности

Есть чувство что дозволено обойтись одной, но с цельной политикой выходила оплошность, о том, что результат обслуживания не содержит заголовков безопасности. А он подлинно их не содержит. Чтоб это обойти пришлось писать пустую политику для результата.

Не обнаружено встроенного решения для хранения учётных данных стороннего обслуживания

Несуразное решение с классом для хранения пароля явственный костыль, тот, что необходимо заменить подходящим решением, либо встроенным, либо велосипедом.

Вывод

  • Часть с реформированием не вызвала задач, помимо того, что настройка дюже крепко размазана по UI. Безусловно дозволено настраивать через цельный xml в том же UI, но в этом случае настройка будет размазана по xml.
  • Достаточно высокий порог вступления для решения примитивной задачи.
  • Задача решена!

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB