<kerberosSecurity> Element

Represents a turnkey security assertion that uses a KerberosToken security token to authenticate the client and protect SOAP messages.

<policies> Element
  <policy> Element (Policy)

<kerberosSecurity
  clientActor
  establishSecurityContext="true|false"
  messageProtectionOrder="Signature and encryption order"
  renewExpiredSecurityContext="true|false"
  requireDerivedKeys="true|false"
  requireSignatureConfirmation="true|false"
  serviceActor
  ttlInSeconds >
  <token/>
  <protection/>
</kerberosSecurity>

Microsoft.Web.Services3.Design.KerberosAssertion

Attributes and Elements

Attributes

Attribute Description

clientActor

Optional attribute. Specifies the actor attribute on the Security SOAP header for a SOAP message that is destined for a Web service client to which this policy assertion applies. When the SOAP message is not routed through an intermediary, such as a SOAP router, the actor attribute is an empty string (""). When the policy assertion applies to an intermediary, specify the URI for the intermediary. The default value is an empty string ("").

establishSecurityContext

Optional attribute. Specifies whether a secure conversation is established using SecurityContextToken security tokens. Possible values are true and false. true specifies that this security assertion secures the security token request and its response (the RST and RSTR) and SOAP messages exchanged between the client and the Web service are secured using SecurityContextToken security tokens. The default value is false.

Note

The establishSecurityContext attribute cannot be set to true when stateful SecurityContextToken security tokens are used. In this scenario, the RST and RSTR are secured using a KerberosToken security token that is also placed in the state of the issued SecurityContextToken security token. KerberosToken security tokens are based on Security Support Provider Interface (SSPI) Kerberos tokens that can be used once and only once. When the KerberosToken is part of the SecurityContextToken security token's state, the SSPI Kerberos token is used every time the SecurityContextToken security token is used. SSPI throws an exception when it is used more than once. Therefore, the establishSecurityContext attribute can only be set to true for the <kerberosSecurity> turnkey security assertion when stateful SecurityContextToken security tokens are not used. To specify whether stateful SecurityContextToken security tokens are used, use the <statefulSecurityContextToken> Element.

messageProtectionOrder

Optional attribute. Specifies the order of operation for digital signatures and message encryption. SignBeforeEncrypting specifies that a digital signature is generated for the SOAP message before any portion of the SOAP message is encrypted, but the digital signature is not encrypted. SignBeforeEncryptingAndEncryptSignature specifies that a digital signature is generated for the SOAP message before any portion of the SOAP message is encrypted and the digital signature is encrypted.

renewExpiredSecurityContext

Optional attribute. Specifies that a new SecurityContextToken security token is automatically requested as the current one expires when a secure conversation is established. This is applicable only when the establishSecurityContext attribute for this policy assertion is true.

requireDerivedKeys

Optional attribute. Specifies whether DerivedKeyToken security tokens are used. Possible values are true and false.

requireSignatureConfirmation

Optional attribute. Specifies whether the Web service sends a confirmation that verifies the client's digital signature and whether the client rejects SOAP responses without a signature confirmation. This is always false.

serviceActor

Optional attribute. Specifies the actor attribute on the Security SOAP header for a SOAP message destined for a Web service to which this policy assertion applies. When the SOAP message is not routed through an intermediary, such as a SOAP router, the actor attribute is an empty string (""). When the policy assertion applies to an intermediary, specify the URI for the intermediary. The default value is an empty string ("").

Note

When the serviceActor attribute is set to a value other than an empty string (""), then the establishSecurityContext attribute must be set to false.

ttlInSeconds

Optional attribute. Specifies the default number of seconds that a SOAP message is valid after its creation. The default value is 5 minutes (300 seconds).

Child Elements

Element Description

<token> Element

Optional element. Specifies the details for the KerberosToken security token. If the details of the KerberosToken security token are not specified in the policy file, the security token must be added using code.

<protection> Element

Optional element. Specifies the portions of the SOAP message that are signed, encrypted, or both.

Parent Elements

Element Description

<policy> Element

Specifies a SOAP message requirement.

Remarks

This security assertion can have zero or more <protection> elements. Use more than one <protection> element to apply protection requirements for each operation using the requestAction attribute. Each of the <protection> elements must have a unique requestAction attribute unless the requestAction is omitted. Only one of the <protection> elements can omit the requestAction attribute, and that element defines the default protection requirements for the policy.

