external-login — backend (Fase 2)
Implementação do login externo no ecosif-auth: validação criptográfica do token IdP, provisionamento de usuário e emissão de JWT ECOSIF.
Contrato HTTP: external-login-api.md
Variáveis de ambiente: variaveis_autenticacao_baseline.md
Starter JWT (Fase 1): starter-security-jwt.md
Fluxo (baseline .env-dev)
Angular MSAL popup
→ id_token Microsoft
→ POST /api/auth/external-login { provider: "AZURE", token, tokenType: "ID_TOKEN" }
→ AzureIdentityProviderValidator (JWKS Entra)
→ UserProvisioningService.findOrProvision (auto-create se necessário)
→ TokenProvider.createToken → JWT ECOSIF
→ { accessToken, user, tenantName }
Login local não passa por este fluxo — continua em POST /api/auth/signin.
Componentes entregues
| Componente | Pacote / classe | Função |
|---|---|---|
| Controller | ExternalLoginController |
POST /api/auth/external-login |
| Orquestração | ExternalAuthenticationService |
Validator → provision → JWT |
| Factory | IdentityProviderValidatorFactory |
Resolve validator por provider |
| Azure simples | AzureIdentityProviderValidator |
@ConditionalOnExpression ECOSIF_AUTH_PROVIDER=AZURE |
| Azure Enterprise | AzureEnterpriseIdentityProviderValidator |
ECOSIF_AUTH_PROVIDER=AZURE_ENTERPRISE |
GoogleIdentityProviderValidator |
ECOSIF_AUTH_PROVIDER=GOOGLE |
|
| JWKS | RemoteJwksTokenValidator |
Assinatura, iss, aud, exp |
| DTO | ExternalIdentity |
oid/sub, email, username, groups (MVP4) |
| Provisionamento | UserProvisioningService |
Auto-create, defaults env, identity_provider_link |
| Config | ExternalAuthProperties + application.yml ecosif.auth.* |
Mapeamento env → propriedades |
Removido (MVP3): POST /api/auth/signin-azure; signin com "azure": true retorna 400.
Regra operacional importante
ECOSIF_AUTH_PROVIDER define qual validator Spring carrega (um por ambiente).
| Env | Bean ativo | provider válido no body |
|---|---|---|
AZURE |
AzureIdentityProviderValidator |
AZURE |
AZURE_ENTERPRISE |
AzureEnterpriseIdentityProviderValidator |
AZURE_ENTERPRISE |
GOOGLE |
GoogleIdentityProviderValidator |
GOOGLE |
NONE |
Nenhum validator externo | external-login retorna 400 |
Se o frontend enviar GOOGLE com ECOSIF_AUTH_PROVIDER=AZURE → 400 Provedor não suportado ou desabilitado.
Validação por provedor
Azure / Azure Enterprise
| Verificação | Regra |
|---|---|
| JWKS | https://login.microsoftonline.com/{tenant}/discovery/v2.0/keys |
| Issuer | ECOSIF_AZURE_EXPECTED_ISSUER ou derivado do tenant |
| Audience | ECOSIF_AZURE_EXPECTED_AUDIENCE ou ECOSIF_AZURE_CLIENT_ID; Enterprise + access token também ECOSIF_AZURE_API_AUDIENCE |
| Username | preferred_username → email → upn → sub |
| Verificação | Regra |
|---|---|
| JWKS | https://www.googleapis.com/oauth2/v3/certs |
| Issuer | ECOSIF_GOOGLE_EXPECTED_ISSUER (default https://accounts.google.com) |
| Audience | ECOSIF_GOOGLE_EXPECTED_AUDIENCE ou ECOSIF_GOOGLE_CLIENT_ID |
email_verified deve ser true |
Provisionamento (MVP1 baseline)
Lê variáveis repassadas pelo docker-compose ao container ecosif-auth:
| Variável | Default baseline | Efeito |
|---|---|---|
ECOSIF_AUTH_AUTO_PROVISION |
true |
Cria gr_user no primeiro login |
ECOSIF_AUTH_DEFAULT_TENANT |
TEMP_TENANT |
Tenant do usuário novo |
ECOSIF_AUTH_DEFAULT_ROLE |
STAFF |
Role inicial |
ECOSIF_AUTH_DEFAULT_CREATED_BY |
AZURE_AD |
Campo created_by |
ECOSIF_AUTH_DEFAULT_EXPIRY_TYPE |
A |
expiry_type |
ECOSIF_AUTH_DEFAULT_EXPIRY_YEARS |
1 |
Validade da conta |
Com ECOSIF_AUTH_AUTO_PROVISION=false → 404 Usuário não encontrado.
MVP4 (groups/claims): ver mvp4-identidade.md.
Segurança HTTP
POST /api/auth/external-loginé público (sem JWT ECOSIF) —WebSecurityConfigpermite/api/auth/**.- Resposta de sucesso: JWT ECOSIF no body (
accessToken), não no header. - Logs:
provider+username; nunca o token completo.
Testes automatizados
| Teste | Cobertura |
|---|---|
ExternalLoginControllerTest |
Validação bean (@NotBlank), delegação ao service |
ExternalAuthenticationServiceTest |
200, 400 provider inválido, 401 token/usuário inativo, 404 sem auto-provision |
UserProvisioningServiceTest |
Auto-create, mapping, link identity_provider_link |
AzureIdentityProviderValidatorTest |
Mapeamento de claims Microsoft |
GoogleIdentityProviderValidatorTest |
Mapeamento Google + JWKS mock + audience/issuer/email_verified |
RemoteJwksTokenValidatorTest |
Regras JWKS (unitário) |
GroupMappingServiceTest |
Mapping YAML (MVP4) |
Executar:
cd ecosif-auth
mvn test -Dtest=ExternalLoginControllerTest,ExternalAuthenticationServiceTest,UserProvisioningServiceTest,AzureIdentityProviderValidatorTest,GoogleIdentityProviderValidatorTest,RemoteJwksTokenValidatorTest,GroupMappingServiceTest
Checklist homologação (baseline Azure simples)
Com .env-dev (ECOSIF_AUTH_PROVIDER=AZURE, ECOSIF_AUTH_AUTO_PROVISION=true).
Evidência: pen-test P4-06 (2026-07-07) + aceite MANUAL homolog.
- [x]
POST /api/auth/external-logincom id_token válido → 200 +accessToken - [x] Token Microsoft inválido/expirado → 401
- [x]
providerdiferente do env → 400 - [x] Usuário novo → criado em
gr_usercomTEMP_TENANT/STAFF - [x] Segundo login do mesmo usuário → 200 sem duplicar usuário
- [x]
POST /api/auth/signinlocal continua funcionando - [x] JWT retornado aceito em
GET /ecosif-masterdata/...comAuthorization: Bearer
Critérios de aceite (Fase 2)
- [x]
external-loginpara AZURE, AZURE_ENTERPRISE e GOOGLE (validators condicionais) - [x] Validação JWKS (Microsoft + Google)
- [x] Provisionamento MVP1 por env vars
- [x]
application.ymlecosif.auth.providers+provisioning - [x] Legado
signin-azureremovido;azure: true→ 400 - [x] Testes unitários do fluxo principal (incl.
GoogleIdentityProviderValidatorTest) - [x] Teste integração com id_token real (jwt.ms + homolog 2026-07-07)
Pendências pós-Fase 2 (não bloqueiam)
| Item | Fase | Notas |
|---|---|---|
| Docs integradores + OpenAPI | ✅ | docs/dev/integradores/, SpringDoc |
| Logs estruturados | ✅ | ExternalAuthLog (external_login) + LocalAuthLog (local_signin) — sem token/senha |
Flyway identity_provider_link |
✅ | V0.7.00.9__identity_provider_link.sql (corrigido de V0.7.00.8 duplicado) |
Rate limit external-login |
✅ | P4-04 — ExternalLoginRateLimitFilter |
| Teste E2E id_token real | ✅ | Pen-test 2026-07-07 (E-02..E-04 + homolog) |