1. As the first step you need to set up Apache Axis2 + Rampart. You can download Axis2 1.5 from here and Rampart 1.5 from here.(Since Rampart 1.5 is not released yet, I have hosted the binaries built from the 1.5 branch) I am using an Axis2 deployment on Apache Tomcat to host services in this post.
* You can simply download Axis2 webapp and deploy it in Apache Tomcat. (I am referring the tomcat installation directory as TOMCAT_HOME from here onwards)
* Copy the set of jars inside the lib directory of Rampart binary distribution into $TOMCAT_HOME/webapps/axis2/WEB-INF/lib and copy the rampart and rahas module archives(.mar) files into $TOMCAT_HOME/webapps/axis2/WEB-INF/modules directory. Rampart makes use of WSS4J for SAML token validation. Because WSS4J release with the SAML 2.0 token validation support is yet to be released, I am using a custom WSS4J implementation in this scenario. Please download wss4j-1.5.7.wso2v2.jar from here and replace the wss4j-1.5.8.jar which is shipped with Rampart.
* To use SAML 2.0 support, it is required to endorse the default JAXP implementation of the JDK with Apache Xerces and Xalan. You can find more information on how to endorse the JDK in the README file of Rampart binary distribution. Since Tomcat uses its own endorsed directory, it is required to endorse the Tomcat deployment. You can copy the same set of jar files which is used to endorse the JDK to $TOMCAT_HOME/endorsed directory. For convenience, I have hosted the necessary endorsing jars here. You can download this set of jars and copy them to $JAVA_HOME/jre/lib/endorsed directory.
2. As the second step you need to set up the STS and the relying party service. I am using the SAML 1.1 sample shipped with Apache Rampart with some modifications to make it use SAML 2.0. We are using a service archive which contains both relying party service and configurations for STS. STS is implemented inside Rampart and it is sufficient to provide only the configuration. You can download the this service archive named “samlple05.aar” from here. This service archive will contain a service group where STS and Sample05 are the members of that service group.
* It is possible to configure STS according to the user requirements. STS configuration of this sample can be found in services.xml file inside the META-INF directory of the extracted service archive. These configurations are available in the
o issuerName – This is used to identify the issuer, this could be the end point of the issuer or any other identifier used by the relying party services.
o issuerKeyAlias – This is the alias of the certificate that STS will be using for signing SAML Assertions.
o issuerKeyPassword – Private key password of the certificate of the STS
o cryptoProperties – The child elements of this configuration element is used to identify the keystore which is used by the STS. Location of the keystore, keystore type and keystore password are specifed as child elements of this parameter.
o timeToLive – Validity period of a SAML assertion(mentioned in seconds)
o trusted-services – Under this parameter, you can specify the EPRs of the trusted relying party services for which users are obtaining SAML tokens. It is possible to specify a wildcard character, so that STS trusts any relying party service. In this sample, we have used a wildcard character. But in real world scenarios, it is recommended not to use this and mention the trusted services specifically.
* STS is a web service, hence it is possible to publish its requirement as a policy. Please note that, it is better if STS can express its authentication requirements for the user in its policy. In this case, we are using a security policy which contains a Asymmetric Binding. So the X.509 certificate of the client is used to authenticate him.
* Then it contains the policy and configuration required for the relying party service (sample05) which has a ‘echo’ operation. The security policy of the relying party service imposes the presence of a SAML 2.0 token in the SAML request.
https://kirillgdev04/Security_Federation_SecurityTokenService_Indigo/Symmetric.svc/Scenario_1_IssuedTokenOverTransport_UsernameOverTransport
This policy assertion establishes the requirement for a SAML 2.0 assertion which uses a symmetric key with a length of 256 bit for SAML subject confirmation. These requirements are specified in the RequestSecurityTemplate policy assertion.
* Then lets deploy this service archive in Axis2. You can simply copy sample05.aar file into $TOMCAT_HOME/webapps/axis2/WEB-INF/services/ directory and restart Tomcat if you haven’t enable hot deployment.
3. Now lets look at the client code.
package org.wso2.sts;
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.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axiom.soap.SOAP12Constants;
import org.apache.axis2.addressing.AddressingConstants;
import org.apache.axis2.addressing.EndpointReference;
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.rahas.RahasConstants;
import org.apache.rahas.Token;
import org.apache.rahas.TokenStorage;
import org.apache.rahas.TrustException;
import org.apache.rahas.TrustUtil;
import org.apache.rahas.client.STSClient;
import org.apache.rampart.RampartMessageData;
import org.apache.ws.secpolicy.SP11Constants;
import org.apache.ws.secpolicy.SPConstants;
import org.opensaml.XML;
import javax.xml.namespace.QName;
public class Client {
public static void main(String[] args) throws Exception {
//TODO : replace with the local paths in your machine
String epr = "http://localhost:8081/axis2/services/sample05";
String repo = "/path/to/repo";
String servicePolicy = "/path/to/service-policy.xml";
String stsPolicy = "/path/to/sts-policy.xml";
ConfigurationContext ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem(repo, null);
STSClient stsClient = new STSClient(ctx);
stsClient.setRstTemplate(getRSTTemplate());
stsClient.setVersion(RahasConstants.VERSION_05_12);
String action = TrustUtil.getActionValue(RahasConstants.VERSION_05_02, RahasConstants.RST_ACTION_ISSUE);
stsClient.setAction(action);
//Obtain the token
Token responseToken = stsClient.requestSecurityToken(loadPolicy(servicePolicy),
"http://localhost:8081/axis2/services/STS", loadPolicy(stsPolicy), epr);
System.out.println("\n------------------------------ Requested Token ---------------------------------------\n");
System.out.println(responseToken.getToken().toString());
TokenStorage store = TrustUtil.getTokenStore(ctx);
store.add(responseToken);
//Call the relying party service
ServiceClient client = new ServiceClient(ctx, null);
Options options = new Options();
options.setAction("urn:echo");
options.setTo(new EndpointReference(epr));
options.setProperty(RampartMessageData.KEY_RAMPART_POLICY, loadPolicy(servicePolicy));
options.setProperty(RampartMessageData.KEY_CUSTOM_ISSUED_TOKEN, responseToken.getId());
client.setOptions(options);
client.engageModule("addressing");
client.engageModule("rampart");
OMElement response = client.sendReceive(getPayload("Hello world1"));
System.out.println("Response : " + response);
}
private static Policy loadPolicy(String xmlPath) throws Exception {
StAXOMBuilder builder = new StAXOMBuilder(xmlPath);
return PolicyEngine.getPolicy(builder.getDocumentElement());
}
private static OMElement getPayload(String value) {
OMFactory factory = OMAbstractFactory.getOMFactory();
OMNamespace ns = factory.createOMNamespace("http://sample05.policy.samples.rampart.apache.org", "ns1");
OMElement elem = factory.createOMElement("echo", ns);
OMElement childElem = factory.createOMElement("param0", null);
childElem.setText(value);
elem.addChild(childElem);
return elem;
}
private static OMElement getRSTTemplate() throws Exception {
OMFactory fac = OMAbstractFactory.getOMFactory();
OMElement elem = fac.createOMElement(SP11Constants.REQUEST_SECURITY_TOKEN_TEMPLATE);
TrustUtil.createTokenTypeElement(RahasConstants.VERSION_05_12, elem).setText(RahasConstants.TOK_TYPE_SAML_20);
TrustUtil.createKeyTypeElement(RahasConstants.VERSION_05_12, elem, RahasConstants.KEY_TYPE_SYMM_KEY);
TrustUtil.createKeySizeElement(RahasConstants.VERSION_05_12, elem, 256);
return elem;
}
}
Above listing depicts the complete version of the Client code. In order to make this work, you need to make some changes in the paths to repos, policies etc. Modify the repo, epr, servicePolicy and stsPolicy accordingly. I am explaining some of the important code segments of the above code for the sake of completion.
* After instantiating the STSClient object, we set its RSTTemplate. In this code, getRSTTemplate() method is used to create the RSTTemplate. The SAML version, key type and the key size are set to the RST(Request Security Token) inside this method. Following code snipped sets the SAML version, Key type and key length in RST.
TrustUtil.createTokenTypeElement(RahasConstants.VERSION_05_12, elem).setText(RahasConstants.TOK_TYPE_SAML_20);
TrustUtil.createKeyTypeElement(RahasConstants.VERSION_05_12, elem, RahasConstants.KEY_TYPE_SYMM_KEY);
TrustUtil.createKeySizeElement(RahasConstants.VERSION_05_12, elem, 256);
* Then we set the RST action. In this scenario, we are requesting a token from the STS. So the corresponding trust action is ISSUE.
String action = TrustUtil.getActionValue(RahasConstants.VERSION_05_02, RahasConstants.RST_ACTION_ISSUE);
stsClient.setAction(action);
* Then the RST is sent to the STS. Here, we are passing the EPR of the RP service as a parameter. This is going to be checked against the set of trusted services we specified in the sts-configuration.
Token responseToken = stsClient.requestSecurityToken(loadPolicy(servicePolicy), "http://localhost:8081/axis2/services/STS", loadPolicy(stsPolicy), epr);
* After obtaining the token, we are storing it in the trust store and then sending it to the RP service.
You can download the source code, policy files and client site key store from here. Please note that you have to change the rampart-config parameters in both policy files to reflect your local settings.
In this sample, we are using a password callback handler to load the passwords of the private keys. In the client’s end, we are using the following password callback handler.
package org.wso2.sts;
import org.apache.ws.security.WSPasswordCallback;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;
public class PWCBHandler implements CallbackHandler{
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) { WSPasswordCallback pwcb = (WSPasswordCallback)callbacks[i]; String id = pwcb.getIdentifer(); if("client".equals(id)) { pwcb.setPassword("apache"); } else if("service".equals(id)) { pwcb.setPassword("apache"); } } } } To get the client code up and running you need to add certain set of jars to your classpath. Most straight forward approach is adding the Axis2 ‘lib’ into your classpath. It contains all the jars required to compile and run this sample. Following listing depicts the RST sent from Client to STS.
http://localhost:8081/axis2/services/sample05
g5WVRpUl7bKno8LYFC9JUGLpe1NZpkZ/
In this RST, RequestType is set to “http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue”. We have passed EPR of the RP service as a parameter when requesting the token. If you carefully observe AppliesTo element, you will note the EPR we have passed has been set as the value of this element. Similarly the token type, key type and the key size are also appearing in the RST as we have set them in the RSTTemplate. The “Entopy” element is used pass a binary secret which is used to derive keys. I am not going into further details about key derivation is WS Trust. Plese refer to the WS Trust specification for further details.
Following is the resulting RSTR(Request Security Token Response) returned by the STS.
http://localhost:8081/axis2/services/sample05
...
r/JgXgGMFb4afwRQpggqky8q4TQm7pdXm8RQq9IgCzI=
SAML assertion contained in the RSTR is removed for brevity.
In this post, we have looked about the STS Configuration of Apache Rampart, how to obtain a SAML 2.0 Token, and how to use it to consume a web service. If you faced any issues, do not hesitate to post them here.
More Here
Courtesy:http://thilinamb.wordpress.com/2009/10/20/saml-2-0-token-profile-support-in-rampart-1-5/