Este artigo foi traduzido por máquina.

Aplicativos baseados em declarações

Autorização baseada em declarações com o WIF

Michele Leroux Leroux

Baixar o código de exemplo

Nos últimos anos, os modelos de segurança federada e o controle de acesso baseado em declarações se tornaram cada vez mais populares. Em um modelo de segurança federada, autenticação pode ser executada por umasegurança STS (serviço de token) e o STS pode emitir tokens de segurança contendo declarações assert a identidade do usuário autenticado e direitos de acesso do usuário. Federação permite que usuários autentiquem em seupróprio domínio enquanto sendo concedido acesso a aplicativos e serviços que pertencem a outro domínio — desde os domínios têm uma relação de confiança estabelecidas. Essa abordagem elimina a necessidade deprovisionar e gerenciar contas duplicadas para um único usuário e permite único cenários sign-on (SSO). Acesso baseado em declarações é central para um modelo de segurança federada pela qual os aplicativos e serviçosautorizam acesso a recursos e funcionalidade com base em declarações de emissores (STS) em domínios confiáveis. Declarações podem conter informações sobre o usuário, funções ou permissões e isso torna para um modelode autorização muito flexível. Juntos, segurança federada e baseada em declarações acesso permitem uma variedade de cenários de integração entre aplicativos, departamentos e parceiros no ecossistema de maior.

As ferramentas de plataforma nessa área também percorreram um longo caminho. O Windows Identity Foundation (WIF) é uma estrutura avançada de modelos de identidade para a criação de aplicativos e serviços baseados emdeclarações e para o suporte a cenários ativos e passivos de segurança federada. Com WIF, você pode habilitar federação passiva para qualquer aplicativo ASP.NET e integrar um modelo de autorização baseada em declaraçõesem seus aplicativos ASP.NET e serviços WCF sem quebrar um esforço. Além disso, WIF fornece o direcionamento para criar implementações do STS personalizadas e inclui recursos e controles para oferecer suporte a cenáriosde autenticação que envolvem cartões de informações gerenciados e seletores de identidade como o Windows CardSpace.

WIF reduz significativamente o código necessário para implementar cenários sofisticados aplicativos que envolvem a segurança federada e baseada em declarações. Este artigo parte dois, me concentrarei na funcionalidadeprincipal do framework para habilitar federação passiva em aplicativos ASP.NET e para modelos de segurança baseada em declarações de suporte em WCF e ASP.NET. Falarei sobre WCF neste artigo e ASP.NET um posterior.

Por que segurança federada e baseada em declarações?

Os benefícios de segurança federada e baseada em declarações podem ser vistos no contexto de alguns objetivos distintos:

  • Desassociação o mecanismo de autenticação de aplicativos e serviços.
  • Substituindo funções com declarações como um artefato mais flexível, granular para autorização.
  • Reduzindo IT sofrimento relacionado ao provisionamento e desprovisionamento de usuários.
  • Concedendo confiáveis domínios, incluindo possivelmente externos parceiros federados, acesso a recursos de aplicativo e funcionalidade.

Se mesmo um essas metas toques true para seu cenário de aplicativo, adotar um modelo baseado em declarações que pode imediatamente ou eventualmente envolver segurança federada é incrivelmente útil.

Ao projetar os aplicativos e serviços, o modelo de autenticação e autorização é parte deste design. Por exemplo, um aplicativo de intranet normalmente espera usuários para autenticar para um determinado domínio com suascredenciais do Windows, enquanto um aplicativo de Internet geralmente usa um armazenamento de credenciais personalizado como o Microsoft SQL Server. Aplicativos também podem exigir certificados ou autenticaçãoSmartcard ou suporte a vários tipos de credenciais para que diferentes grupos de usuários podem usar o tipo apropriado. Se seu aplicativo somente (e sempre) esperam usuários autenticar com um tipo de credencial único, seutrabalho é fácil. No entanto, mais freqüentemente que não, tipos de credenciais suportados por um aplicativo podem evoluir para dar suporte a modos alternativos de autenticação ou modos adicionais que acomodar um conjuntodiferente de usuários.

Por exemplo, um aplicativo pode oferecer suporte a usuários internos atrás do firewall dentro de um domínio enquanto também suporte aos usuários externos através da Internet. Quando o modelo de segurança para um aplicativoé dissociado do modo de autenticação — como pode ser com um modelo baseado em declarações — há muito pouco, se houver, impacto para o aplicativo quando você introduzir novos modos de autenticação.

Em uma veia semelhante, os aplicativos são mais flexíveis se autorização não está vinculada a um conjunto fixo de funções. Se seu aplicativo será sempre confiar em um conjunto específico de funções para autorizar o acesso ese essas funções sempre irão executar o mesmo significado em termos de direitos de acesso a recursos e funcionalidade, você estará novamente na forma boa. Mas o significado das funções freqüentemente varia entredepartamentos que usam um aplicativo e, assim, exigem personalização. Que pode significar avaliar funções de maneira diferente dependendo do domínio do usuário ou permitindo funções personalizadas ser criado para controlaros direitos de acesso. WIF torna adotando um modelo de segurança baseada em declarações fácil, portanto, é possível desacoplar funções (se aplicável) do mecanismo de autorização. Dessa forma, funções lógicas podem sermapeadas para um conjunto de declarações mais granular e o aplicativo autoriza acesso baseado nessas declarações. Se o novas ou modificadas funções garantem um diferente conjunto de declarações para ser emitida, oaplicativo não é afetado.

