martes, marzo 04, 2008

Firmar una llamada SOAP con C# y ASP.NET

En este artículo voy a intentar explicar cómo firmar una llamada SOAP utilizando la extensión para servicios web WS 3.0 de Microsoft. Como siempre, lo primero es un poco de teoría y luego veremos cómo pasar esta teoría a la práctica.

Es recomendable que os leáis el artículo anterior a este sobre certificados digitales de la FNMT puesto que haremos uso de lo que en él comentaba.

1. Teoría
La idea es poder realizar una llamada a un servicio web externo (una administración, por ejemplo) asegurando que el contenido de la misma no ha sido manipulado en el camino. El ejemplo más claro es el de una aplicación web que se integra con la administración, por lo que tiene que firmar las peticiones con el certificado de la FNMT del cliente que en ese momento este usando la aplicación.








La idea es que nosotros seamos una especie de pasarela de certificados de nuestros clientes a los servicios web de la administración o de otro sitio. Para realizar esto tendremos que firmar las llamadas SOAP con el certificado usando el estándar XMLSignature.

2. ¿Cómo lo hacemos?
Para hacerlo, lo primero que tenemos que hacer es descargarnos las extensiones de Servicios Web de Microsoft (WSE 3.0) que podéis encontrar en la dirección:

http://www.microsoft.com/downloads/details.aspx?FamilyID=018a09fd-3a74-43c5-8ec1-8d789091255d&displaylang=en

Una vez instalado en nuestro equipo, tendremos una nueva opción en Visual Studio para el trabajo con las extensiones de Web Services.

¿Cómo funciona WSE 3.0?
El centro del tema este son las políticas y los filtros. Cuando realizamos una llamada a un servicio web, ésta es interceptada por una clase que define lo que hay que realizar con dicha llamada antes de que salga. Cuando recibimos una respuesta, la respuesta es interceptada igualmente, y lo mismo pasa cuando definimos los servicios web.




Donde nosotros vamos a trabajar es en la clase de políticas de seguridad, que será donde se firme la petición.

Paso 1: Habilitar nuestro web para WSE3.0
Lo primero es habilitar nuestro sitio web para que utilice WSE3.0. Al habilitarlo, las clases proxy que se creen estarán preparadas para las extensiones de WSE. Tendremos que crearnos un sitio web en el Visual Studio y en las propiedades del sitio web veremos cómo aparece una nueva opción "WSE Settings 3.0". Al pinchar se abre la ventana:
























Marcamos la primera opción para habilitar las opciones del cliente. La segunda opción es para habilitar las opciones cuando nosotros somos el servicio web.

Paso 2: Agregar la referencia a WSE
Agregar una referencia a la librería Microsoft.Web.Services3 a nuestro proyecto.

Paso 3: Agregar la referencia web
Agregaremos la referencia web al servicio con el que nos queramos comunicar.

Paso 4: Crear la política de seguridad
Vamos a crear la clase que controla la entrada y salida de mensajes SOAP desde el cliente. Esta clase tiene que heredar de
SecurityPolicyAssertion
















La clase tiene cuatro métodos, uno para cada situación: salida/entrada para el cliente y salida/entrada para el servicio. A nosotros el que nos interesa es el de la salida para el cliente, el resto lo ponemos a null.

La sección de imports es la siguiente:












En el constructor le pasamos el certificado del cliente (luego veremos cómo llamamos a esta clase) para poder utilizarlo en el método de salida del cliente. En este método lo que hacemos es instanciar una nueva clase que hereda de SendSecurityFilter que es la que realmente firma la petición:












En esta clase lo que hacemos es obtener el token del certificado y añadirle la firma al mensaje SOAP, haciendo override del método SecureMessage. Con esto tenemos prácticamente hecho todo.

Paso 5: Realizar la llamada
Nos creamos una página aspx desde la que vamos a realizar la llamada. Lo primero será obtener el certificado del cliente (ver el artículo anterior), una vez obtenido tendremos que asociar la política que hemos definido con la llamada al servicio web:
























En este caso, he creado un servicio web con un método llamado "CalculaSuma" el cual suma dos números que se le pasan. En un botón llamado "btnInvocar" de la página le asocio el código para llamar al servicio web. Lo que hacemos es instanciar la clase proxy que se creó al agregar la referencia web y le asociamos la política que hemos creado.

Al realizar la llamada, la política intercepta el mensaje de salida, ejecuta el método "SecureMessage()" y firma la petición. Podemos activar el modo Trace con el asistente de WSE y ver la salida para comprobar que se ha firmado la petición, incluyéndose un nuevo elemento en la llamada SOAP llamado
.

3. Fin
Espero que os haya gustado y servido este post. No ha sido muy exhaustivo pero como punto de partida para la utilización de XMLSignature en SOAP puede ser bueno.


14 comentarios:

carlos dijo...

Hola una explicación la verdad que magnifica, pero me surge una duda, para el caso en el que en vez de firmarlo lo quisieramos securizar con un usuario y password, como podríamos realizarlo.

Manuel Cardenas Thorlund dijo...

Hola Carlos,
utilizar un usuario y contraseña es más complejo porque el servicio web debe estar preparado para recibir en algún lado ese usuario y contraseña y además, se debe enviar de alguna forma que no sea público para alguien que caze el mensaje.

Una alternativa es que se manden como dos parámetros más del mensaje SOAP y que el mensaje se encripte utilizando el certificado o alguna clave compartida. Cuando firmamos la petición SOAP no estamos encriptando el mensaje sino solamente ponerle una especie de checksum con nuestro certificado para asegurar que el contenido no se ha modificado. En este caso habría que además, encriptar el contenido de los campos (previamente), con nuestra firma.

