Web-сервисы Java: Освоение WS-Policy

Детали системы WS-Policy и ее работа с тремя стеками Web-сервисов Java с открытым исходным кодом

WS-Policy обеспечивает общую структуру для настройки функций и опций, применимых к Web-сервисам. В этом цикле статей мы рассмотрели, как она используется для конфигураций WS-Security и в других дополняющих технологиях, таких как WS-ReliableMessaging. В этой статье мы рассмотрим структуру документов WS-Policy и способы прикрепления политик к сервисам средствами языка Web Service Description Language (WSDL) с примерами безопасных конфигураций для Apache Axis2, Metro и Apache CXF.

Денис Сосноски, консультант, Sosnoski Software Solutions, Inc.

Денис Сосноски (Dennis Sosnoski) - основатель и ведущий специалист консалтинговой компании по технологиям Java - Sosnoski Software Solutions, Inc., специализирующейся в обучении и консультировании по проблемам XML и Web-сервисов. Он имеет более чем 30-летний опыт работы в профессиональном проектировании ПО, специализируясь на серверных XML и Java-технологиях. Денис является основным разработчиком интегрированной системы с открытым программным кодом JiBX XML Data Binding, построенной на базе технологии классов Java и связанной системы Web-сервисов JibxSoap, также как и системы Web-сервисов Apache Axis2. Он также был одним их экспертов при разработке спецификаций JAX-WS 2.0.



26.03.2012

Об этом цикле статей

Web-сервисы ― важная функция технологии Java™ в корпоративных вычислениях. В этом цикле статей консультант по XML и Web-сервисам Денис Сосноски рассказывает об основных структурах и технологиях, ценных для Java-разработчиков, использующих Web-сервисы. Следите за статьями цикла, чтобы быть в курсе последних разработок в данной области и знать, как применить их в своих собственных проектах.

В цикле статей Web-сервисы Java много примеров применения WS-Policy и WS-SecurityPolicy, но вопрос о том, как же на самом деле работает WS-Policy (или, по крайней мере, как она должна работать), пока не обсуждался. В этой статье я сначала заполню этот пробел и немного расскажу о WS-Policy. Затем вы увидите, как прикреплять политики к сервисам в WSDL-документах. Наконец, я приведу некоторые примеры конфигураций WS-Policy для Axis2, Metro и CXF и покажу, как они работают на практике. (Полный код примеров приведен в разделе Загрузка.)

Основы WS-Policy

WS-Policy определяет простую XML-структуру, состоящую из четырех элементов и пары атрибутов. В интерпретации WS-Policy эти элементы и атрибуты дают возможность организовывать и комбинировать формулировки политики любой степени сложности. Для определения фактических формулировок, составляющих политику, используется не сама WS-Policy, а ее предметно-ориентированные расширения, такие как WS-SecurityPolicy.

Версии WS-Policy

Детали WS-Policy, рассматриваемые в этой статье, относятся к "официальной" версии WS-Policy 1.5, опубликованной консорциумом W3C, но те же общие правила применимы и к более старой версии submission, которая по-прежнему широко используется. Как и в случае других технологий WS-*, чтобы сказать, какая версия документа используется, нужно проверить пространство имен XML. Пространство имен для WS-Policy 1.5 – это http://www.w3.org/ns/ws-policy, а для версии submission ― http://schemas.xmlsoap.org/ws/2004/09/policy. В этой статье я использую пространство имен http://www.w3.org/ns/ws-policy, представленное префиксом WSP.

Для удобства WS-Policy определяет как выражения политики в нормальной форме, так и набор правил, который можно использовать для создания более компактных выражений. Нормальная форма может быть несколько многословной, так что большинство составителей документов политик (несмотря на рекомендацию WS-Policy о том, что "там, где это целесообразно, СЛЕДУЕТ использовать нормальную форму выражений политики"), как правило, используют по крайней мере некоторые правила компактного выражения, чтобы сделать свои документы более наглядными. Тем не менее, интерпретация документов политик базируется на нормальной форме, так что я в первую очередь расскажу о ней.

