Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Choose the Right Web Services Security Solution : Page 3


UsernameToken Authentication
UsernameToken authentication is very similar to HTTP authentication, where user credentials are passed in the message header. The UsernameToken is added to the SOAP header and may optionally include a hash of the password, referred to as a nonce. This is a weak form of encryption that avoids having to send the password in the clear. Use transport or message-level encryption to guarantee the confidentiality of user passwords.

Application servers support UsernameToken authentication by allowing the configuration of an LDAP that is used for password verification. When the application server receives a SOAP message, it validates the user credentials against the LDAP before forwarding the message to the application. Figure 1 illustrates the authentication sequence.

Click to enlarge

Figure 1. UsernameToken Authentication Sequence

UsernameToken authentication is very appealing given its simplicity and wide support among application servers. However, you must be aware of a few limitations when considering it for you application:

  • Conversational state: UsernameToken requires that the user name and password be passed on every web service call. This implies that a client must cache the password if it converses frequently with the service, resulting in a security risk.
  • Performance: The application server must re-authenticate every web service call. Furthermore, because the password is part of the message, encryption is necessary even if the message does not include sensitive information.

To demonstrate UsernameToken authentication, the following example reuses the calculator service from the previous example. You must configure the application server to support UsernameToken security and specify an LDAP to verify the user credentials. The configuration steps are server specific, so please refer to your server's documentation for details. I tested the example with WebSphere 6.1 and Active Directory. (This article describes the steps to configure UsernameToken security in WebSphere.)

You must add a WSS4J SOAP handler to enable the Java client to send the UsernameToken in the header. The following client code calls the configureClientHandlers method before making the web service call:

public static void main(String[] args) throws MalformedURLException { CalculatorServiceClient sc = new CalculatorServiceClient(); Calculator calc = sc.getCalculator(UT_ENDPOINT); configureClientHandlers(calc); float a = 5f; float b = 7f; System.out.println(a + " * " + b + " = " + calc.multiply(a,b)); }

The configureClientHandlers method creates a new WSS4JOutHandler that holds the UsernameToken properties. The following configureUsernameToken method specifies the properties:

private static void configureClientHandlers(Object svc) { Client client=Client.getInstance(svc); client.addOutHandler(new DOMOutHandler()); Properties properties = new Properties(); // Configure the UsernameToken properties configureUsernameToken(properties); client.addOutHandler(new WSS4JOutHandler(properties)); } protected static void configureUsernameToken(Properties config) { // UsernameToken Action config.setProperty(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN); // Clear Text Password config.setProperty(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT); // User name to send config.setProperty(WSHandlerConstants.USER, "johndoe"); // Callback used to retrieve password for given user. config.setProperty(WSHandlerConstants.PW_CALLBACK_CLASS, PasswordHandler.class.getName()); }

The password is retrieved from the PasswordHandler callback class. It stores the password in a map that is indexed by user names. The following is the code for the sample user credentials:

public class PasswordHandler implements CallbackHandler { private Map passwords = new HashMap(); public PasswordHandler() { passwords.put("johndoe", "abc123"); } ...

The following SOAP message is observed by the TCP/IP monitor after running the client:

<soap:Envelope ...> <soap:Header> <wsse:Security ...> <wsse:UsernameToken ...> <wsse:Username ...> johndoe </wsse:Username> <wsse:Password ...> abc123 </wsse:Password> </wsse:UsernameToken> </wsse:Security> </soap:Header> <soap:Body> <multiply xmlns="http://ejb.security.ws.dev.com"> <a>5.0</a> <b>7.0</b> </multiply> </soap:Body> </soap:Envelope>

The header part of the SOAP message now includes both the username and password. The server authenticates the credentials and either grants or denies access to the target web service. To protect the password from eavesdropping, you'll have to use either message-level encryption or SSL as described earlier.

A .NET 2.0 client can also add a UsernameToken to the SOAP/HTTP header. In order to enable this functionality, you must install the WSE 3.0 libraries and extensions in your Visual Studio environment. (You can download them from here.) You must generate a client stub from the WSDL as in the Java client example. (Refer to this article for step-by-step instructions on how to do this.) The generated stub should look like this:

... public partial class CalculatorServiceWse : Microsoft.Web.Services3.WebServicesClientProtocol { private System.Threading.SendOrPostCallback multiplyOperationCompleted; private bool useDefaultCredentialsSetExplicitly; ...

Once the stub is generated, the client code instantiates the stub and specifies the UsernameToken to be sent to the server. The following C# sample code demonstrates how to do this:

static void Main(string[] args) { CalculatorServiceWse calc = new CalculatorServiceWse(); calc.Url = "http://localhost:9080/WSUTSigEncRouterWeb/services/Calculator"; // UsernameToken token = new UsernameToken("johndoe", "abc123", PasswordOption.SendPlainText); calc.SetClientCredential(token); calc.SetPolicy("usernameTokenSecurity"); float result = calc.multiply(7, 5); Console.WriteLine("Result = " + result); Console.ReadLine(); }

Running the client code produces the expected output:

Result = 35.0

Comment and Contribute








