Por padrão, serviços WCF utilizam as identidades e grupos do Windows para autenticação e autorização, respectivamente. Um dos grandes problemas é quando temos isso sendo disponibilizado através de uma aplicação web, pois iria requerer que todos os clientes que acessam via web estivessem devidamente cadastrados dentro do Windows; além disso, há o problema com relação aos grupos de usuários, já que muitas vezes não temos acesso para cadastrá-los e, quando isso não é um problema, podemos ter um problema adicional quando estivermos rodando em culturas de servidores diferentes.
Com isso, dificilmente uma aplicação ou serviços que são expostos para a internet utilizam as contas e grupos do Windows. A solução é que felizmente o ASP.NET 2.0 fornece uma infraestrutura completa para o gerenciamento de autenticação e autorização, chamada de Provider Model. Ela nos dá uma enorme flexibilidade, onde podemos trocar a fonte de dados/persistência e a aplicação continua trabalhando normalmente. Este provider é um módulo do software que estamos desenvolvendo que fornece uma interface genérica para uma fonte de dados, onde abstraem a base de dados. Além disso ser flexível, a qualquer momento podemos trocar a base de dados (essa arquitetura também é extensível) ou seja, se mais tarde quisermos customizar algo, podemos fazer isso sem maiores problemas.
Com toda essa infraestrutura já bem desenhada e sendo utilizada largamente no mercado, a Microsoft decidiu, em uma das formas de segurança de serviços WCF, integrar com esse modelo disponibilizado pelo ASP.NET 2.0. Este artigo já assume que você tenha conhecimento suficiente nesta infraestrutura e, em alguns pontos, vamos falar de alguns detalhes mais superficialmente. Se você ainda não estiver a vontade nisso, eu aconselho extremamente ler o artigo Entendendo e Implementando Segurança no ASP.NET 2.0 antes de prosseguir.
O transporte da mensagem
Quando estamos em um cenário de internet, as mensagens são enviadas para o serviço através de puro HTTP, porém é extremamente importante proteger o corpo e as credenciais do usuário durante essa "viagem". A solução para isso é criptografar a mensagem para garantir a integridade e privacidade, utilizando a senha do usuário mas, mais uma vez por questões de segurança, o WCF não utiliza essa forma por ser vulnerável, pois o usuário pode ter uma senha pouco complexa e qualquer um que esteja monitorando a comunicação poderá interceptar e, conseqüentemente, "quebrar" a criptografia.
Para proteger a mensagem, o WCF utiliza um certificado do tipo X.509, que fornece uma proteção extremamente confiável. Este tipo de certificado também autentica unicamente o serviço para o cliente, trabalhando com duas chaves: uma pública e outra privada. Quando criptografamos algo com a chave pública, somente quem tiver a chave privada poderá decriptografar o seu conteúdo e, neste nosso cenário, o detentor da chave pública é o serviço WCF que, por sua vez, deverá manter a chave privada armazenada em algum local seguro para que a mesma não caia em mãos erradas.
A chave pública fica disponível no servidor que expõe o serviço e, sendo assim, qualquer cliente pode acessar os endpoints do serviço WCF e obter a chave pública. Como já sabemos, essa chave pública será utilizada pelo cliente para criptografar todas as mensagens que serão enviadas para o serviço que, por sua vez, quando receber a requisição, irá decriptografá-la utilizando a chave privada e utilizará as credenciais fornecidas pelo usuário para autenticá-lo e, conseqüentemente, permitir o acesso ao serviço.
Para o teste que vamos realizar no decorrer deste artigo, necessitamos de um certificado X.509 para utilizarmos durante a criação do serviço. Como não tenho nenhum certicado disponível, podemos criar um para testes. Para isso, utilizaremos um utilitário chamado Makecert.exe que é fornecido junto com o .NET Framework e pode ser encontrado no seguinte endereço: C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\. Este utilitário cria um par de chave pública e privada e armazena em um arquivo de certificado. Para criar o certificado, abra o prompt de comando do Visual Studio .NET 2005 (isso para evitar o path completo do utilitário) e digite:
makecert -sr LocalMachine -ss My -sky exchange -pe -a sha1 -n "CN=IACertificate" IACertificate.cer
|
Basicamente, através da linha acima, criamos um certificado chamado IACertificate e armazenamos ele em um arquivo chamado IACertificate.cer. Mas é importante dizer sobre cada um das opções que são passadas para o utilitário Makecert.exe, opções que são detalhadas através da tabela abaixo:
| Opção |
Descrição |
| -sr |
Especifica o local onde o certificado será armazenado. Entre esses valores temos: currentuser ou localmachine.
|
| -ss |
Especifica o nome do certificado onde o output será armazenado.
|
| -sky |
Especifica o tipo do certificado, que deve ser signature ou exchange.
|
| -pe |
Define como será gerada a chave privada, o que permite que a mesma seja incluída no certificado.
|
| -a |
Indica qual será o algoritmo usado pelo certificado. Entre os algoritmos temos o md5 (padrão) ou o sha1.
|
| -n |
Especifica o nome do certificado, devendo estar em conformidade com o padrão X.500, que é especifcar o nome entre aspas e precedido por CN=.
|
|
Observações: Se quiser uma lista completa de todas as opções fornecidas pelo utilitário Makecert.exe, consulte este link. Depois de criado o certificado, se desejar visualizá-lo, vá até a opção Run do Windows e digite: mmc; em seguida, vá até o menu File, Add/Remove Snap-in..., terá um botão chamado Add no fim da janela; ao clicar nele um novo formulário será apresentado e na listagem terá um item chamado Certificates que, ao selecioná-lo, abrirá um wizard onde você deverá, na primeira tela apresentada, selecionar a opção Computer account. Isso fará com que todos os certificados do seu computador sejam exibidos na console de administração. Ao navegar até Personal, Certificates, verá ali o certificado recém criado.
Como o nosso foco será disponibilizar isso através de uma aplicação que irá correr dentro do IIS, é necessário concedermos direitos de leitura a chave privada do certificado em questão para as contas dos worker process do IIS. Para isso, temos que seguir dois passos que são mostrados abaixo:
-
Através do utilitário FindPrivateKey.exe, conseguimos identificar a chave privada, para que seja possível encontrá-la e, em seguida, conceder os direitos a mesma. Se não tiver o Microsoft SDK for .NET Framework 3.0 instalado, então voce pode baixar os exemplos de WCF da Microsoft que, dentro dele, existe um projeto chamado FindPrivateKey.sln, que é justamente o projeto que gera esse utilitário.
-
Depois de encontrada a chave, voce pode conceder os direitos através do utilitário cacls.exe (como é mostrado neste post) ou via Windows Explorer, através da aba Security.
Criação do contrato e configuração da autorização
Neste momento, vamos nos concentrar na criação e configuração do serviço WCF. Mais uma vez, vou considerar como conhecimento prévio o procedimento para a criação de serviço básico de WCF, principalmente no que diz respeito aos atributos que devem ser aplicados aos tipos para torná-lo um serviço WCF. Para o exemplo, vamos criar um contrato padrão, chamado de IServiceContract, que será implementado pelos serviços concretos. Esse contrato (uma Interface) terá dois métodos simples, chamados de BoasVindas e HoraAtual. Essa Interface está exibida abaixo:
using System;
using System.ServiceModel;
namespace DevMinds.ComponentCS
{
[ServiceContract]
public interface IServiceContract
{
[OperationContract]
string BoasVindas();
[OperationContract]
DateTime DataAtual();
}
}
|
Como estamos falando sobre a integração com a segurança do ASP.NET, esse serviço utilizará como
hosting o IIS. Sendo assim, temos uma arquivo com extensão
*.svc que implementa a
Interface definida acima. A única exceção para um exemplo simples, é que os métodos são decorados com o atributo
PrincipalPermissionAttribute. Esse atributo, contido dentro do
namespace System.Security.Permissions, permite você configurar as informações de segurança, mais especificamente de autorização, utilizando o padrão declarativo e, como podemos notar no exemplo abaixo, cada um dos métodos pode ser invocado por um grupo específico:
using System;
using System.Threading;
using System.Security.Permissions;
using DevMinds.ComponentCS;
public class DefaultService : IServiceContract
{
[PrincipalPermission(SecurityAction.Demand, Role = "User")]
public string BoasVindas()
{
return string.Format("Ola {0}!",
Thread.CurrentPrincipal.Identity.Name);
}
[PrincipalPermission(SecurityAction.Demand, Role = "Manager")]
public DateTime DataAtual()
{
return DateTime.Now;
}
}
|
Um detalhe para a autorização é que se um determinado método é permitido ser invocado por mais de um grupo, você pode adicionar múltiplos atributos
PrincipalPermission. Além disso, esse atributo permite a definição de um nome de usuário que tem acesso ao membro. Segurança declarativa força definirmos o nome dos grupos e usuários em
hardcode. Se esses valores são dinâmicos, o ideal é estar fazendo isso a partir da segurança imperativa, ou seja, via código. Além deste detalhe, a declaração imperativa permite uma melhor customização, pois podemos ter condicionais para determinar se a segurança será ou não aplicada.
A autorização imperativa ou declarativa não é exclusividade do
Windows Communication Foundation ou mesmo da plataforma 2.0 do .NET, mas já existe desde a primeira versão e foi adequado ao sistema de autorização do WCF.
Configuração do serviço Como já estou assumindo que você tenha os devidos conhecimentos sobre a configuração do
Membership e
RoleProvider, vou ocultar aqui a explicação deles, mas no final desta seção, mostrarei o Web.Config na íntegra. Basicamente teremos na seção
connectionStrings a conexão com a base de dados SQL Server onde estarão as tabelas utilizadas pela infraestrutura do
Membership e
RoleProvider.
As configurações no serviço que devemos efetuar se resume às seções de
bindings e
behaviors, as quais iremos analisar individualmente cada um dos elementos e atributos que constituem essa configuração de segurança com integração ao ASP.NET 2.0.
Em um ambiente de internet, as mensagens devem ser transferidas com as credenciais (login e password) informadas pelo usuário. Sendo assim, neste caso utilizaremos o
binding WSHttpBinding. Este, por sua vez, representa um
binding que pode utilizar HTTP ou HTTPs para transporte, suportando transações distribuídas, confiabilidade e segurança nas mensagens. É bom lembrar que a classe
BasicHttpBinding é utilizada para a comunicação com
Web Services (ASMX) e não fornece segurança. Se desejarmos ter um canal seguro utilizando este
binding, devemos recorrer ao HTTPs. Já o
WSHttpBinding possui segurança a nível de mensagem e é isso que veremos a seguir, ou seja, como configurar essa segurança.
A classe
WSHttpBinding possui uma propriedade chamada
Security que expõe um objeto do tipo
WSHttpSecurity. Este objeto possui duas propriedades importantes que utilizaremos na configuração do
binding. A primeira delas é a propriedade
Mode, que aceita uma das opções fornecidas pelo enumerador
SecurityMode. As opções estão descritas na tabela abaixo:
| Opção |
Descrição |
| Message |
Nesta opção, a segurança é fornecida utilizando a segurança do protocolo SOAP.
|
| None |
A segurança está desabilitada.
|
| Transport |
A segurança será fornecida utilizando HTTPs.
|
| TransportWithMessageCredential |
Esta opção permite efetuar um mix das opções anteriores: utilizará um endpoint HTTPs para fornecer autenticação, integridade e confidenciabilidade, enquanto as credenciais do usuário continua sendo enviada através da mensagem SOAP (header) por questões de flexibilidade. Um dos benefícios desta técnica é que todo envelope SOAP é criptografado durante o transporte, incluindo os headers.
|
|
Já a segunda propriedade, chamada
Message, é onde configuramos o nível de segurança para o transporte da mensagem. Essa propriedade expõe um objeto do tipo
NonDualMessageSecurityOverHttp que possui uma propriedade chamada
ClientCredentialType. Através desta propriedade especificamos o tipo da credencial do cliente que é utilizada para a autenticação do mesmo quando estamos utilizando o
WsHttpBinding binding. Essa propriedade recebe uma das opções contidas no enumerador
MessageCredentialType, que estão abaixo descritos:
| Opção |
Descrição |
| Certificate |
Especifica que a autenticação do cliente será efetuada utilizando um certificado.
|
| IssuedToken |
Especifica que a autenticação do cliente será efetuada utilizando um issued token.
|
| None |
Especifica a autenticação anônima.
|
| UserName |
Especifica que a autenticação do cliente será efetuada através de um username.
|
| Windows |
Especifica que a autenticação do cliente será efetuada através do Windows.
|
|
Como já conhecemos as opções disponíveis para a configuração do
binding WSHttpBinding, é necessário neste momento analisarmos os
behaviors que também são uma peça fundamental neste processo. Através dos
behaviors do serviço, iremos especificar o certificado que criamos acima e, além disso, vamos determinar qual será a forma de autenticação (
Membership Provider) e autorização (
Role Provider) que o serviço irá utilizar.
Já falando de arquivo de configuração (
Web.Config), através do elemento
serviceBehaviors vamos customizar a autenticação e autorização. A autenticação (juntamente com o certificado) é realizada dentro do elemento
serviceCredentials e a autorização através do elemento
serviceAuthorization. O elemento
serviceCredentials, responsável pela autenticação, possui dois sub-elementos, a saber:
userNameAuthentication e
serviceCertificate onde, no primeiro, especificamos a forma da autenticação e o segundo, informações relacionadas ao certificado que será utilizado.
Antes de dar maiores detalhes sobre a configuração da autenticação e autorização, vamos visualizar na íntegra o arquivo
Web.Config da aplicação web que hosperará o serviço WCF:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add
name="SqlServerConnString"
connectionString="Data Source=.;Initial Catalog=DBWCF;Integrated Security=SSPI;"
providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.serviceModel>
<services>
<service name="DefaultService" behaviorConfiguration="ServiceBehavior">
<endpoint
name="DevMindsEndpoint"
contract="DevMinds.ComponentCS.IServiceContract"
binding="wsHttpBinding"
bindingConfiguration="ServiceBinding" />
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="ServiceBinding">
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="MembershipProvider"
membershipProviderName="SqlMembershipProvider"/>
<serviceCertificate
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName"
findValue="IACertificate" />
</serviceCredentials>
<serviceAuthorization
principalPermissionMode="UseAspNetRoles"
roleProviderName="SqlRoleProvider" />
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.web>
<membership
defaultProvider="SqlMembershipProvider"
userIsOnlineTimeWindow="15">
<providers>
<clear />
<add
name="SqlMembershipProvider"
type="System.Web.Security.SqlMembershipProvider"
connectionStringName="SqlServerConnString"
applicationName="WCFApp" />
</providers>
</membership>
<roleManager enabled="true" defaultProvider="SqlRoleProvider" >
<providers>
<add
name ="SqlRoleProvider"
type="System.Web.Security.SqlRoleProvider"
connectionStringName="SqlServerConnString"
applicationName="WCFApp"/>
</providers>
</roleManager>
</system.web>
</configuration>
|
Como explicar a configuração dos
providers está fora do escopo deste artigo, vamos abordar diretamente o elemento
userNameAuthentication. Ele possui dois atributos:
userNamePasswordValidationMode e
membershipProviderName. O primeiro deles determina qual será a forma de validar o
username/password. As opções possíveis são fornecidas através do enumerador
UserNamePasswordValidationMode. As opções que ele fornece estão descritas na tabela abaixo:
| Opção |
Descrição |
| Custom |
A validação do usuário será baseada em uma forma customizada. Esse modo exige que você crie seu próprio "validador" e, para isso, herde a classe UsernamePasswordValidator e customize os membros necessários.
|
| MembershipProvider |
Especifica que a validação da autenticação do usuário será efetuada utilizando a estrutura de Membership Provider do ASP.NET 2.0.
|
| Windows |
Os userNames são mapeados para os usuários do Windows.
|
|
Como o foco do artigo é a integração de serviços WCF e a estrutura de autenticação do ASP.NET 2.0, o atributo
userNamePasswordValidationMode será definido como
MembershipProvider, o que nos obriga a definir o atributo
membershipProviderName que, por sua vez, receberá uma
string contendo o nome do
membership provider que irá consistir a validação do usuário. Se reparar, ele recebe o mesmo valor definido no atributo
name do elemento
membership.
Antes de abordarmos a autorização, é necessário entender como configurar o certificado. Como falamos mais acima e você pode notar no
Web.Config, existe um elemento chamado
serviceCertificate, que é onde definimos o certificado que o serviço irá utilizar. Esse elemento possui basicamente quatro atributos que utilizamos para determinar o critério de busca pelo mesmo dentro do computador onde o serviço está rodando. Cada um desses atributos estão descritos na tabela abaixo:
| Atributo |
Descrição |
| FindValue |
Recebe uma string contendo o nome do certificado a ser procurado no repositório.
|
| StoreLocation |
Especifica o local do repositório onde o certificado está armazenado. Os possíveis valores para este campo são:
- CurrentUser: especifica que a busca será realizada no repositório de certificados do usuário corrente.
- LocalMachine: especifica que a busca será realizada no repositório de certificados da máquina local.
|
| StoreName |
Especifica o nome (tipo) do repositório. No nosso caso, utilizaremos a opção My, que indica que deve ser efetuada a busca no repositório de certificados pessoais.
|
| X509FindType |
Especifica por qual campo o valor informado na propriedade FindValue será procurado. No nosso caso, utilizaremos a opção FindBySubjectName que indica que a busca pelo certificado deverá ser realizada comparando o valor definido na propriedade FindValue com o subject name dos certificados armazenados no local especificado.
|
|
Com a autenticação devidamente configurada, chega o momento de analisarmos a autorização. Ainda dentro dos
behaviors do serviço, temos um elemento chamado
serviceAuthorization, que é utilizado para a configuração da autorização dentro do serviço WCF. Esse elemento possui dois atributos chamados
principalPermissionMode e
roleProviderName. O primeiro deles determina qual será o modo de autorização utilizado pelo serviço para controlar o acesso aos membros que utilizam a segurança declarativa (atributo
PrincipalPermissionAttribute) ou imperativa. As opções possíveis são fornecidas através do enumerador
PrincipalPermissionMode. As opções que ele fornece estão descritas na tabela abaixo:
| Opção |
Descrição |
| Custom |
Permite ao desenvolvedor especificar uma forma customizada de autorização, baseando-se em uma classe que implementa a interface IPrincipal, que deve ser vinculada à propriedade CurrentPrincipal.
|
| None |
CurrentPrincipal não definida.
|
| UseAspNetRoles |
Especifica que a autorização será baseada na Role Provider fornecida pelo ASP.NET 2.0.
|
| UseWindowsGroups |
A autorização será baseada nos grupos do Windows.
|
|
Como o foco do artigo é a integração de serviços WCF e a estrutura de autorização do ASP.NET 2.0, o atributo
principalPermissionMode será definido como
UseAspNetRoles, o que nos obriga a definir o atributo
roleProviderName que, por sua vez, receberá uma
string contendo o nome da
role provider que irá consistir a autorização do usuário. Atente-se que ele recebe o mesmo valor definido no atributo
name do elemento
roleManager.
Observação: Quando habilitamos a segurança baseada em
roles no ASP.NET 2.0, utilizando a arquitetura de
Role Provider, o ASP.NET cria um objeto do tipo
RolePrincipal e define o mesmo na propriedade
CurrentPrincipal da classe
Thread que está cuidando da execução do pedido. Quando o método
IsInRole da classe
RolePrincipal for invocado, ela ainda não possui conhecimentos das
roles do usuário e invoca o método
GetRolesForUser do
provider, recuperando as
roles do repositório para o usuário em questão e, em seguida, cria um
cache internamente que evitará ir até o repositório toda vez que este método for chamado. Isso tem um comportamento ligeiramente diferente quando configuramos o serviço WCF para utilizar a arquitetura de
roles do ASP.NET 2.0, pois o WCF utilizará uma classe customizada, chamada
RoleProviderPrincipal, que está contida dentro do
namespace System.ServiceModel.Security e implementa a
Interface IPrincipal. Durante a execução de um serviço WCF, uma instância dessa classe é anexada à propriedade
CurrentPrincipal da classe
Thread. O grande problema com ela é que, ao invocar o método
IsInRole a chamada é encaminhada para o método
IsUserInRole do
provider especificado. Isso quer dizer que, no caso do
SqlRoleProvider, não será efetuado o
cache das
roles do usuário, aumentando assim o número de
round-trips no banco de dados.
Com essa configuração relizada e o serviço já disponível no servidor (incluindo a instalação do certificado), o mesmo já pode ser invocado pelos clientes interessados em consumí-lo. Superficialmente, o que acontece nos bastidores durante a chamada ao serviço WCF, é que o cliente utilizará a chave pública (fornecida pelo serviço) para criptografar todas as mensagens que enviará ao serviço. Quando o serviço recebe essa mensagem, ele utiliza a chave privada para decriptografar a mensagem e, feito isso, o serviço WCF lê as credenciais do usuário e o autentica, permitindo assim, o acesso ao serviço.
Configuração do cliente Assim como o serviço, também é necessário configurarmos o
binding e o
behavior do serviço WCF do lado do cliente e, além disso, necessitamos ter a chave pública do certificado exposta pelo serviço.
Para suportar a autenticação e proteção de mensagens mútuas, os serviços devem fornecer as credenciais para o chamador. Quando utilizamos a segurança a nível de transporte, as credenciais do serviço são negociadas através do protocolo de transporte. Quando utilizamos a segurança baseada em mensagens, podemos também especificar as credenciais do Windows ou um certificado, através do elemento
serviceCredentials, como já vimos acima. Esse processo, chamado de
negociação, pode ser realizado de forma
out-of-band ou através de um
handshake inicial.
Se desejar, você pode desabilitar a negociação das credenciais definindo para
False o atributo
negotiateServiceCredential do elemento
message.
Para os tipos de credenciais diferentes de
Windows, de alguma forma é necessário que o cliente tenha acesso à chave pública do certificado para que ele possa criptografar as requisições para o serviço. Isso é gerado automaticamente quando você adicionar uma referência para um serviço através do Visual Studio .NET 2005 (ou através do utilitário
svcutil.exe) que, nas configurações do arquivo
App.Config já está codificada uma versão pública do certificado, que é informada através do atributo
encodedValue do elemento
certificate que, por sua vez, está contido dentro da seção
identity.
Depois da configuração do certificado, vamos falar sobre o
binding que irá refletir exatamente a mesma configuração que fizemos no serviço do lado do servidor, ou seja, definiremos o atributo
mode do elemento
security para
Message, e o atributo
clientCredentialType do elemento
message é definido também como
UserName, ficando assim exatamente como a configuração estipulada no serviço.
Finalmente, temos a seção dos
behaviors. Essa seção fornece um elemento chamado
serviceCertificate. Esse elemento especifica o certificado que será utilizado pelo cliente. Esse elemento tem um sub-elemento chamado
authentication que, por sua vez, possui um atributo chamado
certificateValidationMode, o qual é extremamente importante na validação do certificado. Esse atributo recebe uma das opções fornecidas pelo enumerador
X509CertificateValidationMode. Essas opções estão descritas na tabela abaixo:
| Opção |
Descrição |
| ChainTrust |
Esta opção instrui o WCF a confiar no certificado somente se ele foi emitido através de um orgão como a VeriSign.
|
| Custom |
O certificado é validado através de um validador customizado. Esse validador deve ser customizado pelo desenvolvedor, herdando o seu validador a partir da classe X509CertificateValidator.
|
| None |
Validação do certificado está desabilitada.
|
| PeerOrChainTrust |
Esta opção permite o WCF confiar em um certificado somente se ele foi emitido através de um orgão como a VeriSign ou se ele estiver dentro do repositório Trusted People do cliente.
|
| PeerTrust |
O certificado é validado se ele estiver dentro do repositório Trusted People do cliente.
|
|
Com isso, o arquivo de configuração do cliente,
App.Config, fica da seguinte forma:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<client>
<endpoint
name="DevMindsService"
address="http://localhost:2969/DevMinds.WebHostingCS/DefaultService.svc"
behaviorConfiguration="ClientBehavior"
binding="wsHttpBinding"
bindingConfiguration="ClientBinding"
contract="DevMinds.ClientUICS.localhost.IServiceContract">
<identity>
<certificate
encodedValue="AwAAAAEAAAAUAAAAUJNV9NaKKu1ufLDJSReysIhSHokgAAAAAQAAALkBAAAwgg
G1MIIBY6ADAgECAhD8doIP5AdsgEtkMqF7eimCMAkGBSsOAwIdBQAwFjEUMBIG
A1UEAxMLUm9vdCBBZ2VuY3kwHhcNMDcwNDAzMTMxNjM3WhcNMzkxMjMxMjM1OT
U5WjAYMRYwFAYDVQQDEw1JQUNlcnRpZmljYXRlMIGfMA0GCSqGSIb3DQEBAQUA
A4GNADCBiQKBgQC/+fgp/kuwIVmhpJW2XFDdFQKT0hDRhbdsIvV8ikrUANCuii
ufPvo10FqMrVPqeowy+c2XxYpQ6lGeMx4QWVeZC9LdGCzli1UNKdarT6wBiBsK
qAxmb6lJkKnkL4HycepYckbT2H65oIDDnfFNv1TYUP1/gPHoz6bsIFCa4eXCMw
IDAQABo0swSTBHBgNVHQEEQDA+gBAS5AktBh0dTwCNYSHcFmRjoRgwFjEUMBIG
A1UEAxMLUm9vdCBBZ2VuY3mCEAY3bACqAGSKEc+41KpcNfQwCQYFKw4DAh0FAA
NBAGoc8S3JfsoQPRqwCIO0WYopE8vJ92IYLkxQ5k68BuN1mLUftbVoEv/TO/Y5
7ToFWzTsDMT5BfG37G1Y0P5Iq+Q=" />
</identity>
</endpoint>
</client>
<bindings>
<wsHttpBinding>
<binding name="ClientBinding">
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="ClientBehavior">
<clientCredentials>
<serviceCertificate>
<authentication certificateValidationMode="PeerTrust" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
|
Invocando os métodos Como as configurações já estão definidas tanto do lado do servidor quanto do cliente, chega o momento em que devemos invocar os métodos que o serviço disponibiliza.
Basicamente, a chamada para os métodos não mudando absolutamente em nada. A única diferença é que devemos, antes de invocar o(s) método(s), informar o nome de usuário e senha para o
proxy, que enviará essas credenciais para o serviço quando o método for invocado. O
proxy expõe uma propriedade chamada
ClientCredentials do tipo
ClientCredentials. Essa classe possui uma propriedade chamada
UserName do tipo
UserNamePasswordClientCredential.
Essa classe habilita o usuário a configurar o
userName e o
password que o WCF deve utilizar quando estiver efetuando a autenticação. Essa simples classe possui duas propriedades que recebem uma
string. Essas propriedades, auto-explicativas, são chamadas de
Password e
UserName. O exemplo (
Windows Application) abaixo ilustra como devemos configurar essas propriedades, informando o
userName e
password:
using (localhost.ServiceContractClient c = new localhost.ServiceContractClient())
{
c.ClientCredentials.UserName.UserName = "Claudia";
c.ClientCredentials.UserName.Password = "123456";
MessageBox.Show(c.DataAtual().ToString());
MessageBox.Show(c.BoasVindas());
}
|
Recapitulando o código de implementação do serviço, o método
BoasVindas somente poderá ser executado por usuários que estão contidos dentro da
role User. Já o método
DataAtual somente pode ser executado por usuários que estão contidos dentro da
role Manager.
Como podemos reparar, passamos como
userName o nome
Claudia, que executa os dois métodos com sucesso pois este usuário está contido dentro das duas
roles. Se alterarmos o
userName para
Juliano, que está contido somente dentro da
role User, ao tentarmos executar o método
DataAtual, que é permitido somente a usuários que estão contidos dentro da
role Manager, uma exceção será atirada informando que o acesso foi negado.
Conclusão: O WCF possui uma grande variedade de formas de autenticação e autorização para os serviços. Neste artigo abordamos uma das formas de segurança que o WCF expõe, que é justamente a integração da autenticação e autorização com toda a infraestrutura que o ASP.NET 2.0 já fornece para os desenvolvedores de aplicações web e, como é o intuíto do WCF, toda a configuração para integrar com o ASP.NET 2.0, bem como a maioria da segurança do WCF, baseado em
plug-and-play.