Claro, declarações podem ser muito mais do que apenas funções ou permissões. Um dos benefícios adicionais de trabalhar com um modelo baseado em declarações é uma declaração pode transportar informações sobre umusuário autenticado, como endereço de email, nome completo, data de nascimento e assim por diante. Declarações também podem ser usadas para verificar informações, por exemplo, sem compartilhamento idade ounascimento data real de um usuário (informações de muitos usuários não desejam ser conhecimento público). Uma declaração poderia indicar se um usuário é pelo menos a idade necessária para executar uma ação (umadeclaração Boolean indicando IsOver21 ou IsOver13) ou verificar que um usuário pertence a um determinado departamento sem compartilhar uma lista de todos os departamentos que o usuário pertence.

Embora desassociação o mecanismo de autenticação e funções específicas de aplicativos e serviços facilita gentil alteração, o modelo baseado em declarações também é central para cenários de segurança federada, que tornarconcedendo acesso aos usuários pertencentes a qualquer domínio confiável muito mais fácil. Federação reduz a sobrecarga IT e alguns riscos associados ao gerenciamento de identidades. Remove a necessidade de mantercredenciais de usuário em vários aplicativos ou domínios e ajuda a reduzir os riscos ao provisionamento e desprovisionamento de contas em domínios — por exemplo, esquecer de excluir uma conta em vários locais. Sincronização de senha quando várias cópias de uma conta não são gerenciadas também deixará de ser um problema. Federação também facilita cenários SSO porque os usuários podem efetuar logon em um aplicativo e serconcedidos acesso para outro (possivelmente por domínios de segurança) sem precisar autenticar novamente. Finalmente, adicionar novas relações de confiança entre domínios é também feita fácil com plataformas de segurançafederada como servidor de federação do Active Directory (ADFS) e WIF. Assim, estender um aplicativo para domínios adicionais dentro de uma entidade corporativa ou até mesmo para domínios de parceiros externos, ésimplificada.

Federação ativa com WIF

Cenários de federação ativa sejam baseiam o perfil solicitante ativo do WS-Federation (consulte o WS-Federation TC em oasis-open.org/committees/tc_home.php?wg_abbrev=wsfedde ) e a especificação WS-Trust (consulte WS-Trust 1.3 em docs.oasis-open.org/ws-sx/ws-trust/200512/ws-trust-1.3-os.html ). De forma geral, o WS-Trust descreve um contrato com quatro operações de serviços: Emitir, validar, renovar e Cancelar. Respectivamente, essasoperações são chamadas por clientes para solicitar um token de segurança para validar um token de segurança, para renovar um token de segurança expirado e para cancelar um token de segurança não deve ser usado. Cadaoperação processa mensagens na forma de uma solicitação para segurança token (RST) e envia respostas no formulário de um RST Response (RSTR) seguindo a especificação WS-Trust. Esses recursos de WS-Trust sãoimplementados por um STS (ou token emissor), um participante importante em qualquer cenário de segurança federados.

Um cenário de federação ativo simples é ilustrado no do Figura 1. Este cenário envolve um aplicativo cliente do Windows (solicitante), um serviço WCF (a terceira parte confiável ou RP) e um STS pertencentes ao domínio RP(RP-STS). Como mostra a figura, o cliente usa um proxy WCF para coordenar autenticando primeiro para o RP-STS, em seguida, solicitando um token de segurança e chamar RP, passando o token de segurança emitido juntocom a solicitação.


Figura 1 federação Active Simple cenário A

Nesse cenário, RP-STS também é o provedor de identidade (IdP) para autenticar usuários no domínio de RP. Isso significa que o RP-STS é responsável por autenticar usuários, declaram a identidade desses usuários e emitirdeclarações relevantes para a RP para autorização. A RP verifica se o token de segurança emitido pela RP-STS e autoriza acesso com base em declarações emitidas.

Criei um aplicativo de lista de Todo para facilitar a implementação discussões para esse cenário. O exemplo de código que acompanha inclui um cliente WPF, um serviço WCF e um STS ativo implementado com WIF. Parafornecer mais contexto, o serviço WCF TodoListService, implementa o contrato de ITodoListService mostrado do Figura 2. O cliente chama o serviço usando um proxy WCF para obter todos os itens de Todo e para adicionar,atualizar ou excluir itens. O TodoListService depende criar, ler, atualizar e excluir declarações para autorizar o acesso a suas operações.

Figura 2 de de definição de ITodoListService

[ServiceContract(Namespace="urn:TodoListApp/2009/06")]
public interface ITodoListService
{
    [OperationContract]
    List<TodoItem> GetItems();
    [OperationContract]
    string CreateItem(TodoItem item);
    [OperationContract]
    void UpdateItem(TodoItem item);
    [OperationContract]
    void DeleteItem(string id);
}

Para implementar esse cenário de federação ativa, você precisará seguir estas quatro etapas:

  1. Expor um ponto de extremidade do WCF de segurança federada para o TodoListService.
  2. Gerar um proxy WCF para o aplicativo cliente e inicializar o proxy com credenciais para autenticar o RP-STS.
  3. Habilite WIF para TodoListService ativar a autorização baseada em declarações.
  4. Colocar demandas de permissão (IsInRole) ou outras verificações de autorização para controlar o acesso a operações de serviço ou outra funcionalidade.