Нормальная форма выражений

В нормальной форме выражений политик используются максимум три элемента, которые всегда должны быть вложены в определенном порядке. Внешний элемент – это всегда <wsp:Policy>, и он должен содержать один дочерний элемент <wsp:ExactlyOne>. Вложенный <wsp:ExactlyOne>, в свою очередь, содержит любое число (включая ноль) дочерних элементов <wsp:All>. Таким образом, простейшей нормальной формой выражения политики является <wsp:Policy><wsp:ExactlyOne/></wsp:Policy>.

Любое утверждение политики в нормальной форме должно быть вложено в элемент <wsp:All>. Эти утверждения политики сами могут содержать выражения политики. Это было видно в прошлых статьях данного цикла, где многие из утверждений WS-SecurityPolicy содержат вложенные выражения политики. В нормальной форме выражения политики все эти вложенные утверждения политики сами должны быть представлены в нормальной форме. (На самом деле, они должны быть представлены в еще более ограниченном подмножестве нормальной формы, где каждый элемент <wsp:ExactlyOne>, за исключением самого верхнего, имеет один и только один дочерний элемент <wsp:All>.) В листинге 1 показан фрагмент кода с несколькими примерами вложенных выражений политики в нормальной форме.

Листинг 1. Фрагмент кода WS-SecurityPolicy с вложенными выражениями политики
<wsp:Policy>
  <wsp:ExactlyOne>
    <wsp:All>
      <sp:AsymmetricBinding
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
        <wsp:Policy>
          <wsp:ExactlyOne>
            <wsp:All>
              <sp:InitiatorToken>
                <wsp:Policy>
                  <wsp:ExactlyOne>
                    <wsp:All>
                      <sp:X509Token
                          sp:IncludeToken=".../IncludeToken/AlwaysToRecipient">
                        <wsp:Policy>
                          <wsp:ExactlyOne>
                            <wsp:All>
                              <sp:RequireThumbprintReference/>
                            </wsp:All>
                          </wsp:ExactlyOne>
                        </wsp:Policy>
                      </sp:X509Token>
                    </wsp:All>
                  </wsp:ExactlyOne>
                </wsp:Policy>
              </sp:InitiatorToken>
              ...

Несмотря на множество уровней вложенных элементов, семантика этой структуры довольно проста. В нормальной форме выражения политики <wsp:Policy> - это всего лишь оболочка для выражения политики, и, в случае выражений политики самого верхнего уровня, место приложения к политике имени или идентификатора. Вложенный элемент <wsp:ExactlyOne> представляет логическую комбинацию или из альтернатив, представленных вложенными элементами <wsp:All> (таким образом, все выражение политики будет выполнено, если выполнена любая из вложенных альтернатив). Каждый элемент <wsp:All> представляет собой логическую комбинацию и вложенных утверждений политики (так что альтернатива выполняется, только если выполнены все утверждения).

Ненормализованная политика

Выражения политики не обязательно должны быть представлены в нормальной форме. Аномальные выражения политики могут содержать вложенные альтернативы (несколько дочерних элементов <wsp:All> элемента <wsp:ExactlyOne> ниже верхнего уровня), а также использовать варианты компактного выражения политики, которые обсуждаются в следующем разделе.

Те, кто изучал математическую логику, заметят, что представление нормальной формы (без вложенных альтернатив) эквиваленто дизъюнктивной нормальной форме логического выражения. Выражения политики на самом деле ― просто логические выражения, использующие формат угловых скобок, с утверждениями в качестве выражений. В математической логике доказывается, что любое логическое выражение можно преобразовать в дизъюнктивную нормальную форму, и тот же принцип применим и к выражениям политики, записанным в форме с вложенными альтернативами - их можно развернуть в представление в нормальной форме с альтернативами только на самом верхнем уровне. Главное преимущество выражений политики в нормальной форме ― то, что они облегчают проверку двух политик на программную совместимость - если две политики в нормальной форме совместимы, они имеют один или более элементов верхнего уровня <wsp:All>, содержащих одни и те же наборы утверждений.

