How to: Create a Security Token Manager for a Custom Security Token

WSE relies on security token managers for creating instances of security tokens based on an XML representation. Primarily this is necessary when WSE receives a SOAP message with security tokens. When the SOAP message is received, WSE can solicit the security token manager for an instance of a security token based on the XML content held within a WS-Security SOAP header. If the security token is one that WSE natively supports, such as Kerberos tickets or an X.509 certificate, WSE knows which security token manager to use. For custom XML security tokens, WSE needs to have a security token manager to call. This topic details how to create a security token manager for WSE to call. For more information about configuring a security token manager so that WSE knows how to call the correct security token manager, see How to: Configure the Security Token Manager for a Custom Security Token.

To create a security token manager for a custom XML security token

  1. Add a new class to the project containing the class representing the security token. Derive the class from the SecurityTokenManager class.

    Public Class XmlTokenManager : Inherits Microsoft.Web.Services3.Security.Tokens.SecurityTokenManager
    
    public class XmlTokenManager : SecurityTokenManager
    
  2. Add the Imports statements or using directives shown in the following code example to the top of the file for the class.

    Imports System
    Imports System.Security.Cryptography
    Imports System.Security.Cryptography.Xml
    Imports System.Security.Permissions
    Imports System.Text
    Imports System.Globalization
    Imports System.Xml
    
    Imports Microsoft.Web.Services3.Addressing
    Imports Microsoft.Web.Services3.Design
    Imports Microsoft.Web.Services3.Security
    Imports Microsoft.Web.Services3.Security.Cryptography
    Imports Microsoft.Web.Services3.Security.Tokens
    Imports Microsoft.Web.Services3.Security.Utility
    
    using System;
    using System.Security.Cryptography;
    using System.Security.Cryptography.Xml;
    using System.Security.Permissions;
    using System.Text;
    using System.Globalization;
    using System.Xml;
    
    using Microsoft.Web.Services3.Addressing;
    using Microsoft.Web.Services3.Design; 
    using Microsoft.Web.Services3.Security;
    using Microsoft.Web.Services3.Security.Cryptography;
    using Microsoft.Web.Services3.Security.Tokens;
    using Microsoft.Web.Services3.Security.Utility;
    
  3. Implement the TokenType property.

    The TokenType property is an XmlQualifiedName class that uniquely identifies the custom XML security token type for which this security token manager is able to create instances of security tokens from XML.

    The following code example returns the XmlQualifiedName class for the custom XML security token.

    Public Overrides ReadOnly Property TokenType() As String
        Get
            Return XmlTokenNames.TypeNames.TokenType
        End Get
    End Property
    
    public override string TokenType 
    { 
        get 
        {
            return XmlTokenNames.TypeNames.TokenType;
        }
    }
    
  4. Implement the LoadTokenFromXml method, which deserializes an XML element into a security token.

    The following code example calls the constructor that takes an XmlElement argument to deserialize the XmlElement class into an instance of the custom XML security token.

    ' The LoadTokenFromXml method deserializes an XML element into
    ' a security token.
    Public Overrides Function LoadTokenFromXml(ByVal element As XmlElement) As SecurityToken
        Return New XmlToken(element)
    End Function
    
    // The LoadTokenFromXml method deserializes an XML element into
    // a security token.
    public override SecurityToken LoadTokenFromXml(XmlElement
        element)
    {
        return new XmlToken(element);
    }
    
  5. Implement the LoadTokenFromKeyInfo method.

    The LoadTokenFromKeyInfo method is called by WSE to retrieve the decryption key for a custom XML security token.

    ' Return a security token based on a KeyInfo clause.
    Public Overrides Function LoadTokenFromKeyInfo(ByVal keyInfo As KeyInfo) As SecurityToken
        ' Verify that the keyInfo parameter contains a value.
        If (keyInfo Is Nothing) Then
            Throw New ArgumentNullException("keyInfo")
        End If
        Dim reference As SecurityTokenReference
        Dim clause As KeyInfoClause
        For Each clause In keyInfo
            reference = CType(clause, SecurityTokenReference)
            ' Check if the custom XML security token is the
            ' security token handled by this security token
            ' manager.
            If (TypeOf clause Is SecurityTokenReference AndAlso _
                (reference.KeyIdentifier.ValueType = _
                XmlTokenNames.TypeNames.TokenType)) Then
                ' If the custom XML security token is the security
                ' token managed by this security token manager,
                ' get the keys for the security token from the
                ' cryptographic key container specified in the
                ' KeyIdentifier property.
                Dim bytes() As Byte = reference.KeyIdentifier.Value
                Dim keyContainer As String = _
                    System.Text.Encoding.Default.GetString(bytes)
    
                ' Let the custom XML security token do the work of
                ' retrieving the key for the security token.
                Dim token As XmlToken = New XmlToken(keyContainer, True)
    
                Return token
            Else
                ' If this custom XML security token is not the
                ' one managed by this security token manager, let
                ' the default security token provider try to
                ' handle it.
                Return Nothing
            End If
        Next
        ' If execution reaches here, the custom XML
        ' security token could not be loaded.
        Return Nothing
    End Function
    
    // Return a security token based on a KeyInfo clause.
    public override SecurityToken LoadTokenFromKeyInfo(KeyInfo
        keyInfo) 
    {
        // Verify that the keyInfo parameter contains a value.
        if (null == keyInfo)
            throw new ArgumentNullException("keyInfo");
        SecurityTokenReference reference;
        foreach ( KeyInfoClause clause in keyInfo )
        {
            reference = (SecurityTokenReference)clause;
            // Check if the custom XML security token is the
            // security token handled by this security token
            // manager.
            if ( clause is SecurityTokenReference && 
                (reference.KeyIdentifier.ValueType ==
                XmlTokenNames.TypeNames.TokenType))
            {
                // If the custom XML security token is the security
                // token managed by this security token manager,
                // get the keys for the security token from the
                // cryptographic key container specified in the
                // KeyIdentifier property.
                byte[] bytes = reference.KeyIdentifier.Value;
                string keyContainer =
                    System.Text.Encoding.Default.GetString(bytes);
    
                // Let the custom XML security token do the work of
                // retrieving the key for the security token.
                XmlToken token = new XmlToken(keyContainer, true);
    
                return token;
            }
            else
            {
                // If this custom XML security token is not the
                // one managed by this security token manager, let
                // the default security token provider try to
                // handle it.
                return null;
            }
        }
        // If execution reaches here, the custom XML
        // security token could not be loaded.
        return null;
    }
    
  6. Implement the VerifyToken method.

    WSE calls the VerifyToken method after a custom XML security token is deserialized to verify whether the security token is still valid.

    ' WSE calls the VerifyToken method after a custom XML security token
    ' is deserialized to verify whether the security token is
    ' still valid.
    Public Overrides Sub VerifyToken(ByVal token As SecurityToken)
        Dim xmlToken As XmlToken = CType(token, XmlToken)
        If (xmlToken Is Nothing) Then
            Throw New ArgumentException( _
                "The security token provided is not an XmlToken instance.", "token")
        ElseIf (xmlToken.IsCurrent = False) Then
            Throw New ApplicationException("The provided XmlToken security token has expired.")
        End If
    End Sub
    
    // WSE calls the VerifyToken method after a custom XML security token
    // is deserialized to verify whether the security token is
    // still valid.
    public override void VerifyToken(SecurityToken token) 
    {
        XmlToken xmlToken = token as XmlToken;
        if (xmlToken == null)
        {
            throw new ArgumentException(
                "The security token provided is not an XmlToken instance.", "token");
        }
        else if (xmlToken.IsCurrent == false)
        {
            throw new ApplicationException("The provided XmlToken security token has expired.");
        }
    }
    