Discutirei essas etapas nas seções a seguem.

Expondo Endpoints federados

Serviços WCF baseados em declarações normalmente exponham federadas extremidades recebem tokens como aqueles com base em SAML padrão emitidas. WCF fornece duas ligações para oferecer suporte a cenários de segurança federada com WS-Trust. WSFederationHttpBinding é a ligação padrão original com base no WS-Trust 2005 (uma versão anterior do protocolo) e WS2007FederationHttpBinding é a versão mais recente da ligação (lançada com o Microsoft .NET Framework 3.5) e oferece suporte ao WS-Trust 1.3, o padrão aprovado. Normalmente, você deve usar WS2007FederationHttpBinding a menos que seja um requisito de interoperabilidade determina o uso da versão anterior. Um STS com base no ADFS versão 2 ou WIF pode oferecer suporte tanto a versão de WS-Trust.

Ao expor um ponto de extremidade federado para um serviço, geralmente fornecem informações sobre o formato de token de segurança esperado, os tipos de declaração necessários e opcionais e o token emissor confiável. Figura 3 mostra System.ServiceModel listando TodoListService, que expõe um único ponto de extremidade federado sobre WS2007FederationHttpBinding.

Figura 3 do Endpoint federado exposto pelo TodoListService

<system.serviceModel>
  <services>
    <service name="TodoList.TodoListService" 
behaviorConfiguration="serviceBehavior">
      <endpoint address="" binding="ws2007FederationHttpBinding" bindingConfiguration="wsFed" contract="Contracts.ITodoListService" />
      <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      <host>
        <baseAddresses>
          <add baseAddress="http://localhost:8000/TodoListService"/>
        </baseAddresses>
      </host>
    </service>
  </services>
  <bindings>
    <ws2007FederationHttpBinding>
      <binding name="wsFed">
        <security mode="Message" issuedTokenType=
“http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-.1#SAMLV1.1" issuedKeyType="SymmetricKey" negotiateServiceCredential="true">
          <message>
            <claimTypeRequirements>
              <add claimType= 
“https://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" isOptional="false"/>
              <add claimType= "urn:TodoListApp/2009/06/claims/permission" 
isOptional="false"/>
            </claimTypeRequirements>
            <issuerMetadata address="http://localhost:8010/rpsts/mex" />
          </message>
        </security>
      </binding>
    </ws2007FederationHttpBinding>
  </bindings>
  <behaviors>
    <serviceBehaviors>
      <behavior name="serviceBehavior">
        <serviceMetadata/>
      </behavior>
    </serviceBehaviors>
  </behaviors>
</system.serviceModel>

Cenários de segurança federada dependem normalmente tokens SAML, embora não seja um requisito estrito. Para esse cenário, tokens SAML 1.1 são usados, como indicado pelo issuedTokenType URI (docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0.pdf do ). Para um tipo de token alternativo, como SAML 1.0 ou SAML 2.0, use o URI para esse padrão.  Claro, o STS indicado na configuração de ligação federado deve suportar o tipo de token que você está solicitando.

Outras configurações na seção mensagem relevantes incluem issuedKeyType e negotiateServiceCredential. A configuração de issuedKeyType indica se a chave de prova (consulte de blogs.msdn.com/vbertocci/archive/2008/01/02/on-prooftokens.aspx ) é simétrica (padrão) ou assimétricas (executa mais sobrecarga). Novamente, essa configuração deve ser compatível com o STS. Se negotiateServiceCredential é definida como true, o cliente não precisa acesso para a RP pública chave um priori, mas a negociação não é um protocolo interoperável. Se o cliente não for um cliente WCF, você deve definir negotiateServiceCredential para false. Mas não se preocupe. Se for definido como false, geração de proxy com SvcUtil fornece o cliente com uma cópia codificado base64 de chave pública da RP.

Tipos de declaração fornecidos na seção claimTypeRequirements indicam que necessários e opcionais reivindicar tipos que o serviço depende para autorização. Nesse caso, o serviço espera uma declaração de nome para identificar o usuário e pelo menos uma permissão de declaração — um personalizado reivindicar tipo que indica os direitos do usuário para criar, ler, atualizar ou excluir itens de Todo. (Esses declarar tipos listados posteriormente do Figura 4.) A lista de tipos de declaração está incluída nos metadados do serviço para que clientes possam incluir essas informações no RST. Freqüentemente, o STS sabe declarações emitirá para uma determinado RP, que significa que a lista não precisa ser exaustiva na ligação federação.

Figura 4 Claims emitido por usuário para o cenário da lista de Todo aplicativo

Emissor confiável token para esse cenário é RP-STS, o que acontece a ser implementado com WIF. RP-STS expõe um único ponto de extremidade do WS-Trust em http://localhost:8010/rpsts e seu endereço de troca de metadados está localizado em http://localhost:8010/rpsts/mex. Do Figura 3, endereço de metadados do emissor é fornecido na seção issuerMetadata para que quando o cliente gera o proxy, pode descobrir os pontos de extremidade do STS disponíveis.

