Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Contenido
Introducción 2
Propósito 2
Especificaciones técnicas 2
Pre - requisitos 2
Ejecución del programa 3
Variables de entorno 4
Desplegar Contenedor 6
Esquemas en la base de datos 6
Cargar datos en mongodb 8
Obtención del token 9
Obtención del token utilizando el formato base 64 9
Obtención del token utilizando el Body 10
Scopes 11
Respuesta de la solicitud 11
Transferencia de conocimiento 13
Tecnologías utilizadas 13
Funciones utilizadas 13
Servicios MongoDB 15
mongoUser 15
mongoClient 16
mongoToken 16
Modelos y Esquemas 16
Lógica principal 17
Respuestas de error y causas 18
Glosario 19
Referencias 19
OAuth 2.0
1. Introducción
El presente documento describe el sistema de autorización Oauth 2.0 para los
mecanismos de interconexión para los Sistemas 2 (S2) y 3 (S3) con la Plataforma
Digital Nacional (PDN) en un ambiente de pruebas. Esta información es
proporcionada a los equipos técnicos de las Secretarías Ejecutivas de los Sistemas
Locales Anticorrupción (SESLAs) y la Secretaría Ejecutiva del Sistema Nacional
Anticorrupción (SESNA) para la implementación de estos mecanismos, con datos
sintéticos, en tres estados pilotos (Chihuahua, Jalisco y Oaxaca).
1. Instalación: el cual muestra los pasos para la preparación del ambiente local,
contempla lo relacionado a Docker, Docker Compose y Mongo. Ref.[2].
Adicionalmente, se cuenta con un Anexo que incluye una serie de guías sobre las
diversas tecnologías utilizadas:
● Anexo, Ref.[4].
1.1. Propósito
2. Especificaciones técnicas
2.1. Pre - requisitos
Versión estable SLP (soporte de largo-plazo) de NodeJs y NPM previamente
instalados, si no se cuenta con ellos puede descargarlos del siguiente enlace
https://nodejs.org/en/download/
OAuth 2.0
- ./mongod.conf:/etc/mongod.conf
- ./log/:/var/log/mongodb/
env_file:
- .env
command: ["-f", "/etc/mongod.conf"]
oauth20:
restart: always
container_name: oauth20
build:
context: ../piloto_oauth2.0/
dockerfile: Dockerfile
ports:
- 9003:9003
links:
- mongodb
depends_on:
- mongodb
Nota: La identación es importante.
La variable ports incluye el mapeo entre el puerto del host y el puerto interno del
contenedor 9003:9003.
// SEED
SEED = YTBGD9YjAUhkjQk9ZXcb
//MONGO CONFIG
USERMONGO = oauthUsr
PASSWORDMONGO= Xy37v7TNhuDrB
HOSTMONGO = mongodb:27017
DATABASE= oauth20
PORTSERVER=9003
Nota: Las diagonales // al inicio de línea indican que es un comentario.
RTEXT: Contiene el número de segundos 900 para la expiración del refresh token.
Este número debe ser mayor al tiempo de expiración del token.
haciendo una petición a la base de datos y verificando los parámetros para generar
un nuevo token.
$ docker-compose up -d
● Verificar que
todos los contenedores dentro del archivo docker-
compose.yml estén corriendo con el siguiente comando:
$ docker-compose ps
Usuarios
Nombre de la colección: users
campo
Clientes
Nombre de la colección: clients
Nombre del
Tipo Valor posible Descripción
campo
Tokens
Nombre de la colección: tokens
Nombre del
Tipo Valor posible Descripción
campo
iwiZXhwIjoxNTk1MzA0MDYyfQ.n
5JLQo0fl7l0LbJ_anPfsA3O2r-
EMlGmvK0fJ-LP2Zg'
'OztWyf5YGjPJxrkkx4feeRGT3e
up21yRMZgfMuNLrwBKvsIcKT3u6
PvyjGlfc951nLhr0tNOZT4UezG9
71FXUNBaUNDaWNO6h8Uzno62wJA Token (random string) el
refresh_token String
5K3iRF9smW4IdgmXMpkr4fB0C5K cual se utiliza para generar
fQmsjNZL02bTzrQBmJ4BEOTmRjs un nuevo token (flujo
eAkr0A3JQU3vFtIyyXHQWxVaW03 refresh token)
tNDgu001feEgQ15XilnmWq9zubn
gnnLLoZrN6bah3UhGxSwFgydgzR
9W19CpxDdryrsE'
db.clients.insert([{
clientId: 'txm.global',
clientSecret: 'pass',
grants: []
}
])
db.tokens.insert([{
Access_token:'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1
c2VybmFtZSI6ImVjYW1hcmdvIiwianRpIjoiR1VoQ1dNR0siLCJzY29
wZSI6IndyaXRlICIsImlhdCI6MTU5NTMwNDAwMiwiZXhwIjoxNTk1Mz
A0MDYyfQ.n5JLQo0fl7l0LbJ_anPfsA3O2r-EMlGmvK0fJ-LP2Zg',
expires_in: 300,
refresh_token:'OztWyf5YGjPJxrkkx4feeRGT3eup21yRMZgfMuNL
rwBKvsIcKT3u6PvyjGlfc951nLhr0tNOZT4UezG971FXUNBaUNDaWNO
6h8Uzno62wJA5K3iRF9smW4IdgmXMpkr4fB0C5KfQmsjNZL02bTzrQB
mJ4BEOTmRjseAkr0A3JQU3vFtIyyXHQWxVaW03tNDgu001feEgQ15Xi
lnmWq9zubngnnLLoZrN6bah3UhGxSwFgydgzR9W19CpxDdryrsE',
Refresh_token_expires_in: 600
Refresh_token_expires_in_date: 1595275826
client: {clientId: 'pdn.resource.1'},
user: {username: 'ecamargo'}
}
])
Nota: Los valores utilizados son para ejemplificar y servir de contexto para los
comandos en este documento.
OAuth 2.0
Para poder generar un nuevo token se requiere enviar una solicitud de tipo POST a
la ruta http://<IP_HOST>:9003/oauth/token. La variable <IP_HOST>
es la dirección IP donde está instalado el Sistema de la PDN.
OAuth 2.0
{
clientId: 'txm.global',
clientSecret: "",
grants: []
}
Para obtener el token, se debe ejecutar el siguiente comando desde el CLI del
sistema operativo de nuestro ordenador
curl --location --request POST '<IP_HOST>:9003/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=txm.global' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'username=ecamargo' \
--data-urlencode 'password=123456' \
--data-urlencode 'scope=read' \
--data-urlencode 'client_secret=pass'
--data-urlencode 'client_secret='
OAuth 2.0
2.8. Scopes
Los scopes son privilegios que se relacionan directamente al usuario para restringir
el nivel de acceso a los recursos protegidos (API).
Cuando se envía una solicitud POST, se pueden enviar los scopes solicitados por
medio del parámetro scope, estos se validan en el servidor de autorización y se
agregan a la respuesta solamente en caso de estar asociados al usuario. En caso
de enviar en la petición un scope inválido para el usuario u omitir el scope para un
usuario que tiene scopes asociados, se retornará un mensaje de error.
Debido a que los scopes son opcionales, o sea, no están definidos; esto queda fuera
del alcance de la implementación Oauth 2.0. Se recomienda generar una colección
con ellos y generar un método de asociación hacia los usuarios.
{
"access_token":
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImVjYW1
hcmdvIiwianRpIjoiYjdjOFBEZkYiLCJzY29wZSI6InJlYWQgIiwiaWF0Ijox
NTk2MDU3ODI2LCJleHAiOjE1OTYwNTgxMjZ9.Zoe3oJwjsuM_0r2Z72fyZnaW
qO0yNLZ06jm3yReDzqE",
"token_type": "bearer",
"expires_in": 300,
"refresh_token":
"D2MeNrnDRnMBsLdV6LQkoDow7Y5Mt8eLgaM76FR3BNVbz6TdtXWXhvB6wLaR
R5jVaj2oCkNLge4ODw1TYSnop7dHJ4zRGgK0iE6CrlcXsrN97XVkYg8Kr75bW
KSBfAm3q4CoRPr31XB3XyV1agFTSdAbYQ6XutVxEsGytZg7ljDBeO0bKicVkS
F7qMTlFWilHtuG7mKCcRJd1y5dROhXI15TvemNlB5eD6LVyyyE3qmKf1Vx9nG
8MYZb4tSV8Ky5",
"refresh_token_expires_in": 600,
"scope": "read"
}
Nota: El resultado puede variar de la imagen mostrada, verifique que los parámetros
definidos estén presentes en la respuesta esperada.
3. Transferencia de conocimiento
3.1. Tecnologías utilizadas
● NodeJS v12.18.2
● MongoDB 4.2.8
mongoose.connect('mongodb://'+process.env.USERMONGO+':'+process.env
.PASSWORDMONGO+'@'+process.env.HOSTMONGO+'/'+process.env.DATABASE,
{ useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('Connect to MongoDB..'))
.catch(err => console.error('Could not connect to MongoDB..',
err))
var tokenResponse = {
access_token: access_token,
token_type: 'bearer',
expires_in: expiresin, //value in seconds
refresh_token: randtoken.uid(256),
refresh_token_expires_in: Number(process.env.RTEXT) , //value
in seconds
refresh_token_expires_in_date: Math.floor(Date.now() / 1000) +
Number(process.env.RTEXT) ,
scope: scope,
client: {clientId: clientId},
user: {username : username}
}
return tokenResponse;
}
OAuth 2.0
let clientId;
let clientSecret ='';
if (!req.headers.authorization ||
req.headers.authorization.indexOf('Basic ') === -1) {
//check the body
if(req.body.client_id){
clientId = req.body.client_id;
if(req.body.client_secret){
clientSecret = req.body.client_secret;
}
}
}else{
const base64Credentials = req.headers.authorization.split('
')[1];
const credentials = Buffer.from(base64Credentials,
'base64').toString('ascii');
[clientId, clientSecret] = credentials.split(':');
}
OAuth 2.0
También se exportan los servicios que son los que realizan las peticiones a la base
de datos :
var userService= require("./mongo/service/mongoUser");
var clientService = require("./mongo/service/mongoClient");
var tokenService = require("./mongo/service/mongoToken");
3.3.1. mongoUser
Dentro del archivo mongoUser se tienen las siguientes funciones:
● getUser(username, password). Esta función devuelve el usuario
correspondiente al username y el password recibidos en el método, en caso de
que existan en la base de datos
3.3.2. mongoClient
Dentro del archivo mongoClient se tiene la siguiente función:
● getClient (clientId).Esta función retorna el cliente correspondiente al
parámetro de entrada clientId
OAuth 2.0
3.3.3. mongoToken
Por último, se tiene el archivo mongoToken donde se tienen las siguientes
funciones:
● getTokenByRefresh (refresh_token). Esta función permite obtener el
documento token en base al parámetro de entrada refresh_token, esto es
usado en el flujo refresh token para la validación de los campos.
schemaInstance);
module.exports = modelInstance;
6. Se genera el token
4. Se valida que sea el mismo cliente el que envía la solicitud al que está
asociado el token
Status del
Mensaje de error causa
error
4. Glosario
El glosario general se incluye en el anexo Guía de ayuda, Ref.[4].
5. Referencias
Ref. Nombre del documento
2 Instalación
3 Generador
4 Anexo