Claims em todo lugar

Há algum tempo eu falei aqui sobre o WIF (Windows Identity Foundation), que consiste em um framework para tornar o gerenciamento de identidades em aplicações .NET mais simples. Ele traz uma série de funcionalidades, que quando utilizado nas aplicações, nos permite lidar com a autenticação e autorização de uma forma mais poderosa, conseguindo inclusive, terceirizar/centralizar isso para uma outra aplicação.

O modelo de objetos do WIF, definia duas novas interfaces: IClaimsIdentity e IClaimsPrincipal, que herdavam de duas interfaces já existentes no .NET Framework desde a sua primeira versão (IIdentity e IPrincipal, respectivamente). Apesar de indiretamente compatíveis com os principals do .NET (WindowsPrincipal e GenericPrincipal), havia um trabalho extra a se fazer quando a conversão fosse necessária, ou melhor, quando a aplicação queria trabalhar com claims ao invés do modelo tradicional.

Com o .NET Framework 4.5, a Microsoft decidiu incorporar o modelo de claims diretamente no .NET Framework ao invés disso ser fornecido exclusivamente pelo WIF. A partir da versão 4.5, o .NET Framework passa a fornecer nativamente os tipos necessários para trabalhar com claims, e ainda, fez com que as classes WindowsPrincipal e GenericPrincipal herdem de ClaimsPrincipal e, consequentemente, toda e qualquer aplicação ao ser migrada para a versão 4.5 do .NET, automaticamente poderá fazer uso de claims. O diagrama abaixo mostra a hierarquia da herança entre essas classes:

System.Security.Claims é um novo namespace que foi adicionado ao .NET Framework, com a finalidade de agrupar os tipos disponíveis para realizar o trabalho via claims. Abaixo temos um exemplo de como podemos fazer o uso de claims em aplicações que utilizam, por exemplo, um modelo de autenticação customizado:

using System;
using System.Security.Claims;
using System.Security.Principal;

namespace App
{
class Program
{
static void Main(string[] args)
{
var principal =
new GenericPrincipal(new GenericIdentity(“Israel Aece”), new [] { “Admin”, “IT” });

foreach (var item in principal.Claims)
Console.WriteLine(“{0}: {1}”, item.Type, item.Value);
}
}
}

Anúncios

Overview do Windows Identity Foundation

Os desafios de desenvolver aplicações que exigem um alto nível de segurança e as soluções oferecidas pela Microsoft para transformar essa tarefa em algo bem mais simples e reutilizável do que existe atualmente.

Com a finalidade de introduzir esse novo framework, coloquei as dificuldades que temos atualmente, a proposta e o modelo básico de objetos que o WIF fornece, em um artigo na edição 26 da revista MundoDotNet. Gostaria de agradecer ao Daniel de Oliveira pela oportunidade.

WIF – Tracing

Há algum tempo eu comentei aqui em como habilitar e manipular o tracing em serviços WCF. Utilizando essa mesma estrutura, a Microsoft também incorporou este recurso no WIF, para possibilitar o diagnóstico de eventuais problemas ou comportamentos estranhos que possam acontecer durante o desenvolvimento ou mesmo durante o ambiente de produção.

Assim como serviços WCF, o WIF também é baseado em mensagens sendo trafegadas entre as partes envolvidas, que determinam as requisições de autenticação, a resposta informando se o usuário é válido ou não, processo de logout, etc. O tracing do WIF também é bastante completo, e nos permite visualizar as mensagens de forma gráfica, utilizando o utilitário Service Trace Viewer.

O uso deste tracing está disponível tanto para o autenticador (STS) quanto pela aplicação cliente (RP), e isso se dá através de trace sources, que foram criados pela Microsoft durante a construção do WIF. Esse trace source é chamado de Microsoft.IdentityModel, e podemos utilizá-lo em ambos os lados (STS e RP), para capturar os procedimentos que estão acontecendo nas duas partes. Abaixo temos o código para habilitar o tracing do lado do autenticador, e se quiser utilizar pelo cliente (RP), tudo o que precisa ser feito é colocar esta mesma configuração, alterando somente o nome do arquivo para que um não sobrescreva o do outro.

