Содержание


Web-сервисы Java

Основы стандарта Axis2 WS-Security

Как установить Rampart и работать с UsernameToken в Axis2

Серия контента:

Этот контент является частью # из серии # статей: Web-сервисы Java

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Web-сервисы Java

Следите за выходом новых статей этой серии.

Безопасность - одно из основных требований многих видов корпоративных сервисов. Это также область риска при попытках создания своих собственных сервисов, поскольку даже незначительная и незаметная оплошность может привести к серьезным уязвимостям. Эти характеристики делают обязательной стандартизацию управления безопасностью, которая позволяет многим экспертам внести свой вклад в стандарт и избежать любых индивидуальных упущений. Web-сервисы на базе SOAP могут использовать широко поддерживаемый стандарт WS-Security и сопряженные с ним стандарты для удовлетворения потребностей в области безопасности, позволяя настраивать защиту для каждого сервиса.

Apache Axis2 поддерживает эти стандарты безопасности с помощью модуля Rampart (см. раздел Ресурсы). В этой статье показано, как установить, настроить и использовать Rampart с Axis2 для обеспечения базовой функции безопасности - отправки имени пользователя и пароля в ответ на запрос сервиса. В последующих статьях этого цикла мы покажем, как использовать Rampart для более сложных форм обеспечения безопасности.

WS-Security

WS-Security — это стандарт применения функций безопасности при обмене сообщениями между Web-сервисами SOAP (см. раздел Ресурсы). Он использует элемент заголовка сообщений SOAP для добавления в них сведений по безопасности в виде маркеров, преобразующих различные типы требований (в числе которых могут быть имена, удостоверения личности, ключи, группы, привилегии, возможности и т. д.) наряду с информацией по шифрованию и цифровой подписи. WS-Security поддерживает множество форматов маркеров, надежных доменов, форматов подписи и технологий шифрования, поэтому в большинстве случаев данные заголовка должны содержать специальный формат и алгоритм идентификации для каждого компонента. Добавленная информация может привести к заголовку со сложной структурой, как показано в листинге 1 (сильно отредактированном) – примере сообщения с подписью и шифрованием:

Листинг 1. Пример сообщения с подписью и шифрованием
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" ...>
 <soap:Header>
  <wsse:Security soap:mustUnderstand="1">
   <wsu:Timestamp wsu:Id="Timestamp-d2e3c4aa-da82-4138-973d-66b596d66b2f">
    <wsu:Created>2006-07-11T21:59:32Z</wsu:Created>
    <wsu:Expires>2006-07-12T06:19:32Z</wsu:Expires>
   </wsu:Timestamp>
   <wsse:BinarySecurityToken ValueType="...-x509-token-profile-1.0#X509v3"
     EncodingType="...-wss-soap-message-security-1.0#Base64Binary"
     xmlns:wsu="...oasis-200401-wss-wssecurity-utility-1.0.xsd"
     wsu:Id="SecurityToken-faa295...">MIIEC56MQswCQY...</wsse:BinarySecurityToken>
   <xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
    <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
    <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
     <wsse:SecurityTokenReference>
      <wsse:KeyIdentifier ValueType=
       "...#X509SubjectKeyIdentifier">LlYsHyhNnOVA9Aj7...</wsse:KeyIdentifier>
     </wsse:SecurityTokenReference>
    </KeyInfo>
    <xenc:CipherData>
     <xenc:CipherValue>g+A2WJhsoGBKUydZ9Za...</xenc:CipherValue>
    </xenc:CipherData>
    <xenc:ReferenceList>
     <xenc:DataReference URI="#EncryptedContent-ba0556c3-d443-4f34-bcd1-14cbc32cd689" />
    </xenc:ReferenceList>
   </xenc:EncryptedKey>
   <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
     <ds:CanonicalizationMethod
       Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"
       xmlns:ds="http://www.w3.org/2000/09/xmldsig#" />
     <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
     <Reference URI="#Id-c80f735c-62e9-4001-8094-702a4605e429">
      <Transforms>
       <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
      </Transforms>
      <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
      <DigestValue>lKjc5nyLQDZAIu/hZb4B6mLquow=</DigestValue>
     </Reference>
     ...
    </SignedInfo>
    <SignatureValue>TiLmWvlz3mswinLVQn58BgYS0368...</SignatureValue>
    <KeyInfo>
     <wsse:SecurityTokenReference>
      <wsse:Reference URI="#SecurityToken-faa295..."
        ValueType="...-x509-token-profile-1.0#X509v3" />
     </wsse:SecurityTokenReference>
    </KeyInfo>
   </Signature>
  </wsse:Security>
 </soap:Header>
 <soap:Body wsu:Id="Id-8db9ff44-7bef-4737-8091-cdac51a34db8">
  <xenc:EncryptedData Id="EncryptedContent-ba05..."
    Type="http://www.w3.org/2001/04/xmlenc#Content"
    xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
   <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
   <xenc:CipherData>
    <xenc:CipherValue>mirmi0KuFEEI56eu2U3cICz...</xenc:CipherValue>
   </xenc:CipherData>
  </xenc:EncryptedData>
 </soap:Body>
