How to: Verify Digital Signatures of SOAP Messages Signed Using a User Name and Password

WSE validates that digital signatures are cryptographically correct. However, you must use code or policy to verify that a signature exists and that the signature applies to the expected set of XML elements. Signature validation is done by WSE before recipient code executes when WSE is enabled to run with the recipient.

To validate digital signatures for incoming SOAP messages created using a UsernameToken, WSE must be configured to process the incoming SOAP messages. An additional two steps are required when the UsernameToken does not represent a Windows account. When the UsernameToken is a Windows account and WSE is processing the incoming SOAP messages, WSE attempts to authenticate the account and if successful, sets the Prinicpal property of the token.

To configure WSE to validate digital signatures created using a UsernameToken for incoming SOAP messages

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

    This step is only required when the recipient of the SOAP message is hosted in ASP.NET. When the SOAP message recipient is a Web service client or the TCP protocol is used with SOAP messaging, this configuration entry is not required. For Web service clients, the base class of the proxy class must be changed to derive from the WebServicesClientProtocol class.

    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> (WSE for Microsoft .NET) element 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>
    
  2. Optionally, create and register a custom security token manager for UsernameToken security tokens.

    When you do not want WSE to authenticate UsernameToken security tokens against Active Directory™ or the UsernameToken is not based on a Windows account, you must derive a class from UsernameTokenManager.

    When you do want WSE to authenticate the UsernameToken against Active Directory, you do not need to create your own class that derives from the UsernameTokenManager class. However, incoming SOAP messages must contain the password in plain text (PasswordOption.SendPlainText). Because the password is being sent in plain text, it is highly recommended that the UsernameToken be encrypted.

    1. Add a new class to the project containing the SOAP message recipient. Derive the class from the UsernameTokenManager class.
      Once the security token manager class is registered in the application's configuration file, WSE calls the class's AuthenticateToken method to get the password for a given user name of the class whenever incoming SOAP messages are received that contain UsernameToken security tokens.

      Public Class CustomUsernameTokenManager
          Inherits UsernameTokenManager
      
      public class CustomUsernameTokenManager : UsernameTokenManager 
      
    2. Ensure that an arbitrary assembly cannot access the class deriving from the UsernameTokenManager class.
      It is recommended that you demand that an assembly accessing this class already have permission to call unmanaged code. Because Microsoft.Web.Services2 is the only assembly that should call this class, you might consider further restricting access to assemblies only signed by Microsoft.
      The following code example applies the SecurityPermissionAttribute attribute to the class deriving from the UsernameTokenManager class, demanding the UnmanagedCode permission.

      <SecurityPermission(SecurityAction.Demand, _
          Flags := SecurityPermissionFlag.UnmanagedCode)> _
      Public Class CustomUsernameTokenManager
          Inherits UsernameTokenManager
      
      [SecurityPermission(SecurityAction.Demand,
          Flags= SecurityPermissionFlag.UnmanagedCode)]
      public class CustomUsernameTokenManager : UsernameTokenManager
      
    3. Override the AuthenticateToken method of the UsernameTokenManager class.
      When a SOAP message is received that contains a UsernameToken, WSE deserializes the UsernameToken and calls the VerifyToken method. The default implementation of the VerifyToken method of the UsernameTokenManager class calls the AuthenticateToken method, and then compares the returned password with the one passed in the SOAP message. The password returned from the AuthenticateToken method must match the password sent by the SOAP sender or a SecurityFault exception is thrown.

      Note

      The AuthenticateToken method is equivalent to the PasswordProvider.GetPassword method in WSE 1.0.

      The following code example overrides the AuthenticateToken method by providing an implementation of the method that gets the UTF-8 encoding of the user name.

      Protected Overrides Function AuthenticateToken(userName As UsernameToken) _
          As String 
      
          ' Ensure that the SOAP message sender passed a UsernameToken.
          If userName Is Nothing Then
              Throw New ArgumentNullException()
          End If 
      
          ' This is a very simple provider.
          ' In most production systems the following code 
          ' typically consults an external database of (userName,hash)
          ' pairs. For this example, it is the UTF-8
          ' encoding of the user name.
          Dim encodedUsername As Byte() = _
              System.Text.Encoding.UTF8.GetBytes(userName.Username)
          Return System.Text.Encoding.GetString(encodedUsername)
      End Function
      
      protected override string AuthenticateToken(UsernameToken userName)
      {
          // Ensure that the SOAP message sender passed a UsernameToken.
          if (userName == null)
              throw new ArgumentNullException();
      
          // This is a very simple provider.
          // In most production systems the following code 
          // typically consults an external database of (userName,hash)
          // pairs. For this example, it is the UTF-8
          // encoding of the user name.
          byte[] encodedUsername =
              System.Text.Encoding.UTF8.GetBytes(userName.Username);
          return System.Text.Encoding.GetString(encodedUsername)
      }
      
    4. Configure the microsoft.web.services2 configuration section handler for the application's configuration file by adding a <section> Element (WSE for Microsoft .NET) element to the <configuration> section.
      The following code example shows how to add the microsoft.web.services2 configuration section handler.

      <configuration>
        <configSections>
          <section name="microsoft.web.services2"
            type="Microsoft.Web.Services2.Configuration.WebServicesConfiguration, Microsoft.Web.Services2, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        </configSections>
      </configuration>
      
    5. Configure the custom UsernameToken security token manager in the application's configuration file.
      In the <configuration> section, add the <microsoft.web.services2>, <security>, and <securityTokenManager> elements.
      The following code example configures the MyNamespace.CustomUsernameTokenProvider security token manager to be called whenever a SOAP message containing a UsernameToken is received for recipients affected by this configuration file. The value of the type attribute must all appear on one line; it appears on multiple lines in the following example for readability.

      <microsoft.web.services2>
        <security>
          <securityTokenManager xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"       qname="wsse:UsernameToken" type=      "MyNamespace.CustomUsernameTokenProvider, MyAssemblyName,      Version=2.0.0.0,      Culture=neutral,      PublicKeyToken=81f0828a1c0bb867" />
        </security>
      </microsoft.web.services2>
      

    Note

    Because the type attribute does not need to reference a type residing in a strong-named assembly, the Version, Culture, and PublicKeyToken parts of the assembly name are optional.