<system.diagnostics>
  <sources>
    <source name=”Microsoft.IdentityModel” switchValue=”All”>
      <listeners>
        <add name=”xml”
             type=”System.Diagnostics.XmlWriterTraceListener”
             initializeData=”C:TempAutenticador.xml” />
      </listeners>
    </source>
  </sources>
  <trace autoflush=”true” />
</system.diagnostics>

Dentro do arquivo gerado, os logs estarão distribuídos entre várias categorias, onde cada uma delas representa um estágio ou processo diferente. Essas categorias estão listadas abaixo, com uma descrição superficial sobre cada uma delas:

  • ChunkedCookieHandler: Nome, tamanho, domínio e data de expieração do cookie gerado para o usuário.
  • ClaimsPrincipal: Informações sobre a IPrincipal que foi criada, contendo o nome e o conjunto de claims.
  • DeflateCookie: Basicamente traz informações sobre o processo de compressão do cookie, incluindo o tamanho original e o comprimido.
  • HashTrace: Informações sobre tamanho e valor das assinaturas digitais do conteúdo Xml.
  • PassiveMessage: Contém um conjunto de informações permitinentes ao ambiente passivo, que são representadas pela requisição HTTP (wa, wresult e wctx).
  • Reference: Cataloga informações sobre o processo de cálculo dos digests (hash).
  • Token: Como o próprio nome diz, temos aqui informações sobre o token, trazendo informações a cada token específico (SessionTokens, Saml11 e Saml2).
  • WsFedMessage: Armazena informações que chegam até a aplicação consumidora, que cataloga cada estágio do processamento do token.
  • Exceptions: Problemas que ocorrem durante o processo de autenticação, incluindo toda a stack até o erro.
  • AppDomain Unloading: Informações sobre o descarregamento do AppDomain da aplicação.

Validando a postagem do WIF

Quando estamos utilizando um STS para autenticar uma aplicação ASP.NET (ambiente passivo), somos redirecionados para a aplicação autenticadora, nos identificamos e caso seja um usuário válido, o token será criado e postado para a aplicação (relying party) que requisitou. Essa aplicação utilizará o WIF para extrair as informações do token, validá-las e deixá-las disponíveis para serem utilizadas.

O token é serializado em formato XML, contendo todas as informações de infraestrutura (envolvendo os artefatos de segurança) e as claims. Como o conteúdo da serialização é extenso, o STS envia isso através do body de uma requisição HTTP, que é realizada através do método POST, e é aqui que o problema reside.

Por questões de segurança, o ASP.NET não permite postar requisições que contenham em seu corpo tags, para evitar problemas de cross-site scripting (XSS). Como o WIF posta uma mensagem com conteúdo XML, o ASP.NET barra logo nos primeiros estágios da requisição. Uma solução que existe desde as primeiras versões do ASP.NET, é desligar essa verificação na página que recebe a requisição com o token do WIF. Para isso basta definir o atributo ValidateRequest da diretiva @Page para False.

Desligando essa verificação, iremos conseguir receber o token do WIF, mas abriremos uma porta para que pessoas maliciosas possam explorar e, consequentemente, danificar a nossa aplicação. Felizmente na versão 4.0 do ASP.NET a Microsoft permitiu que se customize essa validação, criando um validador próprio que podemos analisar a requisição, e mesmo que ela esteja postando tags, não quer dizer que ela seja maliciosa, assim como é o caso do token do WIF.

Para criar um validador customizado, devemos criar uma classe que herde da classe RequestValidator. Essa classe fornece um método virtual chamado IsValidRequestString, que deve ser sobrescrito na classe derivada, que determinará se a requisição é válida ou não. Esse método recebe vários parâmetros, que fornecem todas as informações necessárias para criarmos a regra de validação. Entre esses parâmetros temos o contexto da requisição (HttpContext), uma string que representa o valor a ser validado, que trabalha em conjunto com o um parâmetro do tipo RequestValidationSource, que especifica qual dado da requisição está sendo validado (Forms, QueryStrings, Headers, Cookies, etc.).

