Cenário de delegação de identidade com o AD FS

[Do .NET Framework 4.5 em diante, o WIF (Windows Identity Foundation) foi totalmente integrado ao .NET Framework. A versão do WIF abordada por este tópico, o WIF 3.5, foi preterido e só deve ser usado ao desenvolver no .NET Framework 3.5 SP1 ou no .NET Framework 4. Para obter mais informações sobre o WIF no .NET Framework 4.5, também conhecido como WIF 4.5, consulte a documentação do Windows Identity Foundation no Guia de Desenvolvimento do .NET Framework 4.5.]

Esse cenário descreve um aplicativo que precisa acessar recursos de back-end que exigem que a cadeia de delegação de identidade execute verificações de controle de acesso. Uma cadeia de delegação de identidade simples geralmente consiste nas informações sobre o chamador inicial e a identidade do chamador imediato.

Com o modelo de delegação do Kerberos na plataforma do Windows atualmente, os recursos de back-end têm acesso apenas à identidade do chamador imediato e não ao do chamador inicial. Esse modelo é comumente chamado de modelo de subsistema confiável. O WIF mantém a identidade do chamador inicial, bem como o chamador imediato na cadeia de delegação usando a propriedade Actor.

O diagrama a seguir ilustra um cenário típico de delegação de identidade no qual um funcionário da Fabrikam acessa recursos expostos em um aplicativo Contoso.com.

Identity

Os usuários fictícios que participam desse cenário são:

  • Frank: um funcionário da Fabrikam que deseja acessar os recursos da Contoso.
  • Daniel: um desenvolvedor de aplicativos da Contoso que implementa as alterações necessárias no aplicativo.
  • Adam: o administrador de TI da Contoso.

Os componentes envolvidos neste cenário são:

  • Web1: um aplicativo Web com links para recursos de back-end que exigem a identidade delegada do chamador inicial. Esse aplicativo é criado com ASP.NET.
  • Um serviço Web que acessa um SQL Server, que requer a identidade delegada do chamador inicial, juntamente com a do chamador imediato. Esse serviço é criado com o WCF.
  • sts1: um STS que está na função de provedor de declarações e emite declarações que são esperadas pelo aplicativo (Web1). Ele estabeleceu confiança com Fabrikam.com e também com o aplicativo.
  • sts2: um STS que está na função de provedor de identidade para Fabrikam.com e fornece um ponto de extremidade que o funcionário da Fabrikam usa para autenticar. Estabeleceu confiança com Contoso.com para que os funcionários da Fabrikam possam acessar recursos no Contoso.com.

Observação

O termo "token de ActAs", que é usado com frequência nesse cenário, refere-se a um token emitido por um STS e que contém a identidade do usuário. A propriedade Actor contém a identidade do STS.

Conforme mostrado no diagrama anterior, o fluxo neste cenário é:

  1. O aplicativo Contoso é configurado para obter um token de ActAs que contém a identidade do funcionário da Fabrikam e a identidade do chamador imediato na propriedade Actor. O Daniel implementou essas alterações no aplicativo.
  2. O aplicativo Contoso está configurado para passar o token de ActAs para o serviço de back-end. O Daniel implementou essas alterações no aplicativo.
  3. O serviço Web da Contoso é configurado para validar o token de ActAs chamando sts1. Adam habilitou sts1 para processar solicitações de delegação.
  4. O usuário da Fabrikam, Frank, acessa o aplicativo Contoso e recebe acesso aos recursos de back-end.

Configurar o Provedor de Identidade (IP)

Há três opções disponíveis para o administrador do Fabrikam.com, Frank:

  1. Comprar e instalar um produto STS, como os Serviços de Federação do Active Directory® (AD FS).
  2. Assine um produto STS na nuvem, como o LiveID STS.
  3. Crie um STS personalizado usando o WIF.

Para este cenário de exemplo, supomos que Frank selecione a opção 1 e instale o AD FS como o IP-STS. Ele também configura um ponto de extremidade, chamado \windowsauth, para autenticar os usuários. Ao se referir à documentação do produto do AD FS e conversar com Adam, o administrador de TI da Contoso, Frank estabelece a confiança com o domínio Contoso.com.

Configurar o Provedor de Declarações

As opções disponíveis para o administrador do Contoso.com, Adam, são as mesmas descritas anteriormente para o provedor de identidade. Para este cenário de exemplo, presumimos que Adam selecione a Opção 1 e instale o AD FS 2.0 como o RP-STS.

Configurar confiança com o IP e o aplicativo

Ao fazer referência à documentação do AD FS, Adam estabelece a confiança entre Fabrikam.com e o aplicativo.

Configurar delegação

O AD FS fornece processamento de delegação. Ao fazer referência à documentação do AD FS, Adam habilita o processamento de tokens de ActAs.

Alterações específicas do aplicativo

