Soapui mocks sobre https con apache y centOS 7 desde cero

[:es]Continuando con la serie de servicios mocks con soap-ui, nuestro próximo paso es agregar conexiones seguras https con un certificado gratis emitido por letsencrypt.

Partimos nuestro procedimiento desde un CentOS 6.8, pero a pesar que seguimos un procedimiento similar al que se va a describir, el certificado siempre quedaba inválido, indicando que “Common name” no correspondía al nombre del host (Lo cual era cierto, hablando del archivo /etc/hosts, pero finalmente el certificado que se deseaba emitir correspondía a un subdominio con un registro DNS tipo A, apuntando a la IP de la máquina), considerando ésto, y sumado a las vulnerabildiades con esa distribución al POODLE attack, migramos a CentOS 7.1.1503 (Core).

Bueno, manos a la obra. Como lo indica el post, es desde cero, así que vamos a suponer que tenemos nuestro SO recién instalado con cuenta root. Lo primero será entonces crear una cuenta de usuario con permisos de sudo.

Sistema Operativo

# Instalar sudo para agregar el usuario a los sudoers de la máquina
$ yum install sudo
# Crear el usuario y asignarle un password, así mismo, agregarlo al grupo wheel, 
# que en CentOS por defecto tiene privilegios de sudo
$ adduser username
$ passwd username
$ usermod -aG wheel username
# Instalar crontab para ejecutar la renovación programada del certificado
$sudo yum -y install cronie
# Subir el demonio de crontab:
$ sudo service crond start

De ahora en adelante, conectarse (ssh) con ese usuario, y ejecutar los comandos que requieren privilegios con sudo

Apache

Para la instalación y configuración de apache, se siguió el siguiente procedimiento:

# Instalación de apache
$ sudo yum install httpd
# Instalación de mod_proxy_html para el proxy reverso que va a ir desde apache a soapui
$ sudo yum install mod_proxy_html
# Instalación de mod_ssl que servirá para levantar apache en modo seguro (puerto 443)
$ sudo yum -y install mod_ssl
# Habilitar apache como servicio cada vez que suba
$ sudo systemctl enable httpd.service

Es importante activar mod_ssl, en caso contrario, un error común obtenido con el certbot de letsencrypt será:

Failed authorization procedure. subdomain.domain (tls-sni-01): urn:acme:error:connection :: The server could not connect to the client to verify the domain :: Failed to connect to XXX.YYY.ZZZ.OOO:443 for TLS-SNI-01 challenge

Activar el módulo proxy

# Hacer una copia de la configuración por defecto
$ cp /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.bk
$ sudo vi /etc/httpd/conf/httpd.conf

Buscar por la posición adecuada para agregar las directivas LoadModule y adicionar:

LoadModule proxy_html_module modules/mod_proxy_html.so

Agregar un nuevo archivo de virtual host

$ vi /etc/httpd/conf.d/vhost.conf 

Si hay un firewall activo, permitir el tráfico a apache por el 443 así:

firewall-cmd --add-service=https --permanent
firewall-cmd --reload

En este punto, se asume que la instalación de soap-ui está completa y se ha logrado subir el mockservicerunner de manera exitosa, como recomendación repasar este post y dependiendo en que puerto y contexto esté corriendo la instancia de soapui, agregar:

<VirtualHost *:80>
     ServerName subdomain.domain.com
     ProxyPass /context-path http://0.0.0.0:9090/context-path
     ProxyPassReverse /context-path http://0.0.0.0:9090/context-path
     ErrorLog /var/www/html/my-folder/logs/error.log
     CustomLog /var/www/html/my-folder/logs/access.log combined
</VirtualHost>
# Crear la carpeta de logs referida anteriormente
$ sudo mkdir -p /var/www/html/my-folder/logs    
# Reiniciar apache
$ sudo service httpd restart
# O también, así:
$ sudo systemctl restart httpd.service

Probar que la configuración tenga efecto, para ello se recomienda hacer un llamado a uno de los servicios que se tenga en los mock services, ya no usando el puerto del mock, sino el 80, donde apache haría la magia del proxy reverso enviando la petición. Un ejemplo de llamada exitosa con postman sería:

Certificado

Nuestro último paso es la instalación del certificado usando el servicio gratis de letsencrypt (Usando la configuración Apache + CentOS 7). Recordar que la emisión de este tipo de certificados se hace hasta por 3 meses y luego expirará, por lo que es necesario ir renovándolo.

Lo primero es habilitar el repositorio EPEL (Extra Packages for Enterprise Linux) que para usuarios de centOS se hace con:

$ sudo yum install epel-release

Luego instalar el Certbot de apache de letsencrypt

$ sudo yum install python-certbot-apache

