nodelib-atle-base-security
Biblioteca de segurança para aplicações desenvolvidas com o chassis.
Introdução
A biblioteca de segurança do chassis contém um conjunto de middlewares para immplementar controles de segurança em aplicações baseadas no servidor ExpressJS.
A autenticação e autorização baseia-se no mecanismo JWT (JSON Web Tokens), enviado como um bearer token no header Authorization
.
Para determinar se um determinado token é válido, a biblioteca deve ser configurada com a URL de onde serão baixadas as chaves públicas utilizadas para verificação da assinatura.
Após a validação da assinatura, a biblioteca extrai do token a lista de roles do mesmo, os quais são utilizados para implementar os controles de acesso. Opcionalmente, os roles extraidos do token podem passar por um mecanismo de mapeamento, de forma a permitir que a aplicação não tenha que ser alterada nos diferentes ambientes.
Incluindo a biblioteca em seu projeto
$ npm i @collabee-tech/collabee-ch-security
Utilizando o middleware global de segurança
A função authProviderMiddleware
cria o middleware de segurança global utilizando configurações padrão:
import { authProviderMiddleware } from '@collabee-tech/collabee-ch-security'
let express = require('express');
let app = express();
app.use(authProviderMiddleware())
NOTA: O middleware deve ser adicionado à aplicação via método
use
ANTES da mesma ser iniciada
Adicionando restrições de segurança aos endpoints
Utilize a função rolesAllowed
para criar um middleware que limita o acesso a determinado endpoint a usuários que tenham determinado role:
import { rolesAllowed } from '@collabee-tech/collabee-ch-security'
app.get("/resource", rolesAllowed("admin"), (req,res,next) => {
res.send("Só para admins");
})
Configuração da URL das chaves públicas
A biblioteca utiliza a variável de ambiente COLLABEE_SECURITY_JWKS_URL
para determinar o local de onde o arquivo padrão JWKS será baixado:
$ export COLLABEE_SECURITY_JWKS_URL=https://collabee.io/openid/connect/jwks.json
NOTA: O gateway utiliza certificados assinados pela CA interna da Collabee. Antes de executar sua aplicação, verifique se os certificados estão instalados no ambiente de execução do nodejs. Uma forma simples de fazer esta verificação é executar o comando
curl -v https://endereco-do-jwks
.
Configuração do tempo de vida das chaves públicas
A biblioteca mantem as chaves públicas em um cache interno, o qual é renovado em intervalos periódicos. Por padrão, este intervalo é de 5 minutos, mas pode ser ajustado por meio da variável de ambiente COLLABEE_SECURITY_JWKS_MAX_AGE
. O valor desta variável corresponde ao tempo em minutos
entre atualizações do cache.
Mapeamento de roles físicas em roles lógicas
A biblioteca de segurança permite que o mecanismo de mapeamento das roles extraidas do JWT (roles "físicas") sejam mapeadas em roles "lógicas", as
quais são aquelas utilizadas como argumentos na função rolesAllowed
.
Para casos simples, a biblioteca provê a classe SimpleRoleMapper
, que utiliza um mapa simples em seu construtor. O código abaixo mostra um exemplo
de como carregar este mapa a partir de um arquivo de configuração externo:
import { authProviderMiddleware, SimpleRoleMapper } from '@collabee-tech/collabee-ch-security'
let roles = require(process.cwd() +"/config/roles.json");
let mapper = new SimpleRoleMapper(roles);
let express = require('express');
let app = express();
app.use(authProviderMiddleware(mapper))
O mapa lido arquivo roles.json
deve ter como chaves os roles "físicos" e respectivos roles "lógicos":
{
"ACME_BASE_ADMIN_QA": "admin",
"ACME_BASE_USER_QA": "user"
}
Caso a aplicação necessite uma lógica mais complexa de mapeamento, ela deve criar suam própria implementação da interface RoleMapper
e passá-la
para o método authProviderMiddleware
:
import { RoleMapper } from '@collabee-tech/collabee-ch-security'
export class CustomRoleMapper implements RoleMapper {
mapRole(s: string): string[] {
// ... implementação da lógica de mapeamento
return myMappedRoles
}
}
NOTA 1: O método
mapRole
retorna uma lista de roles lógicos, o que permite que um único role físico seja mapeado para mais de um role lógico.
NOTA 2: Caso o role físico passado como argumento não possua role lógico correspondente,
mapRole
deve retornar uma lista vazia
Acessando informações do usuário autenticado em um controller
O middleware de segurança adiciona na chave REQUEST_PRINCIPAL_KEY
um objeto do tipo Principal
, o qual permite aos controllers
ter acesso a informações do usuário logado:
import {REQUEST_PRINCIPAL_KEY, Principal } from '@collabee-tech/collabee-ch-security'
app.get('/me', (req, res, next) => {
let p = req[REQUEST_PRINCIPAL_KEY] as Principal
// Acesso ao "username"
let subject = await p.subject();
// Determina se o usuário corrente possui ou não determinado role
let isAdmin = await p.isInRole("admin")
// Determina se o usuário está autenticado
let isAuthenticated = await p.isAuthenticated();
})
URLs públicas
Por padrão a biblioteca de segurança bloqueia o acesso de qualquer requisição que não tenha um header de autenticação associado. Caso a aplicação tenha URLs públicas, é necessário passar um AuthorizationManager customizado para o middleware global criado pela função authProviderMiddleware().
Para facilitar esta liberação no caso mais comum, onde as URLs públicas são bem conhecidas, utilize a classe SimpleAuthorizationManager:
// Libera acessos aos caminhos indicados
let customAuthManager = new SimpleAuthorizationManager("/docs","/health", "/metrics");
app.use(authProviderMiddleware(null,null, customAuthManager));