How to: Create a Custom Security Token Provider

This topic shows how to create new token types with a custom security token provider and how to integrate the provider with a custom security token manager.

Note

Create a custom token provider if the system-provided tokens found in the System.IdentityModel.Tokens namespace do not match your requirements.

The security token provider creates a security token representation based on information in the client or service credentials. To use the custom security token provider in Windows Communication Foundation (WCF) security, you must create custom credentials and security token manager implementations.

For more information about custom credentials and security token manager see the Walkthrough: Creating Custom Client and Service Credentials.

For more information about credentials, security token manager, provider and authenticator classes, see the Security Architecture.

To create a custom security token provider

  1. Define a new class derived from the SecurityTokenProvider class.

  2. Implement the GetTokenCore method. The method is responsible for creating and returning an instance of the security token. The following example creates a class named MySecurityTokenProvider, and overrides the GetTokenCore method to return an instance of the X509SecurityToken class. The class constructor requires an instance of the X509Certificate2 class.

    Friend Class MySecurityTokenProvider
        Inherits SecurityTokenProvider
        Private certificate As X509Certificate2
    
        Public Sub New(ByVal certificate As X509Certificate2) 
            Me.certificate = certificate
    
        End Sub 
    
        Protected Overrides Function GetTokenCore(ByVal timeout As TimeSpan) As SecurityToken 
            Return New X509SecurityToken(certificate)
    
        End Function 
    End Class 
    
    internal class MySecurityTokenProvider : SecurityTokenProvider
    {
        X509Certificate2 certificate;
    
        public MySecurityTokenProvider(X509Certificate2 certificate)
        {
            this.certificate = certificate;
        }
    
        protected override SecurityToken GetTokenCore(TimeSpan timeout)
        {
            return new X509SecurityToken(certificate);
        }
    }
    

To integrate a custom security token provider with a custom security token manager

  1. Define a new class derived from the SecurityTokenManager class. (The example below derives from the ClientCredentialsSecurityTokenManager class, which derives from the SecurityTokenManager class.)

  2. Override the CreateSecurityTokenProvider method if is not already overridden.

    The CreateSecurityTokenProvider method is responsible for returning an instance of the SecurityTokenProvider class appropriate to the SecurityTokenRequirement parameter passed to the method by the WCF security framework. Modify the method to return the custom security token provider implementation (created in the previous procedure) when the method is called with an appropriate security token parameter. For more information about the security token manager, see the Walkthrough: Creating Custom Client and Service Credentials.

  3. Add custom logic to the method to enable it to return your custom security token provider based on the SecurityTokenRequirement parameter. The following sample returns the custom security token provider if the token requirements are met. The requirements include an X.509 security token and the message direction (that the token is used for message output). For all other cases, the code calls the base class to maintain the system-provided behavior for other security token requirements.

Friend Class MyClientCredentialsSecurityTokenManager
    Inherits ClientCredentialsSecurityTokenManager
    Private credentials As ClientCredentials
    
    
    Public Sub New(ByVal credentials As ClientCredentials) 
        MyBase.New(credentials)
        Me.credentials = credentials
    
    End Sub 'New
    
    
    Public Overrides Function CreateSecurityTokenProvider(ByVal tokenRequirement As SecurityTokenRequirement) As SecurityTokenProvider 
        ' Return your implementation of the SecurityTokenProvider based on the 
        ' tokenRequirement argument.
        Dim result As SecurityTokenProvider
        If tokenRequirement.TokenType = SecurityTokenTypes.X509Certificate Then
            Dim direction As MessageDirection = tokenRequirement.GetProperty(Of MessageDirection) _
               (ServiceModelSecurityTokenRequirement.MessageDirectionProperty)
            If direction = MessageDirection.Output Then
                result = New MySecurityTokenProvider(credentials.ClientCertificate.Certificate)
            Else
                result = MyBase.CreateSecurityTokenProvider(tokenRequirement)
            End If
        Else
            result = MyBase.CreateSecurityTokenProvider(tokenRequirement)
        End If
        
        Return result
    
    End Function 
End Class 
internal class MyClientCredentialsSecurityTokenManager:ClientCredentialsSecurityTokenManager
{
    ClientCredentials credentials;

    public MyClientCredentialsSecurityTokenManager(ClientCredentials credentials)
        : base(credentials)
    {
        this.credentials = credentials;
    }

