Understanding Web Services Specifications, Parte 4: WS-Security

Hay pocos sistemas (si es que los hay) a nivel de la empresa que no requieran una u otra forma de seguridad. En los servicios web, este proceso es más complicado que en otros campos debido a la naturaleza distribuida y desnacionalizada que los caracteriza. Este tutorial, Parte 4 de la serie “Understanding web services specifications”, explica los conceptos que existen detrás de WS-Security y estándares relacionados como Firma XML, que se combinan para hacer que la seguridad en los servicios web sea no solo posible, sino también práctica.

Nicholas Chase, Freelance writer, Backstop Media

Nicholas Chase participó en el desarrollo de sitios Web para empresas como Lucent Technologies, Sun Microsystems, Oracle y Tampa Bay Buccaneers. Nick fue profesor de física en escuela secundaria, gerente de instalaciones para tratamiento de desechos con bajo nivel de radioactividad, editor de una revista online de ciencia ficción, ingeniero multimedios, instructor de Oracle y Director de Tecnología en una empresa de comunicaciones interactivas. Es autor de varios libros, entre ellos XML Primer Plus (Sams).



08-08-2011

Antes de comenzar

En este tutorial aprenderá sobre Web Services Security, o WS-Security. Es para desarrolladores que desean exponer sus propios servicios en un entorno que requiere protección de mensajes para que no sean alterados ni leídos en tránsito, o en situaciones en las cuales el remitente debe ser identificado positivamente. El término "WS-Security" se utiliza generalmente para referirse a un grupo de especificaciones que manejan cifrado y firmas digitales, lo que le permite crear una aplicación segura.

A fin de poder seguir el hilo de este tutorial, debe tener una comprensión básica de SOAP, la cual puede lograr leyendo la Parte 1 de esta serie de tutorial, y por extensión, necesita una comprensión básica de XML. SOAP es lenguaje de programación agnóstico, pero las muestras de este tutorial utilizan Java y el proyecto Apache Axis2. Los conceptos, sin embargo, se aplican a cualquier lenguaje y entorno de programación.

Acerca de esta serie

Esta serie tutorial enseña los conceptos básicos de los servicios web siguiendo las hazañas del periódico ficticio, The Daily Moon, mientras el personal utiliza servicios web para crear un sistema de flujo de trabajo para incrementar la productividad en el medio de un gran cambio.

La Parte 1 explicaba los conceptos básicos de los servicios web y mostraba cómo utilizar SOAP, la especificación que subyace en la mayoría de lo que vendrá, y conecta el departamento de clasificados con el Sistema de Gestión de Contenido.

La Parte 2 lleva las cosas un poco más allá, al explicar cómo utilizar Web Services Description Language (WSDL) para definir los mensajes producidos como se espera por el servicio web, lo que le permite al equipo crear servicios y a los clientes que se conectan a ellos con más facilidad.

La Parte 3 encuentra al equipo con una cantidad de servicios implementados y un deseo de ubicarlos con facilidad. En respuesta, Universal Description, Discovery and Integration (UDDI) brinda un registro que permite realizar búsquedas de servicios disponibles a una manera de publicitar sus propios servicios a otros.

Ahora, en la Parte 4, Rudy, editor del The Daily Moon, ha decidido que el periódico necesite implementar mejores procedimientos de seguridad para servicios web que acceden a sus sistemas internos.

En la Parte 5, WS-Policy, analizaremos los cambios que necesitan hacer los equipos para acceder a esos servicios recientemente protegidos.

La interoperabilidad es la palabra clave en la Parte 6, ya que se debe acceder a servicios de varias distintas implementaciones desde un sistema único. La Parte 6 cubrirá también los requisitos y las pruebas que involucra la certificación WS-I.

Finalmente, la Parte 7 mostrará cómo utilizar Business Process Execution Language (WS-BPEL) para crear aplicaciones complejas desde servicios individuales.

Ahora veamos qué cubre este tutorial un poco más detalladamente.

Acerca de este tutorial

En este tutorial, seguirá el proceso en que el equipo del periódico The Daily Moon utiliza las especificaciones WS-Security para proteger uno de los servicios web descritos hasta ahora en la serie.

En el transcurso de este tutorial, aprenderá:

  • Qué es WS-Security
  • La diferencia entre cifrado simétrico y asimétrico
  • La diferencia entre firmas y cifrado
  • El efecto de la seguridad sobre los mensajes SOAP
  • Cómo proteger un servicio web SOAP utilizando Axis2

Antes de comenzar, necesitará algunas herramientas.

Prerrequisitos

Gran parte de este tutorial es conceptual, pero a fin de seguir el código que crea mensajes SOAP, deberá contar con el siguiente software disponible e instalado:

Haremos una demostración de la instalación y el uso de Apache Geronimo, que también es la base de WebSphere Community Edition de IBM. También puede usar otros servidores de aplicación como el servidor de aplicación WebSphere. Puede descargar Apache Geronimo. Para obtener más información sobre la instalación de Geronimo, ver la Parte 1 de esta serie de tutoriales.

Estará utilizando Apache Axis2, que contiene implementaciones de diversas API relacionadas con SOAP para que su vida sea significativamente más fácil. Puede descargar Apache Axis2 desde Apache.org. Este tutorial utiliza la versión 0.94, pero versiones posteriores deberían funcionar.

Módulo Apache Axis2 Rampart – La seguridad para el motor de servicios web Axis2 se brinda a través del módulo Rampart, que no está incluido en la instalación predeterminada. Descargue este módulo desde los espejos de descarga de Apache.

Apache WSS4J – Aunque el mismo Axis utiliza Rampart, en algún punto deberá referenciar la dirección de clases WSS4J. Descargue el paquete WSS4J.

Java 2 Standard Edition versión 1.4.2 o superior – Todas esas herramientas están basadas en Java, al igual que los servicios y clientes que construirá en este tutorial. Descargue J2SE SDK.

TCPMon (opcional) – Siempre es más fácil comprender lo que sucede en una aplicación de servicio web cuando puede ver los mensajes. Descargue TCP Monitor para poder ver los mensajes que entran y salen desde el servicio web.

GnuPG (opcional) – Toda la firma de mensajes que haremos está cubierta por Axis2 y Java, pero si desea jugar con la firma de documentos individuales, como lo demostraremos brevemente, descargue GnuPG.

También necesitará un explorador Web y un editor de texto.


Generalidades

Antes de hablar de la protección de un servicio, es útil conocer exactamente las piezas que constituyen ese servicio para saber qué debe hacerse.

La historia hasta ahora

Esta serie de tutoriales ha seguido las hazañas del personal del periódico The Daily Moon, que descubierto una manera nueva de trabajar en la forma de servicios web. Todo comenzó en el departamento de clasificados, que decidió permitir a otros acceder a sus sistemas a través del uso de mensajes SOAP – mensajes XML que se pueden enviar por HTTP.

Por ejemplo, una solicitud de cantidad de avisos clasificados en la subcategoría “a la venta” podría verse como el Listado 1.

Listado 1. U mensaje SOAP de muestra
<?xml version='1.0' ?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/SOAP-envelope"> 
 <env:Header>
 </env:Header>
 <env:Body>
  <cms:getNumberOfArticles xmlns:cms="http://www.daily-moon.com/cms">
    <cms:category>classifieds</cms:category>

    <cms:subcategory>forsale</cms:subcategory>
  </cms:getNumberOfArticles>
 </env:Body>
</env:Envelope>

El mensaje general se llama el Sobre, el contenido del cual consiste en el Encabezado y el Cuerpo. El encabezado contiene información sobre el mensaje mismo, como por ejemplo la información de ruteo, o información que debe ser procesada por “intermediarios SOAP”, o servicios entre el remitente y el destinatario, que puede procesar el mensaje. (En este caso, ver alguno de esos encabezados, pero es donde irá nuestra información de seguridad). El Cuerpo del mensaje incluye la “carga útil”, que incluye los datos reales que pasan al servicio web.

En este caso, la carga útil es el elemento getNumberOfArticles y su contenido.

Gene y Frances, del departamento TI del periódico, han armado un sistema para atender solicitudes de servicios web, así como también la infraestructura para descubrir y crear automáticamente clientes para los servicios. Ahora el editor del periódico, Rudy, insiste en que encuentren una forma de evitar el acceso no autorizado a estos sistemas.

La necesidad de tener seguridad

La especificación SOAP básica no establece la protección de mensajes, y deja esas especificaciones extendidas. El problema yace en la naturaleza de una aplicación de servicios web. En la mayoría de los casos, tratamos con SOAP sobre HTTP, lo que significa que cada mensaje debe pasar por uno o más nodos intermedios, cualquiera de los cuales puede leer y/o alterar un mensaje. Y eso suponiendo que la solicitud SOAP misma fuera directa. En algunos casos, los mensajes SOAP están diseñados específicamente para viajar a través de más de un modo antes de llegar a su destino final.

El resultado final es que necesitamos evitar que alguien que no sea el destinatario deseado lea información confidencial, a fin de evitar la interceptación. Además necesitamos una manera de evitar que alguien que no sea el remitente deseado envíe mensajes, a fin de evitar el acceso no autorizado.

La especificación SOAP brinda un medio para agregar información de seguridad- agregamos información a un elemento de Encabezado del Sobre – pero no especifica qué debe ser la información. Para solucionarlo, necesitamos WS-Security.

Las partes de WS-Security

Hay tres grandes problemas en la protección de intercambios de mensajes SOAP, y WS-Security brinda respuestas para todos ellos, aunque no directamente. Es, de hecho, una especificación que habla no sobre cómo proteger el mensaje, sino cómo hacer saber al destinatario que se ha protegido el mensaje. Para realizar la protección real, WS-Security referencia especificaciones adicionales. Veamos cómo funciona eso.

El primer problema es identificar y autenticar al cliente. Debido a que hay muchas maneras diferentes de crear tokens de seguridad, WS-Security no especifica ningún medio particular, sino que define cómo se deben transferir los token de seguridad dentro de los mensajes SOAP. En otras palabras, hace saber al destinatario cómo extraer tokens de seguridad del mensaje para su procesamiento.

