Consumir API REST Toba con autenticacion JWT

Estimados, buenos dias.
Tenemos una API REST desarrollada en TOBA 3.0.26, la autenticacion la probamos tanto por Basic como Digest y anda todo bien.
Queremos ahora, modificar el tipo de autenticacion para hacerlo por JWT y ahi estamos un poco perdidos para consumir la API desde una aplicación NO TOBA.

El archivo de configuración de servidor.ini es:
autenticacion = jwt
[settings]
formato_respuesta = json
; Configuración para generar/validar tokens JWT
[jwt]
tipo=simetrico
algoritmo=HS512
usuario_id=uid
key_encoder=test
key_decoder=test
expiracion=+1 Day

El archivo de configuración de servidor_usuarios.ini es:
[prueba]
password = prueba_clave

Para probar estamos intentando con POSTMAN:

  • Haciendo un POST a http://url-aplicacion/rest/session
  • Pasando los parametros en el body usuario = prueba y clave = prueba_clave
  • Error: “mensaje”: “Wrong number of segments”

Nos podrian guiar un poco ? que le estamos errando?

Hola Sergio,

Bien, vamos por partes… por un lado vas a necesitar generar los web tokens y por otro lado los vas a consumir, dicho esto… la aplicacion NO TOBA deberia hacer 2 pedidos, uno para obtener el token y el otro para acceder a la API que desea utilizar.

Estimo que siguieron los pasos que se detallan aca para dejar lista la generacion de tokens.

[u]El archivo de configuración de servidor_usuarios.ini es:[/u] [b][prueba] password = prueba_clave[/b]

Bien… aca es donde te voy a cortar, si te fijas en la pagina de jwt-session le esta pasando como callback para la autenticacion el mecanismo estandar de Toba, osea que con esa configuracion va a autenticar contra la bd y los usuarios de Toba… no contra el archivo servidor_usuarios.ini.

La idea es que en lugar de pasar usr/pwd cada vez, obtengas el token desde un server seguro (o un IDP si vamos al caso) y con ese token te manejes en lo que serian las APIs, en definitiva la API lo que hace es descifrar el token y obtener el id de usuario que esta accediendo, la autenticacion se hizo en el servidor que te dio el token.

Para probar estamos intentando con POSTMAN: - Haciendo un POST a http://url-aplicacion/rest/session - Pasando los parametros en el body [b]usuario = prueba[/b] y [b]clave = prueba_clave[/b] - Error: "mensaje": "Wrong number of segments"

Nos podrian guiar un poco ? que le estamos errando?


Veamos un poco el tema de la config para la generacion del Token, me parece que viene por ahi el tema… en lugar de generarte el Token esta tomando el pedido como si vos presentaras un token. La parte del contexto de ejecucion como te quedo?.

Saludos

Correcto, hay cuestiones que ahora me estas confirmando en las cuales estaba confundido, ahora estoy entendiendo un poco mas.
Hay cosas que no las estoy haciendo.
Voy a avanzar con la generación del Token y te aviso novedades.
Gracias

Buenas, perdon por dilatar las pruebas, justo salimos de vacaciones.
Te cuento lo que hicimos hasta ahora:
El proyecto que va a ser la API REST hecho en toba se llama eventos

En \eventos\php\extension_toba: Creamos la clase eventos_contexto_ejecucion.php


<?php
class eventos_contexto_ejecucion  extends toba_contexto_ejecucion
{
   
   function conf__rest(SIUToba\rest\rest $rest)
   {
               // obtener el toba_modelo_proyecto
         $catalogo = toba_modelo_catalogo::instanciacion();
         $id_instancia = toba::instancia()->get_id();
         
         $id_proyecto = toba::proyecto()->get_id();
         $modelo_proyecto = $catalogo->get_proyecto($id_instancia, $id_proyecto);

         // leer la config de JWT, desde servidor.ini
         $ini = toba_modelo_rest::get_ini_server($modelo_proyecto);

         $settings = [
            'tipo' => $ini->get('jwt', 'tipo', null, true),
            'algoritmo' => $ini->get('jwt', 'algoritmo', null, true),
            'usuario_id' => $ini->get('jwt', 'usuario_id', null, true),
            'key_encoder' => $ini->get('jwt', 'key_encoder', null, true),
            'exp' => $ini->get('jwt', 'expiracion', null, true)
         ];

         // obtener una instancia del generador de sesiones JWT
         $session = SIU\JWT\Session::getInstance();

         // configurar la librería para generar tokens JWT
         $session->setConfigJWT($settings);

         // configurar un callback para validar el usuario/clave
         $session->setCallbackAutenticador(array(new toba_autenticacion_basica(), 'autenticar'));

         // decir a toba donde encontrar el recurso REST /session de la librería
         $rest->add_path_controlador(SIU\JWT\Session::getPathControlador());
   }
}
?>