    public override SecurityTokenProvider CreateSecurityTokenProvider(
        SecurityTokenRequirement tokenRequirement)
    {
        // Return your implementation of the SecurityTokenProvider based on the 
        // tokenRequirement argument.
        SecurityTokenProvider result;
        if (tokenRequirement.TokenType == SecurityTokenTypes.X509Certificate)
        {
            MessageDirection direction = tokenRequirement.GetProperty<MessageDirection>(
                ServiceModelSecurityTokenRequirement.MessageDirectionProperty);
            if (direction == MessageDirection.Output)
            {
                result = new MySecurityTokenProvider(credentials.ClientCertificate.Certificate);
            }
            else
            {
                result = base.CreateSecurityTokenProvider(tokenRequirement);
            }
        }
        else
        {
            result = base.CreateSecurityTokenProvider(tokenRequirement);
        }

        return result;
    }
}

Example

The following shows a complete SecurityTokenProvider implementation along with a corresponding SecurityTokenManager implementation.

Imports System
Imports System.IdentityModel.Selectors
Imports System.IdentityModel.Tokens
Imports System.Security.Permissions
Imports System.Security.Cryptography.X509Certificates
Imports System.ServiceModel
Imports System.ServiceModel.Description
Imports System.ServiceModel.Security.Tokens

<assembly: SecurityPermission(SecurityAction.RequestMinimum, Execution := True)>
Friend Class MySecurityTokenProvider
    Inherits SecurityTokenProvider
    Private certificate As X509Certificate2
    
    Public Sub New(ByVal certificate As X509Certificate2) 
        Me.certificate = certificate
    
    End Sub 
    
    Protected Overrides Function GetTokenCore(ByVal timeout As TimeSpan) As SecurityToken 
        Return New X509SecurityToken(certificate)
    
    End Function 
End Class 

Friend Class MyClientCredentialsSecurityTokenManager
    Inherits ClientCredentialsSecurityTokenManager
    Private credentials As ClientCredentials
    
    
    Public Sub New(ByVal credentials As ClientCredentials) 
        MyBase.New(credentials)
        Me.credentials = credentials
    
    End Sub 'New
    
    
    Public Overrides Function CreateSecurityTokenProvider(ByVal tokenRequirement As SecurityTokenRequirement) As SecurityTokenProvider 
        ' Return your implementation of the SecurityTokenProvider based on the 
        ' tokenRequirement argument.
        Dim result As SecurityTokenProvider
        If tokenRequirement.TokenType = SecurityTokenTypes.X509Certificate Then
            Dim direction As MessageDirection = tokenRequirement.GetProperty(Of MessageDirection) _
               (ServiceModelSecurityTokenRequirement.MessageDirectionProperty)
            If direction = MessageDirection.Output Then
                result = New MySecurityTokenProvider(credentials.ClientCertificate.Certificate)
            Else
                result = MyBase.CreateSecurityTokenProvider(tokenRequirement)
            End If
        Else
            result = MyBase.CreateSecurityTokenProvider(tokenRequirement)
        End If
        
        Return result
    
    End Function 
End Class 
using System;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Security.Permissions;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Security.Tokens;

[assembly: SecurityPermission(SecurityAction.RequestMinimum, Execution = true)]
namespace CustomProvider
{
    internal class MySecurityTokenProvider : SecurityTokenProvider
    {
        X509Certificate2 certificate;

        public MySecurityTokenProvider(X509Certificate2 certificate)
        {
            this.certificate = certificate;
        }

        protected override SecurityToken GetTokenCore(TimeSpan timeout)
        {
            return new X509SecurityToken(certificate);
        }
    }

    internal class MyClientCredentialsSecurityTokenManager:ClientCredentialsSecurityTokenManager
    {
        ClientCredentials credentials;

        public MyClientCredentialsSecurityTokenManager(ClientCredentials credentials)
            : base(credentials)
        {
            this.credentials = credentials;
        }

        public override SecurityTokenProvider CreateSecurityTokenProvider(
            SecurityTokenRequirement tokenRequirement)
        {
            // Return your implementation of the SecurityTokenProvider based on the 
            // tokenRequirement argument.
            SecurityTokenProvider result;
            if (tokenRequirement.TokenType == SecurityTokenTypes.X509Certificate)
            {
                MessageDirection direction = tokenRequirement.GetProperty<MessageDirection>(
                    ServiceModelSecurityTokenRequirement.MessageDirectionProperty);
                if (direction == MessageDirection.Output)
                {
                    result = new MySecurityTokenProvider(credentials.ClientCertificate.Certificate);
                }
                else
                {
                    result = base.CreateSecurityTokenProvider(tokenRequirement);
                }
            }
            else
            {
                result = base.CreateSecurityTokenProvider(tokenRequirement);
            }

            return result;
        }
    }
}

See Also

Reference

SecurityTokenProvider
SecurityTokenRequirement
SecurityTokenManager
X509SecurityToken

Concepts

Walkthrough: Creating Custom Client and Service Credentials
How to: Create a Custom Security Token Authenticator
Security Architecture