Example

The following code example is a security token manager for a custom XML security token.

Imports System
Imports System.Security.Cryptography
Imports System.Security.Cryptography.Xml
Imports System.Security.Permissions
Imports System.Text
Imports System.Globalization
Imports System.Xml

Imports Microsoft.Web.Services3.Addressing
Imports Microsoft.Web.Services3.Design
Imports Microsoft.Web.Services3.Security
Imports Microsoft.Web.Services3.Security.Cryptography
Imports Microsoft.Web.Services3.Security.Tokens
Imports Microsoft.Web.Services3.Security.Utility

Namespace CustomXmlSecToken
    Public Class XmlTokenManager : Inherits Microsoft.Web.Services3.Security.Tokens.SecurityTokenManager
        Public Overrides ReadOnly Property TokenType() As String
            Get
                Return XmlTokenNames.TypeNames.TokenType
            End Get
        End Property

        ' The LoadTokenFromXml method deserializes an XML element into
        ' a security token.
        Public Overrides Function LoadTokenFromXml(ByVal element As XmlElement) As SecurityToken
            Return New XmlToken(element)
        End Function

        ' Return a security token based on a KeyInfo clause.
        Public Overrides Function LoadTokenFromKeyInfo(ByVal keyInfo As KeyInfo) As SecurityToken
            ' Verify that the keyInfo parameter contains a value.
            If (keyInfo Is Nothing) Then
                Throw New ArgumentNullException("keyInfo")
            End If
            Dim reference As SecurityTokenReference
            Dim clause As KeyInfoClause
            For Each clause In keyInfo
                reference = CType(clause, SecurityTokenReference)
                ' Check if the custom XML security token is the
                ' security token handled by this security token
                ' manager.
                If (TypeOf clause Is SecurityTokenReference AndAlso _
                    (reference.KeyIdentifier.ValueType = _
                    XmlTokenNames.TypeNames.TokenType)) Then
                    ' If the custom XML security token is the security
                    ' token managed by this security token manager,
                    ' get the keys for the security token from the
                    ' cryptographic key container specified in the
                    ' KeyIdentifier property.
                    Dim bytes() As Byte = reference.KeyIdentifier.Value
                    Dim keyContainer As String = _
                        System.Text.Encoding.Default.GetString(bytes)

                    ' Let the custom XML security token do the work of
                    ' retrieving the key for the security token.
                    Dim token As XmlToken = New XmlToken(keyContainer, True)

                    Return token
                Else
                    ' If this custom XML security token is not the
                    ' one managed by this security token manager, let
                    ' the default security token provider try to
                    ' handle it.
                    Return Nothing
                End If
            Next
            ' If execution reaches here, the custom XML
            ' security token could not be loaded.
            Return Nothing
        End Function

        ' WSE calls the VerifyToken method after a custom XML security token
        ' is deserialized to verify whether the security token is
        ' still valid.
        Public Overrides Sub VerifyToken(ByVal token As SecurityToken)
            Dim xmlToken As XmlToken = CType(token, XmlToken)
            If (xmlToken Is Nothing) Then
                Throw New ArgumentException( _
                    "The security token provided is not an XmlToken instance.", "token")
            ElseIf (xmlToken.IsCurrent = False) Then
                Throw New ApplicationException("The provided XmlToken security token has expired.")
            End If
        End Sub
    End Class