To use policy to require that incoming SOAP messages are signed using a UsernameToken and that the required XML elements are signed

  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. 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. The value of the Id attribute must be unique to the policy file.
    2. Add an <Integrity> Element child element to the <Policy> Element (WSE for Microsoft .NET) (1) element.
      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 http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken.
      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 UsernameToken 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>http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken</wssp:TokenType>      </wssp:TokenType>
    
  3. Optionally, specify requirements for the token by adding <Claims> Element, <SubjectName> Element, and <UsePassword> Element elements

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

    2. Add a <SubjectName> Element child element to the <Claims> Element element.
      The value of the <SubjectName> Element element specifies the user name portion of a UsernameToken. The MatchType attribute of the <SubjectName> Element element specifies the algorithm used to match the value of the <SubjectName> Element element and the user name portion of a UsernameToken. The following table lists the valid values for the MatchType attribute.

      Value Description

      wsse:Exact

      The values must be exactly the same, including case sensitivity.

      wsse:Prefix

      The value of the <SubjectName> Element element must be a prefix of the   Username property.

      wsse:Regexp

      The value of the <SubjectName> Element element is a regular expression that matches the value of the Username property.

    3. Add a <UsePassword> Element child element to the <SecurityToken> Element element
      The Type attribute of the <UsePassword> Element element specifies how the password for a UsernameToken is passed in a SOAP message
      The following table lists the possible values for the Type attribute.

      Value Description

      wssp:PasswordDigest

      Specifies the password must be sent hashed. Use PasswordOption.SendHashed when sending the password.

      wssp:PasswordText

      Specifies the password must be sent in clear text. Use PasswordOption.SendPlainText when sending the password.

      The following code example specifies that a UsernameToken must be used to sign SOAP messages. Furthermore, the UsernameToken must be for the user name someone and the password must be sent hashed.

      <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>http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken</wssp:TokenType>
            <wssp:Claims>        <wssp:SubjectName MatchType="wssp:Exact">someone</wssp:SubjectName>        <wssp:UsePassword Type="wssp:PasswordDigest"          wsp:Usage="wsp:Required" />       </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 sent to the http://www.cohowinery.com/SaleWidgets.asmx endpoint 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>
      
  6. Specify that the signed XML elements (specified in step 5)must exist in incoming SOAP messages.

    1. Add a <MessagePredicate> Element child element to the <Policy> Element (WSE for Microsoft .NET) (1) element in the policy file for the application.
      When using policy to require digital signatures on incoming SOAP messages, always use the <MessagePredicate> element. The <MessagePredicate> element ensures that the XML elements that must be signed actually exist in the SOAP message. Just adding an <Integrity> Element element to a policy file specifies that a digital signature must exist, if the XML elements specified in the <Integrity> element exist in the SOAP messages. If the SOAP message does not contain the XML elements specified in the <Integrity> element, the SOAP message satisfies the requirements of the policy and is allowed to access the Web service. To remedy this potential problem, add a <MessagePredicate> element specifying the XML elements that must exist in the incoming SOAP message.
      Set the Dialect attribute value to "https://schemas.xmlsoap.org/2002/12/wsse#part".

    2. Specify the parts of the message that must exist by listing them, separated by spaces, as the value of the <MessagePredicate> Element element.
      The following code example specifies that the <Body> element and the To, Action, MessageID, and From headers must exist in the SOAP message.

      <wsp:MessagePredicate 
        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) wse:Timestamp()
      </wsp:MessagePredicate>
      