Como precisamos saber se a requisição trata-se de um token gerado pelo WIF, ele próprio traz métodos que permitem a criação de uma mensagem (RSTR) a partir do conteúdo de uma requisição HTTP. Sendo assim, se o conteúdo da postagem for válido e representa um token, então quer dizer que a requisição contém tags, mas são tags que correspondem a uma espécie de informação que sabemos como lidar, ou seja, não é maliciosa. O exemplo abaixo ilustra como efetuar esta implementação, recorrendo a tipos que o WIF fornece:

public class ValidadorDoToken : RequestValidator
{
    protected override bool IsValidRequestString(HttpContext context, string value,
        RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)
    {
        validationFailureIndex = 0;

        if (requestValidationSource == RequestValidationSource.Form &&
            collectionKey.Equals(WSFederationConstants.Parameters.Result, StringComparison.Ordinal))
        {
            SignInResponseMessage message =
                WSFederationMessage.CreateFromFormPost(context.Request) as SignInResponseMessage;

            if (message != null)
            {
                return true;
            }
        }

        return base.IsValidRequestString(context, value, requestValidationSource,
            collectionKey, out validationFailureIndex);
    }
}

Como todas as informações da requisição são passadas para o validador, note que a condicional verifica se estamos recebendo o body da requisição, e como o body pode ter vários campos, estamos interessados apenas naquele campo que corresponde ao token serializado que é representado pelo campo wresult.

O ASP.NET MVC também impõe este mesmo tipo de validação, que felizmente recorre a este mesmo validador, ou seja, podemos criar um único e utilizar por qualquer tipo de projeto, WebForms ou MVC. Apenas é necessário tomar cuidado quando você decora a ação (método) com o atributo ValidateInputAttribute. A finalidade deste atributo é justamente permitir a validação da requisição, mas na versão 4.0 do ASP.NET, a adição deste validador customizado fez com aquele atributo seja executado depois do validador, que por sua vez, roda logo no evento BeginRequest.

Autorização com WIF

Dentro do desenvolvimento de software, o termo autorização descreve o processo de verificar se um determinado usuário possui ou não o acesso à um determinado recurso. Mas é importante dizer que a autorização acontece depois da autenticação, pois primeiramente é necessário saber quem o usuário é, para depois saber que direitos ele tem no sistema.

Recentemente eu comentei em alguns artigos sobre a utilização de um sistema de identidade para autenticar os usuários. Uma das principais finalidades é a terceirização do processo de autenticação, delegando isso à uma outra aplicação/serviço, e assim, todas as aplicações que confiarem naquele autenticador (STS), poderão fazer uso do mesmo para autenticar seus respectivos usuários, ficando essas aplicações totalmente isentas em como isso deve acontecer.

Como comentando nos artigos acima, o WIF (Windows Identity Foundation) abstrai grande parte da complexidade para fazer isso tudo funcionar, mas a autorização ainda continua sendo uma responsabilidade da própria aplicação. A finalidade deste artigo é apresentar algumas alternativas para efetuar a autorização nas aplicações, utilizando as claims emitidas por um determinado autenticador para refinar o acesso.

Grande parte das aplicações fazem uso do modelo baseado em papéis (roles), onde concedem ou negam acesso à algum recurso da aplicação se o usuário está ou não contido em um grupo específico. Tecnicamente falando, sempre recorremos a utilização de alguma implementação da interface IPrincipal, que fornece um método chamado IsInRole, que dado o papel retorna um valor boleano indicando se o usuário corrente está ou não contido nele.

Como já comentei anteriormente, a autorização baseada em claims é muito mais flexível do que isso, ou seja, não estamos condicionados a somente trabalhar com papéis (simples strings), mas também avaliar se o usuário poderá ou não acessar um determinado recurso a partir da sua idade, ou somente se o seu cartão de crédito estiver válido, e assim por diante.