WSE 3.0 works on Windows Server 2000; however a custom policy assertion is required for WSE 3 clients or WSE 3 Web services that are hosted on Windows Server 2000. When a SOAP message is encrypted or digitally signed by a Kerberos ticket, the recipient must obtain the session key to encrypt or decrypt the SOAP message or to validate the digital signature. Windows Server 2000 prevents applications from obtaining the session key for a Kerberos ticket, so it is not possible to digitally sign or encrypt a SOAP message using a Kerberos ticket on Windows Server 2000. Kerberos tickets can still be used for authentication on Windows Server 2000, however. See the code example in the Code section of this topic for an example custom policy assertion that authenticates the client using a Kerberos ticket, but does not protect the SOAP message.

SOAP requests sent by the client and SOAP responses sent by the Web service are protected as specified in the following table.

SOAP message Protection Description

SOAP request

Digital Signature

The SOAP message parts specified in the <request> child element of the <protection> element are digitally signed using a KerberosToken security token.

SOAP request

Encryption

The SOAP message parts specified in the <request> child element of the <protection> element are encrypted using an KerberosToken security token.

SOAP response

Digital Signature

The SOAP message parts specified in the <response> or <fault> child elements of the <protection> element are digitally signed using the KerberosToken security token that encrypted the SOAP request.

SOAP response

Encryption

The SOAP message parts specified in the <response> or <fault> child elements of the <protection> element are encrypted using the KerberosToken security token that encrypted the SOAP request.

Example

The following code example demonstrates how to secure a SOAP message exchange using a KerberosToken security token. The code example defines a policy assertion named kerberosAuthenticationKerberosProtection that specifies that a KerberosToken security token is used to authenticate the client, digitally signs the SOAP message, and encrypts the <body> element of the SOAP message. The keys used to generate the digital signature and encrypt the <body> element are not the same keys, but rather are derived from the same key.

<policies>
  <extensions>
    <extension name="kerberosSecurity"
               type="Microsoft.Web.Services3.Design.KerberosAssertion, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    <extension name="kerberos"
               type="Microsoft.Web.Services3.Design.KerberosTokenProvider, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    <extension name="requireActionHeader"
               type="Microsoft.Web.Services3.Design.RequireActionHeaderAssertion, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  </extensions>
  <policy name="kerberosAuthenticationKerberosProtection">
    <kerberosSecurity establishSecurityContext="false" signatureConfirmation="false" messageProtectionOrder="SignBeforeEncrypting" requireDerivedKeys="true">
      <token>
        <kerberos targetPrincipal="host/contoso4@contoso.com" impersonationLevel="Identification" />
      </token>
      <protection>
        <request signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="true" />
        <response signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="true" />
        <fault signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />
      </protection>
    </kerberosSecurity>
    <requireActionHeader />
  </policy>
</policies>

The following code example is a custom policy assertion that authenticates a client or Web service using a Kerberos ticket where the SOAP messages are not protected by a Kerberos ticket. Applications should modify this custom policy assertion to provide an alternative mechanism for protecting the SOAP messages. For more details about creating a custom policy assertion that secures a SOAP message, see How to: Create a Custom Policy Assertion that Secures SOAP Messages.

Imports System
Imports System.Collections
Imports System.Collections.ObjectModel
Imports System.Collections.Generic
Imports System.Text

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




Enum MessageType
TokenOnly
TokenWithSignatureAndEncryption
End Enum 'MessageType


Class CustomKerberosAssertion
Inherits KerberosAssertion
Private incomingMessageType As MessageType

Public Sub New()

End Sub


Public Overrides Function CreateClientOutputFilter(ByVal context As FilterCreationContext) As SoapFilter
Return New CustomClientOutputFilter(Me)

End Function


Public Overrides Function CreateClientInputFilter(ByVal context As FilterCreationContext) As SoapFilter
Return New CustomClientInputFilter(Me)

End Function


Public Overrides Function CreateServiceInputFilter(ByVal context As FilterCreationContext) As SoapFilter
Return New CustomServiceInputFilter(Me)

End Function


Public Overrides Function CreateServiceOutputFilter(ByVal context As FilterCreationContext) As SoapFilter
Return New CustomServiceOutputFilter(Me)

End Function


