blob: 1793dd4ad8f853291e7c39c03922fdf005526556 [file] [log] [blame]
:index-group: MicroProfile
:jbake-type: page
:jbake-status: published
= MP REST JWT com Public key do MP Config
Este é um exemplo de como configurar e usar o MicroProfile JWT 1.1 no TomEE.
== Executando o teste
Este projeto inclui uma aplicação de exemplo e um teste do Arquillian para mostrar o controle de acesso baseado em função (RBAC) com JWT no MicroProfile.
Para executar o cenário, você pode executar o seguinte comando:
[source, bash]
----
mvn clean test
----
A aplicação representa um recurso REST de livraria com alguns endpoints.
Todos esperam que o cliente forneça um JSON Web Token (JWT) válido, representando um usuário com determinadas funções.
O teste do Arquillian é responsável por gerar os JWTs e anexá-los os requests.
== Configuração no TomEE
Para ativar o JWT, você precisa anotar sua classe de aplicação REST com a anotação `org.eclipse.microprofile.auth.LoginConfig`.
Neste exemplo, a classe é `ApplicationConfig`.
Outra coisa que precisa ser feita é configurar a `public key` para verificar a assinatura do JWT anexada no cabeçalho `Authorization'.
É assinado na criação com a `private key` do issuer.
Isso é feito para evitar adulteração do token enquanto ele trafega do chamador até o endpoint.
Geralmente, a emissão do JWT ocorre em um módulo ou microsserviço especial responsável pela autenticação dos usuários.
Neste projeto de exemplo, isso acontece no `BookstoreTest`.
Cada ambiente de execução que suporta o MicroProfile JWT deveria ser capaz de verificar se a assinatura está correta e se o conteúdo assinado não é alterado ao longo do caminho.
Para fazer isso, ele precisa ter acesso a uma `public key`.
Essa `public key` pode estar no formato `PKCS#8 PEM, JWK ou JWKS`.
Desde o MP JWT 1.1 (que é suportado pelo TomEE), a chave pode ser fornecida como uma string na propriedade de configuração `mp.jwt.verify.publickey` ou como um local ou URL de arquivo especificado em `mp.jwt.verify.publickey.location` na propriedade de configuração.
Neste projeto de exemplo, você pode ver a primeira opção.
O arquivo `src/main/resource/META-INF/microprofile-config.properties` contém a seguinte entrada:
[source,properties]
----
mp.jwt.verify.publickey=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlivFI8qB4D0y2jy0CfEqFyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm+ntyIv1p4kE1sPEQO73+HY8+Bzs75XwRTYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5eUF/F9+KEBWkwVta+PZ37bwqSE4sCb1soZFrVz/UT/LF4tYpuVYt3YbqToZ3pZOZ9AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYnsIYPd99ltwxTHjr3npfv/3Lw50bAkbT4HeLFxTx4flEoZLKO/g0bAoV2uqBhkA9xnQIDAQAB
----
== Trabalhando com JWT
A classe `BookResource` neste projeto de exemplo mostra dois casos em que você pode usar a especificação MP JWT: obter o valor de uma declaração JWT e o controle de acesso baseado em função dos endpoints REST.
=== Obtenção de valores de claim
O JSON Web Token (JWT) anexado no cabeçalho HTTP `Authorization` é essencialmente um objeto JSON que contém vários atributos.
Esses atributos são chamados _claims_.
Você pode obter o valor de cada claim dentro de um bean CDI injetando-o e qualificando-o com a anotação `@Claim`.
Por exemplo, se você deseja recuperar a claim de nome de usuário preferida, fazendo o seguinte:
[source,java]
----
@Inject
@Claim(standard = Claims.preferred_username)
private String userName;
----
NOTE: Observe que você não pode injetar claims dessa maneira em uma classe de recurso REST que também contém endpoints não autenticados.
No entanto, o TomEE tentará extrair a claim do JWT.
Portanto, se não houver JWT ou se a claim não estiver lá, o request falhará.
=== Controle de acesso baseado em função (RBAC)
Uma das claims padrão definidas na especificação MP JWT é `groups`.
Ele contém uma lista de Strings, que representam os grupos aos quais o chamador pertence.
A especificação não distingue funções e grupos de usuários.
Portanto, a declaração `groups` também pode conter as funções atribuídas a um determinado usuário.
Nesse sentido, o MP JWT possui grande integração com os mecanismos de segurança Java EE existentes, como a anotação `@RolesAllowed`.
Portanto, o seguinte método `BookResource` pode ser chamado pelos usuários que estão na função `reader` ou `manager` (ou em ambos):
[source,java]
----
@GET
@Path("/{id}")
@RolesAllowed({"manager", "reader"})
public Book getBook(@PathParam("id") int id) {
return booksBean.getBook(id);
}
----
No entanto, o método abaixo resultará no código HTTP 403 se chamado por um usuário que não possui a função `manager` em sua declaração `groups`:
[source,java]
----
@POST
@RolesAllowed("manager")
public void addBook(Book newBook) {
booksBean.addBook(newBook);
}
----
== O teste do bookstore
O projeto de exemplo contém um teste Arquillian (`org.superbiz.bookstore.BookstoreTest`) usado por alguns motivos:
* Geração do JSON Web Token (JWT)
* Apresentação do comportamento do TomEE em diferentes situações
** Recuperando um valor de Claim
** Chamando endpoints REST com funções apropriadas
** Chamando um endpoint REST com uma função incorreta (resultando no código de status HTTP 403)
** Chamando um endpoint REST sem JWT (resultando no código de status HTTP 401)