Suponha que o STS foram expor vários pontos de extremidade — por exemplo, para autenticar usuários de intranet com credenciais do Windows em http://localhost:8010/rpsts/internal e autenticar usuários de Internet com um nome de usuário e senha no http://localhost:8010/rpsts/external. O serviço RP pode optar por especificar um ponto de extremidade do emissor específico associado à sua configuração de ponto de extremidade federado para que quando os clientes geram um proxy, a configuração para se comunicar com o STS corresponde ao ponto de extremidade em vez do primeiro ponto de extremidade compatível. Para fazer isso fornecendo um endereço para o emissor e issuerMetadata elementos como segue:

<issuerMetadata address="http://localhost:8010/rpsts/mex" />
<issuer address="http://localhost:8010/rpsts/mex/external" />

A vantagem dessa abordagem é simplificar a geração de proxy para clientes se houver vários pontos de extremidade do STS para escolher e a RP quer influenciar qual deles é usado. Se a RP não se importa qual ponto de extremidade autentica o cliente para, é melhor fornecer a configuração de issuerMetadata e deixar que o aplicativo cliente determinar o ponto de extremidade apropriado para autenticação.

Tenha em mente que se a configuração do serviço omite o elemento issuerMetadata e fornece apenas o endereço do emissor, o endereço deve avaliar o emissor 's URI lógico (http://localhost:8010/rpsts/issuer), que pode não necessariamente mapear para um endereço físico de ponto de extremidade do STS. Uma configuração equivalente no cliente solicitará que o usuário selecione um cartão de informações gerenciados da mesmo emissor (via Windows CardSpace) e o cartão também deve atender aos critérios do formato do token solicitado e tipos de declaração. Para obter mais informações sobre cenários de federação ativa com o Windows CardSpace, consulte de wpfandcardspace.codeplex.com .

Geração de proxy do cliente

Quando você gerar um proxy para um cliente Windows usando o SvcUtil ou Add Service Reference, o endereço de troca de metadados para o emissor é usado para reunir informações sobre os pontos de extremidade expostos pelo emissor. Para reiterar, alguns cenários possíveis são:

  • Se a federação ligação para o material de ponto de extremidade de serviço RP metadados um emissor de endereço sem um endereço do emissor específico, a configuração do cliente irá incluir o ponto de extremidade do STS protocolo compatível primeiro com qualquer outro compatíveis pontos de extremidade comentada para o desenvolvedor cliente usar opcionalmente.
  • Se a ligação de federação para o serviço RP fornece um endereço de metadados do emissor e um endereço do emissor específico, a configuração do cliente incluirá esse endereço específico (supondo que é protocolo compatível).
  • Se a ligação de federação para o serviço RP fornece apenas um endereço de metadados, a configuração do cliente irá incluir também, somente o endereço de metadados sem uma configuração de ligação para o emissor. Isso significa um seletor de identidade, como o CardSpace será acionado, como mencionei anteriormente.

Supondo que o cliente gera um proxy para TodoListService cuja configuração é mostrada na Figura 3 e o STS expõe um único ponto de extremidade, a versão do lado do cliente da configuração WS2007FederationHttpBinding incluirá as seguintes configurações de emissor e issuerMetadata:

<issuer address="http://localhost:8010/rpsts" 
        binding="ws2007HttpBinding" 
        bindingConfiguration="http://localhost:8010/rpsts">
  <identity>
    <certificate encodedValue="[base64 encoded RP-STS certificate]" />
  </identity>
</issuer>
<issuerMetadata address="http://localhost:8010/rpsts/mex" />

Observe que o elemento emissor Especifica o ponto de extremidade do emissor e a configuração de ligação necessária para se comunicar com o ponto de extremidade. Nesse caso, o cliente autentica para o STS com um nome de usuário e senha usando segurança de mensagem, como mostrado na seguinte configuração WS2007HttpBinding:

<ws2007HttpBinding>
    <binding name="http://localhost:8010/rpsts" >
        <security mode="Message">
            <message clientCredentialType="UserName" 
                     negotiateServiceCredential="false" 
                     algorithmSuite="Default" 
                     establishSecurityContext="false" />
        </security>
    </binding>
</ws2007HttpBinding>

O ponto de extremidade do cliente associa a configuração de ligação de federação com o ponto de extremidade RP:

<client>
  <endpoint address="http://localhost:8000/TodoListService" 
            binding="ws2007FederationHttpBinding" 
            bindingConfiguration="wsFed"
            contract="TodoList.ITodoListService" name="default">
    <identity>
      <certificate encodedValue="[base64 encoded RP certificate" />
    </identity>
  </endpoint>
</client>

Com essa configuração, o proxy do cliente só precisa ser inicializado a com um nome de usuário válido e uma senha antes de chamar o serviço:

TodoListServiceProxy _Proxy = new TodoListServiceProxy("default");

if (!ShowLogin()) return;

this._Proxy.ClientCredentials.UserName.UserName = this.Username;
this._Proxy.ClientCredentials.UserName.Password = this.Password;
this._TodoItems = this._Proxy.GetItems();

Emissão de token

O proxy primeiro fornece credenciais para autenticar para o RP-STS, enviando um RST pede um token SAML 1.1, indicando que a RP requer pelo menos uma declaração de nome e permissão. O usuário é autenticado contra o armazenamento de credenciais do STS e declarações apropriadas são emitidas para o usuário autenticado. O proxy em seguida, processa o RSTR que transporta o token emitido e passa esse token para a RP para estabelecer uma sessão segura para o usuário autenticado.