El segundo problema es garantizar la integridad del mensaje. WS-Security utiliza firmas digitales para eso, empleando la especificación de Firma XML en lugar de inventar algo nuevo. La Firma XML es una recomendación W3C que incluye un mecanismo para firmar documentos XML de manera digital.

El tercer problema es mantener el mensaje seguro contra la interceptación mientras está en tránsito. Una vez más, WS-Security utiliza otro estándar W3C, esta vez Cifrado XML, que brinda un mecanismo para cifrar documentos XML.

En este tutorial veremos cómo el utilizar estos estándares afecta los mensajes SOAP utilizados, a medida que Gene y Frances trabajan para proteger el servicio existente de Clasificados.

El servicio actual

Antes de analizar la realización de cambios, es útil ver dónde de dónde parten Gene y Frances. El servicio de Clasificados se implementa utilizando Axis2, lo que significa que está dentro de un archivo *.aare. El archivo CMSService.aar consiste en tres archivos, como se muestra en el Listado 2.

Listado 2. El contenido del servicio original
CMSService.class
meta-inf/Manifest.MF

meta-inf/services.xml

La clase misma es directa, y adopta un mensaje SOAP que lista una categoría y devuelve un mensaje SOAP que incluye la cantidad de avisos para esa categoría. Realiza esta función como lo define el archivo services.xml (ver el Listado 3).

Listado 3. El archivo services.xml original
<service name="CMSService">

    <description>
        This is a sample web service for the newspaper's 
        Content Managment System.
    </description>

    <parameter name="ServiceClass" 
               locked="false">CMSService</parameter>

    <operation name="getNumberOfArticles">
        <messageReceiver class=
"org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
    </operation>

</service>

Asegurar el servicio implica tocar solo el archivo services.xml; Gene y Frances no tendrán que tocar la clase Java para nada.

El cliente actual

El cliente en sí es bastante directo, y simplemente hace y muestra la solicitud, como se muestra en el Listado 4:

Listado 4. La clase cliente original
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;

public class ClassifiedClient {
    private static EndpointReference targetEPR = 
           new EndpointReference(
               "http://localhost:8888/axis2/services/CMSService");

    public static OMElement getNumOfArticlesOMElement() {
        SOAPFactory fac = OMAbstractFactory.getSOAP12Factory();
        OMNamespace omNs = fac.createOMNamespace(
                "http://daily-moon.com/cms", "cms");
        OMElement method = fac.createOMElement("getNumberOfArticles",
                                                omNs);
        OMElement value = fac.createOMElement("category", omNs);
        value.addChild(fac.createOMText(value, "classifieds"));
        method.addChild(value);

        return method;
    }

    public static void main(String[] args) {
        try {
            OMElement payload = 
               ClassifiedClient.getNumOfArticlesOMElement();
  
            Options options = new Options();
            options.setTo(targetEPR);
            options.setTransportInProtocol(Constants.TRANSPORT_HTTP);

            ServiceClient sender = new ServiceClient();

            sender.setOptions(options);
            OMElement result = sender.sendReceive(payload);

            String response = result.getText();
            System.out.println("There are "+response+
                               " classifieds at the moment.");
        } catch (Exception e) { 
        	System.out.println(e.toString());
        }
    }
}

Observe que Gene ha cambiado el puerto de punto final a 8888, en lugar de 8080, el puerto en el que está escuchando Geronimo. Lo hizo para insertar un paso adicional para poder ver los mensajes ir y venir.

Ver los mensajes

Para ver los mensajes SOAP reales, descargue TCPMon de http://ws.apache.org/commons/tcpmon/download.cgi. (Sí, Axis2 incluye SOAPMonitor, pero Gene descubrió a su pesar que además de la incomodidad de instalar las cosas, muestra SOAP pero no necesariamente los mensajes sin procesar, los cuales querremos ver específicamente).

Después de descargarlo, descomprima la aplicación y ejecute el archivo tcpmon-1.0-bin\build\tcpmon.bat. Haga clic en la pestaña Admin y cree una nueva escucha, como se ve en la Figura 1.

Figura 1. La pestaña Admin TCPMon
La pestaña Admin TCPMon

Elija 8888 como el puerto para escuchar, y especifique 8080 como el punto destino, para que TCPMon quede entre el Cliente y el servidor. Haga clic en Add, y luego haga clic en la pestaña Port 8888. Haga clic en la casilla de verificación XML Format. Ahora cuando Frances ejecuta el Cliente, Gene puede ver la solicitud y la respuesta, como en la Figura 2.

Figura 2. La solicitud original y la respuesta
La solicitud original y la respuesta

Antes de seguir, analicemos rápidamente los mensajes reales, para poder ver qué cambia.

Los mensajes

Los mensajes en sí son muy directos. La solicitud, como se ve en el Listado 5, simplemente pregunta la cantidad de avisos clasificados en el sistema:

Listado 5. La solicitud original
<?xml version='1.0' encoding='UTF-8'?>
   <soapenv:Envelope
 xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
      <soapenv:Header />
      <soapenv:Body>
         <cms:getNumberOfArticles 
                    xmlns:cms="http://daily-moon.com/cms">
            <cms:category>classifieds</cms:category>

         </cms:getNumberOfArticles>
      </soapenv:Body>
   </soapenv:Envelope>

La respuesta es igual de directa, como se puede ver en el Listado 6:

Listado 6: La respuesta original
<?xml version='1.0' encoding='UTF-8'?>
   <soapenv:Envelope xmlns:soapenv=
           "http://schemas.xmlsoap.org/soap/envelope/">
      <soapenv:Header />
      <soapenv:Body>
         <resp:numberOfArcticles 
               xmlns:resp="http://daily-moon.com/cms/"  
               xmlns:tns="http://ws.apache.org/axis2"
                            >42</resp:numberOfArcticles>

      </soapenv:Body>
   </soapenv:Envelope>

En ambos de estos mensajes, Frances colocará información adicional en el elemento Encabezado para el servidor (o el Cliente) a procesar.

En el momento, cualquier persona puede enviar una solicitud al servicio y obtener una respuesta, y eso es lo que pone nervioso a Rudy. Quiere que el servicio esté configurado para que solo los usuarios puedan obtener información, y por ende los competidores no pueden interceptar la información. Rudy piensa que es un buen sistema de prueba de concepto. En realidad está más preocupado sobre sistemas más complejos, como los que agregan contenido o acceden al sistema de contabilidad. Pero los conceptos son los mismos.

Para brindar esa seguridad, Gene y Frances deben utilizar cifrado y su tecnología relacionada, firmas.


Cifrado y firmas

La mayoría de las medidas de seguridad involucran una forma u otra de cifrado, o cifrado convertido en una firma digital, así que antes de que Frances le permita a Gene comenzar a jugar con la configuración de seguridad del servicio, quiere asegurarse de que comprendan con lo que está tratando.

Tipos de cifrado

El cifrado es el proceso de oscurecer información para hacer que sea ilegible sin conocimiento especial. La historia ha conocido muchos tipos distintos de cifrado. Generalmente el cifrado moderno es una secuencia bien definida de transformaciones aplicada a un mensaje y a alguna forma de “clave”. El resultado es un galimatías ilegible. El descifrado es un proceso inverso y también involucra una clave, así que al mantener la clave secreta uno puede estar razonablemente seguro de que nadie podrá leer el mensaje cifrado. Los métodos modernos de cifrado se pueden clasificar conforme a si usan una o dos claves.

En un algoritmo de clave simétrica (por ejemplo DES), el remitente y el destinatario deben tener una clave compartida establecida anteriormente y que sea secreta para todas las demás partes; el remitente utiliza esta clave para el cifrado, y el destinatario utiliza la misma clave para el descifrado. En este caso, la clave en si no es importante, excepto que la deben conocer las dos partes involucradas, y solo esas dos partes.

En un algoritmo de clave asimétrica (como por ejemplo RSA), hay dos claves individuales: la clave pública se publica y se sabe bien que pertenece a un individuo particular (u organización), mientras que la clave privada correspondiente se mantiene en secreto. Un mensaje cifrado por clave pública solo puede ser descifrado por la clave pública, así que cualquiera puede enviar un mensaje privado a un individuo particular. Pero lo inverso también es cierto, así que un mensaje que puede se descifrado por la clave pública de un individuo debe haber sido enviado por ese individuo. Veremos cómo esto entra en juego en el cifrado y la firma de mensajes SOAP

.

Cómo cifrar un archivo

Gene decide comenzar viendo cómo el texto del mensaje real se ve afectado por el cifrado. Comienza con un archivo de texto, que consiste en una línea única, como se puede ver en el Listado 7.

Listado 7. El texto destino
Hello, world!

Para hacer las cosas simples, él utiliza el programa gratuito GnuPG, ejecutando el comando que se muestra en el Listado 8.

Listado 8. El comando cifrado
gpg.exe -c -a --cipher-algo 3DES msg.txt

Este comando hace que el programa utilice el algoritmo de clave simétrica 3DES para cifrar el archivo. El programa pide una frase secreta, la cual Gene ingresa como “contraseña”, y luego produce el archivo msg.txt.asc. Puede ver el contenido de este archivo en el Listado 9.

Listado 9. El archivo cifrado
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1.4.2.2 (MingW32)

jA0EAgMCqFjZXeujyOJgySoKQ2qhpCpGERKpFn0iKms4kwjpI51BLcoTyH4p61YJ
kDAiRMbC6PfCBmg=
=G4EN
-----END PGP MESSAGE-----

¡Ciertamente nadie podría adivinar cuál es el texto con ese código! Animado, Gene pasa a ver el tema de las firmas digitales.

Cómo funcionan las firmas digitales

Las firmas digitales utilizan las técnicas de cifrado, pero el fin de la firma es distinto. En lugar de oscurecer el mensaje, una firma le da confianza al destinatario en dos trozos de información: el remitente del mensaje, y el mensaje mismo.

