Introdução
Essa publicação foi baseada no artigo [Securing Spring Boot REST APIs with Auth0 and OAuth 2.0]
Na publicação citada, foi utilizada a solução [Auth0] como plataforma de autenticação e autorização.
Nesta publicação nosso objetivo será demonstrar como utilizar o [IAM] da OCI, Oracle Cloud Infrastructure, para prover autenticação e autorização para nossa aplicação desenvolvida em Java, utilizando Spring Boot e Spring Security.
O que mudou?
Para utilizarmos o código de exemplo na OCI, realizamos as seguintes mudanças:
- Na classe [SecurityConfig.java](src/main/java/com/example/auth0demo/config/SecurityConfig.java):
- incluímos um novo atributo: scope, porque iremos restringir a segurança com base nesta informação;
- alteração no jwtDecoder, para utilizar a url JWK do nosso Identity Provider, com os certificados públicos.
- Criação de Confidential Application, uma como resource server e outra como client, para os itens de autenticação e autorização.
Iremos descrever os passos a seguir.
Caso de Uso

Configuração JWK e Confidential Application
As seguintes atividades deverão ser realizadas na console administrativa da OCI.
Habilitando o JWK endpoint no seu Tenancy.
Para esse cenário vamos habilitar o endpoint /admin/v1/SigningCert/jwk do IAM para retornar o certificado de assinatura do tenancy em JWK.
JWK (JSON Web Key) é uma estrutura de dados JavaScript Object Notation (JSON) que representa uma chave criptográfica.
Execute os seguintes passos:
- Seu usuário deve pertencer ao grupo Identity Domain Administrator ou Security Administrator;
- Acesse Identity & Security;
- Clique em Domains, escolha o domain utilizado para os próximos procedimentos;
- Na aba Settings, procure pelo botão Edit domain settings e clique no mesmo;
- No item Access signing certificate, habilite a opção Configure client access e depois salve as alterações.
Para ilustar:
IAM e Domain:

JWK habilitado:

Realize o teste em um navegador, usando uma aba anônima, acessando a seguinte URL:
- [Domain URL]/admin/v1/SigningCert/jwk
A informação Domain URL, consta na aba Details do seu Domain.

#endpoint
https://idcs-yourDomain.identity.oraclecloud.com/admin/v1/SigningCert/jwk
#retorno da API
{
"keys": [
{
"kty": "RSA",
"x5t#S256": "xyz",
"e": "AQAB",
"x5t": "xyz",
"kid": "SIGNING_KEY",
"x5c": [
"xyz"
],
"key_ops": [
"wrapKey",
"verify",
"encrypt"
],
"alg": "RS256",
"n": "xyz"
}
]
}
Confidential Application
Para autenticação e autorização, iremos utilizar [Confidential Application], realizando a criação através da console administrativa da OCI.
Para criação de Confidental Application, seguir:
- Acesse Identity & Security;
- Clique em Domains, escolha o domain utilizado para os próximos procedimentos;
- Navegue até a aba Integrated applications, procure pelo botão Add Application e clique no mesmo;
- Procure por Confidential Application e clique no botão Launch Workflow.
Executar esse procedimento para cada Confidental Application que criaremos a seguir.

Utilizaremos duas Confidental Applicatons, uma resource server e outra como client, para uma melhor organização e governança dentro do IAM.

Resource Server Application
Servidor de Recursos (Resource Server): É o componente que hospeda os dados e serviços que precisam ser protegidos. No contexto do Oracle IAM, o servidor de recursos é configurado para verificar se as requisições de acesso contêm tokens de autorização válidos.
Na criação desta Confidential Application, informe neste momento, os atributos Name e Description, depois clique em Submit.

Atenção: Ative sua aplicação, clicando em “Actions”, “Activate” e depois em “Activate application”.

Agora vá até a aba OAuth configuration e clique em Edit OAuth configuration:

Tela de Edit OAuth configuration:

Vamos escolher a opção Configure this application as a resource server now.
Deixe a opção No client configuration selecionada.

Configure o seguinte:
- Primary audience: spring
- Essa informação será utilizada no arquivo yaml, no atributo: iam.audience
- Add scopes: habilite essa opção e clique em adicionar, vai abrir uma nova tela:
- Scope**: api:get
- Essa informação será utilizada no arquivo yaml, no atributo: iam.scope.
- Display name: get
- Description: scope para get nas API´s
- Scope**: api:get
- clique em adicionar.