</soap:Envelope>

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

WS-Security применяется для обмена сообщения SOAP. Реализация сервиса может проверить, что WS-Security должным образом применяется для входящих сообщений, но клиенты должны заранее знать, что нужно сделать, чтобы использовать эту службу. Ввиду сложности и большого количества поддерживаемых опций WS-Security может быть трудно использовать для этой цели текстовое описание, а ручная настройка обработки WS-Security чревата ошибками. WS-Policy представляет собой среду общего назначения для определения дополнительных требований Web-сервисов, а WS-SecurityPolicy - это расширение WS-Policy, специально предназначенное для поддержки WS-Security. Вместе эти два стандарта поддерживают описание требований WS-Security в машиночитаемой форме. Информация WS-Policy и WS-SecurityPolicy может использоваться самостоятельно или внедряться непосредственно в документы Web Services Description Language (WSDL), так что среда Web-сервиса будет автоматически настраиваться под его требования.

Введение в Rampart

Rampart – это модуль безопасности Axis2, поддерживающий WS-Security, WS-SecurityPolicy, WS-SecureConversation и WS-Trust. В этой статье рассматриваются только функции Rampart, связанные с WS-Security и WS-SecurityPolicy; в последующих статьях будут разбираться другие функции.

Поскольку Rampart реализован в виде модуля (на самом деле, пары модулей – rampart.mar и rahas.mar), он подключается к среде обработки Axis2 и выполняет свою функцию путем перехвата сообщений в определенные моменты процесса обработки входящего и исходящего трафика, проверяя сообщения и при необходимости изменяя их.

Установка Rampart

Rampart поставляется в виде нескольких .jar-файлов (в каталоге дистрибутива lib) и двумя файлами модулей .mar (в каталоге dist). Чтобы использовать Rampart с Axis2, необходимо добавить .jar-файлы в classpath, а файлы .mar ― в classpath или структуру репозитория Axis2.

Самый простой способ работы с файлами Rampart .jar и .mar заключается в том, чтобы добавить их в свою установку Axis2. Можно просто скопировать .jar-файлы из каталога lib Rampart в каталог lib Axis2, а файлы .mar - из каталога dist Rampart в каталог репозитория/модулей Axis2. (Можно также использовать Ant build.xml из каталога образцов Rampart для копирования файлов в установку Axis2. Просто добавьте переменную окружения AXIS2_HOME, в свой каталог установки Axis2 и выполните ant с консоли, открытой для каталога образцов Rampart.)

