Minhas Cicatrizes com o Identity Server 4 (IDS4)
Historinha:
IDS4 é uma ferramenta fantástica para centralizar processos de Autenticação pode ser usado por uma ou várias aplicações , o modelo SingleSignOn , onde você tem apenas uma aplicação cuidando desse processo.
Com ele temos uma implementação de OAuth2 testada e certificada, uma implementação MVC para fazer as principais tarefas de SSO , e uma ótima documentação, alem do melhor, faz parte do .net foundations do.net core, isso nos deixa mais confortáveis em adota-lo.
Mas Como nem tudo são flores ele é temperamental , e se não estiver tudo do jeitinho dele, as coisas não funcionam;
Vou narrar aqui algumas situações que me deram dor de cabeça;
Entenda o fluxo dessa joça
Tem um monte de fluxo bonito na internet , na documentação do IDS4 também tem, mas é mais ou menos assim , o front faz um redirect para o SSO com uma url de retorno e o clientID, o SSO pergunta seu login e Senha e valida as informações da URL com os clients configurados nele.
Manda de volta para a aplicação com um token, chamado access token , você pega esse token guarda e manda no header de cada requisição para a API, a api define que o processo de autenticação sera delegado para um servidor de autenticação em seu pipeLine de inicialização , isso integra com o mecanismo de Autenticação e Autorização do próprio asp net, e é mais ou menos assim que funciona.
Conheça alguns Endpoints
O IDS 4 é uma excelente implementação , mas é sempre bom conhecer o minimo sobre o protocolo Oauth2, saber quais são os endpoints são um bom começo, para isso temos esse endereço que fornece toda a configuração do seu IDS4.
http://localhost:4000/.well-known/openid-configuration
por exemplo para implementar uma aplicação SPA sem usar plugin nenhum basta saber que a url para você autenticar no SSO é :
http://localhost:4000/connect/authorize,
essa controller não existe no exemplo do IDS4 é interno, olha como eu montei meu login, isso esta disponível em um serviço angular no meu git o AuthServices
Flows
O protocolo Oauth 2 oferece vários fluxos de Autenticação, um para cada cenário
Costumo utilizar o Fluxo Implicit Flow para aplicações web SPA que precisam se autenticar em um SSO
Costumo usar o ResourceOwnerPassword para aplicações que podemos armazenar um Client e um Secret com segurança como uma aplicação Server Side, ou um aplicativo nativo que será empacotado para dispositivos moveis , para fazer uma customização do login no servidor pode implementar a interface IResourceOwnerPasswordValidator, escrever o método public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context) e fazer sua customização veja em ResourceOwnerPasswordValidator
E também uso o ClientCredentials para autenticar aplicações com outras aplicações , tipo uma api falando com outra, coisas desse tipo.
Configurações conflitantes do Front com o Client configurado no SSO
No meu contexto costumo criar para um sistema três aplicações, uma para o Front outra para Api e outra para o SSO, isso é muito bom em termos de escalabilidade, deploy e devops , mas gera uma complicação nas configurações pois existe uma amarração do front que aposta para o SSO , o SSO que conhece qual é a url da aplicação e a API que conhece qual é a url do Servidor de SSO.
perceba que existe uma variável na url chamada returnUrl , ela é passada pelo front para o SSO e assim o SSO verifica através do ClientID se o Client configurado no SSO tem essa mesma url , caso as duas não batam , o erro retornado é Cliente não Autorizado!
observe abaixo uma configuração de um client , onde informações sobre as urls envolvidas no processo são especificadas em um fluxo Implicit
veja o fluxo de novo;
vejam o danado do Erro.
Consentimento
o Auth2, foi projetado para integrar várias aplicações em um único sistema de Autenticação , dessa forma diferentes aplicações poderiam usar o mesmo mecanismo para Autenticar seus usuários , mas para isso precisam disponibilizar algumas informações do usuário , e para isso é preciso o consentimento do usuário. Essas informações são geralmente fornecidas em um modelo chamado Claims , onde constam informações como nome , sobrenome , e-mail etc, mas caso não seja esse seu cenário , configurar um Client para evitar não solicitar um consentimento é muito simples, basta configurar o parâmetro RequireConsent
TTL
Tempo de vida do Token, o padrão para o Token deixar de ser valido é de uma hora , mas podemos aumentar ou diminuir , a recomendação é de 30 minutos, depois pede para o usuário se re-logar no sistema.
Claims
São informações do usuário que podemos trafegar dentro do token , mantendo uma especie de sessão que trafega pelo request entre o Front e a API, o SSO já coloca algumas claims no token como o Id do usuário , uma claim chamada SubjectId, mas podemos colocar nossas próprias informações , desde de que façamos essa configuração aqui;
Certificado
o SSO usa certificados para gerar os tokens , o mecanismo é conhecido como mecanismo de assinatura de forma que apenas token gerado sob a chave privada daquele certificado são validos para aquela instancia do SSO, para isso configuramos esse método
esse certificado é um certificado Auto Assinado , da pra fazer pelo IIS mesmo.
Tipos de Tokens
Olha tem vários tipos de Token , mas eu não sei quais são todos , o que nos usamos é um token chamando bearer vejam ;
vocês podem ler o token através desse site , http://jwt.io/
Tamanho dos Tokens
Não abuse , tokens muito grandes vão quebrar sua aplicação, já aconteceu comigo, não sei o tamanho exato mas os mantenha pequenos.
Domínios, Dns e Subdomínios
não se esqueça que você tem três domínios diferentes, e que é importante que existam limitações relacionados as configurações de CORs, essa configuração vão evitar ataques de outras aplicações.
Uma outra coisa que apanhei muito foi quando coloquei alguns sub domínios para o SSO isso me fez cair no cenário citado acima de urls conflitantes , depois de alguma pesquisa achei essa configuração que define quem vai ser o domínio emissor do seu token, e ai seu SSO pode ter várias URLs, de vários domínios diferentes , isso se torna útil em uma aplicação multi-tenant.
CSP (Content Security Policy)
Essa sigla , define um conjunto de configurações de segurança que impedem que algumas peripécias sejam feitas no HTML no JavaScript e CSS, carregamento de scripts externos imagens etc.
Aqui temos algumas configurações que permitem algumas coisinhas, definir um style in line, scripts externos , imagens etc.
LogOut
Para deslogar você joga o token fora , e chama o logOut que vem implementado no SSO do IDS4 , mas atenção o token ainda esta valido no servidor e portanto precisa ser revogado pelo url /connect/revocation, confesso que ainda não implementei isso então segue a documentação do processo de revogação
Persistência
Eu tenho usando o SSO com os clients , resources em memoria , isso não é aconselhável mas , honestamente não tenho tido muitos problemas, normalmente essas configurações são estáticas mesmo, tenho meia duzia de clients , alguns escopos e pronto , nunca mais mexo nisso, a unica coisa que não da pra usar, é o método de exemplo AddTemporarySigningCredential, esse ai da problema pois o expira ai o token deixa de estar valido, fica ruim, o resto não tenho muito do que reclamar não. Uso assim ;
mas podemos definir que usaremos um banco para persistir toda a configuração do IDS4, vejam abaixo;
e no método configure da classe StartUp chama o método
Alem disso , é preciso rodar as “migrations” use o console na pasta da aplicação e rode os seguintes comandos;
Para criar, vá até a pasta do SSO;
dotnet ef migrations add InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrantDbdotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/ConfigurationDb
Caso queira remover;
dotnet ef migrations remove -c PersistedGrantDbContext
dotnet ef migrations remove -c ConfigurationDbContext
e para rodar efetivamente no banco;
dotnet ef database update -c PersistedGrantDbContext
dotnet ef database update -c ConfigurationDbContext
tenho um exemplo de SSO com banco de dados SQL server no git
Também existem iniciativas prontas com uma GUI pronta para administrar um SSO , podendo fazer todas as suas configurações de forma User Friendly , dia desses um amigo me mandou esse exemplo aqui :
Também existem iniciativas prontas com uma GUI pronta para administrar um SSO , podendo fazer todas as suas configurações de forma User Friendly , dia desses um amigo me mandou esse exemplo aqui :
Também tem esse;
ainda não usei , mas parece ser muito bom.
Cuidado com classe TesteUser
Como eu disse anteriormente , podemos manter as configurações do IDS4 em memoria , e para testar podemos configurar a inicialização dele com o método .AddTestUsers(Config.GetUsers()) , uma extensão do middleare services.AddIdentityServer()
na ultima versão do IDS4, eu presenciei um amigo que pegou a implementação Default do IDS4 e apenas implementou um repositório para poder acessas os usuários da sua aplicação, mas esqueceu de tirar esse método do Startup , isso fazia o sistema não logar de forma alguma, até que encontramos uma alma caridoso que relatou o fato no Stackoverflow
Logs
É imprescindível que você habilite logs no SSO , pois vão acontecer muito problemas e as vezes apenas os logs podem nos salvar;
Estou usando o serilog , é uma boa opção, da uma olhada no SSO do meu git que você encontra mais detalhes do processo de implementação de Logs, inclusive tenho um artigo sobre logs também (Logs no .net core com configurações no appsettings.json)
Algumas implementações eu abstrai e encapsulei para reuso (vocês podem encontra-las no meu github)
se quiser saber mais sobre IDS4;