Компактное выражение политики

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

Одной из особенностей компактного выражения является возможность выразить политику через вложения из основных элементов политики (называемых операторами политики, так как каждый элемент подразумевает определенную интерпретацию вложенных утверждений), следующих в любом порядке. Правила вложения определяют также интерпретацию элемента <wsp:Policy>, используемого непосредственно (без дочернего элемента <wsp:ExactlyOne>, который требуется в нормальной форме) в качестве эквивалента <wsp:All>,что, пожалуй, является наиболее широко применяемой особенностью компактных выражений.

В листинге 2 показано компактное выражение той же политики, которая приведена в листинге 1, но с использованием этого представления <wsp:Policy>. Эта версия вдвое короче первой и гораздо проще для понимания.

Листинг 2. Простая политика в компактной форме
<wsp:Policy>
  <sp:AsymmetricBinding
      xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
    <wsp:Policy>
      <sp:InitiatorToken>
        <wsp:Policy>
          <sp:X509Token
              sp:IncludeToken=".../IncludeToken/AlwaysToRecipient">
            <wsp:Policy>
              <sp:RequireThumbprintReference/>
            </wsp:Policy>
          </sp:X509Token>

        </wsp:Policy>
      </sp:InitiatorToken>
      ...

WS-Policy определяет набор преобразований, которые можно применять для преобразования выражения политики с использованием компактного варианта в нормальную форму, так что нет никаких оснований использовать нормальную форму непосредственно. Компьютеру гораздо проще преобразовать компактное выражение в нормальную форму, чем человеку интерпретировать ее.

Включение политики

Помимо упрощения вложения элементов, компактное выражение дает также возможность ссылаться на выражения политики и многократно использовать их. Это можно сделать с помощью четвертого элемента WS-Policy, <wsp:PolicyReference>. Элемент <wsp:PolicyReference> может находиться в любом месте, где допустимо утверждение политики. Указанное выражение политики эффективно заменяется ссылкой на политику (технически - с помощью элемента <wsp:All>, заменяющего указанный элемент <wsp:Policy>). Такой подход замены называется включением политики.

Листинг 3 иллюстрирует использование включения политики, показывая, как выражение политики из листинга 2 преобразуется в форму с использованием отдельного выражения политики и ссылки.

Листинг 3. Ссылка на политику
<!-- Client X.509 token policy assertion. -->
<wsp:Policy wsu:Id="ClientX509"
    xmlns:wsu="http://.../oasis-200401-wss-wssecurity-utility-1.0.xsd">
  <sp:InitiatorToken>
    <wsp:Policy>
      <sp:X509Token
          sp:IncludeToken=".../IncludeToken/AlwaysToRecipient">
        <wsp:Policy>
          <sp:RequireThumbprintReference/>
        </wsp:Policy>
      </sp:X509Token>
    </wsp:Policy>
  </sp:InitiatorToken>
</wsp:Policy>

<wsp:Policy>
  <sp:AsymmetricBinding
      xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
    <wsp:Policy>
      <wsp:PolicyReference URI="#ClientX509"/>
      ...

Ссылку на политику можно использовать как для локальных выражений политики, как показано в листинге 3, так и для внешних. Для внешних выражений политики атрибут ссылки URI обычно содержит фактический URL внешней политики.

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

Альтернативы политики

Как было показано выше, структура WS-Policy поддерживает выбор между альтернативами в рамках политики с помощью элемента <wsp:ExactlyOne>. В компактном выражении можно (по крайней мере, теоретически) использовать также специальные атрибуты для создания вариантов. В соответствии с рекомендацией WS-Policy, можно добавить атрибут wsp:Optional="true" к любому утверждению, чтобы сделать его необязательным, даже если это дочернее утверждение элемента <wsp:All> или <wsp:Policy>.