Ahora, permitiendo que bot haga los cambios de forma autónoma (el otro modo es usando el modificador certonly)

$ certbot --apache

Se ejecutará un asistente que guía el proceso de creación:

  1. Los logs serán almacenados en una ruta como /var/log/letsencrypt/letsencrypt.log,
  2. Se confirma los nombres para emitir el certificado (datos extraídos de vhost.conf)
  3. Se obtiene el certificado y se hace la validación del mismo (tls-sni-01).
  4. Se genera la clave de tamaño 2048 bits, y se almacena en una ruta similar a /etc/letsencrypt/keys/0000_key-certbot.pem
  5. Se genera el CSR (Certificate Signing request) y se almacena en /etc/letsencrypt/csr/0000_csr-certbot.pem
  6. Se habilita apache para operar en el puerto 443 agregando un nuevo virtual host SSL en la carpeta
    /etc/httpd/conf.d/vhost-ssl.conf (Se agrega el sufijo -ssl al archivo original)
  7. Se consulta si HTTPS será opcional, Easy permitirá accesso HTTP como HTTPS, mientras que Secure no permitirá HTTP
  8. Felicidades! El certificado fue almacenado en /etc/letsencrypt/live/subdomain.domain.com/fullchain.pem

Revisemos el archivo generado en la configuración de apache, donde se puede validar en donde quedan finalmente los certificados, la cadena y la llave privada.

<IfModule mod_ssl.c>
<VirtualHost *:443>
     ServerName subdomain.domain.com
     ProxyPass /context-path http://0.0.0.0:9090/context-path
     ProxyPassReverse /context-path http://0.0.0.0:9090/context-path
     ErrorLog /var/www/html/sodexo/logs/error.log
     CustomLog /var/www/html/my-folder/logs/access.log combined
SSLCertificateFile /etc/letsencrypt/live/subdomain.domain.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/subdomain.domain.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateChainFile /etc/letsencrypt/live/subdomain.domain.com/chain.pem
</VirtualHost>
</IfModule>

Siempre se recomienda validar la validez del certificado usando un servicio que provee Qualys SSL Labs, usando la siguiente URL. Si todo está ok, y el rating del certificado es trusted, y ojalá con rating A, estamos listos para que el certificado sea aceptado por browsers y otros clientes.

Reiniciar apache de nuevo y validar que los servicios respondan ahora correctamente (con postman):

$ sudo service httpd restart


Respuesta esperada: 200 OK

Por último, programar la entrada de renovación del certificado para evitar que se invalide luego de los 3 meses, para ello:

# Validar que el demonio este arriba 
$ pgrep cron 
# La salida anterior no debería ser blanca, sino el PID del demonio cron<<</span
$ sudo crontab -e

Agregar la siguiente línea, que se ejecutará todos los lunes a las 2:30 am y si el certificado está por expirar, lo renovará automáticamente.

30 2 * * 1 certbot renew >> /var/log/le-renew.log

Cuando el certificado aún tiene la suficiente vigencia, en el log sale algo como:

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/vhost.conf
-------------------------------------------------------------------------------
The following certs are not due for renewal yet:
  /etc/letsencrypt/live/subdomain.domain.com/fullchain.pem (skipped)
No renewals were attempted.

Referencias

[feather_share show=”twitter, facebook, linkedin” hide=”reddit, pinterest, tumblr, google_plus, mail” size=”24″][:]

Ejecutando SOAP-UI mockservicerunner en modo servidor (Linux)

[:es]La ejecución de servicios mock (simulados) es una de las características mas potentes de SoapUI, hemos explorado en este post, un conjunto de tips que pueden ser útiles en la generación de los mismos. El propósito de esta publicación es compartir la forma cómo hemos automatizado la ejecución de servicios mock en modo servidor.

SoapUI cuenta con un script llamado mockservicerunner.sh el cual permite la ejecución de mock services previamente configurados en un proyecto mediante línea de comandos, lo cual se hace tremendamente útil para disponibilizar un conjunto de mocks en modo servidor, y acceder a estos mismos mediante los endpoints configurados previamente. El uso de la shell es como sigue:

usage: mockservicerunner [options] <soapui-project-file>
-a <arg> Sets the url path to listen on
-b Turns off blocking read for termination
-D <arg> Sets system property with name=value
-G <arg> Sets global property with name=value
-m <arg> Specified the name of the MockService to run
-p <arg> Sets the local port to listen on
-P <arg> Sets or overrides project property with name=value
-s <arg> Sets the soapui-settings.xml file to use
-S Saves the project after running the mockService(s)
-v <arg> Sets password for soapui-settings.xml file
-x <arg> Sets project password for decryption if project is encrypted

Generalmente nuestra configuración es más simple y solo requiere el nombre del mock service, el puerto (sobre-escribiendo la configuración por defecto de los endpoints definidos en el projecto) y el proyecto xml:

mockservicerunner.sh -p 9090 -m "REST MockServices" $PROJECT_HOME/my-project.xml"

Al ejecutar la línea de comandos, por consola se iniciaran los servicios hasta que se presione una tecla para terminar:
23:45:24,638 INFO [SoapUIMockServiceRunner] Started 1 runner
Press any key to terminate...

Sin embargo, este escenario no es muy práctico para el modo en que queremos levantar nuestro servicio, por tanto hemos creado un script para iniciar el mockservicerunner en segundo plano (con nohup), el cual permite iniciar, validar el estado actual, detener y reiniciar el servidor. Considerando que los procesos hijos que levanta SoapUI para la ejecución del runner, cambiaban de Padre (PPID) cuando intentábamos matarlos (con kill -9) fue necesario adaptar un proceso de detención dinámico basado en el nombre de los procesos hijos.

Pre-requsitos básicos (no mayor detalle):

  1. Java instalado
  2. Descargar SoapUI para linux
  3. Descargar el proyecto soapui en el servidor que ejecutará el mockservicerunner

Una vez tengas la herramienta desempaquetada, usaremos las herramientas de línea de commandos para ejectuar el modo servidor. El script que hacemos referencia, lo puedes encontrar en gist de Github acá. Su ejecución es simple:
Usage: ./soapui_mockservicerunner_script.sh { start | stop | restart | status }

Antes de ejecutar, asegurarse de completar las variables requeridas adecuadas:
[code language=”bash”]
# Variables to edit according to your environment
SOAPUI_HOME=$HOME/SoapUI-5.2.1
PROJECT_HOME=$HOME/somefolder/soap-ui
USR=myuser
[/code]

Detalles del script lo puedes encontrar en el gist, para nuestro propósito, sabemos que el servicio mock está ejecutándose en un servidor, con un puerto personalizado y siendo accedido mediante URLs que pueden ser automatizada en una ejecución de tests. Grandioso no? No olvides de probarlo con Postman.

[feather_share show=”twitter, facebook, linkedin” hide=”reddit, pinterest, tumblr, google_plus, mail” size=”24″]

[:]

Mocking REST services con SOAPUI y Postman[:en]Mocking servicios REST con SOAPUI en modo servidor

[:es]El prototipado de servicios es una potente herramienta para acelerar el desarrollo de software, más aún cuando existen dependencias de terceros o cuando simplemente las líneas de tiempo no se cruzan y la gestión de pre-requisitos se convierten en caos y búsqueda de culpables.

La premisa a postular acá, es que sin importar si los servicios (dependencias) con que me estoy integrando están desarrollados  o no, siempre debe existir una capa de “simulación controlada”, que además de servir de base para las pruebas automatizadas, permita validar condiciones de borde, reproduciéndolas fácilmente de manera controlada.

Existen un número importante de herramientas/frameworks que permiten hacer el llamado “mocking”, en nuestra experiencia, las más útiles son las menos invasivas, que al cambiar algo mínimo (como una URL o un parámetro de ambiente), ejecuten un plan simulado o un escenario real.

Al trabajar con servicios web (SOAP/REST) una de las herramientas más versátiles para las pruebas funcionales es SOAPUI, que en su versión OpenSource es suficiente para el objetivo que queremos lograr. Este POST incluye algunas de las prácticas más comunes que seguimos para su implementación, así como algunas de sus ventajas entre las que es importante destacar:

  1. Funciona tanto para un modelo simulado como para conectarse a servicios reales.
  2. El archivo de proyecto es un xml que puede ser versionado fácilmente. Además que el principio asociado a esto es que su edición sea colaborativa.
  3. Se pueden incluir conjuntos de test para un modelo automatizado.
  4. Iniciar el Mock Server puede hacerse mediante la interfaz de usuario como por línea de comandos (ver este post).
  5. El scripting dentro de los mocking es Groovy.