Funciona así. El remitente cifra el mensaje con su clave privada. Esta “firma” luego se envía al destinatario, junto al mensaje original. El destinatario intenta verificar la firma, lo que significa descifrar la firma con la clave pública del remitente, y comparar los resultados con el mensaje original. Si este proceso tiene éxito, el destinatario puede estar seguro de que solo el remitente puede ser el originador del mensaje, porque nadie más excepto el remitente tiene su clave privada. Además, si el mensaje original hubiera cambiado en tránsito, la firma descifrada no coincidiría, así que una verificación de firma exitosa significa también que el mensaje no ha sido interferido.

Generalmente, en vez de firmar todo el mensaje, el remitente calcula un “resumen” del mensaje (utilizando una función hash criptográfica), firma ese resumen, y lo pasa junto al mensaje descifrado. Esto brinda el mismo efecto sin tener que duplicar básicamente el tamaño de cada mensaje. (También reduce el tiempo de procesamiento para crear y verificar las firmas).

Firmar un archivo

Envalentonado, Gene decide ver esto en acción. Su intención es firmar digitalmente el archivo msg.txt que había cifrado anteriormente. Debido a que simplifica el firmado de un archivo, utilizará el mismo software GnuPG, a pesar de que luego deberá utilizar una técnica diferente para crear las claves utilizadas por la aplicación real.

El primer paso es crear el par de claves utilizando el comando que figura en el Listado 10.

Listado 10. Generar un par de claves
gpg.exe --gen-key

El programa hace muchas preguntas sobre la clave, como por ejemplo en nombre, el correo electrónico de Gene y otras cosas. Se decide por los parámetros de clave predeterminados (el algoritmo DSA y la longitud de clave de 2048 bits), e ingresa en nombre "Jon Dow". Esta operación almacena las claves en un archivo keystore en la carpeta principal de Gene.

Ahora puede firmar el mensaje. Utiliza el comando que se muestra en el Listado 11.

Listado 11. Firmado del documento
gpg.exe --clearsign -u "Jon Dow" msg.txt

Esta vez, el programa pide la contraseña relacionada con la clave privada de "Jon Dow", luego produce el archivo msg.txt.asc, como se muestra en el Listado 12.

Listado 12. El documento firmado
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hello, world!
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.2 (MingW32)

iD8DBQFEhftF06oTl3UESDQRArHsAJ0bE2qUEeVb5IDz4gQuRCgOes6v7gCfQhbJ
l356yO+YTkJUJZx4KoTTzok=
=ld3Y
-----END PGP SIGNATURE-----

Una persona que recibe este mensaje sabría descifrar la firma utilizando la clave pública de "Jon Dow", hacer hash al mensaje descifrado (utilizando SHA1), y comparar ambos.

Ahora que entienden cómo funcionan el cifrado y el firmado, Gene y Frances está listo para pasar a la protección del servicio real.


Protección del servicio

La protección del servicio involucra una cantidad de pasos que se deben realizar antes de poder enviar el primer mensaje seguro, y si bien ninguno de ellos es específico para la especificación WS-Security real (a diferencia del software que el equipo utiliza para generar los mensajes), estos pasos son cruciales, y de alguna forma u otra tendrán lugar para cualquier instalación de WS-Security.

Generación del keystore

Ahora que ha visto las firmas y el cifrado en acción, Gene debe comenzar a preparar la instalación propia del equipo. Debe comenzar creando el keystore, que incluirá todos los pares de clave privada-clave pública que puedan necesitarse. Para hacerlo, utilizará la aplicación keytool que viene con JDK.

Para crear una clave nueva y generar un keystore, ejecuta los siguientes comandos, como se ve en el Listado 13.

Listado 13. Crear un par de claves y un keystore
>cd %JAVA_HOME%\bin
>keytool -genkey -keystore mykeys.jks -alias gene
Enter keystore password:  mykeystorepassword
What is your first and last name?
  [Unknown]:  Gene Telluride
What is the name of your organizational unit?
  [Unknown]:  Information Technologies
What is the name of your organization?
  [Unknown]:  The Daily Moon

What is the name of your City or Locality?
  [Unknown]:  New York
What is the name of your State or Province?
  [Unknown]:  NY
What is the two-letter country code for this unit?
  [Unknown]:  US
Is CN=Gene Telluride, OU=Information Technologies, O=The Daily Moon, 
L=New York, ST=NY, C=U
S correct?
  [no]:  yes

Enter key password for <gene>
        (RETURN if same as keystore password):  mypassword

La línea de comandos le dice a la herramienta que genere un par de claves y lo almacene en el archivo mykeys.jks. El par de claves tiene un alias de gene, el cual nos permite referirnos a él con facilidad. Frances puede crear su clave y almacenarla en el mismo archivo, mykeys.jks.

Ahora está listo para empezar a trabajar para proteger el servicio en sí.

Activar la seguridad

El primer paso para agregar WS-Security al servicio es activarlo en el servidor. Apache Axis2, el motor de servicios web en el cual el equipo ejecuta sus servicios, está incorporado de manera modular, y el módulo WS-Security se llama Rampart (ver Prerrequisitos para obtener información de descarga). Una vez que haya descargado Rampart, coloque el archivo rampart-1.0.mar en el directorio de módulos para su instalación de Axis. Por ejemplo, la instalación de Gene tiene la carpeta de módulos en C:\SW\geronimo-1.0\config-store\32\war\WEB-INF\modules.

A continuación, Gene debe hacer que este módulo esté disponible globalmente, porque en la “cadena de controladores” que funciona detrás de escena de Axis2, se debe activar antes de que el mensaje pueda dirigirse a un servicio específico. Reinicie Geronimo e inició sesión en la página de administración de Axis2 en http://localhost:8080/axis2/axis2-admin/login . (El nombre de usuario es admin y la contraseña es axis2.) Haga clic en Engage Module/For all services y seleccione rampart-1.0. Haga clic en Engage, como puede ver en la Figura 3.

Figura 3. Activar el módulo Rampart
Activar el módulo Rampart

También puede activar el módulo Rampart agregándolo al archivoaxis2.xml, como verá cuando veamos cómo proteger al cliente.

Configurar la seguridad en el servicio

Ahora que la infraestructura está implementada, Frances puede comenzar a proteger el servicio real. Primero, cierra Geronimo, porque quiere actualizar el archivo services.xml que está ubicado en el archivo CMSService.aar. (Ella tiene la opción de actualizar y volver a cargar el servicio, pero eligió modificar el archivo directamente). La instalación del periódico tiene el archivo *.aar en la ubicación C:\SW\geronimo-1.0\config-store\32\war\WEB-INF\services\CMSService.aar. Ella actualiza el archivo services.xml para que requiera una marca de tiempo, como se ve en el Listado 14.

Listado 14. Agregar una marca de tiempo al servicio
<service name="CMSService">

    <description>
        This is a sample web service for the newspaper's 
        Content Managment System.
    </description>

    <parameter name="ServiceClass" 
               locked="false">CMSService</parameter>

    <parameter name="InflowSecurity">
       <action>
            <items>Timestamp</items>
       </action>
    </parameter>

    <parameter name="OutflowSecurity">
       <action>
            <items>Timestamp</items>
       </action>
    </parameter> 

    <operation name="getNumberOfArticles">
        <messageReceiver class=
         "org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
    </operation>

</service>

Axis2 le permite a Frances controlar específicamente mensajes que entran y salen del servicio. En este caso, indicó al motor de servicios web que solicite a los mensajes entrantes incluir una marca de tiempo, e incluir una marca de tiempo en los mensajes salientes devueltos al cliente.

En un momento, veremos el efecto que tiene este cambio sobre los mensajes transmitidos entre servidor y cliente, pero cuando Frances intenta ejecutar una prueba, TCPMon muestra que el servidor devuelve un error en vez de la información esperada, como se puede ver en el Listado 15.

Listado15. Encabezados de seguridad faltantes
<?xml version='1.0' encoding='UTF-8'?>
   <soapenv:Envelope 
         xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
         xmlns:wsa="http://www.w3.org/2005/08/addressing">
      <soapenv:Header>
         <wsa:ReplyTo>
            <wsa:Address>
              http://www.w3.org/2005/08/addressing/anonymous
            </wsa:Address>

         </wsa:ReplyTo>
         <wsa:MessageID>
            urn:uuid:1CA9E94A9C7FE9D5B311507328796251
         </wsa:MessageID>
         <wsa:Action>
            http://www.w3.org/2005/08/addressing/fault
         </wsa:Action>

      </soapenv:Header>
      <soapenv:Body>
         <soapenv:Fault>
            <faultcode>soapenv:Client</faultcode>
            <faultstring>WSDoAllReceiver: Request does not 
               contain required Security header</faultstring> 

            <detail>
               <Exception>org.apache.axis2.AxisFault: WSDoAllReceiver: 
                   Request does not contain required Security 
                   header
 at ...
               </Exception>
            </detail>
         </soapenv:Fault>
      </soapenv:Body>

   </soapenv:Envelope>

Lo importante aquí es que Frances ahora se sabe que funciona; el motor no acepta mensajes a menos que se adapten a la seguridad que ha configurado para el servicio.

Ahora puede pasar al cliente.

Protección del cliente

En muchas maneras el cliente también es una especie de servidor, pues también envía y recibe mensajes SOAP, así que quizás no debe ser sorpresa que el primer paso de Frances para proteger al cliente es agregar rampart-1.0.mar a la instalación del cliente. Para hacerlo, primero crea un directorio nuevo, <CLIENT_HOME>\axis-repo\modules, donde <CLIENT_HOME> es el directorio en el cual se ubica el archivo ClassifiedClient.class. Luego agrega el archivo rampart-1.0.mar a ese directorio. También crea un segundo directorio, <CLIENT_HOME>\axis-repo\conf, en el cual crea un archivo nuevo, axis2.xml. El archivo contiene el código que se ve en el Listado 16.

Listado 16. El archivo axis2.xml original
<axisconfig name="AxisJava2.0">

    <!-- Engage the security module -->
    <module ref="ramart"/>
    

    <parameter name="OutflowSecurity">
      <action>

        <items>Timestamp</items>
      </action>
    </parameter>

