Wednesday, October 29, 2008

Secure Conversation with STS

This post explains steps required in setting up a Secure Conversation between a client and a service with the aid of an STS[Secure Token Service].

Lets start with setting up the STS and configuring its security policy.

First, download WSAS from here.

WSO2 WSAS is an enterprise ready Web services engine powered by Apache Axis2 and it comes with a built in STS and a set of sample services[e.g. echo service] which we can use during this demonstration.

Download wso2wsas.jks from here and copy it to [WSAS_HOME]\conf - or basically replace the existing one. This is a work-around for this issue.

Start WSAS and login with admin/admin.

Select 'Services' and then 'wso2wsas-sts'[under 'Services' column].

Click on 'Manage Security Configuration' and select 'option - 3', that is 'Sign and encrypt - X509 Authentication'.

Keep 'wso2wsas.jks' as the private keystore.

Go back to Services\wso2wsas-sts and click on 'STS Configuration'.

Set,

Endpoint Address = http://localhost:9762/services/echo
Certificate Alias = wso2wsas


And apply.

Lets configure security policy for the echo service.

Select 'Services' and then 'echo'[under 'Services' column].

Click on 'Manage Security Configuration' and select 'option - 11', that is 'SecureConversation - Sign and Encrypt - Service as STS - Bootstrap policy - Sign and Encrypt , X509 Authentication'.

Keep 'wso2wsas.jks' as the private keystore.

All set, lets start with the client.

You can download the Eclipse project for the client from here and import it to a new Eclipse workspace.

Share the folder [CLIENT]\lib and map it to the network drive "W".

Refresh your workspace and it should build with no compile errors.

Build and run the client, you should see the out put on the console.

Lets get in to more details.

First, client will request a Security Context Token [SCT] from the STS.

Following code does it for you.
final static String STS_EPR = "http://localhost:9762/services/wso2wsas-sts";
final static String SERVICE_EPR = "http://localhost:9762/services/echo";

ServiceClient client = null;
ConfigurationContext ctx = null;
Policy stsPolicy = null;
STSClient stsClient = null;
Policy servicePolicy = null;
Token responseToken = null;
TokenStorage store = null;

ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem("repo","repo/conf/client.axis2.xml");

stsClient = new STSClient(ctx);
stsClient.setRstTemplate(getRSTTemplate());
stsClient.setAction(RahasConstants.WST_NS_05_02 + RahasConstants.RST_ACTION_SCT);

stsPolicy = loadPolicy("sts.policy.xml");
servicePolicy = loadPolicy("service.policy.xml"); 

responseToken = stsClient.requestSecurityToken(ervicePolicy,STS_EPR,stsPolicy,SERVICE_EPR);

// Store token
store = TrustUtil.getTokenStore(ctx);
store.add(responseToken);
You'll notice the following in the out-going SOAP request.
<wsa:To>http://localhost:9762/services/wso2wsas-sts
<wsa:ReplyTo>
<wsa:Address>
http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
</wsa:Address>
</wsa:ReplyTo>
<wsa:MessageID>urn:uuid:E463557299CDEAE3B71225299469127</wsa:MessageID>
<wsa:Action>http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT</wsa:Action>
And following is a part of the SOAP message reponse from the STS.
<wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
<wsa:MessageID>urn:uuid:292D5247502C9F172F1225299475624</wsa:MessageID>
<wsa:Action>http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue</wsa:Action>
<wsa:RelatesTo>urn:uuid:E463557299CDEAE3B71225299469127</wsa:RelatesTo>
Basically, SCT binding of WS-Trust defines how to use WS-Trust to request and return SCTs.

As you already noticed in the above two extracts when requesting and issuing security context tokens, following Action URIs are used.
<wsa:Action>http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT</wsa:Action>

<wsa:Action>http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue</wsa:Action>
Once received the SCT from STS, client is ready to talk to the service.
ServiceClient client = null;
Options options = null;

client = new ServiceClient(ctx, null);
client.engageModule("rampart");
client.engageModule("addressing");

options = new Options();
options.setAction("urn:echoOMElement");
options.setSoapVersionURI(SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI);
options.setProperty(RampartMessageData.KEY_RAMPART_POLICY, servicePolicy);
options.setProperty(RampartMessageData.SCT_ID, responseToken.getId());
options.setTo(new EndpointReference(SERVICE_EPR));

client.setOptions(options);
client.sendReceive(getPayload("Hello"));
The above code will generate two SOAP request/reponse message pairs in between client and the service.

Lets look at a part of the first SOAP request from the client to the service.
<wsa:To>http://localhost:9762/services/echo</wsa:To>
<wsa:ReplyTo>
<wsa:Address>
http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
</wsa:Address>
</wsa:ReplyTo>
<wsa:MessageID>urn:uuid:E463557299CDEAE3B71225299475512</wsa:MessageID>
<wsa:Action>http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT</wsa:Action>
And following is an extract from the first response from the service.
<wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
<wsa:MessageID>urn:uuid:292D5247502C9F172F1225299476906</wsa:MessageID>
<wsa:Action>http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/SCT</wsa:Action>
<wsa:RelatesTo>urn:uuid:E463557299CDEAE3B71225299475512</wsa:RelatesTo>
Once done with this initial step, client will invoke the services's business logic.
<wsa:To>http://localhost:9762/services/echo</wsa:To>
<wsa:MessageID>urn:uuid:E463557299CDEAE3B71225299475492</wsa:MessageID>
<wsa:Action>urn:echoOMElement</wsa:Action>

3 comments:

IsildurMaC said...

this example work for the WSAS version 3.2.0 ??

thanks a lot.

IsildurMaC said...

I have this error:

log4j:WARN No appenders could be found for logger (org.apache.axiom.om.util.StAXUtils).
log4j:WARN Please initialize the log4j system properly.
org.apache.axis2.AxisFault: General security error (No certificates were found for decryption (KeyId))
at org.apache.axis2.util.Utils.getInboundFaultFromMessageContext(Utils.java:512)
at org.apache.axis2.description.OutInAxisOperationClient.handleResponse(OutInAxisOperation.java:370)
at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:416)
at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:228)
at org.apache.axis2.client.OperationClient.execute(OperationClient.java:163)
at org.apache.axis2.client.ServiceClient.sendReceive(ServiceClient.java:548)
at org.apache.rahas.client.STSClient.requestSecurityToken(STSClient.java:134)
at org.apache.ws.axis2.Client.main(Client.java:59)
Exception in thread "main" org.apache.rahas.TrustException: Error in obtaining token from : "http://localhost:9763/services/wso2carbon-sts/ "
at org.apache.rahas.client.STSClient.requestSecurityToken(STSClient.java:141)
at org.apache.ws.axis2.Client.main(Client.java:59)

can you help me???

Ehsan Hesamifard said...

Hi
Is it possible to update the client code? Link doesn't work...
Thanks