Este é quarto artigo da série que estamos produzindo sobre o Arda – um sistema para gestão de workloads que está sendo desenvolvido pelo time de evangelistas da Microsoft Brasil. Em um futuro próximo, tanto os artigos quanto o código fonte do Arda serão migrados para o GitHub mas até lá, você poderá encontrar todo o material referente aos nossos aprendizados com a ferramenta em uma página aqui mesmo no site, disponível no link abaixo.
Conteúdos sobre o Arda: https://fabriciosanchez.com.br//arda/
O365 como premissa
No artigo de hoje quero falar um pouco sobre o primeiro processo que implementamos aqui no Arda – a autenticação dos usuários. No primeiro artigo falei de maneira mais demorada sobre as várias premissas as quais o projeto deveria atender. Uma das principais é que a solução fosse totalmente integrada ao Office 365. Dessa forma, conseguiríamos usar o poder da plataforma de produtividade online da Microsoft em alguns aspectos realmente relevantes para o Arda.
Se a integração com o O365 era uma premissa, era uma premissa também utilizar o Active Directory Online. Isso porque, como você deve imaginar, todo o processo de autenticação do O365 é realizado no Azure AD. Se você enxerga esta premissa como algo que “engessa” o sistema, mude seu mindset. Na verdade, utilizar o Azure AD como autenticador da solução traz várias características super interessantes para a mesma. Apenas para citar algumas:
- Autenticação de duplo fator;
- Integração com o processo central de autenticação da empresa (usuários e senhas adicionais não são necessários);
- Utilização dos recursos do Office 365 na aplicação;
- Permissionamento do sistema baseado nas roles do AD;
As vantagens vão além, mas acredito que estas devam bastar por hora.
Um pouco de OpenID
Assim como a maioria dos sistemas de autenticação modernos (apenas para citar algumas empresas que utilizam OpenID: Google, Facebook, Yahoo!, Microsoft, AOL, MySpace, Sears, Universal Music Group, France Telecom, Novell, Sun, dentre outras), o Azure AD utiliza o modelo OpenID de identificação de usuários.
Uma observação importante aqui é: nosso objetivo aqui não é esgotar o tema OpenID. Longe disso na verdade. Entretanto, acredito ser importante dar uma visão mínima sobre o assunto para que você possa seguir com a leitura deste artigo sabendo do que estamos falando. De qualquer maneira, recomendo fortemente que você busque saber mais detalhes sobre OpenID, uma vez que este padrão tem se tornado cada vez mais popular nos sistemas modernos. A seguir deixo um link para o site do OpenID Foundation para que você possa aprofundar seus conhecimentos sobre o padrão.
OpenID Foundation: http://openid.net/get-an-openid/what-is-openid/
De maneira geral, podemos entender o OpenID como sendo um modelo universal de distribuição de autenticação baseado no envio de informações criptografadas através de URLs web. A ideia é que, ao receber determinada requisição baseada neste modelo, o servidor (se implementar OpenID) seja capaz de validar se o usuário em questão encontra-se válido na ocasião. Se sim, um token de acesso é devolvido ao chamador. Se não, um erro é devolvido.
O aspecto mais importante do OpenID está no fato de que a identificação do usuário é única. Dessa forma, se o site/sistema ao qual você está navegando suportar OpenID, necessariamente você será único neste contexto. Por este simples motivo, quando você se autentica na sua caixa de entrada do Outlook, por exemplo, ao abrir sua conta do OneDrive que é baseada no mesmo e-mail, tudo funcionará perfeitamente sem um segundo login.
A Figura 1 apresenta uma visão bem humorada sobre “Sem OpenID x Com OpenID”.
Figura 1. A grande vantagem do OpenID
Outra observação importante aqui é: OpenID é o modelo de distribuição e não o login em si. O processo de login deverá ser implementado pelo site/sistema provedor do engine de autenticação. O OpenID irá distribuir este processo de autenticação apenas.
Um pouco sobre o Microsoft Graph
Nota mental: se em algum momento no futuro você for trabalhar com a integração entre recursos do O365 com sua aplicação, você precisa ter a clara noção de que seu melhor amigo nesse processo será o Microsoft Graph (MG). O MG é basicamente um container expõe vários serviços REST que realizam operações específicas nos cloud services do O365. Tudo é centralizado através de um endpoint único: https://graph.microsoft.com.
Imaginando por exemplo que você quisesse obter informações sobre seu Azure AD profile, você poderia chamar “https://graph.microsoft.com/v1.0/me” que as informações seriam obtidas em formato JSON. Simples, não?
A ideia do Microsoft Graph é justamente tornar simples o processo de interação com os recursos do O365. Minha dica pra você é: acesse este site e fique por dentro de tudo o que pode ser feito com as APIs.
O processo de autenticação do Arda
O processo de autenticação no Arda está dividido basicamente em dois momentos (isso por conta do modelo de microserviços que estamos implementando):
- Arda.Main: quando o usuário solicita o sign in através da tela de entrada do sistema;
- Arda.Permissions: quando o controller responsável na tela de login passa a responsabilidade de autenticar o usuário passa para o microserviço responsável (no caso, o Arda.Permissions);
Dessa maneira, vou segmentar o processo de login nestas duas etapas (que veremos neste mesmo artigo). Assim, deixamos para o próximo artigo o entendimento do processo de permissionamento (aos recursos) dos usuários.
Etapa 1: O usuário chega na tela inicial do sistema e solicita “sign in“
Já mencionei em algum dos artigos anteriores que, todos os microserviços de backend do Arda são Web APIs enquanto o microserviço de frontend é um MVC 6. Certo? Dessa forma, o roteamento do request de autenticação respeitará o padrão {controller}/{action}/{value}. Nada demais.
Outro conceito importante de ser relembrado: estamos trabalhando com ASP.NET Core e portanto, temos a premissa de trabalharmos primariamente com middlewares em um pipeline de execução. Ok? Isso posto, vamos as implementações e suas respectivas explicações.
Implementação 1: Adição dos pacotes de necessários a autenticação
Nossa primeira medida, claro, foi adicionar os pacotes dos quais precisaríamos para que a comunicação baseada em OpenID (Microsoft.AspNetCore.Authentication.OpenIdConnect) pudesse ocorrer e ainda, alguns outros elementos importantes para o processo, como: Cookie, Session e Cache. Dessa maneira, adicionamos os respectivos pacotes ao arquivo “project.json” do projeto “Arda.Main”, conforme ilustra a Listagem 1.
Listagem 1. Adicionando os pacotes necessários ao processo de autenticação
Bom, vamos a uma rápida explicação sobre os papéis de cada um desses elementos no processo de autenticação.
- Microsoft.AspNet.Authentication.Cookies: pacote que agrupa implementações para gestão de cookies em aplicações ASP.NET. Precisamos deste pacote no projeto por um motivo muito simples: o processo de autenticação do Azure AD utiliza cookies.
- Microsoft.AspNet.Authentication.OpenIdConnect: OpenIdConnect é a implementação para ASP.NET Core do modelo OpenID do qual falamos anteriormente. Como o processo de autenticação via Azure AD utiliza OpenID precisamos deste pack.
- Microsoft.AspNet.Session: implementação de sessions no ASP.NET Core. Muito embora o processo de autenticação seja persistido em cookies, utilizamos sessões para persistir alguns dados temporários.
- Microsoft.Extensions.Caching.Memory[Redis]: estes dois pacotes são os responsáveis por gerenciar toda a comunicação com o serviço Redis Cache do Azure. Utilizamos o Redis para persistir informações relativas a permissionamento de usuários e algumas outras informações provenientes do AD.
Implementação 2: O arquivo “secrets.json”
No sentido de manter o código limpo e organizado, criamos um arquivo JSON (no Arda estamos chamando de “secrets.json”) na raíz de cada microserviço que agrupa as informações de acesso aos recursos dos quais precisamos (como se fosse um RESX) como string de conexão com o banco de dados, string de conexão com o storage do Azure, string de conexão com o Azure Redis Cache, etc. Como a autenticação tem início no Arda.Main, criamos um “secrets.json” para este microserviço com a seguinte estrutura (apresentada pela Listagem 2).
Listagem 2. O arquivo “secrets.json” do microserviço Arda.Main
Pronto! Agora é só fazer com que a classe Startup leia os valores armazenados aqui. No próximo passo você verá como é simples fazer isso no ASP.NET Core.
Implementação 3: Implementação da lógica de autenticação do Azure AD na classe de Startup
No sentido de manter o arquivo de Startup limpo (como deve ser), o que fizemos foi criar um diretório padrão do ASP.NET (App_Start) dentro da estrutura do projeto “Arda.Main” e claro, dentro dele, adicionamos uma classe parcial de Startup. Chamamos essa classe de “Startup.Auth.cs” e seu conteúdo pode ser visualizado na Listagem 3.
Listagem 3. A classe parcial de Startup que implementa o processo de conexão com o Azure AD
Wow, muitas coisas acontecendo aqui. Muito embora o código seja bem claro e simples, acho que uma rápida explicação pode acelerar o entendimento. Vou segmentá-la por métodos.
- Método “ConfigureAuth“: é o método padrão de configuração chamado pelo Startup. Como o próprio nome sugere, é nesse método que fazemos o set de todas as configurações do processo de autenticação. São basicamente quatro operações de configuração, conforme descrito a seguir.
- Linhas 28 a 33: recuperamos as informações necessárias ao AD e que estão armazenadas no arquivo “secrets.json”. Falamos dele há pouco.
- Linhas 35 a 38: dizemos ao ASP.NET que o processo de autenticação será persistido em cookies.
- Linhas 42 a 47: aqui configuramos a maneira com a qual o AD deverá trabalhar em relação ao OpenID.
- Linhas 49 a 53: dizemos ao ASP.NET quais métodos deverão ser executados em casos de falha e recebimento do token do AD.
- Método “OnAuthenticationFailed“: quando o processo de autenticação no Azure AD falhar por algum motivo, este será o método executado. Basicamente o que ele faz é “entender” o motivo do erro e retornar uma página de erro pré-fixada (/Home/Error) com a mensagem de erro como parâmetro na URI.
- Método “OnAuthorizationCodeReceived“: quando o token de autorização é retornado pelo Azure AD este é o método que é executado. Sua função aqui é a de pegar este token retornado e junto com algumas outras informações, chamar o método responsável por “cacheá-las”. Outra importante operação que fazemos aqui é a de passar este token retornado para o Microsoft Graph para que algumas operações em cima do AD possam ser realizadas.
- Método “AcquireTokenForMicrosoftGraph“: este método é o responsável por pegar o token recebido e realizar a validação no Microsoft Graph para a posterior realização de operações específicas no AD, como por exemplo, recuperar a role do usuário, foto, etc.
Chamo atenção aqui para a linha 85 da Listagem 3. No último artigo que falamos sobre o Arda, mencionamos de algumas configurações globais e decisões técnicas. Uma das configurações que mencionei foi o método genérico de conexão entre os serviços. Está lembrado? A linha 85 mostra exatamente o uso desse método no momento em que passamos a responsabilidade de gravação no cache para o microserviço responsável (no caso, Arda.Permissions).
Etapa 2: “Arda.Permissions” assume algumas responsabilidades…
No último parágrafo chamei sua atenção para a linha 85 da Listagem 3, isso porque é o exato momento em que o microserviço “Arda.Main” terceiriza algumas operações que não lhe dizem respeito para outro microserviço, no caso, “Arda.Permissions”. O que precisamos fazer então para entender com clareza o processo de autenticação, é ampliar o zoom sobre essa chamada, certo?
Como é possível notar, a chamada é feita para “api/permission/setuserpermissionsandcode” com os seguintes parâmetros “HttpMethod.Post, Util.PermissionsURL, uniqueName, code” associados. Como você já deve estar imaginando, trata-se é uma chamada Http (REST) do tipo post para um endpoint específico. “api” é o acrônimo padrão do Web API, “permission” é o controller e “setuserpermissionsandcode” é a ação que implementa determinada rotina. A Listagem 4 apresenta a implementação dessa atividade “terceirizada”.
Listagem 4. Método SetUserPermissionsAndCode chamado pelo microserviço “Arda.Main”
O método realiza basicamente duas operações: 1) verifica se o usuário que está requisitando o acesso já existe no banco de dados do microserviço. Se existir, ele simplesmente coloca as informações do Redis Cache e retorna o token de acesso para liberar o acesso aos recursos. 2) se não existe, ele cria um novo usuário, baixa os dados do Azure AD, adiciona as informações no cache e as copia para o banco de dados local do microserviço.
No caso da criação de um novo usuário, um email é disparado para o administrador do sistema indicando que um novo usuário foi adicionado e que ele precisa validar se este usuário pode ou não acessar o sistema e ainda, quais permissões ele tem acesso. Mas isso é o assunto de nosso próximo artigo: “Permissões”.
E então, o que achou? Não esqueça de deixar seu comentário. É assim que vamos melhorando a maneira através da qual compartilhamos as informações.
Abraços e até a próxima.
Facebook
Twitter
Instagram
LinkedIn
RSS