Uma das grandes preocupações que a Microsoft teve, foi em manter compatibilidade com o modelo de objetos que utilizamos desde a primeira versão do .NET Framework, mas conseguindo já tirar proveito deste novo modelo. E foi justamente pensando nisso, que ela criou as interfaces IClaimsIdentity e IClaimsPrincipal. Elas já foram comentadas com mais detalhes neste artigo, e somente para recapitular, uma das principais propriedades é a Claims, exposta pela interface IClaimsIdentity, que fornece o conjunto de claims que foram emitidas pelo autenticador para o usuário atual.

A propriedade RoleClaimType também foi criada com propósito de compatibilidade. Como todas as informações emitidas por um STS chegam para uma relying party através de claims, é necessário saber qual ou quais as claims representam os papéis (IPrincipal.IsInRole). Com isso, podemos continuar utilizando a autorização baseada em papéis, mas nos bastidores, são claims que estão sendo utilizadas. Com isso, por mais que começamos a utilizar as técnicas de autenticação através do WIF, a autorização pode continuar da forma que está, sem a necessidade de sofrer qualquer alteração.

Como sabemos, entre as claims que existem predefinidas nas especificações, ainda podemos criar claims customizadas. Isso quer dizer que um STS pode emitir uma claim sem vincular ela ao tipo role, que por padrão, a aplicação utiliza quando chamamos o método IsInRole. Mas felizmente isso pode ser configurado de forma declarativa, onde cada aplicação determina qual a claim que ela vai quer utilizar/avaliar quando o método IsInRole for chamado. Para efetuar essa customização, podemos recorrer ao sub-elemento roleClaimType do elemento samlSecurityTokenRequirement, assim como é mostrado abaixo:

<samlSecurityTokenRequirement>
  <roleClaimType value= “http://MinhaAplicacao/departamento&#8221; />
</samlSecurityTokenRequirement>