To use code to require that incoming SOAP messages be signed using a UsernameToken and that the required XML elements are signed

  1. Add a Web service method that processes the UsernameToken.

    1. In Solution Explorer, right-click Service1.asmx, and then select View Code.

    2. Add the following using or Imports directives to Service1.asmx.cs.

      Imports Microsoft.Web.Services2
      Imports Microsoft.Web.Services2.Security
      Imports Microsoft.Web.Services2.Security.Tokens
      Imports System.Security.Cryptography
      
      using Microsoft.Web.Services2;
      using Microsoft.Web.Services2.Security;
      using Microsoft.Web.Services2.Security.Tokens;
      using System.Security.Cryptography;
      
    3. In the class representing the Web service, add code to verify that the <Body> element of the SOAP request was signed using a UsernameToken security token.
      The following code example is a Web service method named sayHello that verifies the request was made using SOAP and calls the method named IsMessageSigned defined in the next step.

      <WebMethod()>  _
      Public Function sayHello() As String
          Dim requestContext As SoapContext = _
              RequestSoapContext.Current
      
          ' Verify that a SOAP request was received.  
          If requestContext Is Nothing Then
              Throw New ApplicationException( "Either a non-SOAP " + _
                  "request was received or WSE is not properly " + _
                  "installed for the Web application hosting the " + _
                  "Web service.")
          End If
      
          ' Verify that the SOAP message is signed.
          If Not IsMessageSigned(requestContext) Then
              Throw New ApplicationException("The request is not " + _
                  "signed using an acceptable signature.")
          End If
          Return "Hello"
      End Function
      
      [WebMethod()]
      public string sayHello() 
      {
          SoapContext requestContext = RequestSoapContext.Current;
      
          // Verify that a SOAP request was received.  
          if (requestContext == null)
          {
              throw new ApplicationException( "Either a non-SOAP " +
                  "request was received or WSE is not properly " +
                  "installed for the Web application hosting the " +
                  "Web service.");
          }
          // Verify that the SOAP message is signed.
          if (!IsMessageSigned(requestContext))
          {
              throw new ApplicationException(
                  "The request is not signed using an acceptable signature.");
          }
          return "Hello";
      }
      
  2. Define a method to verify that a UsernameToken security token signed the expected XML elements of the SOAP message.

    1. In Solution Explorer, right-click Service1.asmx, and then click View Code.

    2. In the Service1 class, add the code shown in the following code example.
      The following code example verifies that a digital signature exists for a SoapContext and that it signed the <Body> element.

      Private Function IsMessageSigned(ByVal context As SoapContext) As Boolean
          Dim element As ISecurityElement
          For Each element In context.Security.Elements
              If (TypeOf (element) Is MessageSignature) Then
                  ' The SoapContext contains a Signature element. 
                  Dim sign As MessageSignature = element
                  If ((sign.SignatureOptions And _
                      (SignatureOptions.IncludeSoapBody Or _
                      SignatureOptions.IncludeTo Or _
                      SignatureOptions.IncludeAction Or _
                      SignatureOptions.IncludeMessageId Or _
                      SignatureOptions.IncludeFrom))) Then
                      If TypeOf sign.SigningToken Is UsernameToken Then
                          ' The SOAP message is signed with a
                          ' UsernameToken.
                          Return True
                      End If
                  End If
              End If
          Next
          Return False
      End Function 
      
      private bool IsMessageSigned(SoapContext context)
      {
          foreach (ISecurityElement element in context.Security.Elements)
          {
              if (element is MessageSignature)
              {
                  MessageSignature sign = element as MessageSignature;
      
                  if ((sign.SignatureOptions & 
                      (SignatureOptions.IncludeSoapBody | 
                      SignatureOptions.IncludeTo |
                      SignatureOptions.IncludeAction |
                      SignatureOptions.IncludeMessageId |
                      SignatureOptions.IncludeFrom)))
                  {
                      // The SOAP message is signed.
                      if (sign.SigningToken is UsernameToken)
                          // The SOAP message is signed 
                          // with a UsernameToken.
                          return true;
                  }
              }
          }
          return false;
      }
      

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 UsernameToken. Furthermore, the UsernameToken must be for the user name someone and the password must be sent hashed.

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="" />
        <fault policy="" />
      </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" >

      <wsp:MessagePredicate
        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)
      </wsp:MessagePredicate>

      <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>http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken</wssp:TokenType>
            <wssp:Claims>
              <wssp:SubjectName MatchType="wssp:Exact">
                someone</wssp:SubjectName> 
              <wssp:UsePassword Type="wssp:PasswordDigest"
                wsp:Usage="wsp:Required" />
            </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) wse:Timestamp()
        </wssp:MessageParts>
      </wssp:Integrity>
    </wsp:Policy>
  </policies>
