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.
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 é:
- 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.
- 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.
- 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.
- 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:
- Comprar e instalar um produto STS, como os Serviços de Federação do Active Directory® (AD FS).
- Assine um produto STS na nuvem, como o LiveID STS.
- 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();
}