How to: Authorize the Message Sender Based on a Kerberos Ticket

WSE enables you to authorize access to a Web service method based on a Kerberos ticket (KerberosToken security token) within a SOAP message. When a SOAP message is received, WSE attempts to authenticate the SOAP message sender. If authentication succeeds, the Principal property of the KerberosToken security token is assigned a principal representing the authenticated user.

For an overview of authorization support in WSE, see Authorizing Access to a Web Service.

The following procedures detail how to use policy or code to authorize access to a Web service by using a Kerberos service ticket. Whether you use policy or code, WSE must be enabled to process the incoming SOAP messages.

The following procedure can be used with both the KerberosToken and KerberosToken2 security tokens. To use the procedure for KerberosToken2 security tokens, do the following:

For more details about the difference between the KerberosToken and KerberosToken2 security tokens, see Differences between KerberosToken and KerberosToken2.

To configure WSE to process incoming SOAP messages

  • In the Web.config file for the Web service, include an <add> Element for <soapExtensionTypes> (WSE for Microsoft .NET) element in the <soapExtensionTypes> section.

    When the SOAP message recipient is a Web service client, this configuration entry is not required. Instead, the base class that the proxy class derives from must be changed to derive from the WebServicesClientProtocol.

    The following code example is the configuration entry that must be placed in the Web.config file for WSE to run with a Web service. The type attribute of the <add> element for <soapExtensionTypes> section must be on one line, even though the following sample shows it split across multiple lines for readability.

    <configuration>
       <system.web>
          <webServices>
             <soapExtensionTypes>
                <add type="Microsoft.Web.Services2.WebServicesExtension, 
                Microsoft.Web.Services2,Version=2.0.0.0, Culture=neutral, 
                PublicKeyToken=31bf3856ad364e35" 
                priority="1" group="0"/>
             </soapExtensionTypes>
          </webServices>
       </system.web>
    
</configuration>

