Context
You are implementing Direct Authentication for an online
application consuming a Web Service that uses Web Service Enhancements (WSE)
2.0. You are using Message layer authentication. The credentials, used to prove
the identity of the calling application or user, are located in an instance of
a Directory Service
Note: In this pattern, Active Directory Application Mode
(ADAM) is used as an example for the purposes of demonstrating how to
authenticate a Subject against an LDAP directory service, though the examples
should be applicable for most LDAP directory services.
Implementation Strategy
The
WSE implementation of UsernameToken is
used to implement Direct Authentication at the message layer. The requestor passes
the subject's credentials, to the Web service as part of a secure message
exchange. The Web service decrypts the message, validates the credentials with
the Directory Service, verifies the message signature, and sends an encrypted
response that indicates whether the subject is authenticated or not.
Approach
Two tasks must be performed to implement Direct Authentication with
UsernameToken using a Directory Service.
1.
Requestor generates Web service request.
2.
Service authenticates Subject and returns a response.
Each
task is divided into a number of steps. While you are strongly encouraged to
follow the recommendations, the steps contain enough information to allow you
to tailor a solution to your specific needs.
Requestor Generates Web Service Request
This task has three steps that are recommended:
1.
Initialize the
UsernameToken
2.
Establish Message Integrity
3.
Encrypt the Message
Each step is discussed in more detail below:
Step One: Initialize
UsernameToken
This pattern
implements a UsernameToken with the
SendPlainText password option, which
sends the password over the network as plaintext. The “plaintext” value may be the
actual password or a password equivalent. This option, used with the Default
implementation of UsernameTokenManager,
is similar to Basic Authentication over SSL.
If the subject’s password is being sent in plaintext the session
should always be encrypted. Where possible, you should also store the passwords
themselves in a hashed form. For more information on this, see
Security Considerations.
Note: If you are not
familiar with UsernameToken, refer
to the UsernameToken Primer for
more information.
The following code shows how to obtain a reference to the SOAP
request context, initialize a UsernameToken
and add it to the security tokens collection of the request context:
// SOAP request context is obtained from the WSE Web service proxy
SoapContext requestContext = serviceProxy.RequestSoapContext;
UsernameToken token =
new
UsernameToken( txtUsername.Text, password, PasswordOption.SendPlainText );
requestContext.Security.Tokens.Add( token );
Step Two: Establish Message
Integrity
An XML signature could be created to sign the request message to
provide data integrity implicitly through Data Origin Authentication, but in
this pattern, an XML signature is of no value. This is because the password
used as the signing key must be included in the message. An attacker could
tamper with the message and then create a new signature using the password as
the signing key.
As the XML signature cannot be used to provide Data Origin
Authentication, another approach must be used. In many cases, full DOA is not
required, only data integrity. However, two approaches are available that can
provide DOA to the requester (though not to the subject). These are:
HTTPS provides data confidentiality and data integrity when server
certificates are used. If you require DOA to the requestor, you should also use
a client certificate for the requestor. For more information, see
Pattlet
–Transport Layer Security using X.509 Certificates and
HTTPS.
WSE 2.0 using X509SecurityToken provides confidentiality without
data integrity when server certificates are used. If you require DOA to the
requestor, you should also implement client certificates. For more information,
see
Implementing Message Layer Security with X.509 Certificates in WSE 2.0.
Step Three: Encrypt the Message
You should encrypt the message from the requestor to the service to
ensure that only the intended recipient of the message is capable of processing
it. The same method chosen to provide DOA in the previous step should be used
for Data Encryption.
HTTPS encrypts
the request message from the Requestor so that only the Service can decrypt it.
For details on implementing HTTPS, see “Pattlet –Transport Layer Security using
X.509 Certificates and HTTPS”.
WSE 2.0 using
X509SecurityToken uses the server’s X.509 certificate to encrypt the request
message. Unlike SSL, parts of the message may be encrypted rather than the
entire communication at the transport layer. For more information on
implementing the alternate approach to SSL with message layer X.509 security,
see Implementing Message Layer Security with X.509
Certificates in WSE 2.0.
If message layer
X.509 encryption is being used, then code must be implemented to encrypt the
message. For more information, and code examples that demonstrate how to encrypt
the message, see Implementing Message Layer Security with
X.509 Certificates in WSE 2.0.
Choosing Between HTTPS and WSE 2.0 using X509SecurityToken
When you implement Direct Authentication with UsernameToken using a
Directory Service, you will need to ensure that you provide Data
Confidentiality, and possibly DOA to the requestor.
HTTPSis
a well-established protocol and is easy to implement on the Windows platform,
requiring no additional code. However, there are circumstances when HTTPS is
not an appropriate choice. If you need to persist messages, or if the messages
must be handled by intermediaries, then you should use WSE 2.0 using
X.509SecurityToken. Unlike
HTTPS, parts of the message may be encrypted at the message layer rather
than the entire communication at the transport
layer.
|
Service Authenticates Subject and Returns a Response
This task has four steps that are recommended:
1. Decrypt
the request message
2. Verify
Message Integrity
3. Validate
the password
4. Encrypt
the response
Each step is discussed in more detail below:
Step One: Decrypt the request
message
The option chosen to encrypt the request message determines how the
request message is decrypted by the Service. Both SSL and WSE 2.0 will decrypt
the message automatically, and require no additional coding.
Step Two: Verify Message
Integrity
The method used
when message integrity was established by the Requestor also defines the method
used by the Service to verify message integrity. Both SSL and WSE (using an Integrity
policy assertion) will verify the message integrity automatically, and require
no additional coding.
Step Three: Validate the
password
Once the message
is received by the service the information in UsernameToken is verified by WSE using
the UsernameTokenManager class.
By default, the AuthenticateToken
method of the UsernameTokenManager
class, is used by WSE to validate the information in the
UsernameToken. However, when you are using an Identity Provider other
than Active Directory, you
need to create a
sub-class of the UsernameTokenManager class, and then
override the AuthenticateToken method.
An entry must be
included in the Service’s web.config file with the <securityTokenManager> element to
designate the CustomUsernameTokenManager as the
handler for incoming UsernameTokens:
<microsoft.web.services2>
<security>
<securityTokenManager
type="DirectTrustWithUsernameToken.
UsernameTokenWithAlternativeDirectory.CustomUsernameTokenManager,
DirectTrustWithUsernameToken. UsernameTokenWithAlternativeDirectory.Service"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
qname="wsse:UsernameToken" />
</security>
</microsoft.web.services2>
The code below
is an example of the overridden AuthenticateToken method in a CustomUsernameTokenManager
implementation:
using System;
using
System.Xml;
using
System.Security.Permissions;
using
System.Runtime.InteropServices;
using
System.DirectoryServices;
using
System.Security.Principal;
using
System.Configuration;
using
Microsoft.Web.Services2.Security;
using
Microsoft.Web.Services2.Security.Tokens;
namespace
DirectTrustWithUsernameToken.UsernameTokenWithAlternativeDirectory
{
...
public class CustomUsernameTokenManager : UsernameTokenManager
{
...
protected
override string AuthenticateToken( UsernameToken token )
{
if
(token.PasswordOption == PasswordOption.SendPlainText)
{
this.AuthenticateUser(token);
return
token.Password;
}
return
null;
}
...
}
...
}
AuthenticateUser is a user
defined function that binds to ADAM and uses System.DirectoryServices to
authenticate the Subject, as shown in the following code
example:
private void AuthenticateUser( UsernameToken token )
{
string
rootPath = ConfigurationSettings.AppSettings[ "LDAPRootPath" ];
if(
rootPath == null )
{
throw new ConfigurationException( RS.LDAPPathRequired );
}
try
{
DirectoryEntry root = new DirectoryEntry(rootPath);
root.Username = token.Username;
root.Password = token.Password;
root.AuthenticationType = AuthenticationTypes.None;
root.RefreshCache();
}
catch(
Exception e )
{
throw new System.Security.SecurityException( RS.AuthenticationError, e );
}
}
In the above code sample, RS
is a user-defined resource string manager that provides text for output and
exception messages and should be replaced with whatever means you are using to
provide resource strings for exception messages.
Another action commonly performed in the
AuthenticateToken method, but not demonstrated in the code samples
above, is obtaining principal information about the authenticated subject and
attaching it to the token so that the service can make authorization decisions
about the Subject. This can be done by creating a
GenericPrincipal instance, adding role information to the instance, and
then assigning the instance to the UsernameToken’s
Principal property.
Step Four: Encrypt the Response
The method used to encrypt the request message, is also used to
encrypt the response message is encrypted by the Service. Both SSL and WSE 2.0
will encrypt the message response automatically, and require no additional
coding.
Resulting Context
The following benefits, liabilities, and security considerations are associated with the implementation of UsernameToken.
Benefits
Liabilities
The UsernameToken Digest setting should not
be used, as it is only intended to protect the data on the wire. This can lead
people to store passwords in clear text in the identity store. Also, hashed
passwords transmitted without encryption are vulnerable to offline guessing
attacks.
Directories are typically optimized for certain read / write
characteristics and also for certain search paths. A directory service may not
be the optimal solution for an Identity Provider that requires heavy updates to
identity information or that have complex queries against the Identity
Provider.
UsernameTokens in WSE prevent replay attacks under the covers by using a nonce and timestamp with a replay cache on the server. However, the replay cache is not shared across a server farm. Approaches to mitigate this issue include:
Security Considerations
The following subjects represent security aspects that should be
considered when using this implementation of Direct Trust.
While passwords are considered one of the weakest forms of identity used for proof of possession, they are also the most common. As a result, it's important to understand threats and vulnerabilities associated with passwords.
References
Microsoft Confidential. © 2005 Microsoft Corporation.
All rights reserved. By using or providing feedback on these materials, you
agree to the attached license agreement.