Desenvolvimento - WIF
Explorando os módulos do WIF para o ASP.NET
Como vimos no artigo anterior, o WIF fornece vários módulos para acoplarmos ao pipeline do ASP.NET, e que farão tudo o que for necessário para efetuar a comunicação com o respectivo STS. Esses módulos são aqueles tradicionais módulos do ASP.NET, que implementam a interface IHttpModule, e se vinculam à eventos que "cortam" a requisição na vertical.
por Israel AéceComo vimos no artigo anterior, o WIF fornece vários módulos para acoplarmos ao pipeline do ASP.NET, e que farão tudo o que for necessário para efetuar a comunicação com o respectivo STS. Esses módulos são aqueles tradicionais módulos do ASP.NET, que implementam a interface IHttpModule, e se vinculam à eventos que "cortam" a requisição na vertical.
Esses módulos são: WSFederationAuthenticationModule e SessionAuthenticationModule, e estão debaixo do namespace Microsoft.IdentityModel.Web. O primeiro é responsável pelo processamento do token que é gerado pelo STS, enquanto o segundo persiste essa informação em um cookie, e nas requisições subsequentes, ele irá analisá-lo, e caso não exista ou esteja inválido, redirecionará o usuário novamente para o STS.
Ambas as classes (módulos), fornecem uma série de membros que permite aos desenvolvedores ASP.NET a interceptarem alguns estágios do processamento através de eventos, adicionando um código customizado seja ele para manipulação ou auditoria. Além disso, esses módulos também oferecem alguns métodos e propriedades para permitir a reutilização de algumas funcionalidades/informações. A finalidade deste artigo é explorar os principais membros públicos e o que e como podemos fazer para efetuar tal customização.
Antes de efetivamente falarmos dos membros que são disponibilizados, precisamos saber como temos acesso à cada um deles. Como é responsabilidade do próprio ASP.NET criar os módulos que disponibilizam esses eventos, de algum forma precisamos acessar essas instâncias criadas. Para isso, existe uma classe estática chamada FederatedAuthentication, que também está debaixo do namespace Microsoft.IdentityModel.Web. Essa classe fornece apenas cinco propriedades, também estáticas, a saber:
-
ClaimsAuthorizationModule: Retorna a instância do módulo ClaimsAuthorizationModule. Este módulo é acoplado ao runtime do ASP.NET no evento OnAuthorizeRequest, invocando o método CheckAccess da classe ClaimsAuthorizationManager, que você pode utilizar para customizar a autorização.
-
ClaimsPrincipalHttpModule: Retorna a instância do módulo ClaimsPrincipalHttpModule, que faz uma espécie de tradução, tranformando o principal e identity corrente, em objetos que implementam as interfaces IClaimsIdentity e IClaimsPrincipal.
-
ServiceConfiguration: Essa propriedade retorna uma instância da classe ServiceConfiguration, que representa a seção do arquivo de configuração que corresponde ao WIF.
-
SessionAuthenticationModule: Retorna a instância do módulo SessionAuthenticationModule. Sua funcionalidade já foi discutida acima e neste outro artigo.
-
WSFederationAuthenticationModule: Retorna a instância do módulo WSFederationAuthenticationModule. Sua funcionalidade também já foi discutida acima e neste outro artigo.
A classe FederatedAuthentication ainda fornece um evento ServiceConfigurationCreated, que é disparado depois que a seção do WIF foi totalmente carregada. Agora, depois de conhecermos como podemos chegar até os eventos, podemos recorrer ao modo tradicional do .NET para nos vincularmos à eles, que é através do operador +=. Mas temos também tem uma segunda alternativa, onde podemos definir o tratador do evento utilizando o nome do módulo (classe) e o nome do evento, diretamente dentro do arquivo Global.asax, assim como podemos ver no exemplo abaixo:
<%@ Import Namespace="Microsoft.IdentityModel.Configuration" %>
<%@ Import Namespace="Microsoft.IdentityModel.Web" %>
voidWSFederationAuthenticationModule_SignedIn(object sender, EventArgs e)
{
//...
}
WSFederationAuthenticationModule - Propriedades
Este módulo fornece várias propriedades que ajudam na configuração do redirecionamento para o STS, na geração da mensagem de requisição e no processamento do token emitido pelo STS. Grande parte dessas propriedades acabam sendo configuradas através da seção do WIF (<microsoft.identityModel />) que encontra-se dentro do arquivo Web.config da aplicação que corresponde à relying party.
Entre essas propriedades, temos a PassiveRedirectEnabled. Essa propriedade recebe um valor boleano, que indica ao WIF que ao detectar que o usuário não está autenticado, irá redirecioná-lo automaticamente para o STS configurado na aplicação. É importante dizer que se utilizarmos o controle FederatedPassiveSignIn, essa propriedade deverá estar definida como False, assim como foi comentado neste outro artigo.
Issuer também é uma propriedade importante, que recebe o endereço do STS, para qual o usuário será redirecionado para efetuar a autenticação. A propriedade Reply contém o endereço da relying party, para que o STS possa identificar se ele pode ou não emitir o token para ela.
WSFederationAuthenticationModule - Métodos
Essa classe ainda fornece vários métodos, mas que na maioria das vezes acabam sendo utilizados pelo próprio runtime. O primeiro deles é o método CanReadSignInResponse, que recebe como parâmetro uma requisição (HttpRequest) e retorna um valor boleano indicando se ela se refere à uma mensagem de autenticação, gerada pelo STS. CreateSignInRequest é um método que dado alguns parâmetros, retorna uma instância da classe SignInRequestMessage, que corresponde à mensagem de solicitação de login ao STS.
Ainda temos um método estático, chamado de FederatedSignOut. Esse método tem a finalidade de efetuar a requisição ao STS para efetivar o logout. Já o método SignOut apenas notifica a relying party de que o usuário efetuou o logout. Quando você invoca o primeiro deles, FederatedSignOut, depois de efetuado o logout no STS, o usuário é redirecionado novamente para a relying party, e quando o WIF dectecta que ele fez o logout no STS, invoca o método SignOut, disparando assim os eventos correspondentes para que a relying party seja notificada de que isso realmente aconteceu.
Já o método IsSignInResponse, dado a requisição (HttpRequest), retorna um valor boleano indicando se a requisição trata-se da resposta dada pelo STS. Você pode utilizá-la para burlar ou evitar algum processamento que não deveria acontecer nesta situação. Temos também o método RedirectToIdentityProvider, que como o próprio nome diz, me permite, de forma explícita, redirecionar o usuário para o STS. Isso te dá uma flexibilidade quando você não quer o redirecionamento automático que o WIF faz ao identificar que o usuário não está autenticado.
WSFederationAuthenticationModule - Eventos
O primeiro evento que temos dentro deste principal módulo do WIF é o RedirectingToIdentityProvider. Este evento é disparado antes do usuário ser redirecionado para o STS, dando a oportunidade de customizar o redirecionamento, a mensagem de requisição que é enviada (RST) e a oportunidade de cancelá-la. Tudo isso é fornecido através do argumento RedirectingToIdentityProviderEventArgs, que possui apenas duas propriedades: Cancel e SignInRequestMessage.
Depois deste evento temos os eventos que são disparados durante o recebimento e processamento do token gerado pelo STS, que são: SecurityTokenReceived, SecurityTokenValidated e SessionSecurityTokenCreated. O primeiro é disparado quando a resposta com o token foi enviada pelo STS. Já o segundo, é disparado depois que o token foi validado pelo WIF e o objeto IClaimsPrincipal já foi criado com as claims devolvidas pelo STS, e que podemos ter acesso através do argumento SecurityTokenValidatedEventArgs que é passado para este evento. Finalmente, o evento SessionSecurityTokenCreated, que tem a finalidade de notificar que o token foi recebido, validado e criado, e já está pronto para emitir o cookie para armazená-lo, mas isso depende do valor que é colocado na propriedade WriteSessionCookie, fornecido pelo argumento SessionSecurityTokenCreatedEventArgs. Depois desse estágio, quem faz as manipulações no cookie é o módulo SessionAuthenticationModule, que veremos mais adiante.
Há também eventos que são disparados durante o processo de login, a saber: SignedIn e SignInError. O primeiro evento é disparado depois que o objeto IClaimsPrincipal já foi definido para a thread/requisição corrente, e com isso, seguramente você poderá recorrer as propriedades HttpContext.Current.User e Thread.CurrentPrincipal. O segundo evento, SignInError, é disparado quando algum erro ocorre dentro deste módulo durante a recepção ou validação do token, e você pode utilizar esse evento para verificar a exceção que foi disparada, ter oportunidade de conseguir tratá-la e, eventualmente, catalogar em algum lugar.
Esse módulo ainda fornece mais três eventos que correspondem ao processo de logout: SigningOut, SignedOut e SignOutError. O primeiro é disparado antes do processo de logout iniciar, e segundoocorre quando o processo de logout foi concluído e, finalmente, o evento SignOutError é disparado se algum problema acontecer durante o logout, e justamente por isso, ele inclui uma propriedade chamada Exception, que retorna a instância da exceção disparada.
E, finalmente, o evento AuthorizationFailed é disparado sempre quando você tenta acessar algum recurso protegido e ainda não está autenticado. Esse evento fornece como argumento um objeto do tipo AuthorizationFailedEventArgs, que por sua vez, disponibiliza uma propriedade chamada RedirectToIdentityProvider, que é do tipo boleana, indicando se o WIF deve ou não redirecionar o usuário para o STS.
SessionAuthenticationModule - Propriedades
A principal propriedade exposta por essa classe é a CookieHandler. Essa propriedade, que expõe um objeto com o mesmo nome, é responsável por armazenar o token gerado pelo STS em um cookie do lado do cliente. Além de gerar o cookie, o módulo SessionAuthenticationModule verifica a existência do mesmo, e caso exista, evita o redirecionamento para o STS em futuras requisições. O cookie handler também é estensível, e veremos mais detalhes sobre isso em um artigo específico.
SessionAuthenticationModule - Métodos
Como essa classe gerencia o cookie que corresponde ao token gerado pelo STS, ela também fornece métodos auxiliares que permitem ter acesso ao cookie em questão. O método ContainsSessionTokenCookie recebe uma coleção de cookies (que na maioria das vezes está dentro do objeto HttpRequest), e retorna um valor boleano indicando se o cookie existe dentro dela. Já o método TryReadSessionTokenFromCookie recebe um parâmetro de saída do tipo SessionSecurityToken, e retorna um valor boleano indicando se foi posssível ler o cookie. Caso retorne True, você pode seguramente acessar o parâmetro de saída, que corresponderá ao token gerado pelo STS.
O método DeleteSessionTokenCookie apenas tem a finalidade de excluir o cookie que corresponde ao token daquele usuário atual. Apesar de público, ele geralmente é invocado durante o processo de logout.
SessionAuthenticationModule - Eventos
Para evitar que o usuário seja redirecionado para o STS a toda requisição que fazemos à alguma página aplicação, esse módulo é adicionado ao runtime do ASP.NET com a finalidade de evitar essa transição a todo momento. Ele verifica se a requisição possui o cookie que corresponde ao token do usuário, que este módulo gerou quando ele (o usuário) se autenticou no STS. Ao detectar a presença deste cookie, ele extrai a informação e permite, através de dois eventos, interceptar o trabalho que ele faz. Esses eventos são: SessionSecurityTokenReceived e SessionSecurityTokenCreated.
Como disse acima, durante a execução este módulo verifica se o cookie está presente, e se estiver, recria o token a partir dele, e após isso, o evento SessionSecurityTokenReceived é disparado. Esse evento fornece como argumento um objeto do tipo SessionSecurityTokenReceivedEventArgs, qual você pode utilizar para re-emitir o cookie, permitindo você a manipular várias características dele, como por exemplo o tempo de expiração do token.
Já o segundo evento, SessionSecurityTokenCreated, é disparado durante a re-emissão do cookie, que muitas vezes acontece quando ele expira. Como argumento, este evento fornece um objeto do tipo SessionSecurityTokenCreatedEventArgs, que fornece duas propriedades: SessionToken e WriteSessionToken. A primeira corresponde ao token do usuário que você pode customizar aqui; já a segunda, recebe um valor boleano indicando se o cookie que irá ser regerado deve ou não ser persistido.
Esse módulo ainda fornece mais três eventos que correspondem ao processo de logout: SigningOut, SignedOut e SignOutError. O primeiro é disparado antes do processo de logout iniciar,o segundoocorre quando o processo de logout for concluído e, finalmente, o evento SignOutError que é disparado se algum problema acontecer durante o logout, e justamente por isso, ele inclui uma propriedade chamada Exception, que retorna a instância da exceção disparada.
Conclusão: Este artigo mostrou os principais membros dos módulos do WIF, e que você pode fazer uso deles quando o WIF estiver habilitado na aplicação. Como notamos na descrição de cada um dos eventos disponibilizados pelos módulos, eles servem para interceptar vários momentos durante o redirecionamento, validação e persistência do token, e você pode ou não optar por utilizá-los, e isso dependerá da sua necessidade.