Migração para os contratos de segurança e dados da versão 4.1
Este guia complementa a migração Jakarta EE 10 existente no guia técnico. As mudanças preservam compatibilidade onde seguro; defaults de autenticação e segredos são fail-closed.
Result e MutableResult
Use Result<T> quando o consumidor só precisa ler conteúdo:
Result<Produto> result = service.find();
List<Produto> produtos = result.getContent();
Implementações que permitem alteração devem implementar MutableResult<T>:
MutableResult<Produto> result = new ResultSet<>();
result.setContent(produtos);
Result#setContent permanece temporariamente como ponte deprecated. Não chame
esse método em PageResult, que é imutável.
MCP seguro
Com demoiselle.mcp.security.enabled=true, inclua demoiselle-security-jwt. O
fallback sem validador real rejeita todas as credenciais. Tanto o GET SSE quanto
cada POST exigem Authorization: Bearer ...; o token do POST deve resolver para
a mesma identidade vinculada à sessão.
demoiselle.mcp.security.enabled=true
demoiselle.mcp.sessionTtlMillis=1800000
demoiselle.mcp.sessionIdleMillis=300000
demoiselle.mcp.maxSessions=10000
demoiselle.mcp.toolRateLimitRequests=60
demoiselle.mcp.toolRateLimitWindowSeconds=60
HashCash
Adicione o módulo pelo BOM e configure um segredo exclusivo de pelo menos 32 bytes. Não existe segredo padrão:
<dependency>
<groupId>org.demoiselle.jee</groupId>
<artifactId>demoiselle-security-hashcash</artifactId>
</dependency>
demoiselle.security.hashcash.hashcashKey=${secret:env:HASHCASH_KEY}
demoiselle.security.hashcash.timetoLiveMilliseconds=300000
demoiselle.security.hashcash.difficultyBits=20
Desafios antigos sem recurso, jti, bits e assinatura válida não são aceitos.
Chaves JWT rotativas
A configuração local compacta é uma lista separada por ;:
demoiselle.security.jwt.activeKeyId=key-2026
demoiselle.security.jwt.keys=key-2025:PUBLIC_DER_B64:-:1798761600000;key-2026:PUBLIC_DER_B64:PRIVATE_DER_B64
demoiselle.security.jwt.keyRefreshSeconds=300
demoiselle.security.jwt.keyRotationWindowSeconds=3600
Cada entrada usa
kid:publicKeyBase64Der[:privateKeyBase64Der[:validUntilEpochMillis]]. Use -
para uma chave apenas de verificação. Um kid explícito desconhecido nunca cai
na chave fallback.
Referências de segredo
Valores de configuração podem apontar para providers incluídos:
app.password=${secret:env:APP_PASSWORD}
app.token=${secret:sys:app.token}
app.privateKey=${secret:file:/run/secrets/private-key}
A propriedade de sistema
demoiselle.configuration.secret.cache.ttl.seconds controla o cache (300 por
padrão; 0 desabilita). Provider ausente ou indisponível causa erro; não há
fallback para texto default.
Proxy e estado de segurança
Headers encaminhados são ignorados até que o peer imediato seja confiável:
demoiselle.security.trustedProxies=10.0.0.10,10.0.0.11
demoiselle.security.storeMaxEntries=100000
Não adicione ranges genéricos sem validar a topologia. Para cluster, forneça uma
implementação distribuída de SecurityStore.
Idempotência, outbox e cursor
- Anote somente operações mutáveis elegíveis com
@Idempotent; clientes devem enviarIdempotency-Keyestável por intenção de negócio. - Para garantia atômica com banco, forneça
OutboxStoreque retorneparticipatesInTransaction() == true; o store local é apropriado para testes e processo único. - Cursor é aditivo: endpoints existentes podem continuar usando
range. Sempre termine a ordenação keyset com campo único (normalmente a chave primária).
Depreciação de APIs
Use @ApiLifecycle em recurso ou método. O filtro só adiciona Deprecation,
Sunset e Link quando a aplicação ainda não definiu esses headers, permitindo
uma migração gradual sem sobrescrever políticas existentes.