Альтернативные политики кажутся потенциально полезной функцией, но нетривиальный пример придумать трудно. На практике эта функция используется, как правило, для того, чтобы сделать тот или иной компонент управления защитой, такой как UsernameToken, факультативным. Более сложные варианты, такие как предоставление клиенту возможности предъявить удостоверение в виде либо UsernameToken, либо сертификата X.509, похоже, выходят за рамки возможностей текущих реализаций WS-SecurityPolicy.


Прикрепление политики

В WSDL 1.1 (несколько устаревшая, но все же наиболее широко используемая форма определения сервисов), для определения сервиса используется иерархическая структура. Первый (нижний) уровень состоит из элементов <wsdl:message>, определяющих структуру XML-сообщений, принимаемых и передаваемых сервисом. Второй уровень – это элементы <wsdl:portType>, определяющие наборы операций, где для каждой операции определены входное сообщение, выходное сообщение или сообщение об ошибке.Третий уровень – это элементы <wsdl:binding>, которые связаны с определенным протоколом сообщений (таким как SOAP) и методом доступа к <wsdl:portType>. Четвертый уровень – это определения конечных точек сервиса в виде элементов <wsdl:port>, содержащих адрес, по которому можно обращаться к <wsdl:binding>.

Схема WSDL

В части определений XML-схемы WSDL 1.1 имеет долгую и богатую событиями историю. Оригинальная версия WSDL 1.1 включала как текстовое описание того, как должны быть структурированы XML-документы WSDL, так и определение XML схемы. К сожалению, прилагаемая XML-схема не соответствовала тексту. Позже это было исправлено в модифицированной версии схемы, но документ WSDL 1.1 не был отредактирован с учетом этого изменения. Затем группа Basic Profile WS-I решила внести еще больше изменений в WSDL-схему и создала то, что преподносится как практические рекомендации к этой сомнительной схеме. Документы, написанные для одной версии схемы, как правило, не совместимы с другими версиями (несмотря на то, что используется одно и то же пространство имен), но к счастью, большинство инструментов Web-сервисов в основном игнорирует схему и принимает все, что выглядит разумным. (См. ссылки на многие схемы WSDL в разделе Ресурсы).

WS-Policy позволяет прикрепить политики к определениям WSDL-сервисов в нескольких разных точках, которые не обязательно совпадают с этими уровнями определения. Если уровни представляют собой логическую структуру определений сервиса, то WS-Policy больше сосредоточена на сообщениях и группировании сообщений. Используются следующие четыре уровня группирования сообщений WS-Policy:

  • Сообщение: политика применяется к конкретному сообщению (везде, где используется сообщение, если политика крепится через элемент<wsdl:message>, или при использовании конкретной операции, если она присоединена посредством определений входа/выхода/ошибки операции в любом из элементов <wsdl:portType> или <wsdl:binding>).
  • Операция: политика применяется ко всем случаям обмена сообщениями для конкретной операции (политика, присоединенная через элемент <wsdl:operation>, внутри <wsdl:binding> или <wsdl:portType>).
  • Конечная точка: политика применяется ко всем случаям обмена сообщениями для конкретной привязки сервиса (политика, присоединенная через элемент<wsdl:port> или <wsdl:binding>) или для всех привязок сервиса на основе определенного типа порта (политика, при соединенная к этому типу порта <wsdl:portType>).
  • Сервис: политика применяется ко всем конечным точкам и всем операциям, связанным с сервисом (политика присоединяется в элементе <wsdl:service>).

Основной механизм присоединения политики, используемый для WSDL, ― тот же, что и для ссылки на одну политику внутри другой политики – элемент <wsp:PolicyReference>, обсуждавшийся в разделе Включение политики. Этот элемент WS-Policy может быть добавлен в качестве дочернего к любым перечисленным выше элементам WSDL для определения политики, которая должна применяться на этом уровне группирования сообщений. Политику можно вставить и непосредственно в качестве элемента <wsp:Policy> с любым подходящим содержанием, но как правило, все же лучше использовать ссылки, чтобы сохранить прозрачную структуру WSDL.

