En ocasiones necesitamos montar un test (ya sea funcional o de integración) sobre un servicio que se encuentra protegido por oAuth y nos encontramos en la situación de tener que montar todo el proceso de autenticación para conseguir hacer la llamada.
En lugar de programar un cliente específico (en .Net o en Java) que haga el trabajo y ejecutarlo como un proyecto de pruebas, podemos usar como alternativa la herramienta SoapUI con bastante poco trabajo. En este post vamos a describir como hacerlo paso a paso
Entorno de pruebas.
Nuestro entorno de pruebas tendrá los siguientes elementos
- Servicio web de petición de token de autenticación : GetRequestToken.svc
- Servicio web de petición de token de acceso al recurso : GetAccessToken.svc
- Servicio web de acceso al recurso : Wall.svc (en nuestro caso)
Para simular la autorización por parte del usuario del acceso al recurso protegido, hemos montado un servicio web que valida los datos de prueba y genera la verificación del token requerida
- Servicio web de validación del token : UserAuthorization.svc
Los servicios REST usados en este ejemplo están desarrollados en C# con VS2010 y emplea la librería de devDefined oAuth (http://code.google.com/p/devdefined-tools/wiki/OAuth) que implementa la versión 1.0 del protocolo
Para el desarrollo de este post hemos usado SoapUIPro versión 4.0.1 aunque la versión libre de la herramienta también sirve para los mismos propósitos.
Creando las peticiones a los servicios.
Lo primero que tenemos que hacer es montar un nuevo proyecto para nuestras pruebas y añadir los servicios REST. Con el servicio, el recurso y la petición asociada al mismo creado tenemos que verificar que todo esta correcto.
Abrimos el método que cuelga del recurso (getToken) y añadiremos a ese método el parámetro que necesitamos. En nuestro caso es un parámetro llamado “Authorization” y le indicamos que es de estilo HEADER

Abrimos la petición asociada, verificamos que la URL es la esperada (la editamos ahí mismo si no es el caso)

Si dispusiéramos de algún valor del parámetro valido, lo podemos testear aquí mismo introduciendo ese dato y usando la flecha verde de ejecución.
Con todos los servicios creados tendremos un proyecto como el mostrado. Verificamos que todas las peticiones tienen el endPoint adecuado en las peticiones y que todas tienen el parámetro Authorization en los métodos.
Creando las pruebas.
El siguiente paso es crear la suite de pruebas que ejecute las llamadas en el orden adecuado preparando las cabeceras de cada llamada y que mueva los datos resultado de cada llamada a la siguiente etapa. Vamos por pasos.
Creamos una nueva TestSuite y un nuevo TestCase en nuestro proyecto. Vamos a usar las propiedades de ese TestCase para mover los datos entre llamadas a los servicios de forma que vamos a la pestaña de “Properties” del caso de test y añadimos las siguientes propiedades mostradas en la captura de pantalla.

