# __Protegiendo servicios REST con Oauth2__ En este proyecto encontrarás algunas herramientas para añadir la seguridad del framework **OAuth2** a los recursos exhibidos por cualquier _endpoint_ de un servicio REST. ## **Clases importantes** ### **GestorHttp** :::info - _recibirToken_ ~ Método se encarga de realizar una llamada POST al endpoint "*/oauth2/token" del servidor **Ory Hydra** y recibe el token que se enviará al cliente. En cualquier otro caso se lanzará una excepción con el código de error Http y la descripción del error devuelto por el servidor. - _intospeccionarToken_ ~ Método se encarga de realizar una llamada POST al endpoint "*/oauth2/introspect" del servidor **Ory Hydra** y recibe comprueba que el token enviado es valido. En cualquier otro caso se lanzará una excepción con el código de error Http y la descripción del error devuelto por el servidor. - _comprobarValidezToken_ ~ Método se encarga de realizar una llamada POST al endpoint "*/oauth2/introspect" del servidor **Ory Hydra** para comprobar que un token en concreto, enviado en la petición, sea válido. También recibe el _Scope_ del recurso desde donde se le llamó para asegurarse de que el token recibido corresponde con el _scope_ del recurso. - _formatearJson_ ~ Método encargado de recibir el cuerpo de las respuestas de __Ory Hydra__ y formatearlas para enviarlas de nuevo al cliente. - _extraerParametrosCuerpoRequest_ ~ Método encargado de recibir el cuerpo de las peticiones recibidas en nuestra aplicación guardando la información necesaria en estructuras de datos para su posterior uso. - _extraerValidezToken_ ~ Método auxiliar privado que extrae el campo de la respuesta del servidor, al realizar la introspección del token, donde se indica la validez del token. - _crearClienteHttpSinSeguridad_ ~ Junto con esta clase envoltorio, que reliza las comunicaciones entre el servidor y nuestros servicios, se incluye un método que construye peticiones HTTP con certificados auto firmados. Este método se incluye por motivos de desarrollo y testeo. La manera de utilzarlo se explicará en la [sección correspondiente](#instalacion). ::: ## **Endpoints importantes** ### **TokenEndpoint** :::info - path ~ */oauth2/token - get ~ Método no permitido. En caso de realizar una petición a este endopoint se envía al cliente información para relizar correctamente la llamada POST. - post ~ Endpoint que recibe el _client_id_, _client_secret_, _scope_ y _grant_type_ por el cuerpo de la llamada POST. Estos datos son después enviados al _GestorHttp_ para procesar las comunicaciones con el servidor. ::: ## **Modo de uso** ### [Incorporación en proyecto](#instalacion) 1. Para incluir estas funcionalidades en cualquier proyecto será necesario incluir la clase **GestorHttp** en tu proyecto. 2. Después debes definir que tipo de cliente se va a crear. Para ello se debe comentar/descomentar un par de líneas de código dentro de **GestorHttp** en los siguientes métodos: - Cliente sin seguridad https (acepta certificados auto firmados), muy útil para desarrollo y testeo) ![a](https://i.imgur.com/0067sCx.png) ![b](https://i.imgur.com/vl10hJu.png) - Cliente con seguridad ![c](https://i.imgur.com/cuILZrM.png) ![d](https://i.imgur.com/sNdwljg.png) ### Uso Una vez seleccionado el tipo de cliente tan sólo habría que instanciar dicha clase dentro del servicio REST que queramos y llamar a los métodos correspondientes: - Recibiendo token ``` java @POST @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Produces(MediaType.APPLICATION_JSON) public Map<String, Object> post(String cuerpo) { try { return gestorHttp.recibirToken(cuerpo); } catch (Exception ex) { ex.printStackTrace(); } return null; } ``` - Realizando la introscpección de un token concreto(El token será válido en caso de que el _SCOPE_ sobre el que se pidió el token coincida con el indicado en el cuerpo de la llamada POST o que no se envíe _SCOPE_ ninguno) ```java @POST @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Produces(MediaType.APPLICATION_JSON) public Map<String, Object> post(String cuerpo) { try { return gestorHttp.introspeccionarToken(cuerpo); } catch (Exception ex) { Logger.getLogger(IntrospectPoint.class.getName()).log(Level.SEVERE, null, ex); } return null; } ``` - Comprobando la validez y recibiendo recursos (una lista de usuarios en nuestro ejemplo). Hay que tener en cuenta que la variable _SCOPE_ es una constante del recurso. ``` java @GET @Produces(MediaType.APPLICATION_JSON) public List<Usuario> get(@Context HttpHeaders header) { try { if(gestorHttp.comprobarValidezToken("", header.getHeaderString("token"), SCOPE)) { return usuarioService.getUsuarios(); } } catch (Exception ex) { ex.printStackTrace(); } return null; } ``` ## **Referencias** - [Ory Hydra Oauth2 Server API](https://www.ory.sh/docs/api/hydra/) - [Configuración Servidor Oauth2](https://hackmd.io/s/Hy3aT4Y8X)