<!--    <parameter name="InflowSecurity">
      <action>

        <items>Timestamp</items>
      </action>
    </parameter> --> 

    <!-- ================================================= -->

    <!-- Parameters -->
    <!-- ================================================= -->
    <parameter name="hotdeployment"
 locked="false">true</parameter>
    <parameter name="hotupdate" locked="false">false</parameter>
    <parameter name="enableMTOM" locked="false">true</parameter>

    <!-- Uncomment this to enable REST support -->
    <!--    <parameter name="enableREST"
 locked="false">true</parameter>-->


    <parameter name="userName" locked="false">admin</parameter>

    <parameter name="password" locked="false">axis2</parameter>

    <!-- ================================================= -->
    <!-- Message Receivers -->
    <!-- ================================================= -->
    <!--This is the Deafult Message Receiver for the system , 
if you want to have MessageReceivers for -->

    <!--all the other MEP implement it and add the correct entry 
to here, so that you can refer from-->
    <!--any operation -->
    <!--Note : You can ovride this for particular service by 
adding the same element with your requirement-->
    <messageReceivers>
        <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only"
                        
 class="org.apache.axis2.receivers.RawXMLINOnlyMessageReceiver"/>
        <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out"
                        
 class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>

    </messageReceivers>
    <!-- ================================================= -->
    <!-- Transport Ins -->
    <!-- ================================================= -->
    <transportReceiver name="http"
                      
 class="org.apache.axis2.transport.http.SimpleHTTPServer">
        <parameter name="port" locked="false">6060</parameter>

        <!--If you want to give your own host address for EPR
 generation-->
        <!--uncommet following paramter , and set as you required.-->
        <!--<parameter name="hostname"
 locked="false">http://myApp.com/ws</parameter>-->
    </transportReceiver>

    <transportReceiver name="tcp"
                       class="org.apache.axis2.transport.tcp.TCPServer">
        <parameter name="port" locked="false">6061</parameter>
        <!--If you want to give your own host address for EPR
 generation-->
        <!--uncommet following paramter , and set as you required.-->
        <!--<parameter name="hostname"
 locked="false">tcp://myApp.com/ws</parameter>-->

    </transportReceiver>

    <!-- ================================================= -->
    <!-- Transport Outs -->
    <!-- ================================================= -->

    <transportSender name="tcp"
                    
 class="org.apache.axis2.transport.tcp.TCPTransportSender"/>

    <transportSender name="local"
                    
 class="org.apache.axis2.transport.local.LocalTransportSender"/>
    <transportSender name="jms"
                     class="org.apache.axis2.transport.jms.JMSSender"/>
    <transportSender name="http"
                    
 class="org.apache.axis2.transport.http.CommonsHTTPTransportSender">
        <parameter name="PROTOCOL"
 locked="false">HTTP/1.1</parameter>
        <parameter name="Transfer-Encoding"
 locked="false">chunked</parameter>

    </transportSender>
    <transportSender name="https"
                    
 class="org.apache.axis2.transport.http.CommonsHTTPTransportSender">
        <parameter name="PROTOCOL"
 locked="false">HTTP/1.1</parameter>
        <parameter name="Transfer-Encoding"
 locked="false">chunked</parameter>
    </transportSender>

    <!-- ================================================= -->
    <!-- Phases  -->
    <!-- ================================================= -->
    <phaseOrder type="inflow">
        <!--  System pre defined phases       -->
         <phase name="Transport">

            <handler name="RequestURIBasedDispatcher"
                    
 class="org.apache.axis2.engine.RequestURIBasedDispatcher">
                <order phase="Dispatch"/>
            </handler>
            <handler name="SOAPActionBasedDispatcher"
                    
 class="org.apache.axis2.engine.SOAPActionBasedDispatcher">
                <order phase="Dispatch"/>
            </handler>

        </phase>
        <phase name="Security"/>
        <phase name="PreDispatch"/>
        <phase name="Dispatch"
 class="org.apache.axis2.engine.DispatchPhase">
            <handler name="AddressingBasedDispatcher"
                    
 class="org.apache.axis2.engine.AddressingBasedDispatcher">
                <order phase="Dispatch"/>

            </handler>

            <handler name="SOAPMessageBodyBasedDispatcher"
                    
 class="org.apache.axis2.engine.SOAPMessageBodyBasedDispatcher">
                <order phase="Dispatch"/>
            </handler>
            <handler name="InstanceDispatcher"
                     class="org.apache.axis2.engine.InstanceDispatcher">
                <order phase="PostDispatch"/>

            </handler>
        </phase>
        <!--  System pre defined phases       -->
        <!--   After Postdispatch phase module author or or 
service author can add any phase he want      -->
        <phase name="OperationInPhase"/>
    </phaseOrder>

    <phaseOrder type="outflow">
        <!--      user can add his own phases to this area  -->
        <phase name="OperationOutPhase"/>
        <!--system predefined phase-->
        <!--these phase will run irrespective of the service-->
        <phase name="PolicyDetermination"/>

        <phase name="MessageOut"/>
    </phaseOrder>
    <phaseOrder type="INfaultflow">
        <phase name="PreDispatch"/>
        <phase name="Dispatch"
 class="org.apache.axis2.engine.DispatchPhase">
            <handler name="RequestURIBasedDispatcher"
                    
 class="org.apache.axis2.engine.RequestURIBasedDispatcher">

                <order phase="Dispatch"/>
            </handler>

            <handler name="SOAPActionBasedDispatcher"
                    
 class="org.apache.axis2.engine.SOAPActionBasedDispatcher">
                <order phase="Dispatch"/>
            </handler>

            <handler name="AddressingBasedDispatcher"
                    
 class="org.apache.axis2.engine.AddressingBasedDispatcher">
                <order phase="Dispatch"/>
            </handler>

            <handler name="SOAPMessageBodyBasedDispatcher"
                    
 class="org.apache.axis2.engine.SOAPMessageBodyBasedDispatcher">
                <order phase="Dispatch"/>
            </handler>

            <handler name="InstanceDispatcher"
                     class="org.apache.axis2.engine.InstanceDispatcher">
                <order phase="PostDispatch"/>
            </handler>
        </phase>
        <!--      user can add his own phases to this area  -->
        <phase name="OperationInFaultPhase"/>

    </phaseOrder>
    <phaseOrder type="Outfaultflow">
        <!--      user can add his own phases to this area  -->
        <phase name="OperationOutFaultPhase"/>
        <phase name="PolicyDetermination"/>
        <phase name="MessageOut"/>

    </phaseOrder>
    </axisconfig>

La mayor parte de este código es estándar, préstamo de otros ejemplos de Axis2. Sin embargo, en la sección en negrita en la parte superior, Frances agrega decirle al cliente que agregue una marca de tiempo el mensaje que envía al servidor. Decide no ocuparse de la marca de tiempo devuelta por el servidor, al menos por el momento. No obstante, a diferencia del servicio, el cliente no obedecerá estas directivas automáticamente. Debe hacer cambios en la clase real.

Cambios en la clase de cliente

Para que la clase de cliente haga los cambios especificados en el archivo axis2.xml. debe conocerlos. Con ese fin, Frances agrega la configuración al proceso de creación de ServiceClient, como se ve en el Listado 17.

Listado 17. Llamar a la nueva configuración desde ClassifiedClient.java
...
    public static void main(String[] args) {
        try {
            OMElement payload = 
                ClassifiedClient.getNumOfArticlesOMElement();
            ConfigurationContext 
                 configContext = ConfigurationContextFactory
                      .createConfigurationContextFromFileSystem(
                                               "axis-repo", null); 
            Options options = new Options();
            options.setTo(targetEPR);
            options.setTransportInProtocol(Constants.TRANSPORT_HTTP);

            ServiceClient sender = 
                  new ServiceClient(configContext, null);

            sender.setOptions(options);
            OMElement result = sender.sendReceive(payload);

            String response = result.getText();
            System.out.println("There are "+response+
                                  " classifieds at the moment.");
        } catch (Exception e) { 
        	System.out.println(e.toString());
        }
    }
}

Primero, Frances crea un nuevo ConfigurationContext, lo que permite al ServiceClient buscar una configuración nueva. Pero para que ocurra, deberá cambiar la manera en que llama a la clase de cliente real.

Unir todo

Para que el cliente y llame al módulo Rampart de manera adecuada, debe saber de dónde encontrar el archivo de configuración, y dónde encontrar cualquier otro elemento de repositorio, como por ejemplo el mismo archivo *.mar. Para hacerlo, Frances agrega más detalles al script que fija su classpath y ejecuta la clase de cliente, como se ve en el Listado 18.

Listado 18. Llamar a la clase
echo off
SET CLASSPATH=C:/SW/axis2/lib/XmlSchema-1.0.2.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/axiom-api-1.0.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/axiom-impl-1.0.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/axis2-kernel-1.0.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/commons-codec-1.3.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/commons-httpclient-3.0.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/commons-logging-1.0.4.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/
                             geronimo-spec-activation-1.0.2-rc4.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/
                             geronimo-spec-javamail-1.3.1-rc5.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/jaxen-1.1-beta-8.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/log4j-1.2.13.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/neethi-1.0.1.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/stax-api-1.0.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/wsdl4j-1.5.2.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/wstx-asl-2.9.3.jar
SET CLASSPATH=%CLASSPATH%;C:/sw/ClassifiedClient/lib/wss4j-1.5.0.jar
SET CLASSPATH=%CLASSPATH%;C:/sw/ClassifiedClient/lib/xmlsec-1.3.0.jar
SET CLASSPATH=%CLASSPATH%;C:/sw/ClassifiedClient/lib/
                             commons-discovery-0.2.jar
SET CLASSPATH=%CLASSPATH%;C:/sw/ClassifiedClient/lib/
                             bcprov-jdk13-132.jar
SET CLASSPATH=%CLASSPATH%;C:/sw/ClassifiedClient/lib/xalan.jar
SET CLASSPATH=%CLASSPATH%;.

java.exe -Daxis2.xml=axis-repo/conf/axis2.xml 
         -Daxis2.repo=axis-repo ClassifiedClient

Observe que Frances también agrega varios archivos *.jar desde la distribución WSS4J (ver Prerrequisitos para obtener información de descarga).