Carlos dijo...

Hola, gracias por tu respuesta, pero finalmente hay dos opciones para poder realizar, la firma del mensaje con usuario y contraseña.

Si estas con .Net 2003 o .Net 2005 tienes las extensiones de servicios Web WSE 2.0 o WSE 3.0 y para .Net 2008 tienes los WCF que añadiendo la política de credenciales de usuario puedes aplicar un user y password a la llamada SOAP.

Un manual para la primera opción podeis encontrarlo en http://www.arcwebservices.com/v2006/help/index_Left.htm#StartTopic=soap/2006_1/samples/1wssecurity_net.htm#|SkinName=ArcWeb

Todo esto como indicas al principio del manual es para temas de comunicación para servicios Web externos a tu Intranet, como el caso de los Servidores @firma

Saludos y gracias y nuevamente felicidades por el Blog

ggarciag dijo...

Hola,

Estoy buscando información sobre cómo firmar solicitudes cuando se consume un webservice. Tu exposición me ha parecido muhco más clara y sencilla que otras muchas que he visto.

Hay algo que no me queda claro, y es si esto que cuentas, no es lo mismo que usar las Configuration Tools de WSE, en que se puede añadir una política para la que se idcia el certificado a emplear en la misma.

Gracias. Un saludo

Manuel Cardenas Thorlund dijo...

Hola,
lo primero gracias por leer este blog. Con respecto a tu pregunta, sí, la herramienta es la de configuración de WSE 3.0, pero lo que se intenta en el artículo es obtener el certificado de usuario del cliente, no utilizar un certificado de servidor para realizar llamadas. En el primer artículo de la serie Usar certificados de cliente se explica cómo configurar IIS para obtener el certificado del cliente.

ggarciag dijo...

Muchas gracias a ti por tu pronta respuesta y por tu aportación de este tema en castellano, que en mi lucha con el inglés casi siempre pierdo yo.

Probaré entonces con WSE tools, pues en nuestro contexto vamos a usar un certificado de componente, siendo una aplicación instalada en un servidor la que siempre se comunicará con un webservice. Salu2.

fito dijo...

Hola desde hace tiempo sigo el blog y me parece estupendo, pero queria comentaros una cosa.

Intento llamar a un ws implementando la seguridad de UserNameToken, pense que tal vez utilizando la firma de la llamada me solucionara el problema, pero no, ya que no tengo clave privada del certificado.

Segun me ha comentado el que esta al otro lado del WS, solo necesito implementar la llamada a webservice con las credenciales del certificado, y hay viene mi problema.

¿Sabeis como realizar una llamada a un webservice implementado UserNameToken?

Siempre me da el error de:

security header is not present in the incoming message

gracias un saludo

Manuel Cardenas Thorlund dijo...

Buenas fito,
me pillas ya un poco desfasado con este tema, pero en la dirección que posteó Carlos, puedes encontrar ejemplos de cómo incluir el usuario y contraseña en la llamada:

http://www.arcwebservices.com/v2006/help/index_Left.htm#StartTopic=soap/2006_1/samples/1wssecurity_net.htm#|SkinName=ArcWeb

fito dijo...

Hola Manu,

Gracias, es una pagina de las 2500 que he vistado y no me funciona.

El problema es que en el context de la peticion SOAP, me responde que no hay seguridad, bueno en concreto:

System.Web.Services.Protocols.SoapException: Security Requirements not met - No Security header in message en System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall) en System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters) en WSHangingDownloadsService.getDownloads(getDownloadsRequestDownloads requestDownloads)

Y ya no se k mas hacer.

Nada haber si el año nuevo lo arregla solo juasss

Saludos

isaias dijo...

Hola que tal!!
Todo lo veo muy bien , solo me queda una duda , como es que meto el certificado valido a la session? no lo veo por ninguna parte :(

Saludos! y Gracias de antemano!!!

Manuel Cardenas Thorlund dijo...

Buenas Isaias,
comprueba este artículo en el que vemos el tema de obtener el certificado de los clientes.

http://nidea-soluciones.blogspot.com/2008/01/usar-certificados-de-cliente-en-una.html

Angelo dijo...

Aca otro ejemplo http://systemdeveloperpy.blogspot.com/2014/02/firmar-mensajes-soap-con-certificado.html

Angelo dijo...

Aca otro ejemplo http://systemdeveloperpy.blogspot.com/2014/02/firmar-mensajes-soap-con-certificado.html

Santiago garcia segurado dijo...

Estimado Señor:
Gracias por su artículo.
Dados sus conocimientos, me atrevo a consultarle para que me oriente.
Tengo que usar un webservice que exige conexión segura y uso de certificado de cliente de la FNMT.
La aplicación está desarrollada en VB.net y es una aplicación de equipo.NO es una aplicación en un servidor.
NO estoy muy ducho en C# ni en el sistema de certificación.He intentado, sin éxito poner en marcha los pasos descritos por usted y ,en concreto,NO he podido traducir la clase PoliticadeclienteOutputFilter.

Por favor , tendría esas clases desarrolladas para VB?
Accedo al servicio y todas sus estructuras. Asigno el certificado de cliente.Pero cuando hago la llmada me sale un mensaje de que NO se establece conexión segura y me rechaza.

Agradezco su atención y el tiempo dedicado
Atentamente
Santiago