Olá pessoal,

Estava conversando com um cliente sobre como um serviço WCF pode autenticar de maneira customizada as chamadas que recebe, confrontando as informações de usuário e senha com os dados de uma tabela em um banco de dados.

O primeiro para é criar uma classe para autenticar as chamadas do serviço. Esta classe deve herdar de System.IdentityModel.Selectors.UserNamePasswordValidator, disponível no assembly System.IdentityModel, e implementar o método Validate, conforme abaixo:

   1:  public class CustomUsernamePasswordValidator : UserNamePasswordValidator
   2:    {
   3:      public override void Validate(string userName, string password)
   4:      {
   5:        if (userName == null || password == null)
   6:        {
   7:          throw new ArgumentNullException();
   8:        }
   9:   
  10:        if (!(userName == "administrator" && password == "P@ssw0rd"))
  11:        {
  12:          throw new FaultException("Unknown username or invalid password");
  13:        }
  14:      }
  15:    }

Notem que por uma questão de facilidade não estou utilizando um banco de dados para validar usuário e senha, mas sim comparando as informações recebidas contra constantes no meu código. Se a autenticação não ocorrer com sucesso emito uma mensagem de erro do tipo FaulException, que é o tipo de exceção possível de ser propagada pelo WCF (isso vale um post).

Em seguida é necessário configurar o serviço para utilizar esta customização para autenticação no arquivo de configurações:

   1:  <services>
   2:      <service behaviorConfiguration="WCFService.CalculatorServiceBehavior" ...>
   3:          ...
   4:      </service>
   5:  </services>
   6:  <behaviors>
   7:      <serviceBehaviors>
   8:          <behavior name="WCFService.CalculatorServiceBehavior">
   9:              <serviceMetadata httpGetEnabled="True"/>
  10:              <serviceDebug includeExceptionDetailInFaults="False" />
  11:              <serviceCredentials>
  12:                  <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WCFCustomAuthentication.CustomUsernamePasswordValidator, WCFCustomAuthentication"/>
  13:              </serviceCredentials>
  14:          </behavior>
  15:      </serviceBehaviors>
  16:  </behaviors>

Agora é necessário configurar tanto o serviço quanto o cliente para autenticar as chamadas através de usuário e senha nos seus bindings:

   1:  <bindings>
   2:      <wsHttpBinding>
   3:          <binding name="wsHttpBindingWithMessageSecurity">
   4:              <security mode="Message">
   5:                  <message clientCredentialType="UserName"/>
   6:              </security>
   7:          </binding>
   8:      </wsHttpBinding>
   9:  </bindings>

Como as informações de usuário e senha passam de maneira aberta é necessário configurar a comunicação para ocorrer de maneira segura utilizando um certificado, mas isto é assunto para o post Autenticação customizada de WCF – Parte II.

Por último também é necessário que o cliente do serviço informe as credenciais na chamadas das operações, assunto do post Autenticação customizada de WCF – Parte III.

Posts da série: