Seguridad - Autenticación delegada: Protocolo de Autorización OAuth 2.0

Partiremos, en esta presentación del protocolo OAuth 2, del punto de vista del sistema que desea facilitar a los usuarios identificarse y autorizarnos a la obtención de sus datos, sin necesidad de que se registren de forma explícita en nuestro sistema, dándole la posibilidad de identificarse con los datos que ya tenga depositados en algún otro servicio de internet.

Cuando hablamos de autorización delegada nos estamos refiriendo a que a nuestro sistema delega la autenticación del usuario a algún servicio que ya aloja una cuenta del mismo, por ejemplo Facebook, Google, GitHub, etc. además el usuario a través de estos servicios proveerán a nuestro sistema de autorización para obtener su información personal, dentro de los límites que él mismo haya establecido en el servicio donde está registrado.

OAuth 2 proporciona flujos de autorización para aplicaciones web, de escritorio y dispositivos móviles. En este escenario, tenemos 4 roles que deben quedar claros;

  • Cliente (client)– es el sistema, aplicación, a la que el usuario quiere acceder y que en este caso sería nuestro sistema.
  • Propietario (Resource Owner) – es el usuario, es decir, la persona o entidad que tiene registrados su información personal en alguno de los servicios de internet.
  • Servidor de Recursos (Resource Server) – Es el servicio que contiene los datos personales del propietario, es decir, del usuario.
  • Servidor de Autorización (Authorization Server)– Es el servicio que tras la validación del usuario nos proveerá de la autorización necesaria para obtener sus datos personales. El flujo suele ser el siguiente, cuando redirigimos al usuario a ellos, si el usuario ya dispone de sesión abierta, suelen conceder la autorización de forma automática sin necesidad de que el usuario se identifique de nuevo, si no es así solicitaran al usuario que se identifique, informándole, habitualmente, de qué aplicación cliente está solicitando el acceso a sus datos personales. Una vez identificado el usuario, concederán al cliente la autorización necesaria para que pueda acceder a los datos personales del usuario.

Ahora que ya conocemos los roles, podríamos describir el proceso como:

“OAuth2 permite que los usuarios accedan a nuestra aplicación o servicio de internet que requiere de sus datos personales, sin necesidad de cumplimentar ningún formulario, sino que simplemente deberán identificarse en alguno de los servicios de internet, donde ya tienen depositados sus datos personales y conceder permiso a nuestra aplicación para que actuando como cliente obtenga acceso a los datos por un tiempo limitado.”

Para que nuestro sistema pueda permitir esta forma de acceso deberemos realizar los siguientes pasos:

Registrar nuestra aplicación en aquellos servicios de internet a través de los cuales, deseemos posibilitar la autorización delegada. Tras este registro nuestra aplicación se convertirá en cliente de dicho servicio y dispondrá de un id de cliente y un id de cliente secreto, en cada una de ellas, que usaremos en nuestras comunicaciones con el Servidor de Recursos y Servidor de Autorización, utilizando la que sea oportuna, cuando un usuario solicite dicha identificación delegada. Además o bien en este registro o bien al solicitar la identificación de un usuario deberemos indicar la URL de Call-Back, que es la dirección a la que el Servicio de Autenticación redirigirá la respuesta del resultado de la identificación del usuario. En esta dirección deberemos tener adecuadamente preparadas las acciones a realizar, bien si la identificación es positiva como si no lo es. Este paso de registrarse deberá realizarse previamente a la implementación de nuestro sistema de autentificación delegada.

Descripción del proceso:

  • Paso 0 – Nuestra aplicación, es decir, el cliente deber haberse registrado en el/los Servicio de Autorización que se desea posibilitar y obtener de ellos el client_id y el client_secret. Esto se debe realizar una sola vez, previo a la puesta en marcha de nuestra aplicación.

Para cada acceso de usuario

  • Paso 1 – El usuario intenta acceder a nuestra aplicación – sistema
  • Paso 2 – El usuario elige el servidor de autorización delegado que desea utilizar, de entre los que nosotros le ofrezcamos
  • Paso 3 – Nuestro sistema reencamina al usuario hacia la página de login de ese servidor de autorización delegado, indicándole nuestro client_id, que al estar previamente registrado, tendrá acceso a este servicio. Además se le indica una url de Call-Back donde enviar la respuesta del proceso de login del usuario.
  • Paso 4 – El usuario se identifica en el servidor de autorización delegada, o bien si ya tenía sesión abierta es posible que no se le solicite identificación. Tras ellos el servidor de autorización responde sobre la dirección de Call-Back, aquí caben dos respuestas, OK-Código de autorización o KO.
  • Paso 5 – Si la respuesta ha sido OK con su código de autorización, tendremos acceso a los datos que el cliente tenga registrado en ese Servidor de Autorización y por ello solicitaremos el Token para poder acceder a ellos, por lo tanto enviaremos una petición de Token al Servidor de Autorización. Que responderá con el mismo. Dicho Token tendrá un tiempo de vida limitado, habitualmente servirá para hacer una sola consulta de datos sobre el Servidor de Recursos, pero esto puede diferir según el servidor.
  • Paso 6 – Ya con el Token de acceso, solicitaremos los datos del usuario, estos estarán limitados al contexto que haya establecido en el Servidor de Recursos.
  • Paso 7 – Damos acceso al usuario a nuestro sistema. Hemos obtenido sus datos, sin necesidad de que tuviese que introducirlos.