Public Property IncomingMsgType() As MessageType
Get
Return Me.incomingMessageType
End Get
Set(ByVal value As MessageType)
Me.incomingMessageType = value
End Set
End Property

Protected Class CustomServiceInputFilter
Inherits KerberosAssertion.ServiceInputFilter
Private assertion As CustomKerberosAssertion

Public Sub New(ByVal assertion As CustomKerberosAssertion)
MyBase.New(assertion)
Me.assertion = assertion

End Sub


Public Overrides Sub ValidateMessageSecurity(ByVal envelope As SoapEnvelope, ByVal security As Security, ByVal request As MessageProtectionRequirements)
If security Is Nothing Then
Throw New SecurityFault("Incoming request does not contain a security header.")
End If
If security.Elements.Count > 0 Then
' The SOAP request came from a client that is running Windows Server 2003.
' NOTE: Set the message type first, in case the base.Validate throws an exception,
' because the code needs to specify which assertion to use to secure
' the outgoing message.
Me.assertion.IncomingMsgType = MessageType.TokenWithSignatureAndEncryption
MyBase.ValidateMessageSecurity(envelope, security, request)
Else
' The SOAP request came from a client that is running Windows 2000.
Me.assertion.IncomingMsgType = MessageType.TokenOnly

' Try and get the Kerberos token in the tokens collection.
Dim kerberosToken As KerberosToken = Nothing
If Not TryGetUniqueKerberosToken(security.Tokens, kerberosToken) Then
If kerberosToken Is Nothing Then
Throw New SecurityFault(String.Format(System.Globalization.CultureInfo.InvariantCulture, "Could not find the Kerberos Token in the incoming message."))
Else
Throw New SecurityFault(String.Format(System.Globalization.CultureInfo.InvariantCulture, "Multiple Kerberos Tokens found in the incoming message."))
End If
End If

Dim serviceActor As String = Me.GetServiceActor(envelope.CurrentSoap)
envelope.Context.Credentials.SetCredentials(New CredentialSet(kerberosToken), serviceActor)
' Set the IdentityToken when this message is for the ultimate destination.
If serviceActor = String.Empty Then
envelope.Context.IdentityToken = kerberosToken
End If
End If

End Sub

Function TryGetUniqueKerberosToken(ByVal tokens As SecurityTokenCollection, ByRef kerbToken As KerberosToken) As Boolean
kerbToken = Nothing
Dim token As SecurityToken
For Each token In tokens
If TypeOf token Is KerberosToken Then
If kerbToken Is Nothing Then
kerbToken = CType(token, KerberosToken)
Else
' This is a second Kerberos token and is therefore not unique.
Return False
End If
End If
Next token

Return Not (kerbToken Is Nothing)

End Function
End Class


Protected Class CustomServiceOutputFilter
Inherits KerberosAssertion.ServiceOutputFilter
Private assertion As CustomKerberosAssertion

Public Sub New(ByVal assertion As CustomKerberosAssertion)
MyBase.New(assertion)
Me.assertion = assertion

End Sub


Public Overrides Sub SecureMessage(ByVal envelope As SoapEnvelope, ByVal security As Security, ByVal response As MessageProtectionRequirements)
' Secure the outgoing response only when  the incoming
' message is signed and encrypted.
If assertion.IncomingMsgType = MessageType.TokenWithSignatureAndEncryption Then
MyBase.SecureMessage(envelope, security, response)
End If

End Sub
End Class

' This class is the client output filter for Windows 2000 clients.
' The outgoing message only contains the Kerberos token and is not signed
' or encrypted by the Kerberos token.
Protected Class CustomClientOutputFilter
Inherits KerberosAssertion.ClientOutputFilter

Private provider As TokenProvider(Of KerberosToken)
Private kerberosToken As KerberosToken


Public Sub New(ByVal assertion As KerberosAssertion)
MyBase.New(assertion)
provider = assertion.KerberosTokenProvider

End Sub


Public Overrides Sub SecureMessage(ByVal envelope As SoapEnvelope, ByVal security As Security, ByVal request As MessageProtectionRequirements)
If envelope Is Nothing Then
Throw New ArgumentNullException("envelope")
End If
If security Is Nothing Then
Throw New SecurityFault(String.Format(System.Globalization.CultureInfo.InvariantCulture, "No security header was found while verifying the incoming message"))
End If
If request Is Nothing Then
Throw New ArgumentNullException("request")
End If
If Not (provider Is Nothing) Then
Me.kerberosToken = provider.GetToken()
End If
Dim kt As KerberosToken = GetClientToken(Me.kerberosToken, Me.GetServiceActor(envelope.CurrentSoap))
security.Tokens.Add(kt)