Algunas Prácticas (Sin importar el orden)

  1. Definir múltiples endpoints de acuerdo a los ambientes que se desean probar (show service viewer). Si tienes un nombre de contexto mucho mejor. service-endpoints
  2. Agregar los recursos que se puedan agrupar a recursos base.
    recursos
  3. Generar el Mock Service después de tener los recursos ya creados, así se crearán todos los mockings de una sola vez.
    mockservices
  4. Editar los headers de las respuestas de acuerdo al caso, en muchas ocasiones se requiere prevenir problemas con CORS (Cross-origin resource sharing) para consumir los servicios independiente al origen. Usar los siguientes con discresión (recordando que propósito principal aqui son las pruebas. No usar en servicios reales).
    headers
  5. Definir diferentes respuestas asociadas a un servicio para seleccionar la adecuada respecto a una entrada.
    response
  6. Puedes usar Scripting (Groovy) para determinar a cual respuesta se debe redireccionar. Aquí un ejemplo que recibe y retorna un json, se toman decisiones basado en el contenido para elegir una respuesta predefinida, la que también puede ser modificada dinámicamente con en el caso 3 de nuestro if.

    [code language=”groovy” highlight=”5,9,18″]
    def slurper = new groovy.json.JsonSlurper()
    def jsonReq = slurper.parseText(mockRequest.requestContent) // Entrada es un json
    log.info jsonReq.userIde
    if (jsonReq.userId == "1") {
    return "sessionNOK" // Retorna una de las respuestas definidas en el mockResponses
    }
    if (jsonReq.userId == "3") {
    sleep (8000) // Lo uso para generar timeouts de la aplicación a propósito
    return "sessionOK"
    }
    else if (jsonReq.userId == "4") { // Caso donde manipulo la salida basado en un parámetro como fecha
    use( groovy.time.TimeCategory ) { //Utilidades de fecha en groovy
    currentDate = new Date()
    after30Mins = currentDate + 5.minutes // Sumando 5m a la fecha actual para retornarlo como parámetro
    }
    dateExpiring = after30Mins.format("yyyy-MM-dd’T’HH:mm:ss’Z’", TimeZone.getTimeZone("UTC")) //Formato ISO 8601
    requestContext.responseMessage = ‘{"id": "0","desc": "OK","result":{"token":"ABCDE123456789", "dateEnd":"’+dateExpiring+’"}}’
    return "expiring" // redirige a este tipo de respuesta, que a su vez usa ${responseMessage} como salida.
    }
    else {
    return "sessionOK"
    }
    [/code]

    Expiring response:
    expiring

  7. Considerando que el archivo de proyecto es xml codificado en UTF-8 hace sentido que los datos que usemos se representen con la codificación adecuada y no tengamos conflicto cuando el servidor mock está arriba. Adicionalmente se recomienda agregar explicitamente el header Accept-Charset: utf-8. Ejemplo de mensaje json codificado utf-8 con acentos.

    [code language=”javascript”]
    { "resultado":"Buenos d\u00EDas UTF8" }
    [/code]

  8. Usar los http codes para emular problemas en las respuestas de los servicios resulta bastante útil para condiciones de borde. Ejm
    401
  9. Una vez tengas los servicios simulados, basta con iniciar el servicio desde la misma interfaz de SoapUI. Luego de esto necesitas probar que todo esto funcione bien…
    startmock

Una de las herramientas que mejor se complmenta con los servicios mock creados en SOAPUI, es Postman, plugin de chrome que también funciona como aplicacion independiente.  Te recomiendo usar Postman para validar todos los servicios creados en los pasos anteriores, Postman valida las salidas mucho mejor que SOAPUI, así que es más fácil encontrar un error (un corchete mal cerrado por ejemplo) en la respuesa de salida. Además permite crear diferentes casos de prueba, almacenar las entradas y el formato de intercambio (almacenamiento) es también un xml que puede ser versionado.

Algunos consejos con Postman

  1. Usar un archivo base json (Collection) que sea incremental, colaborativo y versionado. Este archivo debe ser importado constantemente en la herramienta y a su vez exportado (sobre-escribiendo la versión inicial) cuando haya cambios.
    postman-import-export
  2. Agrupar por carpetas los servicios similares.
  3. Parametrizar los endpoint de tal manera que las URL sean fácilmente intercambiadas entre distintos ambientes. Esta configuración, soporta http y https usando los puertos respectivos (por defecto 80 y 443 respectivamente), además se configura de esta manera buscando soportar nombres de contexto vacío (si los hubiese).
    Formato:{{protocol}}://{{server}}:{{port}}/{{context}}myServiceName
    endpoint1
  4. Los ambientes se parametrizan en la sección “manage environments” que permite almacenar configuraciones por ambiente independientes.environment
  5. Cada ambiente se almacena además como un archivo de configuración json diferente (no olvides exportarlo y versionarlo). Los valores se reemplazan dinámicamente en las variables del contexto de prueba cuando se llama el servicio (endpoint clasificado)
    env-local

Bien, esto es apenas una introducción de todo lo que se puede lograr con SoapUI como herramienta de generación de respuestas simuladas y controladas en nuestros ambientes de desarrollo. La extensión, cobertura, desarrollo de mock services y generación conjuntos de test sobre los mismos, dependerán del contexto y el objetivo que queremos lograr. Pero siempre, será buena idea lograr aislarnos de dependencias fuertes como lo son servicios web.

[feather_share show=”twitter, facebook, linkedin” hide=”reddit, pinterest, tumblr, google_plus, mail” size=”24″][:]