Protocolos que implementan OAuth2 y aportan o facilitan el proceso:

OpenID Connect

Protocolo creado para la identificación de nuestros clientes que está basado en el OAuth2.0.

Este protocolo especifica un API para la identificación, accesible via HTTP con norma RESTFull e intercambiando datos en formato JSON. Además se puede extender con características como la encriptación.

IndieAuth

IndieAuth es un protocolo de autenticación descentralizado estándar que utiliza OAuth 2.0 y permite a los servicios verificar la identidad de un usuario representado por una URL, así como obtener un token de acceso que se puede usar para acceder a los recursos bajo el control del usuario.

Hay varias formas de hacer uso de él todas ellas explicadas en el enlace

IndieAuth.com se creó para que los usuarios y desarrolladores puedan comenzar a utilizar esta nueva forma de iniciar sesión en la web sin la complejidad de OpenID.

WebID-OIDC

WebID-OIDC es un protocolo de delegación de autenticación utilizado por los sistemas descentralizados basados en WebID, como por ejemplo Solid, y Otros sistemas basados en LDP.

Se basa en OAuth2 / OpenID Connect descentralizado.

Ejemplo de uso OAuth 2.0 con Go

Descripción

Este ejemplo presenta al cliente una página web con un enlace a la autentificación vía google, una vez que el usuario se identifica en google se presenta cierta información personal del mismo, que en este caso es simplemente su email.

Antes de probar

Este ejemplo está realizado con Go, lenguaje de programación de Google, y cuyo compilador debe ser instalado en el equipo, si es que no disponemos de él. Enlace para su descarga.

Además antes de probar deberemos para preparar el contexto, para que goolge nos permita solicitar datos de usuarios deberemos registrar nuestra API y obtener un id de cliente para ella con este dato y el id secret deberemos crear asignaciones a las variables de entorno del Sistema. Si para probar el ejemplo, no quereis tener que registraros en Google podéis emplear estos datos:

- GOOGLE_OAUTH2_CLIENT_ID = 696706423016-f62l771ikt4soovips03r28sfouff10c.apps.googleusercontent.com

GOOGLE_OAUTH2_CLIENT_SECRET = YuMeWw_iq2dM6Z4cs57wO7_X

NOTAS:Hay muchas formas para establecer los valores a las variables de entorno, y en muchas ocasiones depende del SO que tengáis, a modo de ayuda dejo este enlace por si os es necesario

También os dejo un enlace al procedimiento para registrar la API en el servicio OAuth2 de google

Para iniciar el servidor

• Inicia el servidor desde la línea de comandos : `go run oauth2.go`

Para probar el API

• Con un Navegador a http://127.0.0.1:1736

Aplicación de los pasos del protocolo en el ejemplo:

• Paso 0 – Nuestra aplicación, es decir, el cliente deber haberse registrado en el/los Servicio de Autorización que se desea posibilitar y obtener de ellos el client_id y el client_secret. Esto se debe realizar una sola vez, previo a la puesta en marcha de nuestra aplicación.

Para cada acceso de usuario

• Paso 1 – El usuario intenta acceder a nuestra aplicación – sistema

• Paso 2 – El usuario elige el servidor de autorización delegado que desea utilizar, de entre los que nosotros le ofrezcamos

 

• Paso 3 – Nuestro sistema reencamina al usuario hacia la página de login de ese servidor de autorización delegado, indicándole nuestro client_id, que al estar previamente registrado, tendrá acceso a este servicio. Además se le indica una url de Call-Back donde enviar la respuesta del proceso de login del usuario.

• Paso 4 – El usuario se identifica en el servidor de autorización delegada, o bien si ya tenía sesión abierta es posible que no se le solicite identificación. Tras ellos el servidor de autorización responde sobre la dirección de Call-Back, aquí caben dos respuestas, OK-Código de autorización o KO.

• Paso 5 – Si la respuesta ha sido OK con su código de autorización, tendremos acceso a los datos que el cliente tenga registrado en ese Servidor de Autorización y por ello solicitaremos el Token para poder acceder a ellos, por lo tanto enviaremos una petición de Token al Servidor de Autorización. Que responderá con él mismo. Dicho Token tendrá un tiempo de vida limitado, habitualmente servirá para hacer una sola consulta de datos sobre el Servidor de Recursos, pero esto puede diferir según el servidor.