Vamos a probar primero como backend del login el esquema de Toba usuarios.

El archivos servidor.ini


autenticacion = jwt
[settings]
formato_respuesta = json
[jwt]
tipo=simetrico
algoritmo=HS512
usuario_id=uid
key_encoder=test
key_decoder=test

Hola Sergio,

no problem yo recien vuelvo tambien.

Asi como lo tenes configurado, eventos seria el sistema que genera los JWT y tambien los consumiria.

Para tener algo asi, vas a tener que permitir que la “ruta” de la API que te lleva a generar el WT sea publica, de otra manera vas a entrar en el dilema del huevo y la gallina.
Para eso vas a tener que modificar la ER que controla las URLs en el archivo servidor.ini de otra manera va a intentar autenticarte con JWT al momento de presentar usuario y password, que creo era el problema original.

Saludos

Richard, yo quiero que eventos publique la API REST y que genere los WT. No quiero que los consuma.

Para probar la generacion de los WT estamos intentando con POSTMAN mandando un POST a http://eventos.unne.edu.ar:80/eventos/1.0/rest/session con usuario y clave de la BD de Toba Usuarios, esto como vos decis quiere autenticarme y no devolver el token generado.

Esto no estamos entendiendo: "modificar la ER que controla las URLs en el archivo servidor.ini "

Hola Sergio,

Si eventos publica una API, quien haga uso de la misma debe autenticarse de alguna manera… ahi es donde se consumiria el Token generado, si no consume el token, van a tener que autenticares a la API (a menos que sea publica) de alguna otra manera.

Para probar la generacion de los WT estamos intentando con POSTMAN mandando un POST a http://eventos.unne.edu.ar:80/eventos/1.0/rest/session con usuario y clave de la BD de Toba Usuarios, esto como vos decis quiere autenticarme y no devolver el token generado. Esto no estamos entendiendo: "modificar la ER que controla las URLs en el archivo servidor.ini "
Bien, el tema es asi:
  • En el archivo servidor.ini donde se configuran los parametros basicos para aquel host que publica la API REST, se encuentra un parametro url_protegida el cual sale configurado para ser lo mas abarcativo posible.

Ese parametro es una expresion regular que matchea contra las URLs (de la API rest) que se desea esten detras de un mecanismo de autenticacion.

En el caso de session, ustedes necesitan que ese acceso sea publico… de otra manera no van a poder generar los JWT, entonces… tienen que modificar el parametro en el archivo servidor.ini, de manera que proteja todo… excepto session… el cual seria publico para poder obtener el token inicial.

Saludos

Richard, hicimos las configuraciones para dejar publica solo la url de session.

Cuando hago la peticion POST a session podemos observar en el log que:

[INFO] El firwall no controla acceso a session
Con esto estamos seguros que esta URL esta publica.

Luego nos dice que no encuentra el recurso session:

Error al ejecutar el pedido. No se encuentra el recurso para session en el directorio /eventos/php/rest. ¿Ruta mal formada?

Esta buscando el recurso session dentro de nuestros recursos del proyecto eventos ( /eventos/php/rest) como si fuera un recurso mas del proyecto, no deberia buscar en eventos\vendor\siu-toba\jwt-session\src\SIU\JWT\rest\session ?

Hola Sergio,

Deberia, al menos si respeta la ultima linea que incluyeron en el contexto ejecucion:

$rest->add_path_controlador(SIU\JWT\Session::getPathControlador());

Tenes a mano el log de WS para ese proyecto?..me lo pasarias? esta dentro de la carpeta instalacion.

Saludos

[239][eventos][DEBUG] Iniciando el pedido
[239][eventos][DEBUG] Procesando URL ‘/session’
[239][eventos][DEBUG] Iniciando Autenticacion
[239][eventos][INFO] El firwall no controla acceso a session
[239][eventos][ERROR] Error al ejecutar el pedido. No se encuentra el recurso para session en el directorio E:/Proyectos/eventos/php/rest. ¿Ruta mal formada?
[239][eventos][ERROR] #0 E:\Proyectos\eventos\vendor\siu-toba\rest\src\SIUToba\rest\rest.php(251): SIUToba\rest\lib\ruteador->buscar_controlador(‘POST’, ‘session’)
#1 E:\Proyectos\eventos\vendor\siu-toba\framework\php\nucleo\lib\toba_rest.php(49): SIUToba\rest\rest->procesar()
#2 E:\Proyectos\eventos\vendor\siu-toba\framework\php\nucleo\toba_solicitud_servicio_rest.php(48): toba_rest->ejecutar()
#3 E:\Proyectos\eventos\vendor\siu-toba\framework\php\nucleo\toba_nucleo.php(183): toba_solicitud_servicio_rest->procesar()
#4 E:\Proyectos\eventos\www\rest.php(21): toba_nucleo->acceso_rest()
#5 {main}
[239][eventos][DEBUG] Pedido finalizado
[239][eventos][DEBUG] SIUToba\rest\http\respuesta_rest::__set_state(array(
‘status’ => 500,
‘headers’ =>
array (
‘Content-Type’ => ‘application/json’,
‘API-Version’ => ‘1.0.0’,
),
‘data’ =>
array (
‘error’ => 500,
‘mensaje’ => ‘500 Internal Server Error’,
‘descripcion’ => ‘Error Interno en el servidor: No se encuentra el recurso para session en el directorio E:/Proyectos/eventos/php/rest. ¿Ruta mal formada?’,
),
‘encoding’ => ‘latin1’,
‘api_version’ => ‘1.0.0’,
))

Hola Sergio,

Entre esas dos lineas que te marque arriba, deberia hacerse la llamada que agrega la ruta de JWT como camino a servir.
Podrias poner un var_dump o un echo en el archivo contexto_ejecucion en el metodo conf__rest para verificar que pasa por dicho lugar y que ruta le esta asignando la llamada SIU\JWT\Session::getPathControlador() a la lib que sirve la api rest?.

Saludos

Richard, puse dos logs en los metodos conf_rest() de estos dos archivos:
\eventos\vendor\siu-toba\framework\php\nucleo\lib\toba_contexto_ejecucion.php
\eventos\php\extension_toba\eventos_contexto_ejecucion.php

El tema es que solo ejecuta el metodo conf_rest() de toba_contexto_ejecucion.php;
[271][eventos][INFO] UNNE: Path del getPathControlador en toba_contexto_ejecucion → conf__rest
[271][eventos][INFO] E:\Proyectos\eventos\vendor\siu-toba\jwt-session\src\SIU\JWT/rest

Asi tenemos la clase \eventos\php\extension_toba\eventos_contexto_ejecucion.php , pero nunca ejecuta este metodo, tambien generamos el autoload.


class eventos_contexto_ejecucion extends toba_contexto_ejecucion
{

    function conf__rest(SIUToba\rest\rest $rest)
    {
        $path = \SIU\JWT\Session::getPathControlador();
        toba::logger_ws()->info('UNNE: Path del getPathControlador en ' . __CLASS__ . ' -> ' . __FUNCTION__);
        toba::logger_ws()->info($path);

        // obtener el toba_modelo_proyecto
        $catalogo     = toba_modelo_catalogo::instanciacion();
        $id_instancia = toba::instancia()->get_id();

        $id_proyecto     = toba::proyecto()->get_id();
        $modelo_proyecto = $catalogo->get_proyecto($id_instancia, $id_proyecto);

        // leer la config de JWT, desde servidor.ini
        $ini = toba_modelo_rest::get_ini_server($modelo_proyecto);

        $settings = [
            'tipo'        => $ini->get('jwt', 'tipo', null, true),
            'algoritmo'   => $ini->get('jwt', 'algoritmo', null, true),
            'usuario_id'  => $ini->get('jwt', 'usuario_id', null, true),
            'key_encoder' => $ini->get('jwt', 'key_encoder', null, true),
            'exp'         => $ini->get('jwt', 'expiracion', null, true)
        ];

        // obtener una instancia del generador de sesiones JWT
        $session = SIU\JWT\Session::getInstance();

        // configurar la librería para generar tokens JWT
        $session->setConfigJWT($settings);

        // configurar un callback para validar el usuario/clave
        $session->setCallbackAutenticador(array(new toba_autenticacion_basica(), 'autenticar'));

        // decir a toba donde encontrar el recurso REST /session de la librería
        $rest->add_path_controlador(\SIU\JWT\Session::getPathControlador());
    }

}