Для многих функций WS-Security необходимо также добавить в конфигурацию безопасности JVM протокол защиты Bouncy Castle Security Provider и библиотеку шифрования Bouncy Castle .jar в установку Axis2. Этот шаг – не обязательный для функции UsernameToken, о котором говорится в этой статье, – требуется для других функций безопасности, рассматриваемых в следующих статьях этого цикла. Из-за патентных ограничений некоторых алгоритмов безопасности Bouncy Castle .jar загружается отдельно от Rampart (см. раздел Ресурсы). Загрузите соответствующую версию .jar для своей среды выполнения Java и добавьте .jar в каталог lib Axis2. Затем необходимо изменить политики безопасности установки Java так, чтобы можно было использовать код Bouncy Castle, добавив строку в файл java.security, присутствующий в каталоге Java runtime lib/security. Найдите раздел этого файла с несколькими разными строками security.provider и добавьте следующую строку:

security.provider.99=org.bouncycastle.jce.provider.BouncyCastleProvider

Порядок строк security.provider в файле не имеет значения, но лучше добавить ее после строк, соответствующих предопределенным реализациям протокола безопасности.

Чтобы использовать код Rampart в установке сервера Axis2, необходимо создать новый файл axis2.war, содержащий добавленные файлы Rampart .jar и .mar. Для создания axis2.war можно использовать Ant build.xml из каталога webapp, если внести одно изменение: удалите строку <exclude name="axis2-codegen*.jar"/> в конце файла. Затем откройте консоль в каталоге Axis2 webapp и выполните ant. После выполнения build.xml созданное Web-приложение axis2.war можно найти в каталоге установки dist Axis2.

Пример приложения

Приложение, приведенное в примере кода (см. Загрузки) основывается на том примере, который я использовал в статье Axis2 Data Binding для демонстрации альтернатив привязки данных для Axis2. В этой и последующих статьях о поддержке Axis2 WS-Security я сократил его всего до трех операций: getBook, addBook и getBooksByType. Для упрощения приведена только версия кода Axis Data Binding (ADB), но это не требование работы с WS-Security в Axis2 – Rampart реализует WS-Security на уровне, не зависящем от используемого метода привязки данных, поэтому он будет работать со всеми формами привязки данных, поддерживаемых Axis2.

Корневой каталог кода примера - jws04code. Внутри этого каталога находятся файлы Ant build.xml и build.properties, файл library.wsdl, который дает определение сервиса для примера приложения, файл log4j.properties, используемый для настройки журнала со стороны клиента, и несколько XML-файлов определения свойств (все они имеют имена типа XXX-policy-client.xml или XXX-policy-server.xml). Файл build.properties настраивает функционирование примера приложения. Предлагаемая версия этого файла свойств показана в листинге 2.

Листинг 2. Прилагаемый файл build.properties
# настройка axis-home на каталог установки Axis2
axis-home=PATH_TO_AXIS2_INSTALLATION
# настройка протокола связи для доступа к службам (http или https)
protocol=http
# настройка имени узла службы
host-name=localhost
# настройка порта для доступа к службам (для мониторинга это нужно изменить)
host-port=8080
# задание базового пути для доступа ко всем службам узла
base-path=/axis2/services/
# задание имени файла политики, используемого клиентом
client-policy=plain-policy-client.xml
# задание имени файла политики, используемого сервером
server-policy=plain-policy-server.xml

Прежде чем работать с примерами, нужно отредактировать файл build.properties и задать фактический путь своей установки Axis2 (с добавленным Rampart, как описано в предыдущем разделе). Если вы используете для своего сервера другой номер узла или порта, необходимо также изменить значения host-name и host-port. Оставшиеся значения мы обсудим позже.

Работа с WS-Security

WS-Security определяет несколько типов маркеров безопасности (включая маркеры, которые являются частью ключевой спецификации, и те, которые определяется профилями как модули расширения спецификации) с большим количеством вариантов способов построения и использования маркеров. Тема этой статьи ― настройка и использование Rampart с Axis2, поэтому я для примера просто воспользуюсь самым простым полезным маркером: UsernameToken, определяемым профилем UsernameToken.

Маркер UsernameToken WS-SecurityPolicy