Политики, применяемые на одном уровне группирования сообщений, наследуются нижними уровнями в сочетании с элементом <wsp:All>. Это делает фактическую (или эффективную в терминах WS-Policy) политику, применяемую к каждому сообщению, сочетанием всех политик, применяемых на уровнях сообщения, операции, конечной точки и сервиса. Таким образом, политика определяется не только самим сообщением, но и контекстом, в котором оно используется.

В листинге 4 показано, как это работает, в виде структуры определения WSDL со ссылками на политики.

Листинг 4. Пример присоединения политик
<wsdl:binding name="LibrarySoapBinding" type="wns:Library">

  <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy" URI="#UsernameToken"/>

  <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
  
  <wsdl:operation name="addBook">
  
    <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy" URI="#AsymmEncr"/>
    ...

  </wsdl:operation>

</wsdl:binding>

В данном случае политика, которая требует UsernameToken, присоединена на уровне <wsdl:binding>, а дополнительная политика, требующая асимметричного шифрования сообщений, ― к операции addBook, определенной как часть этой привязки. Если предположить, этот пример демонстрирует весь набор ссылок для политики WSDL, то UsernameToken требуется всегда, но подписание сообщения используется только для операции addBook.

В качестве альтернативы использованию <wsp:PolicyReference>, ссылок на политику непосредственно из элементов WSDL, можно использовать атрибут wsp:PolicyURIs. Этот атрибут можно добавить к любому элементу WSDL, к которому может присоединяться политика. Она работает в основном так же, как при использовании дочерних элементов <wsp:PolicyReference>.

Вложение WS-SecurityPolicy

WS-SecurityPolicy указывает на уровни группирования сообщений, на которых к описанию сервиса могут присоединяться различные типы утверждений политики. Например, утверждение <sp:TransportBinding>, используемое для определения безопасности транспортировки, может быть присоединено только на уровне конечной точки, в то время как утверждения <sp:AsymmetricBinding> и <sp:SymmetricBinding>, используемые для определения шифрования или подписания сообщений, может использоваться только на уровне конечной точки или операции.

Несмотря на то, что <sp:AsymmetricBinding> или <sp:SymmetricBinding> нельзя указать на уровне сообщений, на этом уровне можно указать компоненты сообщения, которые должны быть зашифрованы или подписаны. Это означает, что, по крайней мере, теоретически, можно задавать шифрование или подписание каждого отдельного сообщения.


Примеры политик

Когда эта статья была впервые опубликована, пример Axis2 не работал. Вскоре после публикации мне удалось решить эту проблему, используя другую конфигурацию. Пересмотренный текст статьи и код для загрузки отражают эти изменения.

Теперь, когда вы знакомы с принципами WS-Policy и знаете, как она работает с WSDL, пришло время привести некоторые примеры политик с использованием этих принципов. Как и в предыдущих статьях, я привожу код для всех трех основных стеков Web-сервисов с открытым исходным кодом для языка Java: Axis2, Metro и CXF.

В листинге 5 показан один из примеров (effective1.wsdl из загрузки) с использованием трех уровней вложений политик в WSDL-определении сервиса. Это следующие три политики:

  • UsernameToken: требует UsernameToken с зашифрованным паролем;
  • SymmEncr: требует симметричного шифрования с использованием секретного ключа, сгенерированного клиентом;
  • EncrBody: требует шифрование тела сообщения.
