Como criar um autenticador de token de segurança personalizado

Este tópico mostra como criar um autenticador de token de segurança personalizado e como integrá-lo a um gerenciador de token de segurança personalizado. Um autenticador de token de segurança valida o conteúdo de um token de segurança fornecido com uma mensagem de entrada. Se a validação for bem-sucedida, o autenticador retornará uma coleção de instâncias IAuthorizationPolicy que, quando avaliadas, retornarão um conjunto de declarações.

Para usar um autenticador de token de segurança personalizado no WCF (Windows Communication Foundation), primeiro você deve criar credenciais personalizadas e implementações do gerenciador de token de segurança. Para obter mais informações sobre como criar credenciais personalizadas e um gerenciador de token de segurança, consulte Passo a passo: Criar credenciais personalizadas de cliente e serviço.

Procedimentos

Criar um autenticador de token de segurança personalizado

  1. Defina uma nova classe derivada da classe SecurityTokenAuthenticator.

  2. Substitua o método CanValidateTokenCore. O método retorna true ou false dependendo se o autenticador personalizado pode validar o tipo de token de entrada ou não.

  3. Substitua o método ValidateTokenCore. Esse método precisa validar o conteúdo do token adequadamente. Se o token passar na etapa de validação, ele retornará uma coleção de instâncias IAuthorizationPolicy. O exemplo a seguir usa uma implementação de política de autorização personalizada que será criada no próximo procedimento.

    internal class MySecurityTokenAuthenticator : SecurityTokenAuthenticator
    {
        protected override bool CanValidateTokenCore(SecurityToken token)
        {
            // Check that the incoming token is a username token type that
            // can be validated by this implementation.
            return (token is UserNameSecurityToken);
        }
    
        protected override ReadOnlyCollection<IAuthorizationPolicy>
            ValidateTokenCore(SecurityToken token)
        {
            UserNameSecurityToken userNameToken = token as UserNameSecurityToken;
    
            // Validate the information contained in the username token. For demonstration
            // purposes, this code just checks that the user name matches the password.
            if (userNameToken.UserName != userNameToken.Password)
            {
                throw new SecurityTokenValidationException("Invalid user name or password");
            }
    
            // Create just one Claim instance for the username token - the name of the user.
            DefaultClaimSet userNameClaimSet = new DefaultClaimSet(
                ClaimSet.System,
                new Claim(ClaimTypes.Name, userNameToken.UserName, Rights.PossessProperty));
            List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>(1);
            policies.Add(new MyAuthorizationPolicy(userNameClaimSet));
            return policies.AsReadOnly();
        }
    }
    
    Friend Class MySecurityTokenAuthenticator
        Inherits SecurityTokenAuthenticator
    
        Protected Overrides Function CanValidateTokenCore(ByVal token As SecurityToken) As Boolean
            ' Check that the incoming token is a username token type that  
            ' can be validated by this implementation.
            Return (TypeOf token Is UserNameSecurityToken)
        End Function
    
        Protected Overrides Function ValidateTokenCore(ByVal token As SecurityToken) As ReadOnlyCollection(Of IAuthorizationPolicy)
    
            Dim userNameToken = TryCast(token, UserNameSecurityToken)
    
            ' Validate the information contained in the username token. For demonstration 
            ' purposes, this code just checks that the user name matches the password.
            If userNameToken.UserName <> userNameToken.Password Then
                Throw New SecurityTokenValidationException("Invalid user name or password")
            End If
    
            ' Create just one Claim instance for the username token - the name of the user.
            Dim userNameClaimSet As New DefaultClaimSet(ClaimSet.System, _
                                                        New Claim(ClaimTypes.Name, _
                                                        userNameToken.UserName, _
                                                        Rights.PossessProperty))
            Dim policies As New List(Of IAuthorizationPolicy)(1)
            policies.Add(New MyAuthorizationPolicy(userNameClaimSet))
            Return policies.AsReadOnly()
        End Function
    
    End Class
    

O código anterior retorna uma coleção de políticas de autorização no método CanValidateToken(SecurityToken). O WCF não fornece uma implementação pública dessa interface. O procedimento a seguir mostra como fazer isso para seus próprios requisitos.

