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
Define a policy assertion and digital signature requirements by adding <Policy> Element (WSE for Microsoft .NET) (1) and <Integrity> Element elements.
- 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. - 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"
- 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.
Specify the token type by adding <TokenInfo> Element, <SecurityToken> Element, and <TokenType> Element elements.
- Add a <TokenInfo> Element child element to the <Integrity> Element element.
- Add a <SecurityToken> Element child element to the <TokenInfo> Element element.
- 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>
Specify the group of users that are authorized to use the Web service by adding <Claims> Element and <Role> Element elements.
Add a <Claims> Element child element to the <SecurityToken> Element element.
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 theTellers
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>
Optionally, specify requirements for the token by adding <SubjectName> Element, and <UsePassword> Element elements
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.
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>
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.
- 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. - 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. - 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>
- Add an <endpoint> Element element to the <mappings> Element element, and set the uri attribute value to the URI of the application.
Specify the XML elements to be signed by adding a <MessageParts> Element for <Integrity> Element element to the <Integrity> Element element.
- 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"
. - 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>
- 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
Specify that the signed XML elements (specified in step 6) must exist in incoming SOAP messages.
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"
.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
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.
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);
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