</policyDocument>

The following code example defines a Web service method that verifies that requests are made using SOAP and that the <Body> element and the To, Action, MessageID, and From headers are signed using a UsernameToken security token

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

<WebService([Namespace] := "https://www.contoso.com")>  _
Public Class StockService
    Inherits System.Web.Services.WebService

    <WebMethod()> _
    Public Function sayHello() As String
         Dim requestContext As SoapContext = _
         RequestSoapContext.Current

         ' Verify that a SOAP request was received.  
         If requestContext Is Nothing Then
             Throw New ApplicationException("Either a non-SOAP " + _
                 "request was received or WSE is not properly " + _
                 "installed for the Web application hosting the " + _
                 "Web service.")
         End If
         If Not IsMessageSigned(requestContext) Then
             Throw New ApplicationException("The request is not " + _
                 "signed using an acceptable signature.")
         End If
         Return "Hello"
     End Function

     Private Function IsMessageSigned(ByVal context As SoapContext) As Boolean
         Dim element As ISecurityElement
         For Each element In context.Security.Elements
             If (TypeOf (element) Is MessageSignature) Then
                 ' The SoapContext contains a Signature element. 
                 Dim sign As MessageSignature = element
                 If ((sign.SignatureOptions And _
                     (SignatureOptions.IncludeSoapBody Or _
                     SignatureOptions.IncludeTo Or _
                     SignatureOptions.IncludeAction Or _
                     SignatureOptions.IncludeMessageId Or _
                     SignatureOptions.IncludeFrom)) = _
                     (SignatureOptions.IncludeSoapBody Or _
                     SignatureOptions.IncludeTo Or _
                     SignatureOptions.IncludeAction Or _
                     SignatureOptions.IncludeMessageId Or _
                     SignatureOptions.IncludeFrom)) Then
                     If TypeOf sign.SigningToken Is UsernameToken Then
                         ' The SOAP message is signed with a
                         ' UsernameToken.
                         Return True
                     End If
                 End If
             End If
         Next
         Return False
     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;

public class HelloService : System.Web.Services.WebService
{
    [WebMethod]
    public string sayHello() 
    {
        SoapContext requestContext = RequestSoapContext.Current;

        // Verify that a SOAP request was received.  
        if (requestContext == null)
        {
            throw new ApplicationException( "Either a non-SOAP " +
                "request was received or WSE is not properly " +
                "installed for the Web application hosting the " +
                "Web service.");
        }
        // Verify that the SOAP message is signed.
        if (!IsMessageSigned(requestContext))
        {
            throw new ApplicationException(
                "The request is not signed using an acceptable signature.");
        }
        return "Hello";
    }

    private bool IsMessageSigned(SoapContext context)
    {
        foreach (ISecurityElement element in context.Security.Elements)
        {
            if (element is MessageSignature)
            {
                // The given context contains a Signature element.
                MessageSignature sign = element as MessageSignature;

                if ((sign.SignatureOptions & 
                    (SignatureOptions.IncludeSoapBody | 
                    SignatureOptions.IncludeTo |
                    SignatureOptions.IncludeAction |
                    SignatureOptions.IncludeMessageId |
                    SignatureOptions.IncludeFrom)) ==
                    (SignatureOptions.IncludeSoapBody | 
                    SignatureOptions.IncludeTo |
                    SignatureOptions.IncludeAction |
                    SignatureOptions.IncludeMessageId |
                    SignatureOptions.IncludeFrom))
                {
                    // The SOAP message is signed.
                    if (sign.SigningToken is UsernameToken)
                        // The SOAP message is signed 
                        // with a UsernameToken.
                        return true;
                }
            }
        }
        return false;
    }
}

See Also

Tasks

How to: Sign a SOAP Message by Using a User Name and Password
How to: Digitally Sign a SOAP Message

Reference

UsernameToken
UsernameTokenManager
<securityTokenManager> Element