Ao término, clique em Submit, para aplicar as alterações na sua aplicação.
Client Application
Aplicação Confidencial (Confidential Application): É uma aplicação de servidor que é confiável para manter suas credenciais seguras (ID do cliente e segredo do cliente + scope).
Ao contrário de aplicações públicas (como as que rodam em um navegador), ela não expõe esses segredos ao usuário final. Ela usa o secret do cliente para autenticar-se junto ao servidor de autorização antes de fazer uma chamada para o servidor de recursos.
Na criação desta Confidential Application, informe neste momento, os atributos Name e Description, depois clique em Submit.

Atenção: Ative sua aplicação, clicando em “Actions”, “Activate” e depois em “Activate application”.

Agora vá até a aba OAuth configuration e clique em Edit OAuth configuration:

Tela de Edit OAuth configuration:

Deixe a opção No resource server configuration selecionada.
Vamos escolher a opção Configure this application as a client now.
Configure o seguinte:
- Em **Authorization**, selecione os seguintes **Allowed grant types**:
- Client credentials
- Refresh token

Add resources: habilite essa opção e clique em Add scope;

Nesta nova tela, busque pela aplicação de resource server criada anteriormente.
Selecione o scope e ATENÇÃO: não se esqueça de clicar no botão Add.

Aqui a tela com o scope adicionado:

ATENÇÃO
Perceba que o scope quando adicionado como resource nesta aplicação, ficou desta forma:
- springapi:get: ocorreu uma concatenação entre [primary audience] + [scope], que constam na aplicação de Resource Server, criada anteriormente;
- Esse é um detalhe que será necessário observar ao gerar o JWT nos comandos curl que estão a seguir.
Ao término, clique em Submit, para aplicar as alterações na sua aplicação.
Colete as seguintes informações desta aplicação, na Aba OAuth configuration, pois as utilizaremos em breve, para gerar o token JWT no processo de OAuth Client Credencials:
- Client ID
- Client secret

Configurando a aplicação
Arquivo [application.yaml](src/main/resources/application.yaml) configurado para uso do IAM.
Verifique as seguintes propriedades:
- issuer-uri: Se você não especificar um Issuer no IAM, o Issuer padrão será utilizado, neste caso: https://identity.oraclecloud.com/
- jwk-set-uri: o endpoint JWK do IAM
- audience: foi o valor que definimos na aplicação do tipo Resource Server no atributo Primary audience
- scope: SCOPE_api:get concatenção do prefixo [SCOPE_] + o scope definido na aplicação Resource Server
- de acordo com a documentação do Spring Security, devemos mapear cada scope com o prefixo SCOPE_
- veja que aqui, usamos exatamente api:get como está na aplicação Resource Server, sem acrescentar nenhuma outra informação.
spring:
application:
name: spring-boot-app
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://identity.oraclecloud.com/
jwk-set-uri: https://idcs-yourDomain.identity.oraclecloud.com/admin/v1/SigningCert/jwk
server:
port: 8585
logging:
level:
root: INFO
# Custom property
iam:
audience: spring
scope: SCOPE_api:get
Testando a aplicação
Comandos para gerar o JWT e testes com as API´s:
#devemos gerar a informação para autenticação em base64 concatenando [Client ID + : + Client secret] da Confidential Application do tipo Client
echo -n "Client ID:Client secret" | openssl enc -base64 -A
#comando curl para retornar o token
#ATENÇÃO: devemos enviar o scope por completo
curl -k -i \
-H "Authorization: Basic [base64 -> client_id:cliente_secret]" \
-H "Content-Type: application/x-www-form-urlencoded;charset=UTF-8" \
--request POST https://idcs-your-instance.identity.oraclecloud.com/oauth2/v1/token \
-d "grant_type=client_credentials&scope=springapi:get"
#aqui extraímos apenas o token do JSON retornado
curl -s \
-H "Authorization: Basic [base64 -> client_id:cliente_secret]" \
-H "Content-Type: application/x-www-form-urlencoded;charset=UTF-8" \
--request POST https://idcs-your-instance.identity.oraclecloud.com/oauth2/v1/token \
-d "grant_type=client_credentials&scope=springapi:get" \
| jq -r '.access_token'
#criamos uma variável com o token retornado, para utilizarmos na chamada da API protegida
TOKEN=$(curl -s --request POST \
--url https://idcs-your-instance.identity.oraclecloud.com/oauth2/v1/token \
--header 'Authorization: Basic [base64 -> client_id:cliente_secret]' \
--header 'content-type: application/x-www-form-urlencoded;charset=UTF-8' \
--data 'grant_type=client_credentials&scope=springapi:get' | jq -r '.access_token'); echo "The token is: " $TOKEN
#testando a API que não possui autenticação
curl -s http://localhost:8585/api/public/hello | jq
#testando a API protegida e enviando o token gerado no cabeçalho de autenticação
curl -s http://localhost:8585/api/private/hello -H "Authorization: Bearer $TOKEN" | jq