Como comentado acima, podemos continuar trabalhando com a segurança baseada em papéis. E para isso, utilizamos o método IsInRole exposto pela interface IPrincipal ou através da classe PrincipalPermission, ou ainda, do atributo PrincipalPermissionAttribute, que nos permite trabalhar de forma imperativa ou declarativa, respectivamente. Todas deverão recorrer as claims do tipo role (http://schemas.microsoft.com/ws/2008/06/identity/claims/role) ou alguma outra, conforme configuramos acima. Mas o WIF também fornece um novo par de classes para trabalhar explicitamente com claims, a saber: ClaimsPrincipalPermission e ClaimsPrincipalPermissionAttribute. Ambas também servem para utilizar de forma imperativa ou declarativa, respectivamente, mas como já podemos perceber, vai além de somente utilizar claims como roles. Podemos aqui utilizar outras claims que foram emitidas pelo STS, e tornar o processo de autorização muito mais inteligente.

Como comentado, o uso pode ser de forma imperativa ou declarativa. Utilizar um modo ou outro tem suas vantagens e desvantagens. De qualquer forma, a utilização é extremamente fácil, pois é semelhante ao modelo que já estamos acostumados a trabalhar dentro da plataforma .NET. Para exemplificar, o exemplo abaixo mostra a utilização de ambas as formas:

[ Modelo Imperativo ]

public string AlgumaOperacao()
{
    new ClaimsPrincipalPermission(“AlgumaOperacao”, “Executar”).Demand();

    //Processamento do Método
}

[ Modelo Declarativo ]

[ClaimsPrincipalPermission(SecurityAction.Demand, Resource = “AlgumaOperacao”, Action = “Executar”)]
public string AlgumaOperacao()
{
    //Processamento do Método
}

Apesar de aparentemente funcionar como o modelo baseado em papéis, o WIF nos induz a não fixar o valor das claims pelo nosso código, que é algo que mais cedo ou mais tarde sempre acaba mudando, e justamente por isso que temos as propriedades Resource e Action, mas não devemos nos preocupar com o que significado delas agora, pois o seu uso está condicionado ao ambiente em que são utilizadas, e que serão detalhados mais abaixo. Um detalhe importante também é que as duas classes que representam a permissão não são responsáveis por efetivamente validar se o usuário poderá ou não acessar aquele recurso; isso é delegado à uma outra classe, chamada ClaimsAuthorizationManager, qual veremos a seguir.

O processo de autorização é altamente customizável, o que nos permite interceptar o momento em que o runtime avalia se o usuário possui ou não permissão, e com isso alterar o comportamento padrão, nos baseando em outras claims que foram emitidas para tomar a decisão se o usuário deverá ou não acessar o recurso.

Independentemente de qual ambiente estamos falando (ativo ou passivo), as classes que lidam com o processo de autorização são as mesmas. A diferença consiste nas informações que são colocadas dentro dessas classes, pois elas são contextualizadas, condicionados ao ambiente. A principal classe que irá gerenciar isso é a ClaimsAuthorizationManager, que fornece um local central para analisarmos a requisição e determinar se o usuário poderá ou não acessar o recurso. Essa classe possui um único método chamado CheckAccess, que é disparado antes de acessar o recurso em si, e dado o contexto da requisição, retorna um valor boleano indicando se o usuário terá acesso ao mesmo, e que por padrão sempre permite o acesso.

Como dito acima, o método CheckAccess recebe o contexto da requisição como parâmetro, fornecendo todas as informações necessárias para a tomada de decisão. Esse parâmetro é do tipo AuthorizationContext, e possui três principais propriedades: Principal, Resource e Action. A primeira propriedade retorna uma instância da classe ClaimsPrincipal, que representa o usuário atual. Já a propriedade Resource determina o recurso que você está tentando acessar, e isso varia de acordo com o ambiente. Finalmente, a propriedade Action determina a operação que está sendo aplicada ao recurso, e assim como a propriedade Resource, também varia de acordo com o ambiente.

Quando implementamos a classe ClaimsAuthorizationManager para o ambiente passivo, a propriedade Resource trará o caminho e nome da página ASPX que estamos tentando acessar e a Action deve retornar se está sendo acessada via GET ou via POST. Já no ambiente ativo, a propriedade Resource deverá representar o endereço do serviço que está sendo acessado, enquanto a propriedade Action deverá refletir a SOAPAction da operação. A propriedade Principal tem o mesmo significado para ambos ambientes, ou seja, representar o usuário que está tentando acessar o recurso. Como há algumas outras diferenças entre os dois ambientes, vamos analisar a sua implementação individualmente a partir de agora.

Autorização no Ambiente Passivo – ASP.NET

A implementação da classe ClaimsAuthorizationManager para o ambiente passivo, consistirá em avaliar se a página (ASPX) que o usuário está acessado poderá ou não ser acessado, de acordo com uma regra determinada. Cada página que for acessada por aquele usuário, o runtime do WIF em conjunto com o ASP.NET invocará o método CheckAccess, que é onde terá toda a lógica de autorização.

Como exemplo, vamos somente permitir o acesso à uma determinada página se o usuário for maior que 21 anos de idade. Como o STS emite uma claim chamada dataDeNascimento, podemos efetuar o cálculo em cima dela, para avaliar se o usuário poderá ou não acessar a página. Abaixo temos a implementação:

public class AutorizadorDePaginas : ClaimsAuthorizationManager
{
    public override bool CheckAccess(AuthorizationContext context)
    {
        if (context.Resource.First().Value == “http://localhost:2721/PaginaRestrita.aspx&#8221;)
        {
            var claimDeDataDeNascimento =
                (
                    from in context.Principal.Identities[0].Claims
                    where c.ClaimType == “http://MinhaAplicacao/dataDeNascimento&#8221;
                    select c
                ).FirstOrDefault();

            if (claimDeDataDeNascimento != null)
            {
                DateTime dataDeNascimento = Convert.ToDateTime(claimDeDataDeNascimento.Value);
                return (DateTime.Now.Subtract(dataDeNascimento).Days / 365) >= 21;
            }

            return false;
        }

        return true;
    }
}

Em primeiro lugar verificamos se a página que está sendo acessada deve ser verificada quanto a permissão. Como sabemos que devemos filtrar o acesso a partir da idade, então vamos em busca de uma claim que represente a data de nascimento do usuário, e se encontrada, verificamos se ele já possui mais que 21 anos. Se ele tiver, então ele pode acessar, do contrário, terá o acessado negado.

Mas essa implementação por si só não funciona. Temos que saber como acoplá-la ao pipeline de processamento do ASP.NET. Na verdade, o responsável por invocar o método CheckAccess será o módulo ClaimsAuthorizationModule, que por padrão, não está configurado. Esse módulo se vincula ao evento AuthorizeRequest do objeto HttpApplication, e quando é disparado, irá extrair o autorizador configurado na seção do WIF e, consequentemente, irá passar a instância da classe AuthorizationContext, onde o Resource representará o caminho até a página ASPX e a Action deve representar o verbo HTTP (GET ou POST). Abaixo temos a configuração no arquivo Web.config que correspondem ao módulo e ao autorizador:

<system.web>
  <!– Outras Configurações –>
  <httpModules>
    <!– Outros Módulos –>
    <add name=”ClaimsAuthorizationModule”
         type=”Microsoft.IdentityModel.Web.ClaimsAuthorizationModule, Microsoft.IdentityModel, …”/>
  </httpModules>
</system.web>
<microsoft.identityModel>
  <service>
    <!– Outras Configurações –>
    <claimsAuthorizationManager
        type=”Servico.AutorizadorDePaginas, Servico, Version=1.0.0.0, …”/>
  </service>
</microsoft.identityModel>

Autorização no Ambiente Ativo – WCF

Já no WCF vamos trabalhar de forma parecida ao que vimos acima, ao que diz respeito a forma de implementar a classe responsável pela autorização do usuário. As ligeiras diferenças estão nas informações que são colocadas na classe AuthorizationContext e como ela é acoplada à execução.

Neste ambiente, a propriedade Resource representará o serviço que está sendo acessado, mais precisamente, o endereço do mesmo. Já a propriedade Action determinará a SOAPAction que o usuário quer invocar. A SOAPAction é um header que é incluído na requisição HTTP, e determina intenção da requisição SOAP. Esse header é representado por uma URI que não aponta necessariamente para um local válido na internet, e que indicará qual o método a ser invocado.

A ideia aqui é justamente analisar a SOAPAction, verificando se trata-se de uma operação que exige a validação da permissão do usuário. Caso seja, então vamos verificar se ele possui a idade suficiente para acessar a operação em questão. Abaixo temos a implementação, bem próxima a qual fizemos no ambiente passivo:

public class AutorizadorDeOperacoes : ClaimsAuthorizationManager
{
    public override bool CheckAccess(AuthorizationContext context)
    {
        if (context.Action.First().Value == “http://tempuri.org/IConsultasFinanceiras/RecuperarLimiteDeCredito&#8221;)
        {
            var claimDeDataDeNascimento =
                (
                    from c in context.Principal.Identities[0].Claims
                    where c.ClaimType == “http://MinhaAplicacao/dataDeNascimento&#8221;
                    select c
                ).FirstOrDefault();

            if (claimDeDataDeNascimento != null)
            {
                DateTime dataDeNascimento = Convert.ToDateTime(claimDeDataDeNascimento.Value);
                return (DateTime.Now.Subtract(dataDeNascimento).Days / 365) >= 21;
            }

            return false;
        }

        return true;
    }
}

A principal diferença aqui é como o WIF acopla isso à execução no WCF, que deve executá-la sempre quando uma nova requisição chegar ao serviço. Para que o serviço faça uso do WIF, é necessário submetermos a instância da classe ServiceHost para o método estático ConfigureServiceHost da classe FederatedServiceCredentials, assim como já foi mostrado neste artigo. Assim como no ASP.NET, o que o WIF faz aqui é utilizar um ponto de estensibilidade do WCF para adicionar a implementação do ClaimsAuthorizationManager, e para isso, o WIF já possui implementado uma classe que deriva de ServiceAuthorizationManager, que é a IdentityModelServiceAuthorizationManager, e em seu método CheckAccessCore captura o autorizador implementado/configurado pelo WIF e invoca o seu método CheckAccess, abastecendo a instância da classe AuthorizationContext com informações que estão dentro do contexto da operação (OperationContext).

Sendo assim, tudo o que precisamos aqui é configurar o autorizador customizado, para que o runtime do WIF possa capturá-lo e, consequentemente, entregar ao WCF para efetuar a validação. O código abaixo ilustra essa configuração, que é realizada da mesma forma que no ambiente passivo:

<microsoft.identityModel>
  <service>
    <!– Outras Configurações –>
    <claimsAuthorizationManager
        type=”Servico.AutorizadorDeOperacoes, Servico, Version=1.0.0.0, …”/>
  </service>
</microsoft.identityModel>

Claims Explícitas

Para ratificar o que disse acima, em ambos cenários não temos as claims espalhadas pela aplicação. Como isso pode mudar, o ideal é manter centralizado, para facilitar a alteração caso ela seja necessária.

O mesmo vale para as classes que falamos acima: ClaimsPrincipalPermission e ClaimsPrincipalPermissionAttribute. Quando as utilizamos, nós vimos que tudo o que precisamos colocar ali é o Resource e Action, que determinam informações sobre o acesso e não sobre a claim que deve ser utilizada/avaliada.

Essas classes não são responsáveis por fazerem a verificação. Intermamente elas recorrem a implementação da classe ClaimsAuthorizationManager, que deve estar configurada da forma que vimos acima. Caso não tenhamos um autorizador explicitamente definido, o WIF utilizará uma implementação padrão, que sempre concederá o acesso. O mais interessante aqui é que as informações que colocamos nestas classes também são enviadas para a classe que herda de ClaimsAuthorizationManager, pois elas invocam o método CheckAccess, abstecendo o AuthorizationContext com as respectivos informações.

Nativamente o WIF não traz suporte para vinculação de claims à um determinado recurso, mas podemos criar algo customizado para isso. A ideia é ter algum repositório para catalogar as políticas de acesso à determinados recursos, por exemplo, para acessar uma determinada página ASPX ou uma operação de um serviço, precisamos verificar se a quantidade de anos da claim dataDeNascimento é maior que 21. Esse repositório pode ser um arquivo Xml, uma base de dados ou até mesmo o próprio arquivo de configuração (*.config). Criando algo customizado, nos permite tornar a implementação do ClaimsAuthorizationManager mais simples, dinâmica e ainda mantendo a centralização.

Conclusão: Vimos neste artigo o processo de autorização de uma aplicação que opta por fazer o uso do WIF para terceirizar a autenticação do usuário. Apesar de autorização ainda ser responsabilidade da relying party, o WIF se preocupou em fornecer classes para tornar esse processo mais suave, e não menos importante, mantendo compatibilidade com o legado, que são aplicações que se baseiam em papéis para refinar o acesso aos seus respectivos recursos.

Inspetor de mensagens para o WIF

Recentemente o Dominick Baier lançou um inspetor de requisições para o Fiddler, que tem a finalidade de mostrar as mensagens geradas pelo WIF de uma forma mais amigável. Abaixo podemos visualizar a inspetor já instalado e em funcionamento. Note que podemos visualizar as claims que foram emitidas pelo STS, facilitando eventuais depurações que talvez serão necessárias durante a utilização do WIF.

Recursos das Palestras do TechEd Brasil 2010

Conforme havia comentado aqui, efetuei duas palestras no TechEd Brasil 2010, onde a primeira foi para falar sobre serviços REST no WCF, e a segunda sobre WIF.

Gostaria de agradecer a todos os presentes, e é importante dizer que qualquer dúvida, crítica ou sugestão é sempre bem-vinda. Obrigado também ao Rodolfo Roim, Rogerio Cordeiro, João Paulo Clementi, Fabio Hara, Renato Haddad e ao Waldemir Cambiucci, que me ajudaram direta ou indiretamente para que essas palestras fossem realizadas.