Por exemplo, o STS foi compilado com WIF e autentica os usuários em um armazenamento de credenciais personalizado, emitir declarações para cada usuário de acordo com do Figura 4.

Observe que um STS com base na versão 2 do ADFS autentica os usuários contra o domínio do Windows e emite declarações de acordo com a sua configuração do ADFS. Um STS personalizado com base em WIF pode autenticar os usuários contra um armazenamento de credenciais de sua escolha, mas você deve reverter seu próprio código para gerenciar o armazenamento de credenciais e o processo de mapeamento de declarações relevante.

 Configuração de modelo de identidade

Para ativar a autorização baseada em declarações para seus serviços WCF usando WIF, inicializar instância ServiceHost para federação. Você pode fazer isso programaticamente, chamando o método ConfigureServiceHost exposto pelo tipo FederatedServiceCredentials, como segue:

ServiceHost host = new ServiceHost(typeof(TodoList.TodoListService));
FederatedServiceCredentials.ConfigureServiceHost(host);
host.Open();

Você pode obter o mesmo resultado declarativamente usando a extensão de comportamento ConfigurationServiceHostBehaviorExtension:

<serviceBehaviors>
  <behavior name="fedBehavior" > 
    <federatedServiceHostConfiguration/>
    <serviceMetadata />
  </behavior>
</serviceBehaviors>

Em qualquer caso, o ServiceHost é atribuído a uma instância do tipo FederatedServiceCredentials ao comportamento de autorização baseada em declarações de unidade para o serviço. Esse tipo pode ser inicializado programaticamente ou pela seção de configuração microsoft.identityModel para o serviço. Configurações de modelo de identidade são específicas para WIF e fornecem configurações de autorização de baseada em declarações em aplicativos ASP.NET e WCF, que o mais do que estão resumidos no do Figura 5.

Figura 5 do Resumo de Essential microsoft.identityModel elementos

Para serviços WCF que usam WIF, você não precisa inicializar o ServiceHost com comportamentos de autenticação e autorização WCF típicos. WIF substitui isso e fornece uma maneira de limpeza para configurar a segurança em geral. (WIF é útil além cenários federados e baseada em declarações). Figura 6 mostra a identidade configurações de modelo usadas para o TodoListService.

Figura 6 do configurações de modelo de identidade fornecidos pelo freqüentemente para serviços WCF

<microsoft.identityModel>
  <service>
    <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.
      ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, 
      Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
      <trustedIssuers>
        <add name="http://localhost:8010/rpsts" thumbprint=
"c3 95 cd 4a 74 09 a7 77 d4 e3 de 46 d7 08 49 86 76 1a 99 50"/>
      </trustedIssuers>
    </issuerNameRegistry>
    <serviceCertificate>
      <certificateReference findValue="CN=RP" storeLocation="LocalMachine" 
         storeName="My" x509FindType="FindBySubjectDistinguishedName"/>
    </serviceCertificate>
    <audienceUris mode="Always">
      <add value="http://localhost:8000/TodoService"/>
    </audienceUris>
    <certificateValidation certificateValidationMode="PeerTrust" />         
    <securityTokenHandlers>
      <remove type="Microsoft.IdentityModel.Tokens.Saml11.
         Saml11SecurityTokenHandler, Microsoft.IdentityModel, 
         Version=1.0.0.0, Culture=neutral, 
         PublicKeyToken=31bf3856ad364e35"/>
      <add type="Microsoft.IdentityModel.Tokens.Saml11.
         Saml11SecurityTokenHandler, Microsoft.IdentityModel, 
         Version=1.0.0.0, Culture=neutral, 
         PublicKeyToken=31bf3856ad364e35">
        <samlSecurityTokenRequirement >
          <roleClaimType 
            value="urn:TodoListApp/2009/06/claims/permission"/>
        </samlSecurityTokenRequirement>
      </add>
    </securityTokenHandlers>
    <claimsAuthorizationManager 
      type="TodoList.CustomClaimsAuthorizationManager, TodoList"/>
  </service>
</microsoft.identityModel>

A configuração de issuerNameRegistry é usada para especificar qualquer emissores de certificado confiável. Se você usar ConfigurationBasedIssuerNameRegistry conforme mostrado no do Figura 6, você deve fornecer uma lista de emissores de certificado confiável especificando suas thumbprints. Em tempo de execução, o ConfigurationBasedIssuerNameRegistry verifica X 509 segurança tokens contra essa lista e rejeita aqueles com thumbprints não encontrados na lista. Você pode usar o SimpleIssuerNameRegistry para permitir que qualquer X 509 ou RSA token, mas mais provavelmente você irá fornecer um tipo personalizado IssuerNameRegistry para validar tokens usando seu próprio heurística se o ConfigurationBasedIssuerNameRegistry não faz a rodada.

A configuração do Figura 6 rejeita qualquer tokens que não são assinados pela RP-STS (usando a impressão digital do certificado para CN = RPSTS). Em vez disso, a seguinte configuração especifica um tipo personalizado IssuerNameRegistry, TrustedIssuerNameRegistry:

<issuerNameRegistry type="TodoListHost.TrustedIssuerNameRegistry, TodoListHost"/>