Листинг 5. Пример действующей политики
<wsdl:definitions targetNamespace="http://ws.sosnoski.com/library/wsdl"...>
  

  <wsp:Policy wsu:Id="UsernameToken" xmlns:wsp="http://www.w3.org/ns/ws-policy"...>
    <sp:SupportingTokens>
      <wsp:Policy>
        <sp:UsernameToken sp:IncludeToken=".../IncludeToken/AlwaysToRecipient">
          <wsp:Policy>
            <sp:HashPassword/>
          </wsp:Policy>
        </sp:UsernameToken>
      </wsp:Policy>
    </sp:SupportingTokens>
  </wsp:Policy>
  
  <wsp:Policy wsu:Id="SymmEncr" xmlns:wsp="http://www.w3.org/ns/ws-policy"...>
    <sp:SymmetricBinding>
      <wsp:Policy>
        <sp:ProtectionToken>
          <wsp:Policy>
            <sp:X509Token sp:IncludeToken=".../IncludeToken/Never">
              ...
            </sp:X509Token>
          </wsp:Policy>
        </sp:ProtectionToken>
        ...
      </wsp:Policy>
    </sp:SymmetricBinding>
    ...
  </wsp:Policy>
  
  <wsp:Policy wsu:Id="EncrBody" xmlns:wsp="http://www.w3.org/ns/ws-policy"...>
    <sp:EncryptedParts>
      <sp:Body/>
    </sp:EncryptedParts>

  </wsp:Policy>
  ...
  <wsdl:binding name="LibrarySoapBinding" type="wns:Library">
    <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
        URI="#UsernameToken"/>
    ...
    <wsdl:operation name="getBook">
      <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
          URI="#SymmEncr"/>
      <wsdlsoap:operation soapAction="urn:getBook"/>
      <wsdl:input name="getBookRequest">
        <wsdlsoap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="getBookResponse">
        <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
            URI="#EncrBody"/>
        <wsdlsoap:body use="literal"/>

      </wsdl:output>
    </wsdl:operation>

    <wsdl:operation name="getBooksByType">
      <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
          URI="#SymmEncr"/>
      <wsdlsoap:operation soapAction="urn:getBooksByType"/>
      <wsdl:input name="getBooksByTypeRequest">
        <wsdlsoap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="getBooksByTypeResponse">
        <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
            URI="#EncrBody"/>
        <wsdlsoap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>

    <wsdl:operation name="getTypes">
    ...
    </wsdl:operation>

    <wsdl:operation name="addBook">
      <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
          URI="#SymmEncr"/>
      <wsdlsoap:operation soapAction="urn:addBook"/>
      <wsdl:input name="addBookRequest">
        <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
            URI="#EncrBody"/>
        <wsdlsoap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="addBookResponse">
        <wsdlsoap:body use="literal"/>
      </wsdl:output>
      <wsdl:fault name="addDuplicateFault">
        <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
            URI="#EncrBody"/>
        <wsdlsoap:fault name="addDuplicateFault" use="literal"/>
      </wsdl:fault>
    </wsdl:operation>
  </wsdl:binding>
  ...
</wsdl:definitions>

С помощью ссылок на политики в листинге 5 (выделены жирным шрифтом) WSDL-документ присоединяет политику UsernameToken к <wsdl:binding>, так что UsernameToken требуется для всех операций. Политика SymmEncr присоединена к отдельной операции <wsdl:operation> для всех операций обмена информацией о книге, а политика EncrBody присоединена к сообщениям, содержащим сведения о книге - так что они всегда передаются в зашифрованном виде.

Это сложная политика, так как она требует, чтобы клиент генерировал секретный ключ и передавал его на сервер с сообщением запроса, даже если этот секретный ключ используется лишь для шифрования ответа. Axis2 1.5.1 (в дистрибутиве 1.5.2 не оказалось файла, необходимого для управления защитой) полностью игнорировал политику как в сгенерированном коде, так и в операциях сервера, благополучно работая без всякой защиты. Когда я изменил политики для использования пространства имен версии submission, Axis2 признал политики и заработал правильно, за исключением отработки ошибки операции addBook. В соответствии с политикой предполагается, что ответ приложения на сообщение об ошибке должен быть зашифрован, но Axis2 отправлял его в незашифрованном виде.

Metro генерировал сообщение-запрос с UsernameToken, но без информации секретного ключа, так что первый обмен сообщениями совсем не удался. CXF 2.3.0 работал гораздо лучше, чем Metro, правильно обрабатывая политики, за исключением двух случаев. Когда операция addBook выполняется успешно, в ответном сообщении шифрование не использовалось. Сервер CXF в этом случае работает правильно, но клиент выдает исключение при обработке ответа. Другая ошибка CXF та же, что и у Axis2 ― неиспользование шифрования при ответе на сообщение об ошибке приложения.

