viernes, 3 de octubre de 2008

Consumir web service con SSL y autenticación

Después de dos días de luchar con este tema, por fin logré que funcione. Podríamos decir que este es un post de descarga...

Escenario

En una aplicación generada con GeneXus 9.0, generador Java web, tenía que consumir un web service HTTP (no es SOAP), que se invoca a través de HTTPS y que además pide usuario y contraseña... El servicio está en un IIS, en .Net. Casi que trivial.

Problema 1: SSL

Con el primer problema que me encontré, obviamente, fue como acceder a una página web que está encriptada.

El primer intento fue con
&httpClient.Host = &host
&httpClient.Port = 443
&httpClient.Secure = 1
que por supuesto no funciona... El problema es que para usar SSL hay que encriptar los datos, para lo cual se necesita un certificado.

Por suerte encontré este documento en el Wiki que explica bien lo que hay que hacer.

Problema 2: Autenticación

Una vez resuelto el problema con el SSL, al consumir el servicio daba un error 401, not authorized.

La forma de configurar la autenticación en GeneXus es con 
&httpClient.AddAuthentication(&httpClient.Basic, &realm, &user, &pass)
El usuario y la contraseña que le estaba pasando estaban bien, eran lo que usaba al probar el servicio desde el navegador y ahí funcionaba.

Como no tengo acceso al servidor donde está corriendo el web service, y así se complicaba para hacer las pruebas, me configuré (en realidad le pedí a Alexander que lo haga...) el servidor local para que acepte conexiones HTTPS.

Después de un rato de probar con distintas configuraciones en el servidor local encontré el problema: el Realm que se le pasa al método AddAuthentication es importante...

Conseguí el Realm del servidor donde está el servicio, y logré que me devolviera un HTTP status 200, es decir OK.

Problema 3: Se conecta pero no trae datos

Si bien ahora pasaba por el SSL y la autenticación, y devolvía un OK, el resultado de
&httpClient.ToString()
era vacío. En el navegador me mostraba datos, pero al consumir el servicio desde GeneXus venía vacío.

Para ver que estaba haciendo el navegador, me instalé un add-on de Firefox, Live HTTP Headers, que permite ver que es lo que se le manda al servidor y la respuesta. No podía compararlo con lo que le manda GeneXus, porque como la conexión está encriptada, no tenía una forma fácil de hacerlo.

Así que le agregué todos los headers HTTP al procedimiento GeneXus con el método
&httpClient.AddHeader()
y ahí por fin funcionó todo espectacular.

Conclusiones

Así que, después de luchar bastante rato con esto, llegué a una solución que funciona...

El código completo es:
&httpClient.Host = &host
&httpClient.Port = 443
&httpClient.BaseUrl = ''
&httpClient.AddHeader('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8')
&httpClient.AddHeader('Accept-Language', 'en-us,en;q=0.5')
&httpClient.AddHeader('Accept-Encoding', 'gzip,deflate')
&httpClient.Secure = 1

&httpClient.AddAuthentication(&httpClient.Basic, &realm, &user, &pass)

&httpClient.Execute('GET', &url)
Fundamental para consumir un servicio que esté con SSL y autenticación:
  1. no olvidarse de importar el certificado del servidor, para que pueda encriptar los datos que manda
  2. averiguar cual es el Realm que hay que usar, y el método de autenticación (basic o digest)
  3. si no funciona, agregarle los HTTP headers que sean necesarios

9 comentarios:

  1. Hola Marcos excelente, la ayuda que nos prestás en estos temas, que diferencia habria en que el WS no sea HTTP sino SOAP.

    ResponderEliminar
  2. Carlos: La diferencia sería que en vez de configurar las propiedades en un objeto HttpClient, lo harías en un Location... Esto no lo probé, así que no se si funciona.

    ResponderEliminar
  3. Marcos, tengo una consulta con respecto a este tema de los WS. yo tengo un webservice externo en formato wsdl , con el wsdl inspector se crean los sdt necesarios para el manejo de estos ws. mi problema esta cuando intento acceder a este ws me sale un error -10001 del tomcat y no hace mas. ya revise la estructura del ws externo y es correcta, en donde podria estar el problema? estoy usando Genexus 9

    ResponderEliminar
    Respuestas
    1. Junior podrías compartir la solución en caso de haberla encontrado, tengo el mismo problema. Gracias.

      Eliminar
  4. Junior: Lamento no poder ayudarte con ese tema. Te sugiero que mandes la pregunta al foro, a ver si alguien sabe cual es el problema.

    ResponderEliminar
  5. Ok lo hare enseguida, muchas gracias Marcos

    ResponderEliminar
  6. --No se puede establecer una conexi¾n ya que el equipo de destino deneg¾ expresamente dicha conexi¾n. - connect(2)

    trabajo con Ruby alguien de Ustedes seria tan amable de ayudarme en este problema

    ResponderEliminar
    Respuestas
    1. Luis, te sugiero que mandes un mail a soporte o al foro... La verdad que hace tiempo que no pruebo esto.

      Eliminar
  7. Alguien tiene a mano una breve explicación como consumir un ws genexus desde eclipse java.

    ResponderEliminar