Tuesday, December 11, 2012

Enabling UsernameToken Authentication with Axis2 without a Policy

What is UsernameToken Authentication?

This is a Web Service Security (WSS) specification published by OASIS that defines how two communicating parties can authenticate a message using a username and a password.

How to enable it in Axis2?

To enable any WSS standard Apache Rampart should be used with Axis2. To engage Rampart with a web service, first Rampart and Rahas modules should be in the server and client repositories, and then add the following to the Axis2 configuration files at the client (axis2.xml) and server (service.xml) sides.
    <module ref="rampart" />
Engaging Rampart to Axis2 will not do any good untill we specify Rampart how to do its job, which is, instructing what sort of security should be provided.

In this post we will only consider UsernameToken Authentication and there are two ways to send the password: as a digested password or as plain-text.

UsernameToken Authentication with Digested Password

To instruct Rampart to use digest mode following markup should be included in the client's Axis2 configuration file...
    <parameter name="OutflowSecurity">
        <action>
            <items>UsernameToken Timestamp</items>
            <user>bob</user>
            <passwordCallbackClass>org.apache.rampart.samples.sample02.PWCBHandler</passwordCallbackClass>
        </action>
    </parameter>
...and in the Service's configuration file...
    <parameter name="InflowSecurity">
      <action>
        <items>UsernameToken Timestamp</items>
        <passwordCallbackClass>org.apache.rampart.samples.sample02.PWCBHandler</passwordCallbackClass>
      </action>
    </parameter>
PWCBHandler is a class that implements the  javax.security.auth.callback.CallbackHandler interface. The client and the service should implement the handle() method of it. Retrival of the password for the sent username is done inside this method.

When a request is sent with this configuration a "Security" tag will be added to SOAP message....
<wsse:Security
    xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
    soapenv:mustUnderstand="1">
    <wsse:UsernameToken wsu:Id="UsernameToken-1">
        <wsse:Username>bob</wsse:Username>
        <wsse:Password
            Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">0wQC3cyuQEGouNGkY2+RNEqWtDg=</wsse:Password>
        <wsse:Nonce
            EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">6NAoEolABdzppsGt40nBQA==</wsse:Nonce>
        <wsu:Created>2012-12-11T09:29:38.599Z</wsu:Created>
    </wsse:UsernameToken>
</wsse:Security>
What we have done is sending the password as a digest, which is computed by  client as follows:

digest == base64 encoded (SHA-1 hashed (password + nonce + timestamp))

[nonce is just a random number]

And then at the service side, Rampart will get the password for the particular username via the PWCBHandler from a local user store, and then do the digest computation using the nonce and timestamp sent by client. If the two digests evaluates to true, then message is authenticated.

However, there's a weakness in this mechanism...

Since Rampart does the computation of the digest using nonce and timestamp, a plain-text password should be supplied to it from the PWCBHandler. Handling plaintext passwords is a security vulnarebility.

Solution for this is using the plain-text way...

UsernameToken Authentication with Plain-text Password

Adding an extra line to the client side configuration we did above will change the mechanism to plain-text passwords. Note the "passwordType" tag in the below markup...
<parameter name="OutflowSecurity">
      <action>
        <items>UsernameToken</items>
        <user>bob</user>
        <passwordCallbackClass>org.apache.rampart.samples.sample03.PWCBHandler</passwordCallbackClass>
        <passwordType>PasswordText</passwordType>
      </action>
    </parameter>
The SOAP request with the plain-text password...
<wsse:Security
    xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
    soapenv:mustUnderstand="1">
    <wsse:UsernameToken wsu:Id="UsernameToken-1">
        <wsse:Username>bob</wsse:Username>
        <wsse:Password
            Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">bobPW</wsse:Password>
    </wsse:UsernameToken>
</wsse:Security>
Here, handling the authentication will be done by the service. Rampart will simply handover the username and the password to the PWCBHandler, and handler will use its specific authentication mechanism (or delegate to an authentication component/system) to compare this plain-text password with a stored password which will be most probably in an encrypted form.

UPDATE 26/12/12: UsernameToken Authentication is no longer used without policies. This blog post was written while playing with Rampart samples. Though this is still available in the latest Rampart dist's samples folder, it should not be used for production.

Ref:
http://wso2.org/library/240

1 comment:

Mike said...

Well written post on UsernameToken Authentication. UsernameToken Authentication is no longer used without policies. Keep posting! I liked info shared by you.
what is a digital signature