A implementação de TrustedIssuerNameRegistry é usada para atingir o mesmo resultado — rejeitando tokens não assinados por CN = RPSTS verificando o nome de assunto do token de entrada:

public class TrustedIssuerNameRegistry : IssuerNameRegistry
{
    public override string GetIssuerName(SecurityToken securityToken)
    {
        X509SecurityToken x509Token = securityToken as
            X509SecurityToken;
        if (x509Token != null)
        {
            if (String.Equals(x509Token.Certificate.SubjectName.Name,
                "CN=RPSTS"))
            {
                return x509Token.Certificate.SubjectName.Name;
            }
        }

        throw new SecurityTokenException("Untrusted issuer.");
    }
}

A configuração de serviceCertificate no do Figura 6 indica o certificado a ser usado para descriptografar a entrada tokens de segurança, supondo que eles são criptografados pelo STS emissão para a RP. Para o aplicativo Todo lista, o RP-STS criptografa tokens usando a chave pública para a RP, CN = RP.

Geralmente, o token SAML inclui um elemento URI público que avalia a RP, indicando que o token emitido para. Você pode recusar explicitamente tokens que não foram se destina a ser enviado para a RP. Por padrão, o modo audienceUris é definido como sempre, o que significa que você deve fornecer pelo menos um URI para validação contra entradas tokens. Do Figura 6, a configuração permite que somente os tokens SAML que incluem um URI correspondentes endereço TodoListService público. Embora geralmente não recomendado, você pode definir o modo audienceUris para nunca para suprimir a avaliação da condição de restrição público para um token SAML entrada:

<audienceUris mode="Never"/>

Esteja ciente de que quando o cliente envia um RST ao STS, ele normalmente inclui uma configuração AppliesTo indica que o token deve ser emitido para — a RP. O STS pode usar essas informações para preencher o público de token SAML URI.

CertificateValidation definir controles como entrada X 509 tokens — aqueles usados para assinaturas de token, por exemplo — são validadas. Em do Figura 6, certificateValidationMode é definida para PeerTrust, que significa que os certificados são válidos somente se o certificado associado encontrado no armazenamento de TrustedPeople. Essa configuração é mais apropriada do que PeerOrChainTrust (padrão) para validação do emissor do token porque requer instalar explicitamente o certificado confiável no armazenamento de certificado. PeerOrChainTrust indica que as assinaturas são autorizadas também se a autoridade de certificação (CA) raiz é confiável, que na maioria das máquinas inclui uma lista de CAs confiáveis significativa.

Discutirei algumas das outras configurações de Figura 5 de e de Figura 6 em breve. Um ponto para tornar sobre o assunto da inicialização WIF é que você pode inicializar uma instância FederatedServiceCredentials também programaticamente e passar para o ConfigureServiceHost em vez de inicializar a partir da seção microsoft.identityModel. O código a seguir ilustra isso:

ServiceHost host = new ServiceHost(typeof(TodoList.TodoListService));

ServiceConfiguration fedConfig = new ServiceConfiguration();
fedConfig.IssuerNameRegistry = new TrustedIssuerNameRegistry();
fedConfig.AudienceRestriction.AudienceMode = AudienceUriMode.Always;
fedConfig.AudienceRestriction.AllowedAudienceUris.Add(new 
Uri("http://localhost:8000/TodoListService"));
fedConfig.CertificateValidationMode = 
X509CertificateValidationMode.PeerTrust;
fedConfig.ServiceCertificate = CertificateUtil.GetCertificate(
StoreName.My, StoreLocation.LocalMachine, "CN=RP");

FederatedServiceCredentials fedCreds = 
new FederatedServiceCredentials(fedConfig);

FederatedServiceCredentials.ConfigureServiceHost(host,fedConfig);
host.Open();

Inicialização programática é particularmente útil para inicializar o ServiceHost de configurações de banco de dados que se aplicam a um farm inteiro.

Arquitetura de componente WIF

Quando você aplicar o comportamento WIF a um ServiceHost, vários componentes WIF são inicializados para facilitar a autorização baseada em declarações — muitas das extensões WCF-los. Basicamente, isso leva a um ClaimsPrincipal anexado ao thread de solicitação e isso oferece suporte a autorização baseada em declarações. Figura 7 captura a relação entre os componentes WIF principais e o ServiceHost.


Figura 7 do componente principal instalado com WIF

Tipo FederatedServiceCredentials substitui o comportamento de ServiceCredentials padrão e IdentityModelServiceAuthorizationManager (instalado durante a inicialização do FederatedServiceCredentials) substitui padrão ServiceAuthorizationBehavior. FederatedServiceCredentials também constrói uma instância de FederatedSecurityTokenManager.  Coletivamente, esses tipos de unidade autenticação e autorização para cada solicitação, com a Ajuda de SecurityTokenHandler que se aplica a solicitação específica, o ClaimsAuthorizationManager e o ClaimsAuthenticationManager.

Figura 8 ilustra o fluxo de comunicação para esses componentes que leva para construir uma entidade de segurança para o thread de solicitação — nesse caso, digite um ClaimsPrincipal — e para oportunidades para autorizar o acesso com base na entidade de segurança.


Figura 8 do componentes que criar e podem autorizar contra o ClaimsPrincipal