• Paso 6 – Ya con el Token de acceso, solicitaremos los datos del usuario, estos estarán limitados al contexto que haya establecido en el Servidor de Recursos.

• Paso 7 – Damos acceso al usuario a nuestro sistema. Hemos obtenido sus datos, sin necesidad de que tuviese que introducirlos.

Código completo: Lo podremos descargar desde aquí.



 package main
import (
"log"
"net/http"
"os"
 "fmt"
oidc "github.com/coreos/go-oidc" // paquete para la implementacion del protocolo OpenID Connect
"golang.org/x/net/context"
"golang.org/x/oauth2"
)
// Obtenemos del contexto de nuestra consola los valores de las variables indicadas
// Estos valores deberan ser establecidos previamente a la ejecución del ejemplo y obtenidos al registrar nuestra API en
Google-Cloud
var (
clientID = os.Getenv("GOOGLE_OAUTH2_CLIENT_ID")
clientSecret = os.Getenv("GOOGLE_OAUTH2_CLIENT_SECRET")
 URL = "127.0.0.1:1736"
ctx = context.Background()
 googleprovider, err = oidc.NewProvider(ctx, "https://accounts.google.com")
// En este punto se debería validar que el acceso al proveedor ha sido posible, es decir si err == nil , en caso
 // de que no lo haya sido, posteriormente podríamos sufrir un error en tiempo de ejecución.
// Creamos la estructura para la peticion OAuth2
googleconfig = oauth2.Config{
ClientID: clientID,
ClientSecret: clientSecret,
Endpoint: googleprovider.Endpoint(),
RedirectURL: "http://"+URL+"/callback",
Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
}

state = "foobar"
)
// Manejador de las peticiones a '/'
func handleMain(w http.ResponseWriter, r *http.Request) {
var htmlBody = `
 
 Api OpenID Connect-OAuth2
 Para el acceso deberemos hacer uso del recurso '/links' o seguir este enlace
 Ver los enlaces delegados
 
 `
fmt.Fprintf(w, htmlBody)
log.Printf(" Enviado al Front la informacion.")
} // FIN Manejador de las peticiones a '/'
// Manejador de las peticiones a '/links'
func handleLinks(w http.ResponseWriter, r *http.Request) {
var htmlBody = `

Api OpenID Connect-OAuth2`
 fmt.Fprintf(w, htmlBody)
 log.Printf(" Enviado al Front los Links a los accesos delegados.")
} // FIN Manejador de las peticiones a '/links'
// Manejador de las peticiones a '/google/login'
func handleGoogleLogin(w http.ResponseWriter, r *http.Request) {
// Establecemos como proveedor de acceso Google
http.Redirect(w, r, googleconfig.AuthCodeURL(state), http.StatusFound)
} // FIN Manejador de las peticiones a ‘/google/login'
// Manejador de las llamadas a '/callback'
func handleCallback(w http.ResponseWriter, r *http.Request) {
var htmlHead = ` 
 
Api OpenID Connect-OAuth2 `
if r.URL.Query().Get("state") != state {
http.Error(w, "state no encontrado", http.StatusBadRequest)
return
}
oauth2Token, err := googleconfig.Exchange(ctx, r.URL.Query().Get("code"))
if err != nil {
http.Error(w, "Fallo al intercambiar el Token: "+err.Error(), http.StatusInternalServerError)
return }
userInfo, err := googleprovider.UserInfo(ctx, oauth2.StaticTokenSource(oauth2Token))
log.Printf("Token obtenido")
if err != nil {
http.Error(w, "Fallo al recuperar los datos del usuario: "+err.Error(), http.StatusInternalServerError)
return }
log.Printf("Datos de usuario obtenidos del Servidor de Recursos")
htmlBody := `  ` + `Datos del usuario: 
    ` +`
  • ` + userInfo.Subject +`
  • ` +`
  • ` + userInfo.Email +`
  • ` + `
` fmt.Fprintf(w, htmlHead + htmlBody) log.Printf("Datos de usuario enviados al front ") } // FIN Manejador de las llamadas a '/callback' // Función principal func main() { // Asignamos los manejadores http.HandleFunc("/", handleMain) http.HandleFunc("/links", handleLinks) http.HandleFunc("/google/login", handleGoogleLogin) http.HandleFunc("/callback", handleCallback) log.Printf("Servidor activo en http://%s/", URL) log.Fatal(http.ListenAndServe(URL, nil)) } // FIN Función principal

 

 

 

He leído y acepto la política de privacidad
Acepto recibir emails sobre actividades de recruiting NTT DATA