How to: Impersonate the Credentials Associated with a KerberosToken

WSE enables you to impersonate the credentials associated with a KerberosToken security token in a SOAP message when a SOAP message sender allows it. A SOAP message sender specifies that the credentials associated with the security token can be impersonated by setting a property in code or adding a claim to send side policy. Once impersonation is enabled by the SOAP message sender, a recipient can impersonate the credentials using code.

To impersonate the credentials associated with a KerberosToken security token in a SOAP message to access a constrained set of resources on a remote computer (constrained delegation), additional configuration steps are required. For more details, see How to: Configure an Application to Use Constrained Delegation.

The following procedures detail how to use policy or code to specify that a KerberosToken security token can be impersonated and how a SOAP message receiver of the KerberosToken security token uses to code to impersonate the credentials associated with it.

Whether you use code, WSE must be enabled to process the incoming SOAP messages.

To use code to specify that a recipient of a KerberosToken can impersonate the credentials associated with a KerberosToken

  1. Open the Web service client project in Visual Studio 2005.

  2. Add references to the Microsoft.Web.Services3 and System.Web.Services assemblies.

    1. On the Project menu, click Add Reference.
    2. On the .NET tab, select the component named Microsoft.Web.Services3.dll, and then click Select.
    3. On the .NET tab, select the component named System.Web.Services.dll, and then click Select.
    4. Click OK.
  3. Add a Web Reference to the Web service that is to receive the SOAP message containing a KerberosToken security token.

    1. On the Project menu, click Add Web Reference.
    2. In the Add Web Reference dialog box, type the URL for the Web service in the Address box, and then click Go.
    3. Verify that the items in the Available references box are the items you want to reference in your project, and then click Add Reference.
  4. Edit the proxy class to derive from WebServicesClientProtocol.

    1. In Solution Explorer, right-click the Reference.cs file for the recently added Web reference, and then click View Code.

      Note

      If the Reference.cs file that contains the proxy class is not visible, click the Show All Files icon in Solution Explorer, and then expand the Reference.map node.

    2. Change the base class of the proxy class to Microsoft.Web.Services3.WebServicesClientProtocol.
      This modifies the proxy class to emit routing and security SOAP headers when communicating with the Web service. The following code example modifies a proxy class named Service1 to derive from Microsoft.Web.Services3.WebServicesClientProtocol.

      Public Class Service1
          Inherits Microsoft.Web.Services3.WebServicesClientProtocol
      
      public class Service1 : Microsoft.Web.Services3.WebServicesClientProtocol
      

      Note

      If you select Update Web Reference in Visual Studio .NET 2003, the proxy class is regenerated, the base class is reset to SoapHttpClientProtocol, and you must change the class the proxy class derives from again.

  5. Add the following using directives to the top of the file containing the Web service client code:

    Imports System
    Imports System.Windows.Forms
    
    Imports Microsoft.Web.Services3
    Imports Microsoft.Web.Services3.Security
    Imports Microsoft.Web.Services3.Security.Tokens
    
    using System;
    using System.Windows.Forms;
    
    using Microsoft.Web.Services3;
    using Microsoft.Web.Services3.Security;
    using Microsoft.Web.Services3.Security.Tokens;
    
  6. Edit the method that communicates with the Web service to add the security credentials to the SOAP message.

    1. Add code to create a KerberosToken security token that can be impersonated.
      Use a constructor that takes an ImpersonationLevel and for that parameter specify ImpersonationLevel.Impersonation.
      The following code example creates an instance of the KerberosToken class and specifies that it can be used for impersonation. The hostname variable is the name of the computer hosting the target Web service, and the dnsDomainName variable is the Kerberos realm that the host is a member of. The Kerberos realm is needed only when the SOAP message sender resides in a different domain or realm from the target Web service.

      Dim kerbToken As KerberosToken = _
          New KerberosToken("host/" + hostname & _
          "@" & domainName, ImpersonationLevel.Impersonation)
      
      KerberosToken kerbToken = new KerberosToken( "host/" + hostname +
          "@" + domainName, ImpersonationLevel.Impersonation);
      
    2. Get the SoapContext for the SOAP request that is being made to the Web service.
      Service1 is the name of a proxy class for the Web service in the following code example.

      ' Creates an instance of the Web service proxy.
      Dim serviceProxy As New AddNumbers
      ' Gets the SoapContext associated with the SOAP request.
      Dim requestContext As SoapContext = _
        serviceProxy.RequestSoapContext
      
      // Creates an instance of the Web service proxy.
      AddNumbers serviceProxy = new AddNumbers();
      // Gets the SoapContext associated with the SOAP request.
      SoapContext requestContext = serviceProxy.RequestSoapContext;
      
    3. Add the SecurityToken to the WS-Security SOAP header.

      ' Adds the token to the SOAP header.
      requestContext.Security.Tokens.Add(kerbToken)
      
      // Adds the token to the SOAP header.
      requestContext.Security.Tokens.Add(kerbToken);
      
    4. Specify the time-to-live (TTL) for the SOAP message to diminish the chance of someone intercepting the message and replaying it. The following code example sets the TTL to one minute.

      ' Sets the TTL to one minute.
      requestContext.Security.Timestamp.TtlInSeconds = 60
      
      // Sets the TTL to one minute.
      requestContext.Security.Timestamp.TtlInSeconds = 60;
      
    5. Call the Web service.

      ' Calls the Web service.
      Dim sum As Integer = serviceProxy.AddInt(a, b)
      
      // Calls the Web service.
      int sum = serviceProxy.AddInt(a, b);
      

