How to: Authorize the Message Sender Based on a User Name and Password

WSE enables you to authorize access to a Web service method based on a UsernameToken used to sign the SOAP message. When a SOAP message is received and the UsernameToken authentication is enabled, WSE attempts to authenticate the SOAP message sender. Authentication is done by WSE by calling the Win32 API LsaLogonUser with the user name and password contained within the UsernameToken that signed the SOAP message. If that succeeds, the Principal property of the UsernameToken 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 user name and password. Whether you use policy or code, WSE must be enabled to process the incoming SOAP messages.

To use policy to authorize access to a Web service method

  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. Specify the group of users that are authorized to use the Web service by adding <Claims> Element and <Role> Element elements.

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

    2. Add a <Role> Element child element to the <Claims> Element element.
      The <Role> Element element specifies the group of users, known as a role, that are authorized to use the Web service. When a SOAP request is received that contains a UsernameToken, WSE attempts to authenticate those credentials against 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 UsernameToken security token that belongs to the Tellers role must be used to sign SOAP messages.

      <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>
                <wse:Role 
                  xmlns:wse="https://schemas.microsoft.com/wse/2003/06/Policy" 
                  value="Tellers" />
              </wssp:Claims>
            </SecurityToken>
          </wssp:TokenInfo>
      
  4. Optionally, specify requirements for the token by adding <SubjectName> Element, and <UsePassword> Element elements

    1. 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 how to compare the value of the <SubjectName> Element element with 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.

      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 must match the value of the Username property.

    2. Add a <UsePassword> Element child element to the <Claims> 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

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

      wssp:PasswordText

      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>
      
  5. 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>
    
  6. 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>
    
  7. Specify that the signed XML elements (specified in step 6) 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.
      Setthe 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)
      </wsp:MessagePredicate>
      

To use code to authorize access to a Web service method

  1. Configure the Web service to authenticate received UsernameToken security tokens.

    For more information, see How to: Verify Digital Signatures of SOAP Messages Signed Using a User Name and Password.

  2. Add code to the Web service method that obtains the UsernameToken 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 decide which security token is used for authentication and authorization. The following code example defines and then calls a GetBodySigningToken method that obtains the UsernameToken that signed the <Body> element of the SOAP request.

    Public Function GetBodySigningToken(ByVal requestContext As _
        SoapContext) As UsernameToken
        Dim token As UsernameToken = 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.
                If ((sig.SignatureOptions And _
                    SignatureOptions.IncludeSoapBody) <> 0) Then
                    Dim sigToken As SecurityToken
                    sigToken = sig.SigningToken
    
                    ' Verify that the security token is a UsernameToken.
                    If TypeOf sigToken Is UsernameToken Then
                        token = CType(sigToken, UsernameToken)
                    End If
                End If
            End If
        Next securityElement
        Return token
    End Function
    
    public UsernameToken GetBodySigningToken(SoapContext 
     requestContext)
    {
        UsernameToken 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 UsernameToken)
                        token = (UsernameToken)sigToken;
                }
            }
        }
        return token;
    }
    

    Add this code to the code in 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 UsernameToken that signed the SOAP request.
    Dim token As UsernameToken = GetBodySigningToken(requestContext) 
    
    // 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 UsernameToken that was used to sign the SOAP request.
    UsernameToken token = GetBodySigningToken(requestContext);
    
  3. Ensure that the user is a member of the role or roles authorized to call this Web service method.

    The following example code ensures that a UsernameToken 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 be signed by a UsernameToken that is a member of the Tellers role.

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>
              <wse:Role 
                xmlns:wse="https://schemas.microsoft.com/wse/2003/06/Policy" 
                value="Tellers" />
            </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 UsernameToken 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

<System.Web.Services.WebService(Namespace:="https://www.contoso.com/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 UsernameToken that was used to sign the SOAP request.
        Dim token As UsernameToken = GetBodySigningToke(requestContext) 
        If (token Is Nothing OrElse (Not _
            token.Principal.IsInRole("Tellers"))) Then
            Throw New UnauthorizedAccessException
        End If
        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 UsernameToken
        Dim token As UsernameToken = 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.
                If ((sig.SignatureOptions And _
                  SignatureOptions.IncludeSoapBody) <> 0) Then
                    Dim sigToken As SecurityToken
                    sigToken = sig.SigningToken

                    ' Verify that the security token is a UsernameToken.
                    If TypeOf sigToken Is UsernameToken Then
                        token = CType(sigToken, UsernameToken)
                    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;

namespace WSESamples
{
    [WebService("Namespace:="https://www.contoso.com/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 UsernameToken GetBodySigningToken(SoapContext 
         requestContext)
        {
            UsernameToken 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 UsernameToken)
                            token = (UsernameToken)sigToken;
                    }
                }
            }
            return token;
        }
    }
}

See Also

Tasks

How to: Digitally Sign a SOAP Message
How to: Verify Digital Signatures of SOAP Messages Signed Using a User Name and Password
How to: Specify the Parts of a SOAP Message That Are Signed or Encrypted

Reference

UsernameToken

Concepts

Authorizing Access to a Web Service