End Sub


Function GetClientToken(ByVal token As KerberosToken, ByVal actor As String) As KerberosToken
If Not (token Is Nothing) Then
Return token
End If
Dim result As KerberosToken = Nothing

If Not (actor Is Nothing) AndAlso Not (SoapContext.Current Is Nothing) Then
Dim cs As CredentialSet = SoapContext.Current.Credentials(actor)
result = cs.GetServiceToken(Of KerberosToken)()
End If

If result Is Nothing Then
Throw New InvalidOperationException(String.Format(System.Globalization.CultureInfo.InvariantCulture, "Unable to determine service token to use. Service token type requested was '{0}'. The token must be provided either through policy by specifying the token in the policy assertion or through code by calling WebServicesClientProtocol.SetCredentials or using properties on the SoapContext.Credentials.", GetType(KerberosToken).ToString()))
End If
Return result

End Function
End Class


Protected Class CustomClientInputFilter
Inherits KerberosAssertion.ClientInputFilter

Public Sub New(ByVal assertion As KerberosAssertion)
MyBase.New(assertion)

End Sub


Public Overrides Sub ValidateMessageSecurity(ByVal envelope As SoapEnvelope, ByVal security As Security, ByVal response As MessageProtectionRequirements)
If envelope Is Nothing Then
Throw New ArgumentNullException("envelope")
End If
If security Is Nothing Then
Throw New SecurityFault(String.Format(System.Globalization.CultureInfo.InvariantCulture, "No security header was found while verifying the incoming message"))
End If

End Sub

Public Overrides Function GetUnattachedTokensCore(ByVal context As SoapContext) As IEnumerable(Of SecurityToken)
Return Nothing

End Function
End Class
End Class
    
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Text;

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


