Showing posts with label Apache Rampart. Show all posts
Showing posts with label Apache Rampart. Show all posts

Tuesday, June 24, 2008

Web Services Security with Apache Rampart – Part 2 (Message-Level Security)

Sometime back I blogged about Nandana's article on using transport level security with Apache Rampart policy based configuration. Here's the part two of the article which talks about using WS-SecurityPolicy to apply and enforce message level on SOAP messages using Apache Axis2 and Apache Rampart.

Thursday, June 19, 2008

Back after a while ...

Hmm ... I've been away from blogging for more than a month ... so here's a recap of what I couldn't blog about :



Well ... thats it for now ... :-) ...

Monday, February 11, 2008

Access a Restricted EJB Method as a Web Service with UsernameToken Authentication

What if we need to expose an EJB as a web service? No problem ... we can simply use the org.apache.axis2.rpc.receivers.ejb.EJBMessageReceiver provided by Axis2. But what if the EJB's methods are access restricted?

I figured out that it is very easy to write a custom wrapper web service to expose such a protected EJB and use standard UsernameToken authentication on it.

Following are the steps I followed to try this out:

Step 1 : Basic EJB sample with OpenEJB

First I followed this "hello world" sample using OpenEJB and setup the OpenEJB container and deployed the EJB.

Step 2 : Modified "HelloBean" to restrict access to "sayHello" method


@RolesAllowed({"committer"})
public String sayHello() {
return "Hello World!!!";
}


Now only users with committer role can access this method.
The users used by the default login module implementation are listed in "conf/users.properties" of the OpenEJB distribution.

Step 3 : Develop and deploy a service to wrap the EJB


We basically have to write a service that is a client to this EJB. I engaged Rampart on this service and configured it with WS-SecurityPolicy to expect a UsernameToken. And then obtained the user name and password from security processing results and used those credentials in invoking the EJB.

Have a look at the following service class :


package org.acme;

import java.io.IOException;
import java.util.Properties;
import java.util.Vector;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

import org.apache.axis2.context.MessageContext;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.WSSecurityEngineResult;
import org.apache.ws.security.WSUsernameTokenPrincipal;
import org.apache.ws.security.handler.WSHandlerConstants;
import org.apache.ws.security.handler.WSHandlerResult;


public class SimpleEJBService implements CallbackHandler {

public String sayHello() throws Exception {


Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.RemoteInitialContextFactory");
props.put(Context.PROVIDER_URL, "ejbd://127.0.0.1:4201");

//Obtain the principal
WSUsernameTokenPrincipal principal = getPrincipal();


//Set the username and password
props.put(Context.SECURITY_PRINCIPAL, principal.getName());
props.put(Context.SECURITY_CREDENTIALS, principal.getPassword());


Context ctx = new InitialContext(props);
Object ref = ctx.lookup("HelloBeanRemote");

//Invoke method
Hello h = (Hello)PortableRemoteObject.narrow(ref, Hello.class);
String result = h.sayHello();
return result;

}

/*
* Traverse the security processing results of rampart and pick the UsernameToken information.
*/
private WSUsernameTokenPrincipal getPrincipal() {
MessageContext msgCtx = MessageContext.getCurrentMessageContext();
Vector results = null;
if ((results = (Vector) msgCtx
.getProperty(WSHandlerConstants.RECV_RESULTS)) == null) {
throw new RuntimeException("No security results!!");
} else {
for (int i = 0; i < results.size(); i++) {
//Get hold of the WSHandlerResult instance
WSHandlerResult rResult = (WSHandlerResult) results.get(i);
Vector wsSecEngineResults = rResult.getResults();

for (int j = 0; j < wsSecEngineResults.size(); j++) {
//Get hold of the WSSecurityEngineResult instance
WSSecurityEngineResult wser = (WSSecurityEngineResult)
wsSecEngineResults.get(j);
int action = ((Integer)wser.get(WSSecurityEngineResult.TAG_ACTION)).intValue();
if(action == WSConstants.UT) {
WSUsernameTokenPrincipal principal = (WSUsernameTokenPrincipal) wser
.get(WSSecurityEngineResult.TAG_PRINCIPAL);
return principal;
}
}
}
}

return null;
}

public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
//Do nothing since we simply want to move forward
//user name and password to the EJB container
}


}



