Friday, November 7, 2008

Secure your services with HTTP Basic Authentication

This post explains how you could secure your web service with HTTP Basic Authentication.

Let's download Axis2 WAR distribution from here and deploy it on Tomcat.

Start Tomcat, and hit the url, http://localhost:8080/axis2/services/Version?wsdl, you'll find no issues in accessing it.

Let's try to protect Axis2 services with HTTP Basic Authentication.

We need to define a new role first, who will be given access.

Find the file [CATALINA_HOME]\conf\tomcat-users.xml and edit it to add the following role and the user.

<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
<role rolename="facilelogin"/>
<user username="prabath" password="prabath" roles="facilelogin"/>
</tomcat-users>
Now let's restricts access to all our web services to the above defined role.

Open the file [CATALINA_HOME]\webapps\axis2\WEB-INF\web.xml and edit to add the following.

<web-app>

<security-constraint>
<web-resource-collection>
<web-resource-name>secured services</web-resource-name>
<url-pattern>/services/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>facilelogin</role-name>
</auth-constraint>
</security-constraint>

<login-config>
<auth-method>BASIC</auth-method>
<realm-name>facilelogin</realm-name>
</login-config>

</web-app>
All set - let's restart Tomcat.

Hit the url, http://localhost:8080/axis2/services/Version?wsdl and you'll be asked for the user credentials.

Let's see how we could invoke the above secured service with a web service client.

Here, the only difference is you need to setup the HTTP header attributes appropriately.

Also, in this case user credentials are not carried by the SOAP header, but the transport header.

package org.apache.ws.axis2;

import java.util.Properties;

import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.transport.http.HttpTransportProperties;

public class Client {

public static void main(String[] args) throws Exception {
ServiceClient client = null;
Options options = null;
OMElement response = null;
HttpTransportProperties.Authenticator authenticator = null;
Properties properties = null;

client = new ServiceClient();
options = new Options();
options.setAction("urn:getVersion");
options.setTo(new EndpointReference("http://localhost:8080/axis2/services/Version"));

authenticator = new HttpTransportProperties.Authenticator();
// Add user creadentials to the transport header
authenticator.setUsername("prabath");
authenticator.setPassword("prabath");
authenticator.setRealm("facilelogin");

properties = new Properties();
properties.put(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, authenticator);

options.setProperties(properties);
client.setOptions(options);

response = client.sendReceive(getPayload());

System.out.println(response);
}

private static OMElement getPayload() {
OMFactory factory = null;
OMNamespace ns = null;
OMElement elem = null;
factory = OMAbstractFactory.getOMFactory();
ns = factory.createOMNamespace("http://axisversion.sample", "ns1");
elem = factory.createOMElement("getVersion", ns);
return elem;
}
}


POST /axis2/services/Version HTTP/1.1
Content-Type: text/xml; charset=UTF-8
SOAPAction: "urn:getVersion"
User-Agent: Axis2
Transfer-Encoding: chunked
Authorization: Basic cHJhYmF0aDpwcmFiYXRo
Host: localhost:8080

3 comments:

ericw78 said...

Good article ! Thanks.

Then do you know how to retrieve username in the web service methods ?

Thanks
Eric

Prabath said...

Hi;

This may be useful.

http://www.keith-chapman.org/2008/09/axis2-rampart-access-username-used-for.html

Thanks.
- Prabath

Fella said...

To work the roles 'security-role' should also be defined in web.xml