Criar uma política de autorização personalizada

  1. Defina uma nova classe implementando a interface IAuthorizationPolicy.

  2. Implemente a propriedade Id somente leitura. Uma maneira de implementar essa propriedade é gerar um GUID (identificador global exclusivo) no construtor de classe e devolvê-lo sempre que o valor dessa propriedade for solicitado.

  3. Implemente a propriedade Issuer somente leitura. Essa propriedade precisa retornar um emissor dos conjuntos de declarações obtidos do token. Esse emissor deve corresponder ao emissor do token ou a uma autoridade responsável por validar o conteúdo do token. O exemplo a seguir usa a declaração do emissor que passou para essa classe do autenticador de token de segurança personalizado criado no procedimento anterior. O autenticador de token de segurança personalizado usa o conjunto de declarações fornecido pelo sistema (retornado pela propriedade System) a fim de representar o emissor do token de nome de usuário.

  4. Implementar o método de Evaluate . Esse método preenche uma instância da classe EvaluationContext (passada como um argumento) com declarações baseadas no conteúdo do token de segurança de entrada. O método retorna true quando é feito com a avaliação. Nos casos em que a implementação depende da presença de outras políticas de autorização que fornecem informações adicionais para o contexto de avaliação, esse método pode retornar false se as informações necessárias ainda não estiverem presentes no contexto de avaliação. Nesse caso, o WCF chamará o método novamente depois de avaliar todas as outras políticas de autorização geradas para a mensagem de entrada se pelo menos uma dessas políticas de autorização tiver modificado o contexto de avaliação.

    internal class MyAuthorizationPolicy : IAuthorizationPolicy
    {
        string id;
        ClaimSet tokenClaims;
        ClaimSet issuer;
    
        public MyAuthorizationPolicy(ClaimSet tokenClaims)
        {
            if (tokenClaims == null)
            {
                throw new ArgumentNullException("tokenClaims");
            }
            this.issuer = tokenClaims.Issuer;
            this.tokenClaims = tokenClaims;
            this.id = Guid.NewGuid().ToString();
        }
    
        public ClaimSet Issuer
        {
            get { return issuer; }
        }
    
        public string Id
        {
            get { return id; }
        }
    
        public bool Evaluate(EvaluationContext evaluationContext, ref object state)
        {
            // Add the token claim set to the evaluation context.
            evaluationContext.AddClaimSet(this, tokenClaims);
    
            // Return true if the policy evaluation is finished.
            return true;
        }
    }
    
    Friend Class MyAuthorizationPolicy
        Implements IAuthorizationPolicy
    
        Private _id As String
        Private _tokenClaims As ClaimSet
        Private _issuer As ClaimSet
    
        Public Sub New(ByVal tokenClaims As ClaimSet)
            If _tokenClaims Is Nothing Then
                Throw New ArgumentNullException("tokenClaims")
            End If
            Me._issuer = tokenClaims.Issuer
            Me._tokenClaims = tokenClaims
            Me._id = Guid.NewGuid().ToString()
        End Sub
    
        Public ReadOnly Property Issuer() As ClaimSet Implements IAuthorizationPolicy.Issuer
            Get
                Return _issuer
            End Get
        End Property
    
        Public ReadOnly Property Id() As String Implements System.IdentityModel.Policy.IAuthorizationComponent.Id
            Get
                Return _id
            End Get
        End Property
    
        Public Function Evaluate(ByVal evaluationContext As EvaluationContext, _
                                 ByRef state As Object) As Boolean Implements IAuthorizationPolicy.Evaluate
    
            ' Add the token claim set to the evaluation context.
            evaluationContext.AddClaimSet(Me, _tokenClaims)
            ' Return true if the policy evaluation is finished.
            Return True
        End Function
    
    End Class
    

Passo a passo: Criar credenciais personalizadas de cliente e serviço descreve como criar credenciais personalizadas e um gerenciador de token de segurança personalizado. Para usar o autenticador de token de segurança personalizado criado aqui, uma implementação do gerenciador de token de segurança é modificada para retornar o autenticador personalizado do método CreateSecurityTokenAuthenticator. O método retorna um autenticador quando um requisito de token de segurança apropriado é passado.

Para integrar um autenticador de token de segurança personalizado a um gerenciador de token de segurança personalizado

  1. Substitua o método CreateSecurityTokenAuthenticator na implementação personalizada do gerenciador de token de segurança.

  2. Adicione lógica ao método a fim de permitir que ele retorne o autenticador de token de segurança personalizado com base no parâmetro SecurityTokenRequirement. O exemplo a seguir retorna um autenticador de token de segurança personalizado se o tipo de token de requisitos de token for um nome de usuário (representado pela propriedade UserName) e a direção da mensagem para a qual o autenticador de token de segurança está sendo solicitado for a entrada (representada pelo campo Input).

    internal class MyServiceCredentialsSecurityTokenManager :
        ServiceCredentialsSecurityTokenManager
    {
        ServiceCredentials credentials;
        public MyServiceCredentialsSecurityTokenManager(ServiceCredentials credentials)
            : base(credentials)
        {
            this.credentials = credentials;
        }
    
        public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator
            (SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
        {
            // Return your implementation of the SecurityTokenProvider based on the
            // tokenRequirement argument.
            SecurityTokenAuthenticator result;
            if (tokenRequirement.TokenType == SecurityTokenTypes.UserName)
            {
                MessageDirection direction = tokenRequirement.GetProperty<MessageDirection>
                    (ServiceModelSecurityTokenRequirement.MessageDirectionProperty);
                if (direction == MessageDirection.Input)
                {
                    outOfBandTokenResolver = null;
                    result = new MySecurityTokenAuthenticator();
                }
                else
                {
                    result = base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
                }
            }
            else
            {
                result = base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
            }
    
            return result;
        }
    }
    
    Friend Class MyServiceCredentialsSecurityTokenManager
        Inherits ServiceCredentialsSecurityTokenManager
    
        Private credentials As ServiceCredentials
    
        Public Sub New(ByVal credentials As ServiceCredentials)
            MyBase.New(credentials)
            Me.credentials = credentials
        End Sub
    
        Public Overrides Function CreateSecurityTokenAuthenticator(ByVal tokenRequirement As SecurityTokenRequirement, _
                                                                   <System.Runtime.InteropServices.Out()> _
                                                                   ByRef outOfBandTokenResolver _
                                                                   As SecurityTokenResolver) As SecurityTokenAuthenticator
            ' Return your implementation of the SecurityTokenProvider based on the 
            ' tokenRequirement argument.
            Dim result As SecurityTokenAuthenticator
            If tokenRequirement.TokenType = SecurityTokenTypes.UserName Then
                Dim direction = tokenRequirement.GetProperty(Of MessageDirection)(ServiceModelSecurityTokenRequirement.MessageDirectionProperty)
                If direction = MessageDirection.Input Then
                    outOfBandTokenResolver = Nothing
                    result = New MySecurityTokenAuthenticator()
                Else
                    result = MyBase.CreateSecurityTokenAuthenticator(tokenRequirement, _
                                                                     outOfBandTokenResolver)
                End If
            Else
                result = MyBase.CreateSecurityTokenAuthenticator(tokenRequirement, _
                                                                 outOfBandTokenResolver)
            End If
    
            Return result
        End Function
    
    End Class
    

Confira também