Ahora está lista para probar la solicitud una vez más.

La solicitud

La ejecución de la solicitud muestra un mensaje SOAP normal, con una excepción, como se ve en el Listado 19.

Listado 19. Un mensaje SOAP con marca de tiempo
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv=
      "http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header>
      <wsse:Security xmlns:wsse="http://docs.oasis-
open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-
1.0.xsd" soapenv:mustUnderstand="1">
         <wsu:Timestamp xmlns:wsu="http://docs.oasis-
open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-
1.0.xsd" wsu:Id="Timestamp-29987161">
            <wsu:Created>2006-06-19T16:22:28.578Z</wsu:Created>

            <wsu:Expires>2006-06-19T16:27:28.578Z</wsu:Expires>
         </wsu:Timestamp>
      </wsse:Security> 
   </soapenv:Header>
   <soapenv:Body>

      <cms:getNumberOfArticles xmlns:cms="http://daily-moon.com/cms">
         <cms:category>classifieds</cms:category>
      </cms:getNumberOfArticles>
   </soapenv:Body>
</soapenv:Envelope>

Ahora, por primera vez, Frances ve un encabezado de Seguridad en sus mensajes. En este caso, es sólo una marca de tiempo, que muestra cuándo se creó el mensaje. El atributo mustUnderstand significa que si el servidor no sabe qué hacer con este elemento de marca de tiempo, debe rechazar el mensaje.

Las marcas de tiempo son quizás el elemento más simple de WS-Security. Brindan una manera de limitar la vida útil de los mensajes, evitan que el contenido malicioso intercepte mensajes, los cambian a voluntad, y los envían. En este caso, la marca de tiempo vence cinco segundos después de la creación del mensaje, así que si el mensaje es más antiguo, debe ser rechazado. (Sí, un contenido malicioso aún puede modificar los valores de la marca de tiempo, pero eso lo abordaremos cuando lleguemos a las firmas.)

La respuesta

Como se especifica en el servicio, la respuesta también tiene una marca de tiempo, como se ve en el Listado 20.

Listado 20. La respuesta
<?xml version='1.0' encoding='UTF-8'?>
   <soapenv:Envelope xmlns:soapenv=
            "http://schemas.xmlsoap.org/soap/envelope/">
      <soapenv:Header>
         <wsse:Security xmlns:wsse="http://docs.oasis-
open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-
1.0.xsd" soapenv:mustUnderstand="1">
            <wsu:Timestamp xmlns:wsu="http://docs.oasis-
open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-
1.0.xsd" wsu:Id="Timestamp-22347273">
              
 <wsu:Created>2006-06-19T16:22:29.281Z</wsu:Created>

              
 <wsu:Expires>2006-06-19T16:27:29.281Z</wsu:Expires>
            </wsu:Timestamp>
            <wsse11:SignatureConfirmation xmlns:wsse11=
"http://docs.oasis-open.org/wss/2005/xx/oasis-2005xx-wss-wssecurity-
secext-1.1.xsd" xmlns:wsu="http://docs.oasis-
open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-
1.0.xsd" wsu:Id="SigConf-5759024" />
         </wsse:Security> 
      </soapenv:Header>

      <soapenv:Body>
         <resp:numberOfArcticles 
                     xmlns:resp="http://daily-moon.com/cms/" 
                     xmlns:tns="http://ws.apache.org/axis2"
                >42</resp:numberOfArcticles>
      </soapenv:Body>
   </soapenv:Envelope>

La respuesta incluye la marca de tiempo, según fue especificada, pero también muestra que la información de seguridad ha sido procesada y verificada, incluso a pesar de que Frances no ha configurado el cliente para verificar ninguno de estos hechos.

Observe que en ambos casos, los mensajes reales quedaron intactos.


Firmar los mensajes

Ahora, en este punto, Frances ha agregado una marca de tiempo a los mensajes salientes y entrantes, pero no se puede hacer nada para evitar que alguien simplemente cambie su valor y lo vuelva a trasmitir. Para resolver ese problema (de cualquier otro problema que surja de la información que puede haber sido modificada) Frances debe firmar sus mensajes.

Cómo funciona el firmado de los mensajes

Como hemos visto anteriormente, firmar un mensaje involucra tener una versión de los datos que se han cifrado de manera conocida, para que al descifrarlo brinde un valor que se pueda comparar con el original. Por ejemplo, digamos que Frances desea firmar digitalmente el elemento marca de tiempo en su mensaje para que el servidor pueda verificar que no hayan sido alterados ni malversados de alguna manera.

Para hacerlo, iniciará un proceso que tomará varios pasos.

Primero, firmará el mensaje (o parte del mensaje). Para hacerlo, utilizará el archivo axis2.xml para especificar un usuario como el firmante. Axis2 tomará esa información y hará dos cosas con ella. Primero, introducirá el alias de usuario a una “clase de callback” (devolución de llamada), que devolverá la contraseña para ese usuario. Armado con esa contraseña, Axis2 entonces recuperará la clave privada de ese usuario del keystore creado anteriormente.

Utilizando la clave privada, Axis2 cifra, o firma, la parte relevante del mensaje y agrega la firma al mensaje. Luego envía el mensaje. Cuando el servicio recibe el mensaje, hace casi lo mismo; accede al keystore para obtener la clave pública para ese usuario, y luego verifica la firma.

Observe que si el servicio iba a enviar contenido que ha sido firmado, estos roles se invertirían para el viaje de regreso.

Veamos cómo prepararlo.

La clase callback

El primer paso es crear la clase callback. En una situación real, esta clase podría acceder a un directorio LDAP o utilizar otros métodos para relacionar un usuario con una contraseña, pero Frances está comenzando con una prueba de concepto, así que creará una clase callback simple que devuelve valores arbitrarios, como se puede ver en el Listado 21.

Listado 21. PWCallback.java, la clase callback
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 PWCallback implements CallbackHandler {

   public void handle(Callback[] callbacks)
            throws IOException, UnsupportedCallbackException {

      for (int i = 0; i < callbacks.length; i++) {
         if (callbacks[i] instanceof WSPasswordCallback) {
            WSPasswordCallback pc=(WSPasswordCallback)callbacks[i];
                if (pc.getIdentifer().equals("gene")) {
                    pc.setPassword("mypassword");
                } else if (pc.getIdentifer().equals("frances")) {
                    pc.setPassword("francespassword");
                } else {
                    throw new UnsupportedCallbackException(
                                   callbacks[i], "Unknown user");
                }
            } else {
                throw new UnsupportedCallbackException(callbacks[i],
                        "Unrecognized Callback");
            }
        }
    }
}

Lo que hace el método handle() no es importante, todo lo que importa es que establezca la contraseña en el objeto WSPasswordCallback o que arroje una excepción.

El archivo de propiedades

A continuación Frances debe encontrar una manera de indicarle a Axis2 dónde encontrar el keystore, y qué clase debe realizar todas estas cosas criptográficas. Para hacerlo, crea un archivo de propiedades, security.properties, como se ve en el Listado 22:

Listado 22. El archivo security.properties
org.apache.ws.security.crypto.provider=org.apache.ws.security.compo
nents.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=mykeystorepa
ssword
org.apache.ws.security.crypto.merlin.file=mykeys.jks

Luego de especificar el proveedor, el archivo de propiedades define el tipo de keystore (en este caso jks, un formato registrado que viene con Java) la contraseña para el keystore, y el nombre del archivo keystore real, el cual por fines de simplicidad coloca en el mismo directorio que el archivo de clase de cliente.

El archivo axis2.xml

Ahora debe incluir en el archivo axis2.xml no que tiene en mente para los mensajes salientes, como se puede ver en el Listado 23.

Listado 23. El archivo axis2.xml, con firma
<axisconfig name="AxisJava2.0">

    <!-- Engage the security module -->
    <module ref="rampart"/>

    <parameter name="OutflowSecurity">
      <action>

        <items>Signature</items>
        <user>gene</user><passwordCallbackClass>PWCallback</passwordCallbackClass>
       
 <signaturePropFile>security.properties</signaturePropFile>

        <signatureKeyIdentifier>SKIKeyIdentifier</signatureK
eyIdentifier>
        <signatureParts>{Element}{http://schemas.xmlsoap.org
/soap/envelope/}Body</signatureParts>
      </action>
    </parameter>
<!--
    <parameter name="InflowSecurity">

      <action>
        <items>Timestamp</items>
      </action>
    </parameter>
-->
...

En este caso, en vez de decirle al cliente que agregue una marca de tiempo, le dice que agregue una Firma. Al verlo, el cliente analiza el archivo especificado en signaturePropFile y utiliza la información que encuentra allí – junto a la passwordCallbackClass - para obtener la contraseña para el usuario gene. Desde ahí, obtiene la clave privada de gene y firma únicamente la parte del mensaje especificada en el elemento signatureParts. En este caso, significa que el elemento representado por el Cuerpo (a diferencia de simplemente el contenido de ese elemento), que es parte del espacio de nombres http://schemas.xmlsoap.org/soap/envelope/.

Puede firmar cualquier parte del mensaje. Por ejemplo, a menudo las personas firman la marca de tiempo, si existe.

La solicitud

¿Entonces qué significan todos estos cambios para los mensajes producidos por el cliente? Puede ver resultante en el Listado 24.

Listado 24. La solicitud firmada
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv=
        "http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header>
      <wsse:Security xmlns:wsse="..." soapenv:mustUnderstand="1">
         <ds:Signature xmlns:ds="..." Id="Signature-8789796">
            <ds:SignedInfo>

               <ds:CanonicalizationMethod Algorithm=
                    "http://www.w3.org/2001/10/xml-exc-c14n#" />
               <ds:SignatureMethod Algorithm=
                 "http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
               <ds:Reference URI="#id-17764792">
                  <ds:Transforms>
                     <ds:Transform Algorithm=
                    "http://www.w3.org/2001/10/xml-exc-c14n#" />
                  </ds:Transforms>

                  <ds:DigestMethod Algorithm=
                     "http://www.w3.org/2000/09/xmldsig#sha1" />
                  <ds:DigestValue
                  >wg+9KsR6BVBiO/hakJJwMdtU7+I=</ds:DigestValue>
               </ds:Reference>
            </ds:SignedInfo>

 <ds:SignatureValue>hom9Enzu3yHBuaF...</ds:SignatureValue>

            <ds:KeyInfo Id="KeyId-19475750">
               <wsse:SecurityTokenReference xmlns:wsu=".." 
                      wsu:Id="STRId-31156635">
                  <wsse:KeyIdentifier EncodingType="http://docs.oasis
-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-
1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/o
asis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier"
>CuJdE1B2dUFd1dkLZSzQ5vj6MYg=</wsse:KeyIdentifier>
               </wsse:SecurityTokenReference>
            </ds:KeyInfo>

         </ds:Signature>
      </wsse:Security>
   </soapenv:Header>
   <soapenv:Body xmlns:wsu="..." wsu:Id="id-17764792">
      <cms:getNumberOfArticles xmlns:cms="http://daily-moon.com/cms">
         <cms:category>classifieds</cms:category>

      </cms:getNumberOfArticles>
   </soapenv:Body>
</soapenv:Envelope>

He cortado valores de espacio de nombres para que esto sea un poco más legible, pero analicémoslo paso a paso. El elemento Security contiene toda la información de seguridad, por supuesto, comenzando con la Firma. La firma comienza con la información sobre que se firmó en realidad. Adelantándonos un poquito, el elemento Reference incluye un atributo URI, que remite al atributo id para el Cuerpo, que es, recuerde, lo que Frances le dijo al cliente que firmara. Así que eso le dice al servicio qué información se firmó en realidad.

Regresando, el primer paso en la firma de contenido es canonicalizarlo (quitar nodos de texto externos, etc.), pero en realidad hay dos maneras de hacerlo, la inclusiva y la exclusiva, y la diferencia está en la manera en que cada método maneja las declaraciones de espacio de nombres. Así que el elemento CanonicalizationMethod especifica qué método utiliza la firma.

Luego pasamos a SignatureMethod, que especifica, como lo sugiere el nombre, el método utilizado para firmar los datos relevantes.

El elemento Reference incluye información sobre todos los pasos que se tomaron para llegar al contenido final a firmar, en orden, para que el proceso de verificación pueda tomar los mismos pasos y (se espera) llegar al mismo SignatureValue.

El KeyInfo brinda la clave real utilizada para firmar los datos o una referencia a la clave.

Hacer los cambios al servicio

Ahora el cliente crea la firma, pero el servicio no sabe qué hacer con ella. Frances está por cambiar eso.

En esencia, el servicio debe realizar muchos de los mismos pasos que realizó el cliente; debe poder buscar contraseñas y claves en el keystore, así que Frances comienza agregando los archivos mykeys.jks, PWCallback.class y security.properties al archivo CMSService.aar file. No tiene que utilizar la misma clase y el mismo keystore que utilizó para el cliente, en este caso, lo hace por comodidad.

También agrega bcprov-jdk13-132.jar, wss4j-1.5.0.jar, y xmlsec-1.3.0.jar al directorio lib de la aplicación Axis2. (Estos archivos provienen de la distribución WSS4J.)

Frances luego debe establecer la definición del servicio (en servicios.xml) para reconocer que en datos firmados vienen hacia el. Lo hace haciendo los cambios que se muestran en el Listado 25.

Listado 25. Indicarle al servicio que espere datos firmados
<service name="CMSService">

    <description>
   This is a sample web service for the newspaper's Content Managment System.
    </description>

    <parameter name="ServiceClass"
 locked="false">CMSService</parameter>

    <parameter name="InflowSecurity">
       <action>
            <items>Signature</items>
           
 <passwordCallbackClass>PWCallback</passwordCallbackClass>

           
 <signaturePropFile>security.properties</signaturePropFile>
       </action>
    </parameter>

    <parameter name="OutflowSecurity">
       <action>

            <items>Timestamp</items>
       </action>
    </parameter>

    <operation name="getNumberOfArticles">
        <messageReceiver
 class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>

    </operation>

</service>

Estos cambios son suficientes para informar al servicio que debe esperar y qué hacer con los datos firmados.

La respuesta

La respuesta es un documento que incluye una marca de tiempo, como se especifica en el parámetro OutFlowSecurity, aunque también incluye información sobre la verificación de la firma, como se ve en el Listado 26.

Listado 26. La respuesta
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv=
         "http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header>
      <wsse:Security xmlns:wsse="..." soapenv:mustUnderstand="1">
         <wsu:Timestamp xmlns:wsu="..." wsu:Id="Timestamp-27995990">
            <wsu:Created>2006-06-19T23:56:55.214Z</wsu:Created>

            <wsu:Expires>2006-06-20T00:01:55.214Z</wsu:Expires>
         </wsu:Timestamp>
         <wsse11:SignatureConfirmation xmlns:wsse11="..." 
             xmlns:wsu="..." Value="hom9Enzu3yHBuaigFl26b6A+5hy..." 
             wsu:Id="SigConf-25877728" />
      </wsse:Security>
   </soapenv:Header>

   <soapenv:Body>
      <resp:numberOfArcticles xmlns:resp="http://daily-moon.com/cms/" 
  
 xmlns:tns="http://ws.apache.org/axis2">42</resp:numberOfArcticles>
   </soapenv:Body>
</soapenv:Envelope>

Ahora veamos cómo agregar cifrado.


Agregar cifrado

Frances está satisfecha con el proceso de verificar parte del mensaje utilizando firmas, pero aún no hay manera de oscurecer la información para que los competidores y otros bellacos no puedan leerla. Para encargarse de eso, tendrá que agregar cifrado a la aplicación.

Modificar el servicio

Esta vez, comienza con el servicio. Ya ha agregado todas las clases adicionales que necesita la aplicación, así que todo lo que debe modificar es el archivo services.xml, como se puede ver en el Listado 27.

Listado 27. Agregar cifrado al servicio
<service name="CMSService">

    <description>
        This is a sample web service for the newspaper's 
        Content Managment System.
    </description>

    <parameter name="ServiceClass" 
               locked="false">CMSService</parameter>

    <parameter name="InflowSecurity">
       <action>
            <items>Timestamp Signature
 Encrypt</items>
           
 <passwordCallbackClass>PWCallback</passwordCallbackClass>

           
 <signaturePropFile>security.properties</signaturePropFile>
       </action>
    </parameter>

    <operation name="getNumberOfArticles">
        <messageReceiver class=
        "org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>

    </operation>

</service>

Aquí Frances le ha indicado tendrán al servicio que a los mensajes entrantes se les ha agregado una marca de tiempo, y luego tendrán que ser firmados, y luego tendrán que ser cifrados, en ese orden.

Ahora solo tiene que indicarle al cliente que lo haga.

Modificar el cliente

Debido a que ella ya ha establecido las bases, agregar el cifrado al cliente es muy directo, e involucra solo un cambio al archivo axis2.xml, como se puede ver en el Listado 28.

Listado 28. Agregar cifrado al cliente
<axisconfig name="AxisJava2.0">

    <!-- Engage the security module -->
    <module ref="rampart"/>
    

    <parameter name="OutflowSecurity">
      <action>

        <items>Timestamp Signature Encrypt</items>
        <user>gene</user>
        <passwordCallbackClass>PWCallback</passwordCallbackClass>
       
 <signaturePropFile>security.properties</signaturePropFile>

        <signatureKeyIdentifier
                        >SKIKeyIdentifier</signatureKeyIdentifier>
        <encryptionKeyIdentifier
                       >SKIKeyIdentifier</encryptionKeyIdentifier>
        <encryptionUser>frances</encryptionUser>
        <signatureParts>{Element}{http://schemas.xmlsoap.org/soap/env
elope/}Body</signatureParts>

       
 <optimizeParts>//xenc:EncryptedData/xenc:CipherData/xenc:Ciph
erValue</optimizeParts>
      </action>
    </parameter>

    <!-- ================================================= -->
    <!-- Parameters -->

    <!-- ================================================= -->
    <parameter name="hotdeployment"
 locked="false">true</parameter>
...

Observe que especifica un usuario diferente para el cifrado que el que utilizó en la firma digital. Esto no es un requisito, pero es posible. Observe además el agregado del elemento optimizeParts que especifica cómo Axis2 debe representar los datos cifrados en el mensaje.

Veamos cuál es el resultado.

La solicitud

Con todo en su lugar, el mensaje se hace algo complejo, como se puede ver en el Listado 29.

Listado 29. La solicitud firmada, sellada y cifrada
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv=
            "http://schemas.xmlsoap.org/soap/envelope/"
         xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
   <soapenv:Header>
      <wsse:Security xmlns:wsse="..." soapenv:mustUnderstand="1">
         <xenc:EncryptedKey Id="EncKeyId-229902">
            <xenc:EncryptionMethod Algorithm=
                 "http://www.w3.org/2001/04/xmlenc#rsa-1_5" />

            <ds:KeyInfo xmlns:ds="...">
               <wsse:SecurityTokenReference>
                  <wsse:KeyIdentifier EncodingType="http://docs.oasis
-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-
1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/o
asis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier"
>Xeg55vRyK3ZhAEhEf+YT0z986L0=</wsse:KeyIdentifier>
               </wsse:SecurityTokenReference>
            </ds:KeyInfo>

            <xenc:CipherData>
              
 <xenc:CipherValue>PpAOXj5P0W8ukm...</xenc:CipherValue>
            </xenc:CipherData>
            <xenc:ReferenceList>
               <xenc:DataReference URI="#EncDataId-30957433" />

            </xenc:ReferenceList>
         </xenc:EncryptedKey>
         <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" 
                       Id="Signature-17764792">
            <ds:SignedInfo>
               <ds:CanonicalizationMethod Algorithm=
                      "http://www.w3.org/2001/10/xml-exc-c14n#" />
               <ds:SignatureMethod Algorithm=
                   "http://www.w3.org/2000/09/xmldsig#rsa-sha1" />

               <ds:Reference URI="#id-30957433">
                  <ds:Transforms>
                     <ds:Transform Algorithm=
                      "http://www.w3.org/2001/10/xml-exc-c14n#" />
                  </ds:Transforms>
                  <ds:DigestMethod Algorithm=
                       "http://www.w3.org/2000/09/xmldsig#sha1" />
                 
 <ds:DigestValue>+ECkM6R4GQ7AQ=...</ds:DigestValue>

               </ds:Reference>
            </ds:SignedInfo>
            <SignatureValue>DIeP5AxVmfw...</ds:SignatureValue>
            <ds:KeyInfo Id="KeyId-16675983">
               <wsse:SecurityTokenReference
 xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-