To use policy to authorize access to a Web service method by using a Kerberos service ticket

  1. Define a policy assertion and digital signature requirements by adding <Policy> Element (WSE for Microsoft .NET) (1) and <Integrity> Element elements.

    1. Add a <Policy> Element (WSE for Microsoft .NET) (1) element to the policy file for the application. Add the <Policy> Element (WSE for Microsoft .NET) (1) element as a child element of the <policies> Element element.
      The <Policy> Element (WSE for Microsoft .NET) (1) element defines criteria that a SOAP message must meet. The criteria are specified as child elements of the <Policy> Element (WSE for Microsoft .NET) (1) element. The Id attribute value provides a name that is used by the <request> Element (WSE for Microsoft .NET), <response> Element (WSE for Microsoft .NET), and <fault> Element elements to refer to the policy assertion when applying the policy to an endpoint.
    2. Add an <Integrity> Element child element to the <Policy> Element (WSE for Microsoft .NET) (1) element.
      Although you can authorize access to the Web service method based on any security token within the SOAP message, it is common practice to use the security token that signed at least the <Body> element of the SOAP message.
      The <Integrity> Element element defines digital signature requirements. The Usage attribute value of "Required" specifies that a signature is required, and additional requirements are specified in child elements.

    The following code example defines a policy assertion named policy-c0a22319-6b89-49ff-9b82-bdbac5f04618 and specifies that there are digital signature requirements.

                  <wsp:Policy wsu:Id="policy-c0a22319-6b89-49ff-9b82-bdbac5f04618"
      xmlns:wsp="https://schemas.xmlsoap.org/ws/2002/12/policy"
      xmlns:wsa="https://schemas.xmlsoap.org/ws/2004/03/addressing">
      <wssp:Integrity wsp:Usage="wsp:Required" 
    
  2. Specify the token type by adding <TokenInfo> Element, <SecurityToken> Element, and <TokenType> Element elements.

    1. Add a <TokenInfo> Element child element to the <Integrity> Element element.
    2. Add a <SecurityToken> Element child element to the <TokenInfo> Element element.
    3. Add a <TokenType> Element child element to the <SecurityToken> Element element and set its value to https://schemas.xmlsoap.org/ws/2003/12/kerberos/Kerberosv5ST.
      The <TokenType> Element element specifies the type of security token that must be used to create the digital signature.

    The following code example specifies that a KerberosToken security token must be used to digitally sign the SOAP message.

                  <wssp:Integrity wsp:Usage="wsp:Required"
                    xmlns:wssp="https://schemas.xmlsoap.org/ws/2002/12/secext">
                    <wssp:TokenInfo>
                      <wssp:SecurityToken>
                        <wssp:TokenType>https://schemas.xmlsoap.org/ws/2003/12/kerberos/Kerberosv5ST</wssp:TokenType>
    
    
  3. Specify the group of users that are authorized to use the Web service by adding <Claims> Element, <ServiceName> Element, and <Role> Element elements.

    1. Add a <Claims> Element child element to the <SecurityToken> Element element.

    2. Add a <ServiceName> Element child element to the <Claims> Element element.
      The <ServiceName> Element element specifies the service principal name. The service principal name is in the following format: host/<hostname>@<domain>, where hostname is the name of the computer receiving the SOAP message and domain is the fully qualified domain name of the Kerberos realm in which the host computer resides.

      Note

      WSE does not verify that a KerberosToken security token matches the specified service principal name for incoming SOAP messages.

    3. Add a <Role> Element child element to the <Claims> Element element.
      The <Role> Element element specifies the group of users, known as a role, which is authorized to use the Web service. All Kerberos tickets have a principal name that is the name of the computer or user whose security credentials are being represented by the Kerberos ticket. When a SOAP request is received that contains a Kerberos service ticket, WSE attempts to authenticate those credentials. If the credentials are valid, then the principal name's role is looked up in Active Directory™. If that role matches the value of the <Role> Element element, then the SOAP request is authorized to use the Web service.
      The following code example specifies that a Kerberos service ticket must be used to sign SOAP messages. Furthermore, the principal name for the Kerberos service ticket must belong to the Administrators role on the computer named computer1@cohowinery.com.

      <wssp:Integrity wsp:Usage="wsp:Required"
        xmlns:wssp="https://schemas.xmlsoap.org/ws/2002/12/secext">
        <wssp:TokenInfo>
          <SecurityToken xmlns="https://schemas.xmlsoap.org/ws/2002/12/secext">
            <wssp:TokenType>https://schemas.xmlsoap.org/ws/2003/12/kerberos/Kerberosv5ST</wssp:TokenType>
              <wssp:Claims>          <wse:Role             xmlns:wse="https://schemas.microsoft.com/wse/2003/06/Policy"             value="BUILTIN\Administrators" />            <wssp:ServiceName>host/computer1@cohowinery.com</wssp:ServiceName>        </wssp:Claims>
            </SecurityToken>
          </wssp:TokenInfo>
      
  4. Map the policy assertion to an endpoint by adding an <endpoint> Element element. Optionally, designate the policy as the default for all SOAP messages by adding the <defaultOperation> Element element.

    1. Add an <endpoint> Element element to the <mappings> Element element, and set the uri attribute value to the URI of the application.
      The <endpoint> Element element maps a policy assertion to an endpoint. The uri attribute value specifies the URI of the service to which the policy is mapped.
    2. Add a <defaultOperation> Element child element to the <endpoint> Element element.
      The <defaultOperation> Element element specifies the default policy for all operations at the URI specified in the uri attribute.
    3. Add <request> Element (WSE for Microsoft .NET), <response> Element (WSE for Microsoft .NET), and <fault> Element child elements to the <defaultOperation> Element element. The value of the policy attribute must match the value of the Id attribute of the <Policy> Element (WSE for Microsoft .NET) (1) element that defines the policy assertion.

    The following code example sets the default policy for all SOAP messages to the policy-c0a22319-6b89-49ff-9b82-bdbac5f04618 policy assertion.

    <mappings xmlns:wse="https://schemas.microsoft.com/wse/2003/06/Policy">
      <endpoint uri="http://www.cohowinery.com/SaleWidgets.asmx">
        <defaultOperation>
          <request policy="#policy-c0a22319-6b89-49ff-9b82-bdbac5f04618" />
          <response policy="#policy-c0a22319-6b89-49ff-9b82-bdbac5f04618" />
          <fault policy="#policy-c0a22319-6b89-49ff-9b82-bdbac5f04618" />
        </defaultOperation>
      </endpoint>
    </mappings>
    
  5. Specify the XML elements to be signed by adding a <MessageParts> Element for <Integrity> Element element to the <Integrity> Element element.

    1. Add a <MessageParts> Element for <Integrity> Element child element to the <Integrity> Element element in the policy file for the application, and set the Dialect attribute value to "https://schemas.xmlsoap.org/2002/12/wsse#part".
    2. Specify the parts of the message to be signed by listing them, separated by spaces, as the value of the <MessageParts> Element for <Integrity> Element element.

    The following code example specifies that the <Body> element and the To, Action, MessageID, and From headers are signed.

    <wssp:MessageParts Dialect="https://schemas.xmlsoap.org/2002/12/wsse#part">
      wsp:Body() wsp:Header(wsa:To) wsp:Header(wsa:Action) wsp:Header(wsa:MessageID) wsp:Header(wsa:From)
    </wssp:MessageParts>
    