namespace TestPolicyAssertion
{
enum MessageType
{
TokenOnly,
TokenWithSignatureAndEncryption
}

class CustomKerberosAssertion : KerberosAssertion
{
MessageType incomingMessageType;
public CustomKerberosAssertion()
: base()
{
}

public override SoapFilter CreateClientOutputFilter(FilterCreationContext context)
{
return new CustomClientOutputFilter(this);
}

public override SoapFilter CreateClientInputFilter(FilterCreationContext context)
{
return new CustomClientInputFilter(this);
}

public override SoapFilter CreateServiceInputFilter(FilterCreationContext context)
{
return new CustomServiceInputFilter(this);
}

public override SoapFilter CreateServiceOutputFilter(FilterCreationContext context)
{
return new CustomServiceOutputFilter(this);
}

public MessageType IncomingMsgType
{
get { return this.incomingMessageType; }
set { this.incomingMessageType = value; }
}

protected class CustomServiceInputFilter : KerberosAssertion.ServiceInputFilter
{
CustomKerberosAssertion assertion;
public CustomServiceInputFilter(CustomKerberosAssertion assertion)
: base(assertion)
{
this.assertion = assertion;
}

public override void ValidateMessageSecurity(SoapEnvelope envelope, Security security, MessageProtectionRequirements request)
{
if (security == null)
throw new SecurityFault("Incoming request does not contain a security header.");

if (security.Elements.Count > 0)
{
// The SOAP request came from a client that is running Windows Server 2003.
// NOTE: Set the message type first, in case the base.Validate throws an exception,
// because the code needs to specify which assertion to use to secure
// the outgoing message.
this.assertion.IncomingMsgType = MessageType.TokenWithSignatureAndEncryption;
base.ValidateMessageSecurity(envelope, security, request);
}
else
{
// The SOAP request came from a client that is running Windows 2000.
this.assertion.IncomingMsgType = MessageType.TokenOnly;

// Try and get the Kerberos token in the tokens collection.
KerberosToken kerberosToken = null;
if (!TryGetUniqueKerberosToken(security.Tokens, out kerberosToken))
{
if (kerberosToken == null)
{
throw new SecurityFault(String.Format(System.Globalization.CultureInfo.InvariantCulture, "Could not find the Kerberos Token in the incoming message."));
}
else
{
throw new SecurityFault(String.Format(System.Globalization.CultureInfo.InvariantCulture, "Multiple Kerberos Tokens found in the incoming message."));
}
}

string serviceActor = this.GetServiceActor(envelope.CurrentSoap);
envelope.Context.Credentials.SetCredentials(new CredentialSet(kerberosToken), serviceActor);
// Set the IdentityToken when this message is for the ultimate destination.
if (serviceActor == String.Empty)
envelope.Context.IdentityToken = kerberosToken;
}
}

bool TryGetUniqueKerberosToken(SecurityTokenCollection tokens, out KerberosToken kerbToken)
{
kerbToken = null;
foreach (SecurityToken token in tokens)
{
if (token is KerberosToken)
{
if (kerbToken == null)
{
kerbToken = (KerberosToken)token;
}
else
{
// This is a second Kerberos token and is therefore not unique.
return false;
}
}
}

return kerbToken != null;
}
}

protected class CustomServiceOutputFilter : KerberosAssertion.ServiceOutputFilter
{
CustomKerberosAssertion assertion;
public CustomServiceOutputFilter(CustomKerberosAssertion assertion)
: base(assertion)
{
this.assertion = assertion;
}

public override void SecureMessage(SoapEnvelope envelope, Security security, MessageProtectionRequirements response)
{
// Secure the outgoing response only when  the incoming
// message is signed and encrypted.
if (assertion.IncomingMsgType == MessageType.TokenWithSignatureAndEncryption)
{
base.SecureMessage(envelope, security, response);
}
}
}

/// This class is the client output filter for Windows 2000 clients.
/// The outgoing message only contains the Kerberos token and is not signed
/// or encrypted by the Kerberos token.
protected class CustomClientOutputFilter : KerberosAssertion.ClientOutputFilter
{
TokenProvider<KerberosToken> provider;
KerberosToken kerberosToken;

public CustomClientOutputFilter(KerberosAssertion assertion)
: base(assertion)
{
provider = assertion.KerberosTokenProvider;
}

public override void SecureMessage(SoapEnvelope envelope, Security security, MessageProtectionRequirements request)
{
if (envelope == null)
throw new ArgumentNullException("envelope");
if (security == null)
throw new SecurityFault(String.Format(System.Globalization.CultureInfo.InvariantCulture, "No security header was found while verifying the incoming message"));
if (request == null)
throw new ArgumentNullException("request");

if (provider != null)
this.kerberosToken = provider.GetToken();

KerberosToken kt = GetClientToken(this.kerberosToken, this.GetServiceActor(envelope.CurrentSoap));
security.Tokens.Add(kt);
}

KerberosToken GetClientToken(KerberosToken token, string actor)
{
if (token != null)
return token;

KerberosToken result = null;

if (actor != null && SoapContext.Current != null)
{
CredentialSet cs = SoapContext.Current.Credentials[actor];
result = cs.GetServiceToken<KerberosToken>();
}

if (result == null)
throw new InvalidOperationException(String.Format(System.Globalization.CultureInfo.InvariantCulture, "Unable to determine service token to use. Service token type requested was '{0}'. The token must be provided either through policy by specifying the token in the policy assertion or through code by calling WebServicesClientProtocol.SetCredentials or using properties on the SoapContext.Credentials.", typeof(KerberosToken).ToString()));

return result;
}
}

protected class CustomClientInputFilter : KerberosAssertion.ClientInputFilter
{
public CustomClientInputFilter(KerberosAssertion assertion)
: base(assertion)
{
}

public override void ValidateMessageSecurity(SoapEnvelope envelope, Security security, MessageProtectionRequirements response)
{
if (envelope == null)
throw new ArgumentNullException("envelope");
if (security == null)
throw new SecurityFault(String.Format(System.Globalization.CultureInfo.InvariantCulture, "No security header was found while verifying the incoming message"));
}

public override IEnumerable<SecurityToken> GetUnattachedTokensCore(SoapContext context)
{
return null;
}
}
}
}
    

See Also

Reference

<token> Element
<protection> Element
<policy> Element
KerberosToken

Other Resources

Implementing Message Layer Security with Kerberos in WSE 3.0
Kerberos Technical Supplement for Windows
Protocol transition & constrained delegation