wss-wssecurity-utility-1.0.xsd" wsu:Id="STRId-21866740">

                  <wsse:KeyIdentifier
 EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-
wss-soap-message-security-1.0#Base64Binary"
 ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-
wss-x509-token-profile-1.0#X509SubjectKeyIdentifier">
CuJdE1B2dUFd1dkLZSzQ5vj6MYg=</wsse:KeyIdentifier>
               </wsse:SecurityTokenReference>
            </ds:KeyInfo>
         </ds:Signature>
         <wsu:Timestamp
 xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-
wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-13665843">

            <wsu:Created>2006-06-20T00:46:58.263Z</wsu:Created>
            <wsu:Expires>2006-06-20T00:51:58.263Z</wsu:Expires>
         </wsu:Timestamp>
      </wsse:Security>
   </soapenv:Header>

   <soapenv:Body xmlns:wsu="..." wsu:Id="id-30957433">
      <xenc:EncryptedData Id="EncDataId-30957433" Type=
                "http://www.w3.org/2001/04/xmlenc#Content">
         <xenc:EncryptionMethod Algorithm=
           "http://www.w3.org/2001/04/xmlenc#aes128-cbc" />
         <xenc:CipherData>
            <xenc:CipherValue>DZ3vWPtabb5vBpZMlEYLPjFc8r2DMJ...
fSjXpBFa7gybNA==</xenc:CipherValue>

         </xenc:CipherData>
      </xenc:EncryptedData>
   </soapenv:Body>
</soapenv:Envelope>

Comenzando desde abajo, observe que falta la solicitud real, o que Axis2 la ha reemplazado con un elemento EncryptedData que incluye información sobre cómo se cifraron los datos, así como también los datos cifrados reales (en los elementos CypherData y CypherValue).

Los datos se cifraron con una clave compartida, lo que significa que el mensaje debe incluir esa clave para poder ser descifrado. La clave compartida se ha cifrado con la clave pública del destinatario e incrustada en el Encabezado, en el elemento EncryptedKey. Esta clave incluye también una ReferenceList, que incluye una DataReference que señala los datos utilizados por la clave para el cifrado.

Así que para invertir el sentido, el destinatario (en este caso, el servidor) recibe el mensaje, utiliza su propia clave para descifrar la clave compartida, y luego utiliza la clave compartida para descifrar el cuerpo del mensaje.

Y después de todo eso, ¿cómo se ve la respuesta?

La respuesta

La respuesta es bastante simple en realidad, porque Frances no estableció ningún OutFlowSecurity en el servidor, como se puede ver en el Listado 30.

Listado 30. La respuesta
<?xml version='1.0' encoding='UTF-8'?>
   <soapenv:Envelope xmlns:soapenv=
            "http://schemas.xmlsoap.org/soap/envelope/">
      <soapenv:Header />
      <soapenv:Body>
         <resp:numberOfArcticles xmlns:resp=
                "http://daily-moon.com/cms/" xmlns:tns=
                "http://ws.apache.org/axis2"
         >42</resp:numberOfArcticles>

      </soapenv:Body>
   </soapenv:Envelope>

Esta es una respuesta SOAP perfectamente válida, excepto por una cosa. Puede que recuerde que Frances ha establecido para que el cliente espere, como mínimo, una marca de tiempo en su propio InFlowSecurity. Así que después de todo, la solicitud fallará a menos que el servidor y el cliente estén produciendo y esperando los mismos métodos de seguridad.


Unir todo

En este punto Frances y Gene tienen algunos ejemplos inconexos, así que deciden unir todo en una única implementación para mostrarle a Rudy.

La especificación final del servicio

Rudy desea que el servicio acepte únicamente solicitudes de individuos autorizados (o entidades), y no desea que los competidores lean las respuestas. Para hacerlo, Gene y Frances configuren las cosas de la siguiente manera:

  1. El cliente agregará una Marca de tiempo, que deberá firmar con la clave privada de un usuario aprobado. Esto resuelve el problema del acceso autorizado, y evita que los mensajes sean interceptados y reproducidos.
  2. El servidor agregará una marca de tiempo, pero también cifrará el cuerpo de la respuesta para que los espías no puedan ver los datos que regresan.

Veamos cómo se une todo.

El servicio

Del lado del servicio, Gene establece el archivo services.xml como se ve en el Listado 31.