To use code to authorize access to a Web service method by using a Kerberos service ticket

  1. Add code to the Web service method that obtains the KerberosToken security token that the application wants to use for authentication and authorization.

    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 used for authorization.

    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)
                ' Verify that this signature signed the SOAP Body element.
                If ((sig.SignatureOptions And _
                  SignatureOptions.IncludeSoapBody) <> 0) Then
                    Dim sigToken As SecurityToken
                    sigToken = sig.SigningToken
                    ' Verify that the security token is a KerberosToken security token.
                    If TypeOf sigToken Is KerberosToken Then                    token = CType(sigToken, KerberosToken)                End If
                End If
            End If
        Next securityElement
        Return token
    End Function
    ' Add this code to the code within the Web service method.
    ' 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 signed the SOAP request.
    Dim token 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) != 0)
                {
                    SecurityToken sigToken = sig.SigningToken;
                    if (sigToken is KerberosToken)                    token = (KerberosToken)sigToken;
                }
            }
        }
        return token;
    }
    // Add this code to the code within the Web service method.
    // 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 is used to sign the SOAP request.
    KerberosToken token = GetBodySigningToken(requestContext);
    
  2. Ensure that the user is a member of the role or roles authorized to call this Web service method.

    The following code example ensures a KerberosToken security token was used to sign the SOAP message and that the user is a member of the Tellers role.

    If (token Is Nothing OrElse (Not token.Principal.IsInRole("Tellers"))) Then
        Throw New UnauthorizedAccessException
    End If
    
    if (token == null || !token.Principal.IsInRole("Tellers"))
        throw new UnauthorizedAccessException();
    

Example

The following code example is a policy file specifying that all SOAP messages sent to the http://www.cohowinery.com/SaleWidgets.asmx endpoint must have the <Body> element and the To, Action, MessageID, and From headers signed by a Kerberos service ticket whose principal name belongs to the Administrators role on the computer named computer1@cohowinery.com.

Note

This code example is designed to demonstrate WSE features and is not intended for production use.