Задача UsernameToken состоит в том, чтобы передавать информацию об имени пользователя и пароле в заголовках WS-Security. Простейшая форма UsernameToken передает имя пользователя и пароль как обычный текст. Это не оптимальное решение с точки зрения безопасности (хотя нет ничего плохого в использовании этого подхода при безопасных соединениях), зато легко увидеть, что именно передается, а это делает его полезной отправной точкой.

Конфигурация WS-SecurityPolicy для UsernameToken, переданного как текст, может быть простой, как показано в листинге 3. Эта политика (здесь одна строка разбита на две из-за ширины страницы – не годится для фактического использования) состоит из стандартной оболочки WS-Policy (элементы с префиксом wsp) вокруг утверждения WS-SecurityPolicy UsernameToken.

Листинг 3. WS-SecurityPolicy для UsernameToken с передачей обычного текста
<wsp:Policy wsu:Id="UsernameToken" xmlns:wsu=
    "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
    xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
  <wsp:ExactlyOne>
    <wsp:All>
      <sp:SupportingTokens
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
        <wsp:Policy>
          <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/
               ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"/>
        </wsp:Policy>
      </sp:SupportingTokens>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

UsernameToken в листинге 3 использует атрибут IncludeToken для указания типа потока сообщений, который должен включать маркер – в данном случае это все потоки сообщений, поступающие от инициатора запроса (то есть клиента) к получателю запроса (серверу). Можно указать другие значения атрибута IncludeToken для задания других способов использования маркера, но для UsernameToken это, как правило, единственное значение, которое имеет смысл.

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

WS-Policy и WS-SecurityPolicy предназначены для поддержки внедрения определений сервисов в WSDL. Ссылки используются для привязки политики к одному или нескольким определениям <wsdl:binding>, <wsdl:binding>/<wsdl:operation> или <wsdl:message>. Axis2 1.4.X осуществляет предварительную обработку политик, встроенных в WSDL, но в Axis2 1.4.1 эта реализация пока ненадежна. В этой статье, чтобы политики были совместимыми с версией кода 1.4.1, они присоединяются непосредственно к клиенту и серверу.

Обработка политик на сервере

Со стороны сервера политики применяются путем добавления их в файл конфигурации services.xml, включенный в каждый архив службы .aar Axis2. Политики могут добавляться непосредственно как дочерний элемент <service> для применения ко всем операциям, определенным этой службой. Также необходимо добавить к services.xml элемент <module>, чтобы указать Axis2, что в конфигурацию службы должен быть включен модуль Rampart. Листинг 4 - это отредактированный вариант services.xml, используемый в примере приложения, с добавленной ссылкой на модуль и информацией о политике, которая выделена жирным шрифтом:

Листинг 4. Модуль services.xml со встроенной политикой
<serviceGroup>
  <service name="library-username">
    <messageReceivers>
      <messageReceiver
          class="com.sosnoski.ws.library.adb.LibraryUsernameMessageReceiverInOut"
          mep="http://www.w3.org/ns/wsdl/in-out"/>
    </messageReceivers>
    <parameter
        name="ServiceClass">com.sosnoski.ws.library.adb.LibraryUsernameImpl</parameter>
    <parameter name="useOriginalwsdl">true</parameter>
    <parameter name="modifyUserWSDLPortAddress">true</parameter>
    <operation mep="http://www.w3.org/ns/wsdl/in-out" name="getBook"
        namespace="http://ws.sosnoski.com/library/wsdl">
      <actionMapping>urn:getBook</actionMapping>
      <outputActionMapping>http://.../getBookResponse</outputActionMapping>
    </operation>
    ...

    <module ref="rampart"/>
    <wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
        xmlns:wsu="http://.../oasis-200401-wss-wssecurity-utility-1.0.xsd"
        wsu:Id="UsernameToken">
      <wsp:ExactlyOne>
        <wsp:All>
          <sp:SupportingTokens
              xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
            <wsp:Policy>
              <sp:UsernameToken
                  sp:IncludeToken="http://.../IncludeToken/AlwaysToRecipient">
                <wsp:Policy>
                  <sp:HashPassword/>
                </wsp:Policy>
              </sp:UsernameToken>
            </wsp:Policy>
          </sp:SupportingTokens>

          <ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">
            <ramp:passwordCallbackClass>...PWCBHandler</ramp:passwordCallbackClass>
          </ramp:RampartConfig>

        </wsp:All>
      </wsp:ExactlyOne>
    </wsp:Policy>
  </service>