Como veréis, solamente las primeras tienen un valor establecido que es el necesario para iniciar la autenticación oAuth. El resto de variables irán tomando valor en cada uno de los pasos del test. El valor de las variables user y password se emplea para simular la autorización por parte del propietario del recurso en el servicio web UserAuthorization.svc
Con las propiedades listas, vamos a ir añadiendo pasos a nuestro caso de test. Para cada servicio estableceremos cuatro pasos simples
- Crear la cabecera oAuth con un script
- Insertar la cabecera en el siguiente paso (Property Transfer)
- Ejecutar la llamada al servicio REST
- Extraer los datos de la respuesta del servicio y rellenar las variables del Test Case pertinentes.
Empecemos por el primer servicio (GetRequestToken.svc) y empecemos por crear el script que realiza la firma y monta las cabeceras oAuth (Add Step:Groovy Script)
El contenido del script es el mostrado en el siguiente fichero :
import java.util.Random
import java.net.URLEncoder
import java.util.regex.Pattern
import java.util.regex.Matcher
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import org.apache.commons.codec.binary.Base64
// Generate auth_nonce
Random rand = new Random()
def rn1 =(rand.nextFloat() * 100000000)
def rn2 =(rand.nextFloat() * 100000000)
String oa_nonce = "oauth_nonce="+ rn1.round().toString()+ "-" + rn2.round().toString()
// Generate ticks
Date now = new Date();
int tm = (now.getTime()/1000)
String oa_timestamp = "oauth_timestamp=" + tm
//Otras variables
def oa_consumer = "oauth_consumer_key=" + testRunner.testCase.getPropertyValue( "oauth_consumer_key" )
def oa_version = "oauth_version=" + testRunner.testCase.getPropertyValue( "oauth_version" )
def oa_sig_method = "oauth_signature_method=" + testRunner.testCase.getPropertyValue( "oauth_signature_method" )
def oa_secret = testRunner.testCase.getPropertyValue( "oauth_secret" )
// Montamos la firma
String baseURL = "http://localhost:50595/"
String resource = "GetRequestToken.svc"
String headerParams = "oauth_callback=GetRequestToken.svc" +
"&" + oa_consumer +
"&" + oa_nonce +
"&" + oa_sig_method +
"&" + oa_timestamp +
"&" + oa_version
String sigBase = "GET&" +
URLEncoder.encode(baseURL+resource+"/") +
"&" + URLEncoder.encode(headerParams);
String keyF = URLEncoder.encode(oa_secret)+"&"
Mac m = Mac.getInstance("HmacSHA1");
m.init(new SecretKeySpec(keyF.getBytes(), "HmacSHA1"));
m.update(sigBase.getBytes());
byte[] res = m.doFinal();
def signature = new String(Base64.encodeBase64(res));
String cabecera = "OAuth " + headerParams.replaceAll('&', ',') + ",oauth_signature=" +signature;
return cabecera
Como podéis ver, el script calcula la firma de los parámetros y monta la cabecera oAuth con los mismos devolviéndolos como resultado del script. Merece la pena fijarse en la forma de acceder a las propiedades del caso de test (testRunner.testCase.getPropertyValue ) ya que en todos los demás pasos iremos accediendo a las propiedades que vamos guardando después de cada ejecución de la llamada REST.
A continuación incluimos un nuevo paso de test para mover los resultados del script a la llamada y la llamada al servicio REST. (Incluir los pasos y luego configurar)
El paso de mover parámetros, tomara como origen el resultado del script anterior y como destino la propiedad “Authorization” del paso de llamada a servicio REST.

El ultimo paso es de nuevo un “Property Transfer” que obtiene los datos del resultado de la llamada al servicio REST y los introduce en las propiedades del caso de Test.

En nuestro caso, sacamos el token y el secret de la llamada con dos transferencias. Fijaros en que tenemos como origen el paso de llamada REST, la propiedad es “ResponseAsXml” y usamos un XPath (diferente en cada valor) para acceder al dato dentro de la respuesta. El destino es el caso de test y la propiedad correspondiente.
Esto finalizaría el primer paso de llamada al primer servicio REST.
Completando el test.
Procedemos de la misma forma en el resto de casos de llamada a los servicios hasta ir completando toda la información necesaria para el último paso que es la llamada al servicio protegido con oAuth. El caso de test completo se puede ver debajo
Para completar el test, incluimos en la llamada una aserción de test que cuente los nodos de comentario y lo contraste con el número esperado.

Ejecutando el test.
Con todos los pasos creados, podemos ejecutar el test del tirón y comprobar que aparece el resultado en verde.
Pulsando sobre cada paso del log, podemos ver los detalles de ejecución del paso o el error que aparezca en caso de tener alguno.
Mejoras y evolución.
Puesto que la llamada a los métodos oAuth son comunes a todas las llamadas a métodos protegidos, podria crearse un caso de test que contuviera solamente las llamadas oAuth y llamarlo como un paso mas en cada uno de los tests de nuestros servicios como paso previo. Esto nos permitiría reutilizar el mismo grupo de llamadas y simplificaría el test de regresión de todos los servicios ofrecidos por nuestro aplicativo.
Conclusiones.
Como veis, es bastante sencillo montar un proyecto de test y extenderlo para cubrir todos los servicios ofrecidos por nuestra aplicación que se encuentren protegidos con oAuth.
Os animo a probar este método de prueba y a crearos vuestros própios proyectos de test de las aplicaciones de forma que podais efectuar un test de regresión rápidamente después de cada despliegue.