Monday, April 8, 2019

Keycloak Server: delegando a segurança de sua aplicação (parte 2)

Na primeira parte deste post, no console de administração, configuramos o Keycloak Server segurar uma aplicação web que vamos criar. A aplicação não vai conter nenhuma linha de código relacionada à login/logout, ela simplesmente vai terceirizar para o Keycloak toda essa tarefa.

Nesta parte 2, criamos a aplicação e testamos seu login e o logout via Keycloak. Nosso container de aplicação será o Wildfly 15.

Criando e publicando MyWebApp

MyWebApp é uma aplicação maven com JSF e uma página inicial index.xhtml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" 
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:h="http://java.sun.com/jsf/html">

<h:head>
 <title>My App</title>
</h:head>
<h:body>
 <h:form>
  <h:panelGrid>
  <h1>Welcome to My APP!</h1>
  <h:commandButton value="LOGOUT" action="#{indexMB.logout()}" />
  </h:panelGrid>
 </h:form>
</h:body>
</html>

E o managed bean IndexMB:
package acme.view;

import javax.enterprise.inject.Model;
import javax.faces.context.FacesContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;

import org.keycloak.KeycloakSecurityContext;

@Model
public class IndexMB {

 public String logout() throws ServletException {
  
  System.out.println("Logout!.....");
  HttpServletRequest req = (HttpServletRequest)
      FacesContext.getCurrentInstance().getExternalContext().getRequest();
  KeycloakSecurityContext context = (KeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
  System.out.println("-------- realm name: "+context.getRealm());
  req.logout();
  return null;
 }
}

Abaixo o arquivo de configuração pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
 <groupId>com.acme</groupId>
 <artifactId>MyWebApp</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>war</packaging>
 <properties>
  <java.version>1.8</java.version>
 </properties>
 <dependencies>
  <!-- https://mvnrepository.com/artifact/org.keycloak/keycloak-core -->
  <dependency>
 <groupId>org.keycloak</groupId>
 <artifactId>keycloak-core</artifactId>
 <version>5.0.0</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/javax/javaee-api -->
  <dependency>
   <groupId>javax</groupId>
   <artifactId>javaee-api</artifactId>
   <version>7.0</version>
   <scope>compile</scope>
  </dependency>  
 </dependencies>
 <build>
 <finalName>myapp</finalName>
 </build>
</project>

E o arquivo web.xml em WEB-INF. Nele é necessário especificar o método de autenticação como KEYCLOAK:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
 <display-name>myapp</display-name>
 <welcome-file-list>
  <welcome-file>index.xhtml</welcome-file>
 </welcome-file-list>
 <servlet>
  <servlet-name>Faces Servlet</servlet-name>
  <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
  <servlet-name>Faces Servlet</servlet-name>
  <url-pattern>*.xhtml</url-pattern>
 </servlet-mapping>
  <!-- Keycloak confs -->
 <security-constraint>
  <web-resource-collection>
   <url-pattern>/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
   <role-name>Developer</role-name>
  </auth-constraint>
 </security-constraint>

 <login-config>
  <auth-method>KEYCLOAK</auth-method>
  <realm-name>TeamSecurity</realm-name>
 </login-config>