The services.xml is as follows :


<service>
<parameter name="ServiceClass" locked="false">org.acme.SimpleEJBService</parameter>
<operation name="sayHello">
<messageReceiver
class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
</operation>

<module ref="rampart"/>

<wsp:Policy wsu:Id="UTOverTransport" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<wsp:ExactlyOne>
<wsp:All>
<sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:TransportToken>
<wsp:Policy>
<sp:HttpsToken RequireClientCertificate="false"/>
</wsp:Policy>
</sp:TransportToken>
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:Basic256/>
</wsp:Policy>
</sp:AlgorithmSuite>
<sp:Layout>
<wsp:Policy>
<sp:Lax/>
</wsp:Policy>
</sp:Layout>
<sp:IncludeTimestamp/>
</wsp:Policy>
</sp:TransportBinding>
<sp:SignedSupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:UsernameToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient" />
</wsp:Policy>
</sp:SignedSupportingTokens>

<ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">
<ramp:passwordCallbackClass>org.acme.SimpleEJBService</ramp:passwordCallbackClass>
</ramp:RampartConfig>

</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>


</service>


Note that I didn't bother with authentication of the incoming UsernameToken because this will be handled by the login module of the EJB container.

I first copied all (probably we don't need all of them ...) openejb-* jars from the OpenEJB distro and the jar'ed org.acme.Hello interface to the "lib" directory of WSO2WSAS-2.2 standalone and deployed the service.

Step 4 : Web service client


Finally I generated a client stub using the WSDL2Java tool and developed my client code


package org.acme;

import org.acme.HelloEJBStub.SayHelloResponse;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.neethi.Policy;
import org.apache.neethi.PolicyEngine;
import org.apache.rampart.RampartMessageData;

public class Client {

public static void main(String[] args) throws Exception {

//This is because we use a self signed SSL cert in WSO2WSAS
System.setProperty("javax.net.ssl.trustStore", "/path/to/wso2wsas.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "wso2wsas");

ConfigurationContext ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem("/path/to/my/client/repo");

HelloEJBStub stub = new HelloEJBStub(ctx);
ServiceClient client = stub._getServiceClient();

//Engage Rampart
client.engageModule("rampart");

Options options = client.getOptions();


//Set user name and password
options.setUserName("jonathan");
options.setPassword("secret");

//Load and set UsernameToke/HTTPS policy
options.setProperty(
RampartMessageData.KEY_RAMPART_POLICY,
loadPolicy("/path/to/simpl/usernametoken/over/https/policy.xml"));

//Invoke service operation
SayHelloResponse resp = stub.sayHello();

System.out.println(resp.get_return());
}

private static Policy loadPolicy(String xmlPath) throws Exception {
StAXOMBuilder builder = new StAXOMBuilder(xmlPath);
return PolicyEngine.getPolicy(builder.getDocumentElement());
}

}


Note that I have used "jonathan" as the user name and "secret" as the password. This user is there by default in the OpenEJB distro.

That's it !!! ... When I ran the client I got the following response:


Hello World!!!


And when I tried chaing the username I get :


Exception in thread "main" org.apache.axis2.AxisFault: This principle is not authorized.
at org.apache.axis2.util.Utils.getInboundFaultFromMessageContext(Utils.java:479)
at org.apache.axis2.description.OutInAxisOperationClient.handleResponse(OutInAxisOperation.java:351)
at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:397)
at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:214)
at org.apache.axis2.client.OperationClient.execute(OperationClient.java:163)
at org.acme.HelloEJBStub.sayHello(HelloEJBStub.java:433)
at org.acme.Client.main(Client.java:32)


Now it is clear that the login module was not able to authenticate the user.

Friday, January 04, 2008

UsernameToken authentication with the *nix account credentials

Ever wondered how we can enable users of a Linux box to authenticate against a web service?

Apache Rampart can be used with JPam to easily set this up. You can simply set up UsernameToken authentication (policy/sample01 in the Apache Rampart distro) and use this callback handler implementation to authenticate against PAM. Make sure you follow the instruction in INSTALL.txt in JPam distribution to set up JPam before using the callback handler.

Thursday, September 06, 2007

Apache Rampart 1.3 Released

