Segurança & Controle de Acesso

O módulo security expõe actors de autenticação, scopes de autorização, políticas e token stores. Esta página é uma referência de API com receitas parciais de autorização. IDs de registry, actors, metadados de requisição, valores de tokens, objetos da aplicação como user e doc e callbacks como show_admin_features vêm da aplicação; os exemplos não formam um deployment completo de autenticação.

O Wippy usa o modo de segurança estrito por padrão. A entrada executável deve habilitar security, ter um actor e um scope e autorizar exatamente as operações chamadas. Em particular, criar ou alterar scopes exige security.actor.create ou security.scope.create; consultas ao registro exigem security.policy.get ou security.policy_group.get; operações com tokens exigem security.token_store.get e a permissão específica da operação. new_actor, new_scope, scope:with, scope:without e a obtenção negada de token_store lançam erro Lua em vez de retornar um error estruturado. Conceda esses pré-requisitos no contexto de segurança da entrada. Veja Modelo de Segurança para configurar.

Carregamento

local security = require("security")

actor

Retorna o actor de segurança atual do contexto de execução.

local actor = security.actor()
if actor then
    local id = actor:id()
    local meta = actor:meta()
    -- Use only the fields required for authorization or application logic.
    local role = meta.role
end

Os metadados do actor podem conter identificadores ou dados pessoais. Não registre a tabela completa de metadados nem copie segredos para ela.

Retorna: Actor|nil

scope

Retorna o escopo de segurança atual do contexto de execução.

local scope = security.scope()
if scope then
    local policies = scope:policies()
    for _, policy in ipairs(policies) do
        print("Active policy:", policy:id())
    end
end

Retorna: Scope|nil

can

Verifica se o contexto atual permite uma ação em um recurso.

-- Check read permission
if not security.can("read", "user:" .. user_id) then
    return nil, errors.new("Não pode ler dados do usuário"):kind(errors.PERMISSION_DENIED)
end

-- Check write permission
if not security.can("write", "order:" .. order_id) then
    return nil, errors.new("Não pode modificar pedido"):kind(errors.PERMISSION_DENIED)
end

-- Check with metadata
local allowed = security.can("delete", "document:" .. doc_id, {
    owner_id = doc.owner_id,
    department = doc.department
})
Parâmetro Tipo Descrição
action string Ação a verificar
resource string Identificador do recurso
meta table Metadados adicionais (opcional)

Retorna: boolean

new_actor

Cria um novo actor com ID e metadados.

-- Create user actor
local actor = security.new_actor("user:" .. user.id, {
    role = user.role,
    department = user.department,
    email = user.email
})

-- Create service actor
local service_actor = security.new_actor("service:payment-processor", {
    type = "service",
    version = "1.0.0"
})
Parâmetro Tipo Descrição
id string Identificador único do actor
meta table Pares chave-valor de metadados

Retorna: Actor

new_scope

Cria um novo escopo customizado.

-- Empty scope
local scope = security.new_scope()

-- Scope with policies
local read_policy, read_err = security.policy("app:read-only")
if read_err then
    return nil, read_err
end
local scope = security.new_scope({read_policy})

-- Build scope incrementally
local scope = security.new_scope()
local policy1, policy1_err = security.policy("app:read")
if policy1_err then
    return nil, policy1_err
end
local policy2, policy2_err = security.policy("app:write")
if policy2_err then
    return nil, policy2_err
end
scope = scope:with(policy1):with(policy2)

Cada alternativa acima é um padrão de construção isolado. new_scope e scope:with podem gerar erro quando faltar contexto ou houver negação de permissão; elas não retornam nil, error nessas verificações.

Retorna: Scope

policy

Obtem uma política do registry.

local policy, err = security.policy("app:admin-access")
if err then
    return nil, err
end

-- Evaluate policy
local result = policy:evaluate(actor, "delete", "user:123")
if result == "allow" then
    -- permitted
elseif result == "deny" then
    -- forbidden
else
    -- undefined, check other policies
end
Parâmetro Tipo Descrição
id string ID da política "namespace:nome"

Retorna: Policy, error

named_scope

Obtem um grupo de políticas pre-definido.

-- Get admin scope
local admin_scope, err = security.named_scope("app:admin")
if err then
    return nil, err
end

-- Use for elevated operations
local result = admin_scope:evaluate(actor, "delete", "user:123")

Carregar um scope não eleva o contexto de execução atual. A chamada produz um valor para avaliação explícita ou para uma API que aceite um scope; o chamador ainda precisa de permissão para executar a operação protegida.

Parâmetro Tipo Descrição
id string ID do grupo de políticas

Retorna: Scope, error

token_store

Obtem um token store para gerenciar tokens de autenticação.

local store, err = security.token_store("app:tokens")
if err then
    return nil, err
end