Listado 31. El archivo services.xml final
<service name="CMSService">

    <description>
        This is a sample web service for the newspaper's 
        Content Managment System.
    </description>

    <parameter name="ServiceClass" 
               locked="false">CMSService</parameter>

    <parameter name="InflowSecurity">
       <action>
            <items>Timestamp Signature</items>
           
 <passwordCallbackClass>PWCallback</passwordCallbackClass>

           
 <signaturePropFile>security.properties</signaturePropFile>
       </action>
    </parameter>

    <parameter name="OutflowSecurity">
      <action>

        <items>Timestamp Signature Encrypt</items>
        <user>gene</user>
        <passwordCallbackClass>PWCallback</passwordCallbackClass>
       
 <signaturePropFile>security.properties</signaturePropFile>

        <signatureKeyIdentifier
                        >SKIKeyIdentifier</signatureKeyIdentifier>
        <encryptionKeyIdentifier
                       >SKIKeyIdentifier</encryptionKeyIdentifier>
        <encryptionUser>frances</encryptionUser>
        <signatureParts>

           {Element}{http://schemas.xmlsoap.org/soap/envelope/}Body
        </signatureParts>
        <optimizeParts>
            //xenc:EncryptedData/xenc:CipherValue/xenc:CipherData
        </optimizeParts> 
       </action>
    </parameter>

    <operation name="getNumberOfArticles">
        <messageReceiver class=
           "org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
    </operation>

</service>

El InflowSecurity es lo que espera el servidor - un mensaje al que se le ha agregado una Marca de tiempo y luego ha sido firmado - y OutflowSecurity es lo que enviará de regreso al cliente – un mensaje al que se le ha agregado una Marca de tiempo y se ha firmado, con los datos cifrados.

El cliente

Del lado del cliente, Frances configura l inverso, como se puede ver en el Listado 32.

Listado 32. El archivo axis2.xml final
<axisconfig name="AxisJava2.0">

    <!-- Engage the security module -->

    <module ref="rampart"/>
    
    <parameter name="OutflowSecurity">
      <action>
        <items>Timestamp Signature</items>
        <user>gene</user>

        <passwordCallbackClass>PWCallback</
passwordCallbackClass>
       
 <signaturePropFile>security.properties</signaturePropFile>
        <signatureKeyIdentifier
                        >SKIKeyIdentifier</signatureKeyIdentifier>
        <signatureParts>

            {Element}{http://docs.oasis-open.org/wss/2004/01/oasis
-200401-wss-wssecurity-utility-1.0.xsd}Timestamp</signatureParts>
      </action>
    </parameter>

    <parameter name="InflowSecurity">
      <action>

        <items>Timestamp Signature Encrypt</items>
        <user>gene</user>
        <passwordCallbackClass>PWCallback</passwordCallbackClass>
       
 <signaturePropFile>security.properties</signaturePropFile>

        <signatureKeyIdentifier
                        >SKIKeyIdentifier</signatureKeyIdentifier>
        <encryptionKeyIdentifier
                       >SKIKeyIdentifier</encryptionKeyIdentifier>
        <encryptionUser>frances</encryptionUser>
        <signatureParts>

           {Element}{http://schemas.xmlsoap.org/soap/envelope/}Body
        </signatureParts>
        <optimizeParts>
           //xenc:EncryptedData/xenc:CipherValue/xenc:CipherData
        </optimizeParts> 
      </action>
    </parameter>

    <!-- ================================================= -->
    <!-- Parameters -->
    <!-- ================================================= -->
    <parameter name="hotdeployment" locked="false">true</parameter>
...

Ahora el cliente enviará mensajes que tienen marca de tiempo y están firmados, e insistirá en que toda respuesta tenga marca de tiempo, esté firmada y cifrada.

Veamos qué significa eso para los mensajes reales.

La solicitud

Listado 33 muestra la solicitud final.

Listado 33. La solicitud final
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv=
          "http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header>
      <wsse:Security xmlns:wsse="http://docs.oasis-
open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
soapenv:mustUnderstand="1">
         <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" 
                                             Id="Signature-5525185">
            <ds:SignedInfo>

               <ds:CanonicalizationMethod Algorithm=
                        "http://www.w3.org/2001/10/xml-exc-c14n#" />
               <ds:SignatureMethod Algorithm=
                     "http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
               <ds:Reference URI="#Timestamp-1741620">
                  <ds:Transforms>
                     <ds:Transform Algorithm=
                        "http://www.w3.org/2001/10/xml-exc-c14n#" />
                  </ds:Transforms>

                  <ds:DigestMethod Algorithm=
                         "http://www.w3.org/2000/09/xmldsig#sha1" />
                  <ds:DigestValue>
                     TQSR9wUuJ7rJi582TsbNjiAUqZI=
                  </ds:DigestValue>
               </ds:Reference>
            </ds:SignedInfo>
             <ds:SignatureValue>aRI5mvvvXZusAB/5cKCx/fOcW+CDjdk1F3Icl
lObVcEOWws9/mV4X2kWEX3hhwK7koX5jMPpl7AtLSbEh8UQGCa8yBua++yveprFl020To
VtePVOcWsBLM+9VHu9bJbhvaaps43RiUkym6xvVU/yL3eKTbhdhB/RQDI3kylXdas=

</ds:SignatureValue>
             <ds:KeyInfo Id="KeyId-26644003">
                <wsse:SecurityTokenReference xmlns:wsu=
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-
utility-1.0.xsd" wsu:Id="STRId-26174005">
                   <wsse:KeyIdentifier EncodingType="http://docs.oasi
s-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Bas
e64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-
200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier"
>CuJdE1B2dUFd1dkLZSzQ5vj6MYg=</wsse:KeyIdentifier>
                </wsse:SecurityTokenReference>
             </ds:KeyInfo>

          </ds:Signature>
          <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/20
04/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
                                          wsu:Id="Timestamp-1741620">
             <wsu:Created>2006-06-22T11:34:02.453Z</wsu:Created>
             <wsu:Expires>2006-06-22T11:39:02.453Z</wsu:Expires>
          </wsu:Timestamp>

       </wsse:Security>
    </soapenv:Header>
    <soapenv:Body>
       <cms:getNumberOfArticles 
                     xmlns:cms="http://daily-moon.com/cms">
          <cms:category>classifieds</cms:category>

       </cms:getNumberOfArticles>
    </soapenv:Body>
 </soapenv:Envelope>

La respuesta

El listado 34 muestra la respuesta final.

Listado 34. La respuesta final
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv=
            "http://schemas.xmlsoap.org/soap/envelope/" 
            xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
   <soapenv:Header>
      <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004
/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
soapenv:mustUnderstand="1">
         <xenc:EncryptedKey Id="EncKeyId-28585008">
            <xenc:EncryptionMethod Algorithm=
                "http://www.w3.org/2001/04/xmlenc#rsa-1_5" />

            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
            <wsse:SecurityTokenReference>
               <wsse:KeyIdentifier EncodingType="http://docs.oasis-
open.org/wss/2004/01/oasis-200401-wss-soap-message-security-
1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2
004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKey
Identifier">Xeg55vRyK3ZhAEhEf+YT0z986L0=</wsse:KeyIdentifier>
            </wsse:SecurityTokenReference>
         </ds:KeyInfo>

         <xenc:CipherData>
            <xenc:CipherValue>NSkylkASezzHSp37izSN3xnxf6v/zwN3C70uU2n
UTNk4a9xYxhNcgiVQuS2/Tm3/x3Jm1d9rj2V8x1uqlKmi89MFifN34SDxaDTMBFzhfRv4
CmQSITEFjY1ySVDvMb7WZszGDhVIGYkjcDkoK+SfWdxyuaUdNUbPgEihSnFVRXs=</xen
c:CipherValue>
         </xenc:CipherData>
         <xenc:ReferenceList>
            <xenc:DataReference URI="#EncDataId-19400027" />

         </xenc:ReferenceList>
      </xenc:EncryptedKey>
      <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" 
                                      Id="Signature-17174249">
         <ds:SignedInfo>
            <ds:CanonicalizationMethod Algorithm=
                     "http://www.w3.org/2001/10/xml-exc-c14n#" />
            <ds:SignatureMethod Algorithm=
                  "http://www.w3.org/2000/09/xmldsig#rsa-sha1" />

               <ds:Reference URI="#id-19400027">
                  <ds:Transforms>
                     <ds:Transform Algorithm=
                    "http://www.w3.org/2001/10/xml-exc-c14n#" />
                  </ds:Transforms>
                  <ds:DigestMethod Algorithm=
                       "http://www.w3.org/2000/09/xmldsig#sha1" />
                 
 <ds:DigestValue>HfdufYEGpvPpfz2+HWKui4npV9s=</ds:Di
gestValue>

               </ds:Reference>
               <ds:Reference URI="#SigConf-17122634">
                  <ds:Transforms>
                     <ds:Transform Algorithm=
                        "http://www.w3.org/2001/10/xml-exc-c14n#" />
                  </ds:Transforms>
                  <ds:DigestMethod Algorithm=
                         "http://www.w3.org/2000/09/xmldsig#sha1" />

                 
 <ds:DigestValue>e88WWqudpvW69wN23fgZjQ9ZAio=</ds:Di
gestValue>
               </ds:Reference>
            </ds:SignedInfo>
            <ds:SignatureValue>aZLon//vwkw2G2Jxcligxod/CgxMjwtlefZiho
yUz5FpgSY6RUoI5vuHX2unrWV+EVA2vWdtz/Iyq+RS7j4QtE2XTYovxdyiZPbKXNdFKHy
AkpDr0aDLG9rSjyFVcTrUKgAY06t10zi13Daq95nDMH+wAJCYUO0Vor/u0V9Iv7I=</ds
:SignatureValue>
            <ds:KeyInfo Id="KeyId-22768665">

               <wsse:SecurityTokenReference xmlns:wsu="http://docs.oa
sis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
wsu:Id="STRId-18220809">
                  <wsse:KeyIdentifier EncodingType="http://docs.oasis-
open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Bas
e64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-
200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier"
>CuJdE1B2dUFd1dkLZSzQ5vj6MYg=</wsse:KeyIdentifier>
               </wsse:SecurityTokenReference>
            </ds:KeyInfo>
         </ds:Signature>

         <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/20
04/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
wsu:Id="Timestamp-6400133">
            <wsu:Created>2006-06-22T11:34:04.062Z</wsu:Created>
            <wsu:Expires>2006-06-22T11:39:04.062Z</wsu:Expires>
         </wsu:Timestamp>
         <wsse11:SignatureConfirmation xmlns:wsse11="http://docs.oasi
s-open.org/wss/2005/xx/oasis-2005xx-wss-wssecurity-secext-1.1.xsd" 
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-
wssecurity-utility-1.0.xsd" Value="aRI5mvvvXZusAB/5cKCx/fOcW+CDjdk1F3
IcllObVcEOWws9/mV4X2kWEX3hhwK7koX5jMPpl7AtLSbEh8UQGCa8yBua++yveprFl02
0ToVtePVOcWsBLM+9VHu9bJbhvaaps43RiUkym6xvVU/yL3eKTbhdhB/RQDI3kylXda
s=" wsu:Id="SigConf-17122634" />

      </wsse:Security>
   </soapenv:Header>
   <soapenv:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/o
asis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id-19400027">
      <xenc:EncryptedData Id="EncDataId-19400027" Type=
"http://www.w3.org/2001/04/xmlenc#Content">
         <xenc:EncryptionMethod Algorithm=
              "http://www.w3.org/2001/04/xmlenc#aes128-cbc" />
         <xenc:CipherData>

               <xenc:CipherValue>f6uWHGsYmGwHuno2j4H7a4qCMhPLTlCIg40p
KLciESBzeCT8rvyl+qHXsFkZJq2m4uj9TEFtRX6efQ5MHBEJozMgI03LSVanh6MmHgt5o
ilIJClWcQifEx0Azeo3KWnQKSc9lg0ywhKJH+JVBsPSP7E19jZAsR77wUEBBIprxs5W59
7C/mJh38iXSncwWccE7OCckf1x34FCfKHSqn46MCohZWiPZRjSmAI5dGFMKwttzpmsmXr
LHLVrsjm4w9onis+Xr5gbi3Gcx6P0F2ZJGLBb9bkGh/IvjYutgzRD7zhyRZxUmM/oZTVs
JJ7dA9YOED5l1C64f4yuqR6TtuVw3gIiuspxWafKwlJuuD0/9m6Ri4AvQuOVEioz45MM
5FBCQU+0LFceSlEFFKhN9yLUI9hgLsCYRzc8eedPAhZDjJEDHec5M9LZ0C07sKu7Cvnr
jiino53xZmk5uQHs4JlNoA==</xenc:CipherValue>
         </xenc:CipherData>
      </xenc:EncryptedData>
   </soapenv:Body>
</soapenv:Envelope>

Resumen

Para que los servicios web resulten verdaderamente útiles en el entorno empresarial, deben tener las capacidades de seguridad adecuadas. Al combinarse con tecnologías como Firma XML y Cifrado XML y brindar una manera estándar de presentar dicha información. WS-Security hace posible la protección de mensajes SOAP entrantes y salientes contra varias amenazas de seguridad distintas.

Al solicitar firmas digitales, puede limitar el acceso a organizaciones o individuos autorizados, así como también puede verificar que la información no se haya alterado en tránsito. Al incluir el cifrado, puede evitar que los datos sean vistos (o al menos comprendidos) por destinatarios no deseados. Y al agregar una Marca de tiempo (y firmarla) puede evitar que los mensajes se capturen y se vuelvan a reproducir.

En este tutorial, el personal de Daily Moon protegió los servicios web que crearon en partes anteriores de esta serie. A continuación, en la Parte 5, analizarán la aplicación de políticas de seguridad al servicio.


Descargar

DescripciónNombretamaño
Source codesecurity-code-files.zip20KB

Recursos

Aprender

Obtener los productos y tecnologías

Comentarios

developerWorks: Ingrese

Los campos obligatorios están marcados con un asterisco (*).


¿Necesita un IBM ID?
¿Olvidó su IBM ID?


¿Olvidó su Password?
Cambie su Password

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


La primera vez que inicie sesión en developerWorks, se creará un perfil para usted. La información en su propio perfil (nombre, país/región y nombre de la empresa) se muestra al público y acompañará a cualquier contenido que publique, a menos que opte por la opción de ocultar el nombre de su empresa. Puede actualizar su cuenta de IBM en cualquier momento.

Toda la información enviada es segura.

Elija su nombre para mostrar



La primera vez que inicia sesión en developerWorks se crea un perfil para usted, teniendo que elegir un nombre para mostrar en el mismo. Este nombre acompañará el contenido que usted publique en developerWorks.

Por favor elija un nombre de 3 - 31 caracteres. Su nombre de usuario debe ser único en la comunidad developerWorks y debe ser distinto a su dirección de email por motivos de privacidad.

Los campos obligatorios están marcados con un asterisco (*).

(Por favor elija un nombre de 3 - 31 caracteres.)

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


Toda la información enviada es segura.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=90
Zone=SOA y servicios web
ArticleID=660822
ArticleTitle=Understanding Web Services Specifications, Parte 4: WS-Security
publish-date=08082011