Политика из листинга 5 демонстрирует избирательное применение шифрования сообщений, шифрование только тех сообщений, которые содержат сведения о книге. Тем не менее, эта политика использует симметричное шифрование. Было бы здорово иметь возможность делать то же с применением асимметричного шифрования, когда у клиента имеется собственный сертификат (особенно если нужно подписывать сообщения для проверки отправителя). В листинге 6 приведен пример, разработанный с этой целю (effective2.wsdl в загрузке). В нем используются только две политики из WSDL:

  • AsymmBinding: требует асимметричного шифрования с применением двух сертификатов;
  • SignBody: требует подписания тела сообщения.
Листинг 6. Пример асимметричного подписаня
<wsdl:definitions targetNamespace="http://ws.sosnoski.com/library/wsdl"...>

  <wsp:Policy wsu:Id="AsymmBinding" xmlns:wsp="http://www.w3.org/ns/ws-policy" ...>
    <sp:AsymmetricBinding>
      <wsp:Policy>
        <sp:InitiatorToken>
          <wsp:Policy>
            <sp:X509Token sp:IncludeToken=".../IncludeToken/AlwaysToRecipient">
              ...
            </sp:X509Token>
          </wsp:Policy>
        </sp:InitiatorToken>
        <sp:RecipientToken>
          <wsp:Policy>
            <sp:X509Token sp:IncludeToken=".../IncludeToken/Never">
              ...
            </sp:X509Token>
          </wsp:Policy>
        </sp:RecipientToken>
        ...
      </wsp:Policy>
    </sp:AsymmetricBinding>
  </wsp:Policy>
  
  <wsp:Policy wsu:Id="SignBody" xmlns:wsp="http://www.w3.org/ns/ws-policy" ...>
    <sp:SignedParts>
      <sp:Body/>
    </sp:SignedParts>
  </wsp:Policy>
  ...
  <wsdl:binding name="LibrarySoapBinding" type="wns:Library">
    ...
    <wsdl:operation name="getBook">
      <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
          URI="#AsymmBinding"/>
      <wsdlsoap:operation soapAction="urn:getBook"/>
      <wsdl:input name="getBookRequest">
        <wsdlsoap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="getBookResponse">
        <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
            URI="#SignBody"/>
        <wsdlsoap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>

    <wsdl:operation name="getBooksByType">
      <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
          URI="#AsymmBinding"/>
      <wsdlsoap:operation soapAction="urn:getBooksByType"/>
      <wsdl:input name="getBooksByTypeRequest">
        <wsdlsoap:body use="literal"/>
      </wsdl:input>

      <wsdl:output name="getBooksByTypeResponse">
        <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
            URI="#SignBody"/>
        <wsdlsoap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>

    <wsdl:operation name="getTypes">
      ...
    </wsdl:operation>

    <wsdl:operation name="addBook">
      <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
          URI="#AsymmBinding"/>
      <wsdlsoap:operation soapAction="urn:addBook"/>
      <wsdl:input name="addBookRequest">
        <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
            URI="#SignBody"/>
        <wsdlsoap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="addBookResponse">
        <wsdlsoap:body use="literal"/>
      </wsdl:output>
      <wsdl:fault name="addDuplicateFault">
        <wsdlsoap:fault name="addDuplicateFault" use="literal"/>
      </wsdl:fault>
    </wsdl:operation>
  </wsdl:binding>
  ...
</wsdl:definitions>

В примере из листинга 6 используется асимметричное шифрование для подписания всех сообщений, содержащих сведения о книге. Это означает, что ответные сообщения getBook и getBooksByType должны быть подписаны сервером, а сообщение запроса addBook ― клиентом. Так как это делается с помощью асимметричного шифрования, при котором каждая сторона имеет свой собственный сертификат и секретный ключ, управлять этим должно быть несколько проще, чем в примере симметричного шифрования из листинга 5.