</serviceGroup>

Если вы сравните встроенную политику в листинге 4 с базовой политикой в листинге 3, то увидите одно дополнение – элемент <ramp:RampartConfig>. Этот элемент добавляет Rampart-расширения к информации о политике, в данном случае, имя класса, который будет использоваться для обработки обратных вызовов пароля. Обратный вызов – это способ проверки кодом сервера комбинации имени пользователя и пароля, предоставленной клиентом по запросу.

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

Листинг 5. Код обратного вызова проверки пароля
import org.apache.ws.security.WSPasswordCallback;

public class PWCBHandler implements CallbackHandler
{
    public void handle(Callback[] callbacks)
        throws IOException, UnsupportedCallbackException {
        for (int i = 0; i < callbacks.length; i++) {
            WSPasswordCallback pwcb = (WSPasswordCallback)callbacks[i];
            String id = pwcb.getIdentifer();
            if (pwcb.getUsage() == WSPasswordCallback.USERNAME_TOKEN_UNKNOWN) {

                // used when plain-text password in message
                if (!"libuser".equals(id) || !"books".equals(pwcb.getPassword())) {
                    throw new UnsupportedCallbackException(callbacks[i], "check failed");
                }

            }
        }
    }
}

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

Настройка со стороны клиента

Чтобы использовать Rampart для клиентского кода, необходим модуль, доступный для использования с Axis2. Это можно сделать, настроив структуру репозитория Axis2 для клиента, но обычно проще включить файл модуля rampart.mar (и любые другие модули, которые нужно использовать) в свой classpath. В приведенном примере используется подход с classpath.

Затем необходимо настроить для клиента политику безопасности и любые связанные с ней параметры. Самый простой способ такой настройки - задать значения непосредственно в заглушке сервиса. В листинге 6 показано, как выполняется такая настройка в коде примера.