To use code to impersonate the credentials associated with a KerberosToken

  1. Add code to the Web service method to obtain the KerberosToken security whose credentials you want to impersonate.

    A SOAP message can contain multiple security tokens, which might sign or encrypt different portions of the SOAP message. Therefore, it is up to the application to determine which security token is impersonated.

    The following code example defines and then calls a GetBodySigningToken method that obtains the KerberosToken security token that signed the <Body> element of the SOAP request.

        Public Function GetBodySigningToken(ByVal requestContext As SoapContext) As KerberosToken
            Dim token As KerberosToken = Nothing
            Dim securityElement As ISecurityElement
            For Each securityElement In requestContext.Security.Elements
                If (TypeOf securityElement Is MessageSignature) Then
                    Dim sig As MessageSignature = _
                        CType(securityElement, MessageSignature)
                    If ((sig.SignatureOptions And _
                        SignatureOptions.IncludeSoapBody) <> SignatureOptions.IncludeSoapBody) Then
                        Dim sigToken As SecurityToken = sig.SigningToken
                        If (TypeOf sigToken Is KerberosToken) Then
                            token = CType(sigToken, KerberosToken)
                        End If
                    End If
                End If
            Next
            Return token
        End Function
    
    
    
    ...
    
    
                ' Get the KerberosToken security token that was used to sign the SOAP
            ' request.
            Dim kerbToken As KerberosToken = GetBodySigningToken(requestContext)
    
        public KerberosToken GetBodySigningToken(SoapContext requestContext)
        {
            KerberosToken token = null;
            foreach (ISecurityElement securityElement in
                requestContext.Security.Elements)
            {
                if (securityElement is MessageSignature)
                {
                    MessageSignature sig =
                        (MessageSignature)securityElement;
                    if ((sig.SignatureOptions &
                        SignatureOptions.IncludeSoapBody) != SignatureOptions.IncludeSoapBody)
                    {
                        SecurityToken sigToken = sig.SigningToken;
                        if (sigToken is KerberosToken)
                            token = (KerberosToken)sigToken;
                    }
                }
            }
            return token;
        }
    
    
    
    ...
    
    
                // Get the KerberosToken security token that was used to sign the SOAP
            // request.
            KerberosToken kerbToken = GetBodySigningToken(requestContext);
    
  2. Ensure that the SOAP message sender specified that the KerberosToken security token can be used for impersonation.

    The following code example ensures that a KerberosToken security token can be used for impersonation.

    If kerbToken.ImpersonationLevel = ImpersonationLevel.Impersonation Then
    
    if (kerbToken.ImpersonationLevel == ImpersonationLevel.Impersonation)
    
  3. Get the Windows identity associated with the KerberosToken.

    The following code example gets the Windows identity associated with the KerberosToken security token.

    Dim identity As WindowsIdentity = _
        CType(kerbToken.Principal.Identity, WindowsIdentity)
    
    WindowsIdentity identity = kerbToken.Principal.Identity as WindowsIdentity;
    
  4. Create a WindowsImpersonationContext object by impersonating the Windows identity.

    The following code example creates a WindowsImpersonationContext object by impersonating the Windows identity.

    Dim context As WindowsImpersonationContext = Nothing
    Try
        context = identity.Impersonate()
    
    WindowsImpersonationContext context = null;
    try
    {
        context = identity.Impersonate();
    
  5. Do the action required by your application that requires the Windows credentials associated with the KerberosToken security token.

    The following code example opens a file on the Web service's computer using the credentials associated with the KerberosToken security token.

    Dim stream As FileStream = File.Open("C:\Temp\test.txt", _
        FileMode.Open, FileAccess.Read, FileShare.None)
    stream.Close()
    
    FileStream stream = File.Open(@"C:\Temp\test.txt", FileMode.Open,
       FileAccess.Read, FileShare.None);
    stream.Close();
    
  6. Stop impersonating the credentials associated with the KerberosToken security token.

    The following code example stops impersonating the credentials associated with the KerberosToken security token.

    context.Undo()
    
    if (context != null)
        context.Undo();
    

Example

The following code example demonstrates how to impersonate the credentials associated with a KerberosToken security token.

Imports System
Imports System.IO
Imports System.Security.Principal
Imports System.Web.Services

Imports Microsoft.Web.Services3
Imports Microsoft.Web.Services3.Security
Imports Microsoft.Web.Services3.Security.Tokens

Namespace KerbImpersonate
    <WebService(Namespace:="http://www.cohowinery.com/webservices/")> _
    Public Class Service1
        <WebMethod()> _
        Public Function SayHello() As String
            ' Ensure that the request is a SOAP request.
            Dim requestContext As SoapContext = RequestSoapContext.Current
            If requestContext Is Nothing Then
                Throw New ApplicationException("Only SOAP requests are permitted.")
            End If

            ' Get the KerberosToken security token that was used to sign the SOAP
            ' request.
            Dim kerbToken As KerberosToken = GetBodySigningToken(requestContext)
            If kerbToken.ImpersonationLevel = ImpersonationLevel.Impersonation Then
                ' Get the Windows identity associated with the KerberosToken.
                Dim identity As WindowsIdentity = _
                    CType(kerbToken.Principal.Identity, WindowsIdentity)

                ' Create a WindowsImpersonationContext object by impersonating
                ' the Windows identity.                        
                Dim context As WindowsImpersonationContext = Nothing
                Try
                    context = identity.Impersonate()
                    ' Access the file on the local computer using the token's
                    ' identity.
                    Dim stream As FileStream = File.Open("C:\Temp\test.txt", _
                        FileMode.Open, FileAccess.Read, FileShare.None)
                    stream.Close()

                Finally ' Stop impersonating the credentials associated with the KerberosToken.                        
                    If Not context Is Nothing Then
                        context.Undo()
                    End If
                End Try
                
            End If
            Return "Hello World"
        End Function

        Public Function GetBodySigningToken(ByVal requestContext As SoapContext) As KerberosToken
            Dim token As KerberosToken = Nothing
            Dim securityElement As ISecurityElement
            For Each securityElement In requestContext.Security.Elements
                If (TypeOf securityElement Is MessageSignature) Then
                    Dim sig As MessageSignature = _
                        CType(securityElement, MessageSignature)
                    If ((sig.SignatureOptions And _
                        SignatureOptions.IncludeSoapBody) <> SignatureOptions.IncludeSoapBody) Then
                        Dim sigToken As SecurityToken = sig.SigningToken
                        If (TypeOf sigToken Is KerberosToken) Then
                            token = CType(sigToken, KerberosToken)
                        End If
                    End If
                End If
            Next
            Return token
        End Function
    End Class
End Namespace
using System;
using System.IO;
using System.Security.Principal;
using System.Web.Services;

using Microsoft.Web.Services3;
using Microsoft.Web.Services3.Security;
using Microsoft.Web.Services3.Security.Tokens;

namespace KerbImpersonate
{
    [WebService(Namespace="http://www.cohowinery.com/webservices/")]
    public class Service1
    {
        [WebMethod]
        public string SayHello()
        {
            // Ensure that the request is a SOAP request.
            SoapContext requestContext = RequestSoapContext.Current;
            if (requestContext == null)
                throw new ApplicationException("Only SOAP requests are permitted.");
                
            // Get the KerberosToken security token that was used to sign the SOAP
            // request.
            KerberosToken kerbToken = GetBodySigningToken(requestContext);

            if (kerbToken.ImpersonationLevel == ImpersonationLevel.Impersonation)
            {
               // Get the Windows identity associated with the KerberosToken.
               WindowsIdentity identity = kerbToken.Principal.Identity as WindowsIdentity;
                
                
               // Create a WindowsImpersonationContext object by impersonating
               // the Windows identity.                        
               WindowsImpersonationContext context = null;
               try
               {
                   context = identity.Impersonate();


                   // Access the file on the local computer using the token's
                   // identity.
                   FileStream stream = File.Open(@"C:\Temp\test.txt", FileMode.Open,
                      FileAccess.Read, FileShare.None);
                   stream.Close();
               }
               finally
               {

                   // Stop impersonating the credentials associated with the KerberosToken.
                   if (context != null)
                       context.Undo();
               }
            }
            return "Hello World";
        }

        public KerberosToken GetBodySigningToken(SoapContext requestContext)
        {
            KerberosToken token = null;
            foreach (ISecurityElement securityElement in
                requestContext.Security.Elements)
            {
                if (securityElement is MessageSignature)
                {
                    MessageSignature sig =
                        (MessageSignature)securityElement;
                    if ((sig.SignatureOptions &
                        SignatureOptions.IncludeSoapBody) != SignatureOptions.IncludeSoapBody)
                    {
                        SecurityToken sigToken = sig.SigningToken;
                        if (sigToken is KerberosToken)
                            token = (KerberosToken)sigToken;
                    }
                }
            }
            return token;
        }
    }
}

See Also

Tasks

How to: Configure an Application to Use Constrained Delegation

Reference

KerberosToken

Other Resources

Kerberos Ticket
Brokered Authentication – Kerberos
Kerberos Technical Supplement for Windows
Protocol transition & constrained delegation