Ссылки на внешние политики

Ссылки на внешние политики плохо вписываются в структуру приведенных примеров, но я их пробовал. Для своего теста я использовал как относительные ссылки вида <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy" URI="./asymm-binding-policy.xml"/>, так и абсолютные URL, размещенные на Web-сервере. И Axis2, и Metro не смогли справиться с ссылками на политики этого типа. Но с CXF они работали правильно.

Axis2 не сработал точно так же, как и в предыдущем примере, полностью игнорируя компоненты политики с использованием пространства имен WS-Policy 1.5. Когда я изменил его на пространство имен submission, Axis2 справился с этим примером без ошибок. Из-за этих проблем использования пространства имен WS-Policy 1.5 с Axis2 во всех примерах Axis2 в коде загрузки используется пространство имен submission.

Metro оказался не в состоянии работать с этой конфигурацией политики и отвечал клиенту исключением NullPointerException в самом первом запросе. Проведя исследование, я обнаружил, что проблема исчезает, если применить политики на уровне конечной точки, а не только на уровнях операции и сообщения. Пример Metro содержит effective3.wsdl со ссылкой на политику #AsymmBinding только из <wsdl:binding>, и этот пример работает без проблем (хотя, как и CXF в случае симметричного шифрования, Metro не применяет политику безопасности в ответах на ошибки приложений).

CXF тоже не справлялся с конфигурацией политики из листинга 6, но никаких простых решений для текущего кода не нашлось. Код клиента CXF неправильно генерирует подпись при отправке сообщения запроса getBook, а код сервера не может обработать сообщение запроса. Похоже, что текущий код CXF при наличии AsymmetricBinding настаивает на создании подписи, даже если подписывать нечего.


Заключение

WS-Policy определяет гибкую и мощную структуру для выражения ограничений в любой форме. К сожалению, реализация обработки WS-Policy и WS-SecurityPolicy, используемая стеками Web-сервисов, не обеспечивает большую часть этой гибкости. По этой причине многие полезные функции WS-Policy не могут использована для Web-сервисов, рассчитанных на взаимодействие со всеми стеками.

Базовая обработка действующих политик, при которой политики присоединяются в разных точках WSDL-определения сервиса, является одной из основных функций политик и WSDL, и ее по мере необходимости следует использовать в своих сервисах. Но одна из потенциально полезных функций конфигурации этого типа - возможность подписывать и шифровать сообщения выборочно на индивидуальной основе - работает ненадежно (только Apache Axis2 правильно выполнил примеры, и то только после изменения пространства имен политик). Ввиду этого ограничения, если требуется наилучшее взаимодействие, то пока, вероятно, лучше придерживаться вложений политики на уровнях <wsdl:binding> и <wsdl:operation>.

Внешние политики могут быть особенно полезными для среды типа SOA, где можно настроить набор общих политик для использования по всей организации, и каждый сервис будет ссылаться на политику с учетом своих потребностей. Даже несмотря на то, что эта функция пока не поддерживается всеми стеками Web-сервисов Java с открытым исходным кодом, (только Apache CXF работает правильно), крупным организациям все равно есть смысл применять эту функцию, ограничив реализацию Web-сервиса использованием одного из стеков (с открытым исходным кодом или коммерческого), который ее поддерживает. Тот же эффект можно получить и с помощью других средств, например, с помощью включений WSDL.

В следующей статье этого цикла мы рассмотрим проблемы производительности и взаимодействия трех основных стеков Web-сервисов Java и сравним эти стеки с точки зрения их применения для реализации безопасных Web-сервисов. Не пропустите ее, если вы используете безопасные Web-сервисы в своей организации.


Загрузка

ОписаниеИмяРазмер
Пример кода для данной статьиj-jws18.zip94 КБ

Ресурсы

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java, SOA и web-сервисы, Open source
ArticleID=806889
ArticleTitle=Web-сервисы Java: Освоение WS-Policy
publish-date=03262012