O FederatedSecurityTokenManager retorna o manipulador de token apropriado para a solicitação — que nesse caso seria o Saml11SecurityTokenHandler — fornecendo com uma referência para o ClaimsAuthorizationManager. O manipulador de token constrói um ClaimsIdentity do token entrado, cria ClaimsPrincipal (via uma classe de wrapper) e passa-o para o método ValidateToken para o ClaimsAuthorizationManager. Isso produz uma oportunidade para modificar ou substituir o ClaimsPrincipal será anexada ao thread de solicitação. A implementação padrão simplesmente retorna o mesmo ClaimsPrincipal fornecido:

public virtual IClaimsPrincipal Authenticate(string resourceName, IClaimsPrincipal incomingPrincipal)
{
    return incomingPrincipal;
}

Você pode considerar fornecendo um ClaimsAuthenticationManager personalizado para transformar declarações entradas do token de segurança em algo que a RP pode usar para autorizar o acesso. Por exemplo, no entanto, o token SAML transporta as declarações RP apropriadas emitidas pela RP-STS e portanto ClaimsPrincipal construído a partir essas declarações funciona para autorização.

Em seguida, IdentityModelServiceAuthorizationManager, que faz referência a ClaimsAuthorizationManager chama seu método CheckAccess, produzindo uma oportunidade para personalizar como o acesso é controlado. A implementação padrão não restringe o acesso:

public virtual bool CheckAccess(AuthorizationContext context)
{
    return true;
}

O parâmetro AuthorizationContext fornece acesso ao ClaimsPrincipal e suas declarações associadas, uma coleção de ações relevantes para a solicitação (como um URI que indica a operação de serviço a ser chamado) e informações sobre o recurso associado à solicitação (por exemplo, o serviço URI), que pode ser útil disambiguate chamadas para vários serviços passando pelo mesmo caminho de autorização. Para implementar a autorização centralizada, você pode fornecer um ClaimsAuthorizationManager personalizado. Descreverei um exemplo quando discutir as técnicas para autorização.

Segurança baseada em função no .NET Framework é fundou a premissa que uma entidade de segurança com base em IPrincipal anexada a cada thread, e essa entidade de segurança encapsula a identidade do usuário autenticado em uma implementação IIdentity. Sem WIF, o WCF anexa uma entidade de segurança para cada thread de solicitação com base na configuração System.ServiceModel para autenticação e autorização. Um tipo de IIdentity é construído com base no tipo de credenciais apresentadas para autenticação. Por exemplo, irá avaliar uma credencial do Windows para uma WindowsIdentity, um certificado X.509 para um X509Identity e um token de UserName para um GenericIdentity. O ServiceAuthorizationBehavior controla o tipo de IPrincipal wrapper para a identidade. Por exemplo, com autorização do Windows, um WindowsPrincipal é construído; com o provedor de associação do ASP.NET, um RoleProviderPrincipal. Caso contrário, uma diretiva de autorização personalizada é usada para construir um objeto IPrincipal de sua escolha. O objeto IPrincipal expõe um método IsInRole que pode ser chamado diretamente ou indiretamente através de demandas de permissão para controlar o acesso a recursos e funcionalidade.

WIF estende esse modelo, fornecendo tipos ClaimsPrincipal e ClaimsIdentity — com base em IClaimsPrincipal e IClaimsIdentity — basicamente que derive de IPrincipal e IIdentity. Todos os tokens são mapeados para um ClaimsIdentity com WIF. Quando cada token de segurança de entrada é validada, seu tipo de SecurityTokenHandler associado constrói um ClaimsIdentity, fornecendo declarações apropriadas. Esse ClaimsIdentity é encapsulado em um ClaimsIdentityCollection (no caso um token produz ClaimsIdentity várias instâncias), e essa coleção é encapsulada em um ClaimsPrincipal e anexada ao thread de solicitação. É essa ClaimsPrincipal é o coração de autorização WIF para seus serviços WCF.

Autorização baseada em declarações

Para serviços WCF, sua abordagem para autorização provavelmente envolverá uma das seguintes técnicas:

  • Use o ClaimsPrincipal para executar verificações de IsInRole dinâmicas.
  • Use o tipo PrincipalPermission realizar demandas de permissão dinâmico.
  • Use o PrincipalPermissionAttribute para fornecer demandas de permissão declarativa em cada operação.
  • Fornece um ClaimsAuthorizationManager personalizado para centralizar verificações de acesso em um único componente.

Os primeiros três dessas opções dependem basicamente o método IsInRole exposto pelo tipo ClaimsPrincipal. Isso não significa exatamente que estão fazendo segurança baseada em função; significa apenas que você selecione um tipo de declaração de função, para que as declarações corretas sejam verificadas contra as declarações solicitadas passadas para IsInRole. O tipo de declaração de função padrão para WIF é schemas.microsoft.com/ws/2008/06/identity/claims/role. Se o STS associado com os problemas do cenário de federação esse tipo de declaração, opcionalmente, você pode controlar acesso com base no tipo de declaração. Para o cenário de aplicativo lista Todo, mencionei que um tipo de declaração de permissão personalizada é usado para autorização, portanto, a configuração de modelo de identidade deve especificar isso como o tipo de declaração de função para facilitar a verificações de IsInRole.