This is the 1.3 release of Apache Rampart.

Apache Rampart 1.3 is a toolkit that provides implementations of the WS-Sec* specifications for Apache Axis2 1.3, based on Apache WSS4J 1.5.3 and the Apache AXIOM-DOOM 1.2.5 implementations.

You can download the releases from:
http://www.apache.org/dyn/closer.cgi/ws/rampart/1_3

There are two main Apache Axis2 modules provided with this release.

* rampart-1.3.mar
This provides support for WS-Security and WS-SecureConversation
features.
* rahas-1.3.mar
This module provides the necessary components to enable SecurityTokenService functionality on a service.

Apache Rampart 1.3 uses a configuration model based on WS-Policy and WS-Security Policy. It is important to note that the Apache Rampart 1.0 style configuration is also available even though being marked as deprecated.

Apache Rampart 1.3 can be successfully used with the next Apache Sandesha2 release targeted towards Apache Axis2 1.3 to configure WS-SecureConversation + WS-ReliableMessaging scenarios.

The rampart module was successfully tested for interoperability with other WS-Security implementations.

WS - Sec* specifications supported by Apache Rampart are as follows:

* WS - Security 1.0
* WS - Secure Conversation - February 2005
* WS - Security Policy - 1.1 - July 2005
* WS - Trust - February 2005
* WS - Trust - WS-SX spec - EXPERIMENTAL

Thank you for using Apache Rampart.

Apache Rampart team

Apache WSS4J 1.5.3 Released

Apache WSS4J Team is happy to announce the WSS4J-1.5.3 release.

Apache WSS4J is an implementation of the OASIS Web Services Security (WS-Security) from OASIS Web Services Security TC. WSS4J is a Java library that can be used to sign and verify SOAP Messages with WS-Security information.

You can download the releases from:
http://www.apache.org/dyn/closer.cgi/ws/wss4j/1_5_3

Apart from the binary and source distributions, we have an additional ZIP file that contains other required JAR files to install and run WSS4J.

Please refer to the *readme.* files in the distribution for further information regarding implemented features, additional information, links to the Wiki pages, etc.

Enjoy !

The WSS4J team

Thursday, August 02, 2007

Podcast on Rahas

Rahas is the WS-Trust implementation of Apache Rampart. I recently did a podcast with WSO2 Oxygen Tank about Rahas and its available here.

Saturday, June 02, 2007

Apache Rampart 1.2 Released

This is the 1.2 release of Apache Rampart.

Apache Rampart 1.2 is a toolkit that provides implementations of the
WS-Sec* specifications for Apache Axis2 1.2, based on Apache WSS4J 1.5.2
and the Apache AXIOM-DOOM 1.2.4 implementations.

There are two main Apache Axis2 modules provided with this release.

* rampart-1.2.mar
This provides support for WS-Security and WS-SecureConversation
features.
* rahas-1.2.mar
This module provides the necessary components to enable
SecurityTokenService functionality on a service.


Apache Rampart 1.2 uses a configuration model based on WS-Policy and
WS-Security Policy and it is important to note that Apache Rampart 1.0
style configuration is also available even though being marked as
deprecated.

Apache Rampart 1.2 can be successfully used with the next Apache
Sandesha2 release targeted towards Apache Axis2 1.2 to configure
WS-SecureConversation + WS-ReliableMessaging scenarios.

The rampart module was successfully tested for interoperability with
other WS-Security implementations.

WS - Sec* specifications supported by Apache Rampart are as follows:

* WS - Security 1.0
* WS - Secure Conversation - February 2005
* WS - Security Policy - 1.1 - July 2005
* WS - Trust - February 2005
* WS - Trust - WS-SX spec - EXPERIMENTAL

Rampart-1.2 artifacts can be downloaded from :
http://www.apache.org/dyn/closer.cgi/ws/rampart/1_2

Thank you for using Apache Rampart.

Apache Rampart team

Monday, May 07, 2007

Friday, April 27, 2007

Training courses on Apache Axis2 and Apache Rampart

I will be in Maryland, US in the second week of May. Is anybody
interested in attending tutorials on Apache Axis2 and Apache Rampart?
Both are 1/2 day programs.

This would be on Thursday the 10th of May.

Please drop me a note at training@wso2.com and let me know.