molde do realm: papel atm_responsavel e mapper acompanhante_id (app dos pais); 2FA TOTP obrigatorio para atm_admin (browser-2fa-dono)

This commit is contained in:
ATM Platform
2026-10-07 12:25:37 +00:00
parent 45b7cc2a1b
commit 85035b44d6
2 changed files with 245 additions and 0 deletions
+22
View File
@@ -5,6 +5,14 @@ DERIVADO de `tenants/plataforma/realm/athleticmap-realm.json`, que e o realm
que existe hoje. Os nove papeis e o cliente `spa` sao os de la — NAO inventei
nenhum, e um papel a mais aqui seria um papel que nenhum codigo verifica.
06/10/2026 — DECIMO papel: `atm_responsavel` (responsavel legal: app dos pais
e o portal). Verificado por codigo: o cadastro o da ao marcar o acompanhante
como responsavel (AcessoAoAppServico), o SPA leva quem so o tem ao /portal, e
a TravaDaEquipe o deixa FORA da leitura da equipe. Junto, o mapper
`acompanhante_id` (atributo -> claim) nos clients `spa` e `app`, como o
`funcionario_id`. Realm que ja existe nao reimporta: rodar
`scripts/papel_responsavel_nos_realms.py --check` / `--aplicar`.
── OS MARCADORES ───────────────────────────────────────────────────────────
{{REALM}} `athleticmap-<N>` — decidido em 2026-09-19
@@ -76,3 +84,17 @@ pelos runtimes.
Nao da para resolver so no `KC_HOSTNAME` porque ele e um so, e a plataforma
depende do valor antigo — os servicos dela estao configurados com
`auth-plataforma`. Dai o `frontendUrl` por realm, que e exatamente para isto.
── DUPLO FATOR DO DONO (07/10/2026) ────────────────────────────────────────
`browserFlow: browser-2fa-dono` e os quatro `authenticationFlows`: copia do
`browser` de fabrica do 26.7.5 com OTP OBRIGATORIO para `atm_admin` (quem nao
tem configura no primeiro login) e passkey dispensando o codigo. Politica OTP
TOTP/SHA1/6 digitos/30 s (Google e Microsoft Authenticator). Os outros fluxos
(`direct grant`, `clients`...) o Keycloak cria sozinho na importacao — provado
num 26.7.5 descartavel. Realms que ja existem: `scripts/dois_fatores_nos_realms.py`
(le ESTE arquivo). Recuperacao e saida de emergencia: docs/dois-fatores-do-dono.md.
ATENCAO ao testar este molde num Keycloak local: o `frontendUrl` aponta para
`https://auth.athleticmap.com` — o formulario de login POSTA EM PRODUCAO. Zere
`attributes.frontendUrl` no realm de teste.
+223
View File
@@ -16,6 +16,197 @@
"webAuthnPolicyPasswordlessPasskeysEnabled": true,
"webAuthnPolicyPasswordlessUserVerificationRequirement": "required",
"webAuthnPolicyPasswordlessRpEntityName": "Athletic Map",
"otpPolicyType": "totp",
"otpPolicyAlgorithm": "HmacSHA1",
"otpPolicyDigits": 6,
"otpPolicyPeriod": 30,
"otpPolicyLookAheadWindow": 1,
"otpPolicyCodeReusable": false,
"browserFlow": "browser-2fa-dono",
"authenticationFlows": [
{
"alias": "browser-2fa-dono",
"description": "Copia do browser padrao (26.7.5) com OTP obrigatorio para quem tem atm_admin",
"providerId": "basic-flow",
"topLevel": true,
"builtIn": false,
"authenticationExecutions": [
{
"requirement": "ALTERNATIVE",
"priority": 10,
"userSetupAllowed": false,
"authenticatorFlow": false,
"authenticator": "auth-cookie"
},
{
"requirement": "DISABLED",
"priority": 20,
"userSetupAllowed": false,
"authenticatorFlow": false,
"authenticator": "auth-spnego"
},
{
"requirement": "ALTERNATIVE",
"priority": 25,
"userSetupAllowed": false,
"authenticatorFlow": false,
"authenticator": "identity-provider-redirector"
},
{
"requirement": "ALTERNATIVE",
"priority": 30,
"userSetupAllowed": false,
"authenticatorFlow": true,
"flowAlias": "browser-2fa-dono-forms"
}
]
},
{
"alias": "browser-2fa-dono-forms",
"description": "Usuario e senha (ou passkey), e o segundo fator",
"providerId": "basic-flow",
"topLevel": false,
"builtIn": false,
"authenticationExecutions": [
{
"requirement": "REQUIRED",
"priority": 10,
"userSetupAllowed": false,
"authenticatorFlow": false,
"authenticator": "auth-username-password-form"
},
{
"requirement": "CONDITIONAL",
"priority": 20,
"userSetupAllowed": false,
"authenticatorFlow": true,
"flowAlias": "browser-2fa-dono-otp-obrigatorio"
},
{
"requirement": "CONDITIONAL",
"priority": 30,
"userSetupAllowed": false,
"authenticatorFlow": true,
"flowAlias": "browser-2fa-dono-2fa-opcional"
}
]
},
{
"alias": "browser-2fa-dono-otp-obrigatorio",
"description": "atm_admin: OTP obrigatorio (configura no 1o login); passkey dispensa",
"providerId": "basic-flow",
"topLevel": false,
"builtIn": false,
"authenticationExecutions": [
{
"requirement": "REQUIRED",
"priority": 10,
"userSetupAllowed": false,
"authenticatorFlow": false,
"authenticator": "conditional-user-role",
"authenticatorConfig": "2fa-dono-papel-atm-admin"
},
{
"requirement": "REQUIRED",
"priority": 20,
"userSetupAllowed": false,
"authenticatorFlow": false,
"authenticator": "conditional-credential",
"authenticatorConfig": "2fa-dono-sem-passkey"
},
{
"requirement": "REQUIRED",
"priority": 30,
"userSetupAllowed": false,
"authenticatorFlow": false,
"authenticator": "auth-otp-form"
}
]
},
{
"alias": "browser-2fa-dono-2fa-opcional",
"description": "Os demais: como o padrao (2FA so de quem configurou)",
"providerId": "basic-flow",
"topLevel": false,
"builtIn": false,
"authenticationExecutions": [
{
"requirement": "REQUIRED",
"priority": 10,
"userSetupAllowed": false,
"authenticatorFlow": false,
"authenticator": "conditional-user-configured"
},
{
"requirement": "REQUIRED",
"priority": 20,
"userSetupAllowed": false,
"authenticatorFlow": false,
"authenticator": "conditional-credential",
"authenticatorConfig": "2fa-opcional-sem-passkey"
},
{
"requirement": "REQUIRED",
"priority": 30,
"userSetupAllowed": false,
"authenticatorFlow": false,
"authenticator": "conditional-user-role",
"authenticatorConfig": "2fa-opcional-nao-dono"
},
{
"requirement": "ALTERNATIVE",
"priority": 40,
"userSetupAllowed": false,
"authenticatorFlow": false,
"authenticator": "auth-otp-form"
},
{
"requirement": "DISABLED",
"priority": 50,
"userSetupAllowed": false,
"authenticatorFlow": false,
"authenticator": "webauthn-authenticator"
},
{
"requirement": "DISABLED",
"priority": 60,
"userSetupAllowed": false,
"authenticatorFlow": false,
"authenticator": "auth-recovery-authn-code-form"
}
]
}
],
"authenticatorConfig": [
{
"alias": "2fa-dono-papel-atm-admin",
"config": {
"condUserRole": "atm_admin",
"negate": "false"
}
},
{
"alias": "2fa-dono-sem-passkey",
"config": {
"credentials": "webauthn-passwordless",
"included": "false"
}
},
{
"alias": "2fa-opcional-sem-passkey",
"config": {
"credentials": "webauthn-passwordless",
"included": "false"
}
},
{
"alias": "2fa-opcional-nao-dono",
"config": {
"condUserRole": "atm_admin",
"negate": "true"
}
}
],
"roles": {
"realm": [
{
@@ -44,6 +235,10 @@
},
{
"name": "atm_financeiro-leitura"
},
{
"name": "atm_responsavel",
"description": "Responsavel legal (pai, mae ou outro): app dos pais e o portal web. Dado pelo cadastro ao marcar o acompanhante como responsavel (06/10/2026)."
}
]
},
@@ -80,6 +275,20 @@
"access.token.claim": "true",
"userinfo.token.claim": "true"
}
},
{
"name": "acompanhante_id",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"user.attribute": "acompanhante_id",
"claim.name": "acompanhante_id",
"jsonType.label": "String",
"id.token.claim": "true",
"access.token.claim": "true",
"userinfo.token.claim": "true"
}
}
]
},
@@ -123,6 +332,20 @@
"access.token.claim": "true",
"userinfo.token.claim": "true"
}
},
{
"name": "acompanhante_id",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"user.attribute": "acompanhante_id",
"claim.name": "acompanhante_id",
"jsonType.label": "String",
"id.token.claim": "true",
"access.token.claim": "true",
"userinfo.token.claim": "true"
}
}
]
}