Fornecer o tipo de declaração de função para o SecurityTokenHandler para o tipo de token esperado, nesse caso o Saml11SecurityTokenHandler. Como do Figura 6 ilustra, você pode modificar a configuração padrão para um SecurityTokenHandler removendo-o e adicionando o mesmo que novamente, especificando as configurações de propriedade preferencial. Manipuladores de token SAML têm uma seção samlSecurityTokenRequirement no qual você pode fornecer uma configuração para o nome ou tipo, juntamente com outras configurações relacionadas à validação do certificado e o Windows tokens de declaração de função. Para esse cenário, eu fornecido um tipo de declaração de função personalizado:

<samlSecurityTokenRequirement >
  <roleClaimType value= "urn:TodoListApp/2009/06/claims/permission"/>
</samlSecurityTokenRequirement>

Isso significa que qualquer tempo que IsInRole é chamado para o ClaimsPrincipal verificar para uma declaração de permissão válido. Uma maneira para realizar isso é explicitamente chamada IsInRole antes de que executa uma seção de código que requer uma declaração específica. Você pode acessar o objeto atual através da propriedade thread.CurrentPrincipal como segue:

if (!Thread.CurrentPrincipal.
IsInRole("urn:TodoListApp/2009/06/claims/permission/delete"))
  throw new SecurityException("Access is denied.");

Além de verificações explícitas de IsInRole em tempo de execução, você também pode escrever demandas de permissão clássica baseada em função usando o tipo PrincipalPermission. Inicializar o tipo com a declaração de função necessários (o segundo parâmetro de construtor) e quando Demand é chamado, o método IsInRole do objeto atual é chamado. Uma exceção é lançada se a declaração não for encontrada:

PrincipalPermission p = new PrincipalPermission("", "urn:TodoListApp/2009/06/claims/permission/delete");
p.Demand();

Você também pode construir um PermissionSet para coletar várias declarações para verificar:

PermissionSet ps = new PermissionSet(PermissionState.Unrestricted);
ps.AddPermission(new PrincipalPermission("", "urn:TodoListApp/2009/06/claims/permission/create"));
ps.AddPermission(new PrincipalPermission("", "urn:TodoListApp/2009/06/claims/permission/read"));
ps.Demand();

Se aplicam verificações de acesso para a operação de serviço inteira, você pode aplicar o PrincipalPermissionAttribute em vez disso, que é uma boa maneira de associar declarativamente declarações necessárias para a operação sendo chamado. Esses atributos também podem ser empilhados para verificar várias declarações:

[PrincipalPermission(SecurityAction.Demand, Role = Constants.Permissions.Create)]
[PrincipalPermission(SecurityAction.Demand, Role = Constants.Permissions.Read)]
public string CreateItem(TodoItem item)

Em alguns casos, pode ser útil para centralizar a autorização para um único componente, o que significa que você forneceria uma ClaimsAuthorizationManager personalizado para executar verificações de acesso. Figura 6 ilustra como configurar um ClaimsAuthorizationManager personalizada e a implementação de isso para o TodoListService é mostrada no de Figura 9 (parcialmente listado para concisão).

Figura 9 implementação de ClaimsAuthorizationManager personalizada

class CustomClaimsAuthorizationManager : ClaimsAuthorizationManager
{
    public CustomClaimsAuthorizationManager()
    {
    }

    public override bool CheckAccess(AuthorizationContext context)
    {
        
        if (context.Resource.Where(x=> x.ClaimType == 
            System.IdentityModel.Claims.ClaimTypes.Name && x.Value == 
            "http://localhost:8000/TodoListService").Count() > 0)
        {
            if (context.Action.Where(x=> x.ClaimType == 
                System.IdentityModel.Claims.ClaimTypes.Name && x.Value == 
                Constants.Actions.GetItems).Count() > 0)
            {
                return
                    context.Principal.IsInRole(
                       Constants.Permissions.Read);
            }

        // other action checks for TodoListService
        }
        return false;
    }  
}

O ClaimsAuthorizationManager fornece uma substituição para CheckAccess recebe um parâmetro AuthorizationContext com referência a recurso (no caso, o URI de serviço); uma coleção de ações (no caso, uma única ação indicando a operação de serviço URI); e o ClaimsPrincipal, não está anexado ao thread de solicitação.Você pode verificar o recurso se o componente é compartilhado entre serviços, como este exemplo faz para ilustração.Principalmente, verificará a ação contra uma lista de URIs de operação de serviço e executar verificações de IsInRole acordo com a requisitos da operação.

Geralmente, não sou grande fã do desassociação seleção autorização da operação protegida ou bloco de código.É muito mais fácil de manter o código que é declarado em um local no contexto com a atividade.

Para ser continuado

Neste ponto você deve ter uma boa idéia de como configurar um cenário de federação ativa com o WCF e WIF, incluindo noções básicas sobre ligações de federação para semântica de geração de proxy e WCF; o processo de emissão de token; configurando WIF no serviço; e implementando várias técnicas de autorização baseada em declarações.Em um artigo de acompanhamento, moverei para federação passiva com ASP.NET e WIF.

Michele Leroux Bustamante é chefe de arquitetura na IDesign, Microsoft diretor regional de San Diego e MVP da Microsoft para sistemas conectados.Seu livro mais recente é “ Learning WCF ”. Entre em contato com ela pelo email mlb@idesign.net ou visite idesign.net.Ela também blogs em dasblonde.net de .