-- Use store...
return store:close()

O chamador é responsável pelo token store adquirido até chamar close(). Feche-o depois da operação final em todos os caminhos de sucesso ou erro verificados; fechamentos repetidos são seguros. Uma negação de permissão durante a aquisição gera um erro Lua, enquanto falhas de lookup e de recurso retornam nil, error.

Parâmetro Tipo Descrição
id string ID do token store "namespace:nome"

Retorna: TokenStore, error

Métodos do Actor

Método Retorna Descrição
actor:id() string Identificador do actor
actor:meta() table Metadados do actor

Métodos do Scope

with / without

Adiciona ou remove políticas do escopo.

local scope = security.new_scope()

-- Add policy
local write_policy, err = security.policy("app:write")
if err then
    return nil, err
end
scope = scope:with(write_policy)

-- Remove policy
scope = scope:without("app:read-only")

with e without retornam novos valores de scope imutáveis e geram erro quando security.scope.create não é permitido para o recurso with ou without.

evaluate

Avalia todas as políticas no escopo.

local result = scope:evaluate(actor, "read", "document:123")
-- "allow", "deny", or "undefined"

if result ~= "allow" then
    return nil, errors.new("Acesso negado"):kind(errors.PERMISSION_DENIED)
end

contains

Verifica se o escopo contem uma política.

if scope:contains("app:admin") then
    show_admin_features()
end

policies

Retorna todas as políticas no escopo.

local policies = scope:policies()
for _, policy in ipairs(policies) do
    print(policy:id())
end

Retorna: Policy[]

Métodos da Policy

Método Retorna Descrição
policy:id() string Identificador da política
policy:evaluate(actor, action, resource, meta?) string "allow", "deny", ou "undefined"

Métodos do TokenStore

create

Criar token de autenticação.

local actor = security.new_actor("user:123", {role = "user"})
local scope, scope_err = security.named_scope("app:default")
if scope_err then
    return nil, scope_err
end
local store, store_err = security.token_store("app:tokens")
if store_err then
    return nil, store_err
end

local token, err = store:create(actor, scope, {
    expiration = "24h",  -- or milliseconds
    meta = {
        login_ip = request_ip,
        user_agent = user_agent
    }
})
store:close()
if err then
    return nil, err
end
return token

request_ip e user_agent são valores de requisição fornecidos pela aplicação. Armazene apenas os metadados necessários às decisões de segurança, aplique limites de retenção e nunca registre nem persista o bearer token retornado fora do credential store previsto.

Parâmetro Tipo Descrição
actor Actor Actor para o token
scope Scope Escopo de permissões
options.expiration string/number String de duração ou ms
options.meta table Metadados do token

Retorna: string, error

validate

Validar token e obter actor/scope.

local actor, scope, err = store:validate(token)
store:close()
if err then
    return nil, errors.new("Token inválido"):kind(errors.PERMISSION_DENIED)
end

Aqui e abaixo, store é um handle ativo com proprietário e token é uma credencial bearer não confiável fornecida pelo chamador. Não registre o token, inclusive em erros de validação ou revogação.

Retorna: Actor, Scope, error

revoke

Invalidar um token.

local ok, err = store:revoke(token)
store:close()
if err then
    return nil, err
end

Retorna: boolean, error

close

Liberar o recurso do token store.

store:close()

Retorna: boolean

Permissões

Operações de segurança estao sujeitas a avaliação de política de segurança.

Acoes de Segurança

Ação Recurso Descrição
security.policy.get ID da Policy Acessar definicoes de política
security.policy_group.get ID do Grupo Acessar escopos nomeados
security.scope.create custom, with, without Criar escopos customizados (new_scope) e adicionar/remover políticas (scope:with, scope:without)
security.actor.create ID do Actor Criar actors
security.token_store.get ID da Store Acessar token stores
security.token.validate ID da Store Validar tokens
security.token.create ID da Store Criar tokens
security.token.revoke ID da Store Revogar tokens

Veja Modelo de Segurança para configurar as políticas.

Erros

Condição Tipo Retentável
Sem contexto errors.INTERNAL não
ID de token store vazio errors.INVALID não
Permissão negada (policy, named_scope, token create/validate/revoke) errors.INVALID não
Permissão negada (new_scope, new_actor, token_store, scope:with/without) levantada como erro Lua não
Política não encontrada errors.INTERNAL não
Token store não encontrado errors.INTERNAL não
Token store fechado errors.INTERNAL não
Formato de expiração inválido errors.INVALID não
Validação de token falhou errors.INTERNAL não
local store, err = security.token_store("app:tokens")
if err then
    if errors.is(err, errors.INVALID) then
        print("Invalid request:", err:message())
    end
    return nil, err
end
store:close()

Veja Tratamento de Erros para trabalhar com erros.

Veja Também