Листинг 6. Настройка клиента
    /**
     * Загрузка файла политики из classpath
     */
    private static Policy loadPolicy(String name) throws XMLStreamException {
        ClassLoader loader = WebServiceClient.class.getClassLoader();
        InputStream resource = loader.getResourceAsStream(name);
        StAXOMBuilder builder = new StAXOMBuilder(resource);
        return PolicyEngine.getPolicy(builder.getDocumentElement());
    }

    public static void main(String[] args) throws IOException, XMLStreamException {

        // Проверка параметров командной строки
        if (args.length < 4) {
            System.out.println("Usage:\n  java " +
                "com.sosnoski.ws.library.adb.WebServiceClient protocol host port path");
            System.exit(1);
        }

        // Создание заглушки клиента
        String target = args[0] + "://" + args[1] + ":" + args[2] + args[3];
        System.out.println("Connecting to " + target);
        LibraryUsernameStub stub = new LibraryUsernameStub(target);

        // Настройка и вызов Rampart
        ServiceClient client = stub._getServiceClient();
        Options options = client.getOptions();
        options.setProperty(RampartMessageData.KEY_RAMPART_POLICY,
            loadPolicy("policy.xml"));
        options.setUserName("libuser");
        options.setPassword("books");
        client.engageModule("rampart");

Часть, относящаяся к настройке, это последний блок кода листинга 6. Она получает экземпляр org.apache.axis2.client.ServiceClient из созданной заглушки и устанавливает сведения о политике (загруженные из-за classpath) и имя пользователя/пароль в свойствах клиента. Затем запускается модуль Rampart в конфигурации Axis2, используемой клиентом. После этого заглушку можно использовать для доступа к службе, как без использования WS-Security, а Rampart будет автоматически добавлять UsernameToken к каждому запросу.

Проверка результатов

При установленном Ant, чтобы создать код сервера и клиента, достаточно запустить ant с консоли, открытой для каталога кода примера. Затем можно развернуть созданный файл library-username.aar на сервере Axis2 (который, конечно, содержит файлы .jar и .mar Rampart) и попробовать запустить клиент, набрав на консоли ant run. Если все установлено правильно, вы должны увидеть результат, показанный на рисунке 1.

Рисунок 1. Вывод на консоль при запуске приложения
Вывод на консоль при запуске приложения
Вывод на консоль при запуске приложения

Конечно, чтобы увидеть, что происходит, простого выполнения клиента и сервера недостаточно. Чтобы увидеть маркер UsernameToken WS-Security в действии, можно использовать такой инструмент, как TCPMon, который выступает посредником между клиентом и сервером и перехватывает обмен сообщениями (см. раздел Ресурсы ). Для этого сначала нужно настроить TCPMon, чтобы он принимал соединения от клиента на один порт, а затем направлял их на сервер, работающий через другой порт (или в другом узле). После этого можно отредактировать файл build.properties и изменить значение host-port для прослушивания порта инструментом TCPMon. Если теперь снова набрать на консоли ant run, вы должны видеть передаваемые сообщения. Пример перехвата сообщений клиента приведен в листинге 7.

Листинг 7. Сообщение клиента с маркером UsernameToken
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <wsse:Security xmlns:wsse="...wss-wssecurity-secext-1.0.xsd"
        soapenv:mustUnderstand="1">
      <wsse:UsernameToken xmlns:wsu="...wss-wssecurity-utility-1.0.xsd"
          wsu:Id="UsernameToken-1815911473">
        <wsse:Username>libuser</wsse:Username>
        <wsse:Password Type="...wss-username-token-profile-1.0#PasswordText"
            >books</wsse:Password>
      </wsse:UsernameToken>
    </wsse:Security>
  </soapenv:Header>
  <soapenv:Body>
    <ns2:getBooksByType xmlns:ns2="http://ws.sosnoski.com/library/wsdl">
      <ns2:type>scifi</ns2:type>
    </ns2:getBooksByType>
  </soapenv:Body>
</soapenv:Envelope>

Защита маркера UsernameToken

Маркер UsernameToken на основе обычного текста не обеспечивает надежной защиты, так как имя пользователя и пароль видны каждому, кто прочтет сообщение. Если использовать канал связи с шифрованием, эта проблема снимается – если канал шифрования надежен, ― так как посторонний не может прочесть сообщения. WS-SecurityPolicy предлагает удобный способ потребовать использования шифрованного канала, как показано в листинге 8 (опять же, строка разбита на две из-за ширины страницы — для реального использования политики см. файл secure-policy-server.xml в пакете с примерами кода).

Листинг 8. Политика, требующая соединения HTTPS
<wsp:Policy wsu:Id="UsernameToken" xmlns:wsu=
  "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
  xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
 <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>
     </wsp:Policy>
   </sp:TransportBinding>
   <sp:SupportingTokens
     xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
    <wsp:Policy>
     <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/
          ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"/>
    </wsp:Policy>
   </sp:SupportingTokens>
  </wsp:All>
 </wsp:ExactlyOne>
</wsp:Policy>

Добавленная часть листинга 8 выделена жирным шрифтом и состоит из элемента <sp:TransportBinding> и вложенного элемента <sp:HttpsToken>. Элемент <sp:HttpsToken> указывает на то, что для связи со службой необходимо использовать безопасное HTTPS-соединение. Если попытаться создать службу .aar с этой политикой (изменив значение server-policy в build.properties на secure-policy-server.xml и выполнив ant build-server) и установить ее, вы увидите, что Rampart вынуждает соблюдать это требование, отвергая любые обычные HTTP-соединения.

Чтобы подключить к службе HTTPS-соединение, сначала необходимо настроить Web-сервер на поддержку HTTPS. (В Tomcat есть хорошие инструкции для этого, см. /tomcat-docs/ssl-howto.html.) Кроме того, нужно изменить значение protocol в build.properties на https, а при использовании для Web-сервера самозаверяющегося сертификата, нужно передать клиенту надежное хранилище при выполнении целевой функции Ant test. Прилагаемый файл build.xml содержит закомментированную строку для этого, так что можно просто раскомментировать ее и указать местоположение файла надежного хранилища в своей системе.

Еще один способ сделать UsernameToken более безопасным работает даже по нешифрованным линиям. При этом методе используется значение digest, рассчитанное по строке, состоящей из двух других текстовых значений в сочетании с паролем. Одно из текстовых значений, nonce, представляет собой случайное значение, генерируемое отправителем для каждого запроса. Другое, метка времени, это просто время создания отправителем маркера UsernameToken. Оба эти значения включены в UsernameToken как обычный текст. При правильном использовании клиента и сервера комбинация этих значений с паролем в дайджесте позволяет серверу убедиться, что при генерации дайджеста использовался правильный пароль, что затрудняет подделку пароля для посторонних. В листинге 9 приведен пример политики для использования дайджеста пароля, после чего следует фактический перехват сообщения с помощью дайджеста пароля (оба кода переформатированы под ширину страницы — за реальной политикой обращайтесь к файлу hash-policy-client.xml). Отличия от первоначальной политики снова выделены жирным шрифтом.

Листинг 9. Политика с использованием дайджеста пароля и пример сообщения
<wsp:Policy wsu:Id="UsernameToken" xmlns:wsu=
    "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
    xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
  <wsp:ExactlyOne>
    <wsp:All>
      <sp:SupportingTokens
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
        <wsp:Policy>
          <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/
ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
            <wsp:Policy>
              <sp:HashPassword/>
            </wsp:Policy>
          </sp:UsernameToken>
        </wsp:Policy>
      </sp:SupportingTokens>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <wsse:Security xmlns:wsse=".../oasis-200401-wss-wssecurity-secext-1.0.xsd"
        soapenv:mustUnderstand="1">
      <wsse:UsernameToken xmlns:wsu="...wss-wssecurity-utility-1.0.xsd"
          wsu:Id="UsernameToken-1421876889">
        <wsse:Username>libuser</wsse:Username>
        <wsse:Password Type="...wss-username-token-profile-1.0#PasswordDigest"
          >/Wt/2yDdZwa8a5qd7U70hrp29/w=</wsse:Password>
        <wsse:Nonce>4ZQz5ytME/RXfChuKJ03iA==</wsse:Nonce>
        <wsu:Created>2009-03-17T11:20:57.467Z</wsu:Created>
      </wsse:UsernameToken>
    </wsse:Security>
  </soapenv:Header>
  <soapenv:Body>
    <ns2:getBooksByType xmlns:ns2="http://ws.sosnoski.com/library/wsdl">
      <ns2:type>scifi</ns2:type>
    </ns2:getBooksByType>
  </soapenv:Body>
</soapenv:Envelope>

Заключение

В этой статье показано, как использовать Axis2 и Rampart в простом случае работы с WS-Security на базе политики. В следующей статье цикла Web-сервисы Java будут представлены две мощные функций WS-Security: XML-шифрование и подписи. XML-шифрование позволяет засекретить содержимое сообщений при работе через любое соединение, даже когда в обработке участвуют ненадежные посредники. Использование подписей XML гарантирует, что сообщения действительно отправлены тем, кто значится отправителем, и их содержимое не было изменено при передаче. Шифрование и подпись служат основой большинства реализаций системы безопасности предприятия, так что обязательно возвращайтесь, чтобы узнать, как применять эти возможности в своих собственных Web-сервисах.


Ресурсы для скачивания


Похожие темы

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java, SOA и web-сервисы
ArticleID=777492
ArticleTitle=Web-сервисы Java: Основы стандарта Axis2 WS-Security
publish-date=05262009