 <security-role>
  <role-name>Developer</role-name>
 </security-role>
</web-app>
Na pasta WEB-INF colocamos o arquivo keycloak.json que foi gerado pelo console admin do Keycloak na parte 1 deste post. O código completo do projeto se encontra no github.

Frameworks de Autorização e Autenticação

O Keycloak trabalha com 2 formas de autenticação: OpenID Connect e o SAML 2.0.

OpenID Connect (OIDC) é uma camada de autenticação e identificação de usuário no topo do framework OAuth 2.0. O OAuth 2.0 trabalha com autorizações (o quê pode ser acessado), enquanto o OIDC define um fluxo de autenticação de usuários (quem está acessando).

SAML 2.0 é um padrão de troca de informações entre partes sobre autorização e autenticação por meio de um arquivo XML digitalmente assinado.

Quando for segurar uma aplicação pelo Keycloak a primeira coisa a decidir é qual mecanismo de autenticação e autorização você ira usar. Na maioria dos casos recomenda-se o OIDC, o qual será usado neste post.

Client Adapters

São bibliotecas que tornam mais fácil segurar aplicações e serviços com o Keycloak. Há vários adpaters diferentes dependendo de qual plataforma sua aplicação esteja rodando. Se for uma aplicação Java, existem adpaters para o Wildfly, Tomcat, Spring Boot, Jetty, etc. Há ainda outros adapaters para Java Script, Node.js, Python, iOS, entre outras. Veja a relação completa aqui.

Como nosso container é o WildFly, vamos utilizar seu respectivo adapter para o OIDC. Baixe o arquivo keycloak-wildfly-adapter-dist-5.0.0.zip. Descompacte seu conteúdo (pastas bin, docs e modules) na pasta raiz do Wildfly.

Após descompactar o arquivo, execute o seguinte comando dentro do diretório raiz do Wildfly:
wildfly-15.0.1.Final$ ./bin/jboss-cli.sh --file=bin/adapter-elytron-install-offline.cli
Esse script edita os arquivos de configuração do Wildfly para que ele fique ciente do método de autenticação do Keycloak referenciados no web.xml.

Os próximos passos são:

1 Subir o Keycloak
keycloak-5.0.0$ ./bin/standalone.sh -Djboss.socket.binding.port-offset=100
Após executar o comando, acesse o Keycloak em http://localhost:8180/auth/.

2 Subir o WildFly
wildfly-15.0.1.Final$ ./bin/standalone.sh
Após executar o comando, acesse o Wildfly em http://localhost:9990.

3 Empacotar a aplicação
~/workspace/MyWebApp$ mvn install
Nesse caso utilizamos o Maven. Como alternativa, você pode construir a aplicação utilizando as ferramentas de alguma IDE. O comando acima gera o arquivo myapp.war dentro da pasta target. Copie a URL do arquivo.

4 Publicar myapp.war no Wildfly

Para fazer o deploy da aplicação, vamos utilizar o cliente do Wildfly jboss-cli.sh, que se encontra dentro da pasta bin do Wildfly (ou jboss-cli.bat se for Windows). Execute o seguintes comandos, substituindo o caminho de myapp.war de acordo com o seu ambiente:
~/Servers/wildfly-15.0.1.Final$ ./bin/jboss-cli.sh
You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands.
[disconnected /] connect
[standalone@localhost:9990 /] deploy /home/rafael/workspace/MyWebApp/target/myapp.war
Não esqueça de substituir o caminho até myapp.war de acordo com o seu ambiente.

Pronto! Aplicação foi publicada e possui um mecanismo de autenticação totalmente desacoplado. Para testar acesse a aplicação em http://localhost:8080/myapp. Você vai bater de frente com a seguinte página:


Logue com o usuário que você criou na parte 1 deste post, para o qual foi atribuida a role Developer.

Após logar, você será direcionado para a página da aplicação:


Clique em logout. E o Keycloak vai encerrar sua sessão e você é novamente redirecionado para a página de login.

Servidor de Sessão

O Keycloak também funciona como um servidor de sessão. Acesse myapp de um browser diferente e em seguida logue com o admin na console de administração do Keycloak.

No realm  TemSecurity, no menu client, escolha o client MyWebApp, e depois clique na aba Sessions:



Você verá que o keycloak lista o usuário que você criou com 2 sessões ativas. Clique no usuário, e você poderá derrubá-lo a partir do console do Keycloak.

O Keycloak é uma solução muito interessante que fornece autenticação como microserviço, ou seja, não há dependência entre os componentes internos da aplicação e os processos de autenticação, autorização e manipulação dos dados do usuário. Nenhuma linha de código para login/logout foi escrita e a aplicação já está totalmente segurada.

referências:
https://www.keycloak.org/documentation.html  


"Determinarás tu algum negócio, e ser-te-á firme, e a luz brilhará em teus caminhos."

Jó 22:28

       

Thursday, April 4, 2019

Keycloak Server: delegando a segurança de sua aplicação (parte 1)

Adicionar autenticação para qualquer aplicação é uma tarefa trabalhosa. Se sua aplicação não usa alguma forma de autenticação e controle de autorização e acessos de usuário, esteja certo de que uma hora isso será necessário, você terá que implementar autentiação, autorização e todo um esquema de gestão de usuários. E você fatalmente acabará fazendo isso do jeito errado.
Já que autenticação e diversas questões relacionadas à segurança de sua aplicação demandam tempo considerável de análise e implementação, e mesmo depois de prontas, após um longo trabalho, sua implementação apresentará alguma falha, por que não delegar tudo isso para quem sabe fazer? 

Na parte 2 deste post criamos uma aplicação web simples sem escrever uma única linha relacionada a login/logout de usuário, mas que vai rodar tendo por trás um sistema robusto e confiável de autenticação. Nesta parte 1 apresentamos e configuramos o Keycloak Server.

Keycloak Server

Keycloak Server é uma solução open source, baseado no Wildfly server, para identificação e autenticação de usuários para as aplicações e serviços modernos, ou, em outras palavras, é uma aplicação JAX-RS que expõe diversos serviços customizáveis relacionados à autenticação e autorização de usuários que qualquer aplicação pode fazer uso. Embora seja uma distribuição do Wildfly, o Keycloak não pode ser usado como container de aplicações.

Conceitos

Antes de começar a testar o Keycloak, é importante entender alguns termos importantes presentes no seu contexto:

  • Realm: é um território que você cria. No Keycloak as aplicações são agrupadas por realms, os usuários também, entre outras entidades.
  • Client: são as aplicações e serviços segurados pelo Keycloak (não confundir com o usuário).
  • Roles: tipo ou categoria de usuário, geralmente vinculada a um tipo de acesso ou permissão.
  • Users: Entidades que podem logar no sistema.
  • User role mapping: a relação entre users e roles. Um user pode ter várias roles.
  • Groups: Conjunto de usuários. Groups também podem ter atributos e roles.
  • Acess token: Um token JSON que concede acesso a um serviço especificado

Configurando o Keycloak para o uso

Faça download do arquivo keycloak-5.0.0.[zip|tar.gz], que contem a distribuição do server. Descompacte o arquivo zipado. Se você já utilizou o Widlfly server, vai reparar que a estrutura de diretórios do Keycloak é praticamente idêntica a dele:



Para subir o Keycloak, vá para a pasta bin e execute o arquivo standalone.bat (se o seu ambiente for windows) ou standalone.sh (para Linux). O argumento -Djboss.socket.binding.port-offset=100 é opcional e foi passado para impedir que o Keycloak ocupe a porta 8080 e assim não cause conflito com o Wildfly server (que será executado logo mais).

$ ./standalone.sh -Djboss.socket.binding.port-offset=100

Após executar o comando acima, você pode acessar o console de administração do Keycloak no endereço http://localhost:8180/auth/:


Na tela acima, cadastre um novo usuário administrador (com login e senha). Esse processo também cria o realm master automaticamente. Após clicar em create,  clique no link Administration Console:

Logue com o usuário e senha de administrador que você acabou de criar. A tela inicial é a que segue:



No canto superior esquerdo, temos o realm default Master. Vamos criar um novo realm chamado TeamSecurity. Posicione o cursor em Master e clique no botão add realm:



Em name, coloque o nome do novo realm. Após, clique em create. Repare no canto superior esquerdo que o nome do realm mudou de Master para TeamSecurity (podemos alternar entre os diversos realms criados).

Agora vamos adicionar um cliente chamado MyWebApp dentro do realm TeamSecurity. No menu lateral esquerdo, clique em client e depois (à direita) create. Na combo-boox client protocol deixe a opção default openid-connect. Em Root URL coloque a URL da aplicação, que neste caso pode ser http://localhost:8080/myapp.


Após salvar, a seguinte tela aparece:



Preencha os campos Root URL, Valid Redirect URL e Web Origins conforme a imagem abaixo. myapp será aplicação que será protegida pelo Keycloak. Na combobox Access type, escolha confidential. Após selecionar o access type, as opções Service Accounts Enabled e Authorization Enabled vão aparecer, ative-as colocando em ON, conforme a imagem abaixo. E clique em save.



Keycloak Adapters

Keycloak suporta autenticação por meio de dois protocolos: OpenID Connect (OIDC) e SAML 2.0. Você deve escolher qual dos dois será usado na sua aplicação. Neste caso escolhemos o OIDC.

Dependendo de qual framework/container sua aplicação Java esteja utilizando (Wildfly, Tomcat, Spring Boot, Jetty, etc), o Keycloak provê alguns adaters para integrar de forma mais eficiente com a plataforma, há ainda adapters para outras linguagens.

No caso dos Java Adapters, todos eles compartilham uma série de configurações em comum, as quais podem ser definidas em um arquivo JSON colocado dentro da pasta WEB-INF ou, no caso do Wildfly, definí-las em um arquivo de configurações do servidor, como o standalone.xml por exemplo (dessa forma você não precisa alterar o arquivo .war).

Neste post, vamos gerar o arquivo de configuração JSON.

Ainda na área do client MyWebApp, na aba Instalation, na combobox format option, selecione Keycloak OIDC JSON. Esse procedimento dispões para download as configurações básicas no formato JSON, incluindo a secret-key do realm para a criptografia das informações trocadas entre o cliente e o servidor. A public-key para está acessível na url http://localhost:<keycloak-port>/auth/realms/{realm} (neste exemplo a url seria http://localhost:8180/auth/realms/TeamSecurity)

Salve esse arquivo como keycloak.json. Ele será usado na parte 2 deste post.



Agora vamos criar uma role de usuário. No menu lateral esquerdo clique em Roles. E depois em add role. Dê a esta role o nome de Developer, depois salve-a.

Agora vamos criar um usuário. No menu lateral, clique em users. E depois Add User. Dê um nome ao user. Você também pode preencher os campos First Name, Last Name e email. Marque a opção  Email Verified (ON), para habilitá-lo imediatamente. Salve.

Esse usuário que você criou poderá logar no console, mas não como admin, na url http://localhost:8180/auth/realms/{realmName}/account. Uma vez logado em sua própria conta, o usuário poderá atualizar seu perfil, entre outras atividades.



Depois de salvar esse user, na aba role mappings, adicione a role Developer para ele:


Na aba credentials, crie e guarde uma senha para esse usuário. Em seguida, clique em Reset Password. Teste se seu usuário foi criado com sucesso logando na área de usuários em http://localhost:8180/auth/realms/TeamSecurity/account/. Use o login e senha que você acabou de criar. No primeiro acesso, o Keycloak solicita ao usuário que mude sua senha.

Essa configurações representam o básico para proteger a aplicação MyWebApp no Keycloak. Na parte dois deste post criamos a aplicação e delegamos o seu processo de autenticação e autorização de usuários para o Keycloak.

"E não sede conformados com este mundo, mas sede transformados pela renovação do vosso entendimento, para que experimenteis qual seja a boa, agradável, e perfeita vontade de Deus"

Romanos 12:2