Acceder a los header SOAP en programas GeneXus

Un cliente nos pidió que necesitaba un servicio web SOAP, que recibiera un header y realizar con dicha información una validación de seguridad.

Con GeneXus nativo, no tenemos la posibilidad de recuperar los header soap aunque si se pueden setear cuando hago una invocación.

El problema era recibir algo asi (no es con usuario y contraseña, sino con un token, pero lo hago así para el ejemplo).

?xml version = "1.0"?>
<SOAP-ENV:Envelope 
   xmlns:SOAP-ENV = " http://www.w3.org/2001/12/soap-envelope"   
   SOAP-ENV:encodingStyle = " http://www.w3.org/2001/12/soap-encoding">

   <SOAP-ENV:Header>
      <s:Security  xmlns:s = "http://ealmeida.blogspot.com/security/" 
         user="Usuario" password="Peñarol">
      </s:Security>
   </SOAP-ENV:Header>
   ...
   ...
</SOAP-ENV:Envelope>

Teniamos varias opciones:

1) Modificar el programa fuente generado por Genexus, para capturar los header mientras los procesa en un procedure SOAP.
2) Programar el servicio como procedure con call protocol = HTTP, con lo cual nos perdíamos las ventajas de tener el WSDL y hay que procesar a mano todo el request.

Decidimos hacer algo intermedio, que fue hacer un procedure HTTP, que reciba el request SOAP, realice la validación, y luego pase el contenido de dicho request a un servicio interno SOAP.

Una de las contras de este enfoque era que perdíamos la posibilidad de tener el WSDL dinámico como lo tenemos con Genexus.

Para eso, agregamos que si nos llegaba un GET, con parámetro WSDL, recuperamos el WSDL del web service original y lo devolvemos (modificando el location, para que llame al objeto correcto).


Nicolas programó el código del procedure main / call protocol = HTTP de la siguiente forma:
//Recibe &SoapURL es la URL del servicio SOAP (solo interna)          
//       &RestURL es la URL del procedure REST (es este mismo programa)
//Esto para procesar los POST, en un llamado normal al WS
if &HTTPRequest.Method = "POST"
&RequestString = &HTTPRequest.ToString()
&SOAPAction = &HTTPRequest.GetHeader("SOAPAction")
//Valido el header
if ValidateSoapHeader(&RequestString)
//Ejecuto la llamada al web service SOAP
&HTTPClient.AddHeader("SOAPAction", &SOAPAction)
&HTTPClient.AddString(&RequestString)
&HTTPClient.Execute("POST", &SoapURL)
//Armo la respuesta con la respuesta recibida del web service SOAP
&HTTPResponse.AddHeader("Content-Type", "text/xml;charset=utf-8")
&HTTPResponse.AddString(&HTTPClient.ToString())
        else
                //Devuelvo error 403 
endif
endif
//Procesamos los GET, para devolverl el WSDL
if &HTTPRequest.Method = "GET"
&QString = &HTTPRequest.QueryString 
if &QString.ToLower() = "wsdl"
&HTTPClient.AddString(&RequestString)
//Valido el header
if ValidateSoapHeader(&RequestString)
//Ejecuto la llamada al web service SOAP
&HTTPClient.Execute("GET", &SoapURL + "?wsdl")
&ClientResponse = &HTTPClient.ToString()
                        //Esta sustitucion es necesaria para cambiar el  <soap:address location="xxxx" del WSDL 
&ClientResponse = &ClientResponse.Replace(&SoapURL, &RestURL)
&HTTPResponse.AddString(&ClientResponse)
endif
endif
endif
Falta probarlo bien con https (necesita algunos cambios), pero funciona bien para WS desarrollados con GX con varios stubs y diferentes parámetros.

Hay que asegurar con algun mecanismo adicional, para que no se pueda acceder desde afuera al servicio SOAP pues este no tendra la validacion.

 Lo comparto pues posiblemente le pueda servir a alguien mas.

Comentarios

Entradas más populares de este blog

Paleta de colores en GeneXus

Impresión directa a impresora en el WEB con aplicaciones GeneXus.