Autenticador de token
Este exemplo demonstra como implementar um autenticador de token personalizado. Um autenticador de token no Windows Communication Foundation (WCF) é usado para validar o token usado com a mensagem, verificar se ele é autoconsistente e autenticar a identidade associada ao token.
Os autenticadores de token personalizados são úteis em uma variedade de casos, como:
Quando você deseja substituir o mecanismo de autenticação padrão associado a um token.
Quando você está criando um token personalizado.
Este exemplo demonstra o seguinte:
Como um cliente pode autenticar usando um par de nome de usuário/senha.
Como o servidor pode validar as credenciais do cliente usando um autenticador de token personalizado.
Como o código de serviço WCF se conecta com o autenticador de token personalizado.
Como o servidor pode ser autenticado usando o certificado X.509 do servidor.
Este exemplo também mostra como a identidade do chamador é acessível a partir do WCF após o processo de autenticação de token personalizado.
O serviço expõe um único ponto de extremidade para comunicação com o serviço, definido usando o arquivo de configuração App.config. O ponto de extremidade consiste em um endereço, uma vinculação e um contrato. A associação é configurada com um padrão wsHttpBinding
, com o modo de segurança definido como mensagem - o modo padrão do wsHttpBinding
. Este exemplo define o padrão wsHttpBinding
para usar a autenticação de nome de usuário do cliente. O serviço também configura o certificado de serviço usando serviceCredentials
comportamento. O securityCredentials
comportamento permite especificar um certificado de serviço. Um certificado de serviço é usado por um cliente para autenticar o serviço e fornecer proteção de mensagem. A configuração a seguir faz referência ao certificado localhost instalado durante a instalação de exemplo, conforme descrito nas instruções de configuração a seguir.
<system.serviceModel>
<services>
<service
name="Microsoft.ServiceModel.Samples.CalculatorService"
behaviorConfiguration="CalculatorServiceBehavior">
<host>
<baseAddresses>
<!-- configure base address provided by host -->
<add baseAddress ="http://localhost:8000/servicemodelsamples/service" />
</baseAddresses>
</host>
<!-- use base address provided by host -->
<endpoint address=""
binding="wsHttpBinding"
bindingConfiguration="Binding1"
contract="Microsoft.ServiceModel.Samples.ICalculator" />
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="Binding1">
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="CalculatorServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="False" />
<!--
The serviceCredentials behavior allows one to define a service certificate.
A service certificate is used by a client to authenticate the service and provide message protection.
This configuration references the "localhost" certificate installed during the setup instructions.
.... -->
<serviceCredentials>
<serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
A configuração do ponto de extremidade do cliente consiste em um nome de configuração, um endereço absoluto para o ponto de extremidade do serviço, a associação e o contrato. A associação do cliente é configurada com o apropriado Mode
e clientCredentialType
.
<system.serviceModel>
<client>
<endpoint name=""
address="http://localhost:8000/servicemodelsamples/service"
binding="wsHttpBinding"
bindingConfiguration="Binding1"
contract="Microsoft.ServiceModel.Samples.ICalculator">
</endpoint>
</client>
<bindings>
<wsHttpBinding>
<binding name="Binding1">
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
A implementação do cliente define o nome de usuário e a senha a serem usados.
static void Main()
{
...
client.ClientCredentials.UserNamePassword.UserName = username;
client.ClientCredentials.UserNamePassword.Password = password;
...
}
Autenticador de token personalizado
Use as seguintes etapas para criar um autenticador de token personalizado:
Escreva um autenticador de token personalizado.
O exemplo implementa um autenticador de token personalizado que valida que o nome de usuário tem um formato de email válido. Deriva o UserNameSecurityTokenAuthenticator. O método mais importante nesta classe é ValidateUserNamePasswordCore(String, String). Nesse método, o autenticador valida o formato do nome de usuário e também que o nome do host não é de um domínio não autorizado. Se ambas as condições forem atendidas, ele retornará uma coleção somente leitura de instâncias que será usada para fornecer declarações que representam as informações armazenadas no token de nome de IAuthorizationPolicy usuário.
protected override ReadOnlyCollection<IAuthorizationPolicy> ValidateUserNamePasswordCore(string userName, string password) { if (!ValidateUserNameFormat(userName)) throw new SecurityTokenValidationException("Incorrect UserName format"); ClaimSet claimSet = new DefaultClaimSet(ClaimSet.System, new Claim(ClaimTypes.Name, userName, Rights.PossessProperty)); List<IIdentity> identities = new List<IIdentity>(1); identities.Add(new GenericIdentity(userName)); List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>(1); policies.Add(new UnconditionalPolicy(ClaimSet.System, claimSet, DateTime.MaxValue.ToUniversalTime(), identities)); return policies.AsReadOnly(); }
Forneça uma política de autorização que é retornada pelo autenticador de token personalizado.
Este exemplo fornece sua própria implementação de IAuthorizationPolicy chamado
UnconditionalPolicy
que retorna conjunto de declarações e identidades que foram passadas para ele em seu construtor.class UnconditionalPolicy : IAuthorizationPolicy { String id = Guid.NewGuid().ToString(); ClaimSet issuer; ClaimSet issuance; DateTime expirationTime; IList<IIdentity> identities; public UnconditionalPolicy(ClaimSet issuer, ClaimSet issuance, DateTime expirationTime, IList<IIdentity> identities) { if (issuer == null) throw new ArgumentNullException("issuer"); if (issuance == null) throw new ArgumentNullException("issuance"); this.issuer = issuer; this.issuance = issuance; this.identities = identities; this.expirationTime = expirationTime; } public string Id { get { return this.id; } } public ClaimSet Issuer { get { return this.issuer; } } public DateTime ExpirationTime { get { return this.expirationTime; } } public bool Evaluate(EvaluationContext evaluationContext, ref object state) { evaluationContext.AddToTarget(this, this.issuance); if (this.identities != null) { object value; IList<IIdentity> contextIdentities; if (!evaluationContext.Properties.TryGetValue("Identities", out value)) { contextIdentities = new List<IIdentity>(this.identities.Count); evaluationContext.Properties.Add("Identities", contextIdentities); } else { contextIdentities = value as IList<IIdentity>; } foreach (IIdentity identity in this.identities) { contextIdentities.Add(identity); } } evaluationContext.RecordExpirationTime(this.expirationTime); return true; } }
Escreva um gerenciador de token de segurança personalizado.
O SecurityTokenManager é usado para criar um SecurityTokenAuthenticator para objetos específicos SecurityTokenRequirement que são passados
CreateSecurityTokenAuthenticator
para ele no método. O gerenciador de token de segurança também é usado para criar provedores de token e serializadores de token, mas esses não são cobertos por este exemplo. Neste exemplo, o gerenciador de token de segurança personalizado herda da classe e substitui o método para retornar autenticadorCreateSecurityTokenAuthenticator
de token de nome de usuário personalizado quando os requisitos de token passados indicam que o autenticador de nome de ServiceCredentialsSecurityTokenManager usuário é solicitado.public class MySecurityTokenManager : ServiceCredentialsSecurityTokenManager { MyUserNameCredential myUserNameCredential; public MySecurityTokenManager(MyUserNameCredential myUserNameCredential) : base(myUserNameCredential) { this.myUserNameCredential = myUserNameCredential; } public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver) { if (tokenRequirement.TokenType == SecurityTokenTypes.UserName) { outOfBandTokenResolver = null; return new MyTokenAuthenticator(); } else { return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver); } } }
Escreva uma credencial de serviço personalizada.
A classe de credenciais de serviço é usada para representar as credenciais configuradas para o serviço e cria um gerenciador de token de segurança que é usado para obter autenticadores de token, provedores de token e serializadores de token.
public class MyUserNameCredential : ServiceCredentials { public MyUserNameCredential() : base() { } protected override ServiceCredentials CloneCore() { return new MyUserNameCredential(); } public override SecurityTokenManager CreateSecurityTokenManager() { return new MySecurityTokenManager(this); } }
Configure o serviço para usar a credencial de serviço personalizada.
Para que o serviço use a credencial de serviço personalizada, excluímos a classe de credencial de serviço padrão depois de capturar o certificado de serviço que já está pré-configurado na credencial de serviço padrão e configuramos a nova instância de credencial de serviço para usar os certificados de serviço pré-configurados e adicionar essa nova instância de credencial de serviço aos comportamentos de serviço.
ServiceCredentials sc = serviceHost.Credentials; X509Certificate2 cert = sc.ServiceCertificate.Certificate; MyUserNameCredential serviceCredential = new MyUserNameCredential(); serviceCredential.ServiceCertificate.Certificate = cert; serviceHost.Description.Behaviors.Remove((typeof(ServiceCredentials))); serviceHost.Description.Behaviors.Add(serviceCredential);
Para exibir as informações do chamador, você pode usar o PrimaryIdentity conforme mostrado no código a seguir. O Current contém informações de declarações sobre o chamador atual.
static void DisplayIdentityInformation()
{
Console.WriteLine("\t\tSecurity context identity : {0}",
ServiceSecurityContext.Current.PrimaryIdentity.Name);
return;
}
Quando você executa o exemplo, as solicitações de operação e as respostas são exibidas na janela do console do cliente. Pressione ENTER na janela do cliente para desligar o cliente.
Arquivo em lote de instalação
O arquivo em lote Setup.bat incluído neste exemplo permite configurar o servidor com certificados relevantes para executar um aplicativo auto-hospedado que requer segurança baseada em certificado de servidor. Esse arquivo em lotes deve ser modificado para funcionar entre computadores ou para funcionar em um caso não hospedado.
A seguir apresentamos uma breve visão geral das diferentes seções dos arquivos em lote para que eles possam ser modificados para serem executados na configuração apropriada.
Criação do certificado do servidor.
As linhas a seguir do arquivo em lotes Setup.bat criam o certificado do servidor a ser usado. A
%SERVER_NAME%
variável especifica o nome do servidor. Altere essa variável para especificar seu próprio nome de servidor. O padrão neste arquivo em lotes é localhost.echo ************ echo Server cert setup starting echo %SERVER_NAME% echo ************ echo making server cert echo ************ makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=%SERVER_NAME% -sky exchange -pe
Instalando o certificado do servidor no armazenamento de certificados confiáveis do cliente.
As linhas a seguir no arquivo em lote Setup.bat copiam o certificado do servidor para o armazenamento de pessoas confiáveis do cliente. Esta etapa é necessária porque os certificados gerados por Makecert.exe não são implicitamente confiáveis pelo sistema cliente. Se você já tiver um certificado enraizado em um certificado raiz confiável do cliente, por exemplo, um certificado emitido pela Microsoft, esta etapa de preencher o armazenamento de certificados do cliente com o certificado do servidor não será necessária.
certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople
Nota
O arquivo em lote de instalação foi projetado para ser executado a partir de um prompt de comando do SDK do Windows. Ele requer que a variável de ambiente MSSDK aponte para o diretório onde o SDK está instalado. Essa variável de ambiente é definida automaticamente em um prompt de comando do SDK do Windows.
Para configurar e compilar o exemplo
Certifique-se de ter executado o procedimento de instalação única para os exemplos do Windows Communication Foundation.
Para criar a solução, siga as instruções em Criando os exemplos do Windows Communication Foundation.
Para executar o exemplo no mesmo computador
Execute Setup.bat a partir da pasta de instalação de exemplo dentro de um prompt de comando do Visual Studio aberto com privilégios de administrador. Isso instala todos os certificados necessários para executar o exemplo.
Nota
O arquivo em lotes Setup.bat foi projetado para ser executado a partir de um prompt de comando do Visual Studio. A variável de ambiente PATH definida no prompt de comando do Visual Studio aponta para o diretório que contém executáveis exigidos pelo script Setup.bat.
Inicie service.exe a partir de service\bin.
Inicie client.exe a partir de \client\bin. A atividade do cliente é exibida no aplicativo de console do cliente.
Se o cliente e o serviço não puderem se comunicar, consulte Dicas de solução de problemas para exemplos de WCF.
Para executar o exemplo em computadores
Crie um diretório no computador de serviço para os binários de serviço.
Copie os arquivos de programa de serviço para o diretório de serviço no computador de serviço. Copie também os arquivos Setup.bat e Cleanup.bat para o computador de serviço.
Você deve ter um certificado de servidor com o nome do assunto que contém o nome de domínio totalmente qualificado do computador. O arquivo App.config do serviço deve ser atualizado para refletir esse novo nome de certificado. Você pode criar um usando o Setup.bat se definir a
%SERVER_NAME%
variável como nome de host totalmente qualificado do computador no qual o serviço será executado. Observe que o arquivo setup.bat deve ser executado a partir de um prompt de comando do desenvolvedor para Visual Studio aberto com privilégios de administrador.Copie o certificado do servidor para o armazenamento CurrentUser-TrustedPeople do cliente. Não é necessário fazer isso, exceto quando o certificado do servidor é emitido por um emissor confiável do cliente.
No arquivo App.config no computador de serviço, altere o valor do endereço base para especificar um nome de computador totalmente qualificado em vez de localhost.
No computador de serviço, execute service.exe a partir de um prompt de comando.
Copie os arquivos de programa cliente da pasta \client\bin\, na pasta específica do idioma, para o computador cliente.
No arquivo Client.exe.config no computador cliente, altere o valor de endereço do ponto de extremidade para corresponder ao novo endereço do seu serviço.
No computador cliente, inicie Client.exe a partir de um prompt de comando.
Se o cliente e o serviço não puderem se comunicar, consulte Dicas de solução de problemas para exemplos de WCF.
Para limpar após a amostra
- Execute Cleanup.bat na pasta de exemplos assim que terminar de executar o exemplo.