As alterações a seguir devem ser feitas para adicionar suporte à delegação de identidade a um aplicativo existente. O Daniel usa o WIF para fazer essas alterações.

  • Armazene em cache o token de inicialização que a Web1 recebeu de sts1.
  • Use CreateChannelActingAs com o token emitido para criar um canal para o serviço Web de back-end.
  • Chame o método do serviço de back-end.

Armazenar em cache o token de inicialização

O token de inicialização é o token inicial emitido pelo STS e o aplicativo extrai declarações dele. Neste cenário de exemplo, esse token é emitido pelo sts1 para o usuário Frank e o aplicativo o armazena em cache. O exemplo de código a seguir mostra como recuperar um token de inicialização em um aplicativo ASP.NET:

// Get the Bootstrap Token
SecurityToken bootstrapToken = null;

IClaimsPrincipal claimsPrincipal = Thread.CurrentPrincipal as IClaimsPrincipal;
if ( claimsPrincipal != null )
{
    IClaimsIdentity claimsIdentity = (IClaimsIdentity)claimsPrincipal.Identity;
    bootstrapToken = claimsIdentity.BootstrapToken;
}

O WIF fornece um método CreateChannelActingAs, que cria um canal do tipo especificado que aumenta as solicitações de emissão de token com o token de segurança especificado como um elemento do ActAs. É possível passar o token de inicialização para esse método e, em seguida, chamar o método de serviço necessário no canal retornado. Neste cenário de exemplo, a identidade do Frank tem a propriedade Actor definida como identidade da Web1.

O snippet de código a seguir mostra como chamar o serviço Web com CreateChannelActingAs e, em seguida, chamar um dos métodos do serviço, ComputeResponse, no canal retornado:

// Get the channel factory to the backend service from the application state
ChannelFactory<IService2Channel> factory = (ChannelFactory<IService2Channel>)Application[Global.CachedChannelFactory];

// Create and setup channel to talk to the backend service
IService2Channel channel;
lock (factory)
{
// Setup the ActAs to point to the caller's token so that we perform a
// delegated call to the backend service
// on behalf of the original caller.
    channel = factory.CreateChannelActingAs<IService2Channel>(callerToken);
}

string retval = null;

// Call the backend service and handle the possible exceptions
try
{
    retval = channel.ComputeResponse(value);
    channel.Close();
} catch (Exception exception)
{
    StringBuilder sb = new StringBuilder();
    sb.AppendLine("An unexpected exception occurred.");
    sb.AppendLine(exception.StackTrace);
    channel.Abort();
    retval = sb.ToString();
}

Alterações específicas do serviço da Web

Como o serviço Web é criado com o WCF e habilitado para o WIF, depois que a associação é configurada com IssuedSecurityTokenParameters com o endereço do Emissor adequado, a validação do ActAs é tratada automaticamente pelo WIF.

O serviço Web expõe os métodos específicos necessários para o aplicativo. Não há alterações de código específicas necessárias no serviço. O exemplo de código a seguir mostra a configuração do serviço Web com IssuedSecurityTokenParameters:

// Configure the issued token parameters with the correct settings
IssuedSecurityTokenParameters itp = new IssuedSecurityTokenParameters( "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1" );
itp.IssuerMetadataAddress = new EndpointAddress( "http://localhost:6000/STS/mex" );
itp.IssuerAddress = new EndpointAddress( "http://localhost:6000/STS" );

// Create the security binding element
SecurityBindingElement sbe = SecurityBindingElement.CreateIssuedTokenForCertificateBindingElement( itp );
sbe.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;

// Create the HTTP transport binding element
HttpTransportBindingElement httpBE = new HttpTransportBindingElement();

// Create the custom binding using the prepared binding elements
CustomBinding binding = new CustomBinding( sbe, httpBE );

using ( ServiceHost host = new ServiceHost( typeof( Service2 ), new Uri( "http://localhost:6002/Service2" ) ) )
{
    host.AddServiceEndpoint( typeof( IService2 ), binding, "" );
    host.Credentials.ServiceCertificate.SetCertificate( "CN=localhost", StoreLocation.LocalMachine, StoreName.My );

// Enable metadata generation via HTTP GET
    ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
    smb.HttpGetEnabled = true;
    host.Description.Behaviors.Add( smb );
    host.AddServiceEndpoint( typeof( IMetadataExchange ), MetadataExchangeBindings.CreateMexHttpBinding(), "mex" );

// Configure the service host to use WIF
    ServiceConfiguration configuration = new ServiceConfiguration();
    configuration.IssuerNameRegistry = new TrustedIssuerNameRegistry();

    FederatedServiceCredentials.ConfigureServiceHost( host, configuration );

    host.Open();

    Console.WriteLine( "Service2 started, press ENTER to stop ..." );
    Console.ReadLine();

    host.Close();
}

Próximas etapas

Desenvolvimento do AD FS