End Namespace
using System;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Security.Permissions;
using System.Text;
using System.Globalization;
using System.Xml;

using Microsoft.Web.Services3.Addressing;
using Microsoft.Web.Services3.Design; 
using Microsoft.Web.Services3.Security;
using Microsoft.Web.Services3.Security.Cryptography;
using Microsoft.Web.Services3.Security.Tokens;
using Microsoft.Web.Services3.Security.Utility;

namespace CustomXmlSecToken
{    
    public class XmlTokenManager : SecurityTokenManager
    {
        public override string TokenType 
        { 
            get 
            {
                return XmlTokenNames.TypeNames.TokenType;
            }
        }

        // The LoadTokenFromXml method deserializes an XML element into
        // a security token.
        public override SecurityToken LoadTokenFromXml(XmlElement
            element)
        {
            return new XmlToken(element);
        }

        // Return a security token based on a KeyInfo clause.
        public override SecurityToken LoadTokenFromKeyInfo(KeyInfo
            keyInfo) 
        {
            // Verify that the keyInfo parameter contains a value.
            if (null == keyInfo)
                throw new ArgumentNullException("keyInfo");
            SecurityTokenReference reference;
            foreach ( KeyInfoClause clause in keyInfo )
            {
                reference = (SecurityTokenReference)clause;
                // Check if the custom XML security token is the
                // security token handled by this security token
                // manager.
                if ( clause is SecurityTokenReference && 
                    (reference.KeyIdentifier.ValueType ==
                    XmlTokenNames.TypeNames.TokenType))
                {
                    // If the custom XML security token is the security
                    // token managed by this security token manager,
                    // get the keys for the security token from the
                    // cryptographic key container specified in the
                    // KeyIdentifier property.
                    byte[] bytes = reference.KeyIdentifier.Value;
                    string keyContainer =
                        System.Text.Encoding.Default.GetString(bytes);

                    // Let the custom XML security token do the work of
                    // retrieving the key for the security token.
                    XmlToken token = new XmlToken(keyContainer, true);

                    return token;
                }
                else
                {
                    // If this custom XML security token is not the
                    // one managed by this security token manager, let
                    // the default security token provider try to
                    // handle it.
                    return null;
                }
            }
            // If execution reaches here, the custom XML
            // security token could not be loaded.
            return null;
        }

        // WSE calls the VerifyToken method after a custom XML security token
        // is deserialized to verify whether the security token is
        // still valid.
        public override void VerifyToken(SecurityToken token) 
        {
            XmlToken xmlToken = token as XmlToken;
            if (xmlToken == null)
            {
                throw new ArgumentException(
                    "The security token provided is not an XmlToken instance.", "token");
            }
            else if (xmlToken.IsCurrent == false)
            {
                throw new ApplicationException("The provided XmlToken security token has expired.");
            }
        }
    }
}

See Also

Tasks

How to: Configure the Security Token Manager for a Custom Security Token
How to: Create a Class Representing a Custom Binary Security Token

Reference

SecurityTokenManager Class

Other Resources

Creating Custom Security Tokens