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).
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:
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.
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).
Falta probarlo bien con https (necesita algunos cambios), pero funciona bien para WS desarrollados con GX con varios stubs y diferentes parámetros.//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 WSif &HTTPRequest.Method = "POST"&RequestString = &HTTPRequest.ToString()&SOAPAction = &HTTPRequest.GetHeader("SOAPAction") //Valido el headerif 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 403endifendif//Procesamos los GET, para devolverl el WSDLif &HTTPRequest.Method = "GET"&QString = &HTTPRequest.QueryStringif &QString.ToLower() = "wsdl"&HTTPClient.AddString(&RequestString) //Valido el headerif 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) endifendifendif
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.
Que bueno, me gusta la solución mas que nada, pues casi ya no uso soap, pero muy buena !
ResponderBorrarGracias, Alberto.
BorrarExcelente, 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.
ResponderBorrarEste comentario ha sido eliminado por el autor.
BorrarPodrias indicarme como veo el request, tengo el mismo problema.. ?
BorrarMuchas gracias!
Para ver los request y el response, podes utilizar herramientas que permitan probar web services.
BorrarEl 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.
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
ResponderBorrarEs lo que intente explicarte en el comentario anterior.
BorrarCon 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,
Muchas gracias Enrique!!!! Muy amable
ResponderBorrarHola 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
ResponderBorrarHola 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
ResponderBorrarEsta bien lo que hiciste, tenes que llamar al procedure nuevo (http) como soap, con el request que tenias antes.
BorrarY te va a funcionar igual, pues las respuestas va a ser la que dio el otro procedure.
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
ResponderBorrarSi 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".
BorrarDe esta forma va a permitir funcionar sin cambios a los programas que que ya existen y hoy llaman al web service soap.