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

  1. Que bueno, me gusta la solución mas que nada, pues casi ya no uso soap, pero muy buena !

    ResponderBorrar
  2. Excelente, muchas gracias. Llegué a este artículo por un caso relacionado que se me ha presentado: al consumir un web service SOAP como cliente desde Genexus, el web service devuelve un mensaje de error y quien desarrolló el web service nos pide el request que estamos haciendo al invocar el web service. Terminamos utilizando un proxy que tiene muchas funcionalidades: https://www.membrane-soa.org/, permite entre muchas otras cosas "rutear" el consumo hacia el proxy, donde se registran los request y a su vez los redirecciona al web service a consumir, permite utilizar https indicando la ruta del trustore y en caso de ser necesario del keystore.

    ResponderBorrar
    Respuestas
    1. Este comentario ha sido eliminado por el autor.

      Borrar
    2. Podrias indicarme como veo el request, tengo el mismo problema.. ?
      Muchas gracias!

      Borrar
    3. Para ver los request y el response, podes utilizar herramientas que permitan probar web services.
      El que a mi mas me ha resultado, es SoapUI. https://www.soapui.org/
      Tenes que armar un proyecto SOAP, poner el WSDL y te arma un request de llamada, donde podes poner el valor a los parametros y al ejecutarlo, tenes la respuesta que devuelve el servidor.

      Borrar
  3. Muy amable.. muchas gracias por la pronta respuesta! me gustaria saber por favor como hago para ver el request que genera con genexus.. mi servicio SOAP

    ResponderBorrar
    Respuestas
    1. Es lo que intente explicarte en el comentario anterior.
      Con SOAPui, puedes ver el request de la llamada y la respuesta de cualquier servicio SOAP, sea GeneXus o desarrollado con cualquier

      Si lo que tenes es un programa Genexus que esta haciendo un request a otro servicio externo, podes usar los tipos de datos &HttpRequest y &HttpResponse https://wiki.genexus.com/commwiki/servlet/wiki?6932,HttpClient+data+type,

      Borrar
  4. Hola se que no mi pregunta no iría acá, pero necesito ayuda con el uso de servicios rest con genexus para poder consumirlos desde otra plataforma de desarrollo, saludos

    ResponderBorrar
  5. Hola Enrique, si bien entiendo la solución no me queda claro como implementarla. Es decir, a mi WS SOAP le cambie la propiedad main a FALSE y cree otro procedure de tipo MAIN = TRUE, pero este nuevo procedure, que va a tener la propiedad Call Protocol como 'HTTP' como deberia llamarse para que la infocacion sea transparente? Me falta comprender eso, si me enviaras el XPZ seria buenisimo. Desde ya muchas gracias

    ResponderBorrar
    Respuestas
    1. Esta bien lo que hiciste, tenes que llamar al procedure nuevo (http) como soap, con el request que tenias antes.
      Y te va a funcionar igual, pues las respuestas va a ser la que dio el otro procedure.

      Borrar
  6. Enrique, por ahi no me explique bien. mi Ws SOAP se llama "solicitudPagoProveedores", como deberia llamar el HTTP para que la invocacion sea transparente ya que Genexus no me deja definir dos procedures con mismo nombre. Saludos

    ResponderBorrar
    Respuestas
    1. Si ya lo tenes publicado, lo que podes hacer es renombrar el objeto soap "solicitudPagoProveedores" a "solicitudPagoProveedores_soap" y el nuevo queda con el nombreo "solicituPagoProveedores".

      De esta forma va a permitir funcionar sin cambios a los programas que que ya existen y hoy llaman al web service soap.

      Borrar

Publicar un comentario

1) Lee el post
2) Poné tu opinión sobre el mismo.
Todos los comentarios serán leidos y la mayoría son publicados.

Entradas más populares de este blog

Aplicación monolítica o distribuida?

La nefasta influencia del golero de Cacho Bochinche en el fútbol uruguayo

Funcionalidades de GeneXus que vale la pena conocer: DATE Constants.