Hola Sergio,

consulta, tenes asignado el contexto de ejecucion al proyecto no?.. toba_editor->conf->propiedades->extensiondelnucleo->contextoejecucion.
Asumi que lo tenian cargado en metadatos ya… y que lo venian usando, de otra manera tendria que estar levantando el metodo ese… el nombre esta bien (que suele ser el error mas comun), asi que no hay forma para que levante el de toba en lugar de ese.

Saludos

Perfecto, ahi si me esta ejecutando el metodo conf_rest() de eventos_contexto_ejecucion.php

Ahora me da error en la validación del recurso:


[335][eventos][DEBUG] Iniciando el pedido
[335][eventos][DEBUG] Procesando URL '/session'
[335][eventos][DEBUG] Iniciando Autenticacion
[335][eventos][INFO] El firwall no controla acceso a session
[335][eventos][DEBUG] Controlador encontrado E:\Proyectos\eventos\vendor\siu-toba\jwt-session\src\SIU\JWT/rest\session\recurso_session.php :: post_list ()
[335][eventos][INFO] Entra a la sesion de login
[335][eventos][INFO] La api retorn贸 un error. Status: 400
[335][eventos][INFO] array (
  'error' => 400,
  'mensaje' => '400 Bad Request',
  'descripcion' => 'Error en la validaci髇 del recurso',
  'detalle' => 
  array (
    'usuario' => 
    array (
      0 => 'El campo \'usuario\' es obligatoio.',
    ),
    'clave' => 
    array (
      0 => 'El campo \'clave\' es obligatoio.',
    ),
  ),
)
[335][eventos][DEBUG] Pedido finalizado
[335][eventos][DEBUG] SIUToba\rest\http\respuesta_rest::__set_state(array(
   'status' => 400,
   'headers' => 
  array (
    'Content-Type' => 'application/json',
    'API-Version' => '1.0.0',
  ),
   'data' => 
  array (
    'error' => 400,
    'mensaje' => '400 Bad Request',
    'descripcion' => 'Error en la validaci髇 del recurso',
    'detalle' => 
    array (
      'usuario' => 
      array (
        0 => 'El campo \'usuario\' es obligatoio.',
      ),
      'clave' => 
      array (
        0 => 'El campo \'clave\' es obligatoio.',
      ),
    ),
  ),
   'encoding' => 'latin1',
   'api_version' => '1.0.0',
))

Probe hacer un POST pasando los valores de usuario y clave en el body, que por lo que veo en el recurso es desde donde busca estos valores.


 $datos = rest::request()->get_body_json();
 rest_validador::validar($datos, $this->_get_modelos()['Autenticar'], false);
 return $datos;

El tema es que me esta pasando al validador el arregro $datos vacio.

Probe por las dudas pasando en el Header y como Params los valores usuario y clave y obviamente tampoco me da.

Si modifico el metodo POST y le digo que los parametros los tome de Params, le paso estos como Params y modifico el recurso_session para que tome de Params me genera bien el token.

Hola Sergio,

si esta devolviendo el contenido como vacio es… o porque no esta leyendo el strem php://input o luego de leerlo esta perdiendo el contenido al intentar convertir el encoding.
Yo descartaria un par de cuestiones en orden y despues intentaria ubicar el punto en el que se pierde.

    • Miraria que allow_url_fopen este activado
    • Me fijaria que el POST al servidor no sea con enctype=“multipart/form-data”. Ya que eso hace que no se lea nada de php://input
    • Intentaria hacer un echo de lo que llega al servidor para verificar que se esta recibiendo algo

Saludos