<?xml version="1.0" encoding="utf-8"?>
<policyDocument xmlns="https://schemas.microsoft.com/wse/2003/06/Policy">
  <mappings xmlns:wse="https://schemas.microsoft.com/wse/2003/06/Policy">
    <endpoint uri="http://www.cohowinery.com/SaleWidgets.asmx">
      <defaultOperation>
        <request policy="#policy-c0a22319-6b89-49ff-9b82-bdbac5f04618" />
        <response policy="#policy-c0a22319-6b89-49ff-9b82-bdbac5f04618" />
        <fault policy="#policy-c0a22319-6b89-49ff-9b82-bdbac5f04618" />
      </defaultOperation>
    </endpoint>
  </mappings>
  <policies xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <wsp:Policy wsu:Id="policy-c0a22319-6b89-49ff-9b82-bdbac5f04618"
      xmlns:wsp="https://schemas.xmlsoap.org/ws/2002/12/policy"
      xmlns:wsa="https://schemas.xmlsoap.org/ws/2004/03/addressing" >
      <wssp:Integrity wsp:Usage="wsp:Required"
        xmlns:wssp="https://schemas.xmlsoap.org/ws/2002/12/secext">
        <wssp:TokenInfo>
          <SecurityToken xmlns="https://schemas.xmlsoap.org/ws/2002/12/secext">
            <wssp:TokenType>https://schemas.xmlsoap.org/ws/2003/12/kerberos/Kerberosv5ST</wssp:TokenType>
            <wssp:Claims>
              <wssp:ServiceName>host/computer1@cohowinery.com</wssp:ServiceName>
              <wse:Role                 xmlns:wse="https://schemas.microsoft.com/wse/2003/06/Policy"                 value="BUILTIN\Administrators" />            <wssp:ServiceName>host/computer1@cohowinery.com</wssp:ServiceName>

            </wssp:Claims>
          </SecurityToken>
        </wssp:TokenInfo>
        <wssp:MessageParts Dialect="https://schemas.xmlsoap.org/2002/12/wsse#part">
            wsp:Body() wsp:Header(wsa:To) wsp:Header(wsa:Action) wsp:Header(wsa:MessageID) wsp:Header(wsa:From)
        </wssp:MessageParts>
      </wssp:Integrity>
    </wsp:Policy>
  </policies>
</policyDocument>

The following code example authorizes SOAP requests to the SayHello Web service in which a KerberosToken security token signs the SOAP <Body> element and the user is a member of the Tellers role.

Imports System.Web.Services
Imports Microsoft.Web.Services2
Imports Microsoft.Web.Services2.Security
Imports Microsoft.Web.Services2.Security.Tokens
Imports Microsoft.Web.Services2.Security.Kerberos

<System.Web.Services.WebService(Namespace:="https://www.contoso.com/KerbAuthVB1/Service1")> _
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 signed the SOAP request.
        Dim token As KerberosToken = _
          GetBodySigningToken(requestContext)
        If (token Is Nothing OrElse (Not _
          token.Principal.IsInRole("Tellers"))) Then
            Throw New UnauthorizedAccessException
        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)
                ' Verify that this signature signed the SOAP Body element.
                If ((sig.SignatureOptions And _
                  SignatureOptions.IncludeSoapBody) <> 0) Then
                    Dim sigToken As SecurityToken
                    sigToken = sig.SigningToken
                    ' Verify that the security token is a KerberosToken security token.
                    If TypeOf sigToken Is KerberosToken Then
                        token = CType(sigToken, KerberosToken)
                    End If
                End If
            End If
        Next securityElement
        Return token
    End Function

End Class
using System;
using System.Web.Services;
using Microsoft.Web.Services2;
using Microsoft.Web.Services2.Security;
using Microsoft.Web.Services2.Security.Tokens;
using Microsoft.Web.Services2.Security.Kerberos;

namespace KerbAuth
{
    [WebService((Namespace="https://www.contoso.com/KerbAuthVB1/Service1")]
    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 token = GetBodySigningToken(requestContext);

            if (token == null || !token.Principal.IsInRole("Tellers"))
                throw new UnauthorizedAccessException();

            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) != 0)
                    {
                        SecurityToken sigToken = sig.SigningToken;
                        if (sigToken is KerberosToken)
                            token = (KerberosToken)sigToken;
                    }
                }
            }
            return token;
        }
    }
}

See Also

Other Resources

Kerberos Ticket