Axis
Axis2 is a Java based open source web service runtime. It consists of tools for generating a Java proxy based from a WSDL service description. The web service proxy is used for invoking web services, as well as tools for generating web services on the provider side.Checking SAP Notes
SAML Sender-vouches is supported with releases AS ABAP 7.00 (SP 15) and higher. Please ensure the following SAP notes have been applied:AS ABAP 7.00:
- SAP Notes: 1176558, 1325457
- Kernel Patch level: 207
- Support Package SP5
- Kernel patch level: 74
- SAP Notes 1170238, 1325457
- Kernel patch level: 150
Checking Axis versions
I used the following library to run this example:1) Axis 1.4.1 from http://ws.apache.org/axis2/download.cgi
2) Wss4J 1.5.7 from http://www.apache.org/dyn/closer.cgi/ws/wss4j/
Due to a bug in wss4j version 1.5.4 shipped with Axis2 1.4.1, I replaced the wss4j with version 1.5.7. wss4j 1.5.4 ignores the SignedParts elements in axis2.xml and does not sign the timestamp element.
Configure the provider
The ws provider needs to be configured to SAML Sender-Vouches authentication. To create such a configuration, follow the instructions.Configure Trust between Axis2 and SAP WebAS ABAP
The scenario involves an XML Signature. If you already have a certificate for signing the messages, feel free to use it. Otherwise, create a certificate with the java keytool by invoking the commands below (passwords are only as an example):Create the keypair
keytool -genkey -alias SAML -keyalg RSA -keysize 1024 -validity 1000 -keypass abcd1234 -storepass abcd1234 -keystore axis.jks
Export the key
keytool -export -file axis.crt -alias SAML -keypass abcd1234 -storepass abcd1234 -keystore axis.jks
- SAML Issuer: Axis
- SAML Name Identifier: (empty,not used)
- Subject of the X.509 certificate used for the message signature (from the example): CN=Axis, OU=NW SIM, O=NW, L=Walldorf, SP=Baden Wuerttemberg, C=DE
saml.properties
org.apache.ws.security.saml.issuerClass=saml.SAPSAMLIssuerImpl
org.apache.ws.security.saml.issuer.cryptoProp.file=crypto.properties
org.apache.ws.security.saml.issuer.key.name=SAML
org.apache.ws.security.saml.issuer.key.password=abcd1234
saml.issuer=Axis
saml.validity=200
org.apache.ws.security.saml.authenticationMethod=password
crypto.properties
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=abcd1234
org.apache.ws.security.crypto.merlin.keystore.alias=SAML
org.apache.ws.security.crypto.merlin.file=keys/axis.jks
Create the consumer
From the service configuration created in the previous step, copy the WSDL url and open it in the browser. By default the SAP WSDL contains WS-Policy. Axis is not able of processing these assertions, therefore it is best to take the WSDL without policy. Obtain the WSDL without policy by replacing ws_policy with standard in the WSDL url, i.e.:With WS-Policy
http://host:port/sap/bc/srt/wsdl/bndg_001560AB336002ECB9B230CE92A94CD0/wsdl11/allinone/ws_policy/document?sap-client=001
Without WS-Policy
http://host:port/sap/bc/srt/wsdl/bndg_001560AB336002ECB9B230CE92A94CD0/wsdl11/allinone/standard/document?sap-client=001
Save the WSDL in a file.
Configure Axis2 to issue SAML assertions
The axis2.xml configuration file must configure a SAML assertion, a wsu:TimeStamp and a Signature over SOAP Body, wsu:TimeStamp and SAML assertion in the request and a TimeStamp in the response. This is configured by the following piece of XML."rampart"/>
"OutflowSecurity">
Timestamp SAMLTokenSigned
{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body;{Content}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;
saml.properties
DirectReference
"InflowSecurity">
Timestamp
false
"enableSignatureConfirmation" value="false"/>
´
package saml;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Properties;
import org.apache.ws.security.components.crypto.Crypto;
import org.apache.ws.security.components.crypto.CryptoFactory;
import org.apache.ws.security.saml.SAMLIssuer;
import org.opensaml.SAMLAssertion;
import org.opensaml.SAMLAuthenticationStatement;
import org.opensaml.SAMLException;
import org.opensaml.SAMLNameIdentifier;
import org.opensaml.SAMLStatement;
import org.opensaml.SAMLSubject;
import org.w3c.dom.Document;
/**
* Builds a WS SAML Assertion supported by SAP AS ABAP/Java
*
* @author Martijn de Boer
*/
public class SAPSAMLIssuerImpl implements SAMLIssuer {
private SAMLAssertion samlAssertion = null;
private Properties properties = null;
private Crypto issuerCrypto = null;
private String issuerKeyPassword = null;
private String issuerKeyName = null;
private String username;
/**
* Constructor.
*/
public SAPSAMLIssuerImpl() {
System.err.println("Error: no cfg properties passed");
}
public SAPSAMLIssuerImpl(Properties prop) {
/*
* if no properties .. just return an instance, the rest will be done
* later or this instance is just used to handle certificate conversions
* in this implementation
*/
if (prop == null) {
return;
}
properties = prop;
String cryptoProp = properties.getProperty("org.apache.ws.security.saml.issuer.cryptoProp.file");
if (cryptoProp != null) {
issuerCrypto = CryptoFactory.getInstance(cryptoProp);
issuerKeyName = properties.getProperty("org.apache.ws.security.saml.issuer.key.name");
issuerKeyPassword = properties.getProperty("org.apache.ws.security.saml.issuer.key.password");
}
}
/**
* Creates a newSAMLAssertion
.
*
*
* A completeSAMLAssertion
is constructed.
*
* @return SAMLAssertion
*/
public SAMLAssertion newAssertion() { // throws Exception { // Issuer must enable crypto functions to get the issuer's certificate String issuer = properties.getProperty("saml.issuer");
int validity = Integer.parseInt(properties.getProperty("saml.validity", "300"));
String qualifier = "";
try {
SAMLNameIdentifier nameId = new SAMLNameIdentifier(username, qualifier, "");
nameId.setFormat("urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified");
String subjectIP = null;
String authMethod = null;
if ("password".equals(properties.getProperty("org.apache.ws.security.saml.authenticationMethod"))) {
authMethod = SAMLAuthenticationStatement.AuthenticationMethod_Password;
}
Date authInstant = new Date();
SAMLSubject subject = new SAMLSubject(nameId, Arrays.asList(new String[] { SAMLSubject.CONF_SENDER_VOUCHES }), null, null);
SAMLStatement[] statements =
{ new SAMLAuthenticationStatement(subject, authMethod, authInstant, subjectIP, null, (Collection) null) };
Date now = new Date();
Date expires = new Date();
expires.setTime(now.getTime() + validity * 1000);
samlAssertion = new SAMLAssertion(issuer, now, expires, null, null, Arrays.asList(statements));
} catch (SAMLException ex) {
throw new RuntimeException(ex.toString(), ex);
}
return samlAssertion;
}
/**
* @param userCrypto
* The userCrypto to set.
*/
public void setUserCrypto(Crypto userCrypto) {
// ignored for sender vouches }
/*
* ignored (non-Javadoc)
*
* @see org.apache.ws.security.saml.SAMLIssuer#setUsername(java.lang.String)
*/
public void setUsername(String username) {
this.username = username;
}
/**
* @return Returns the issuerCrypto.
*/
public Crypto getIssuerCrypto() {
return issuerCrypto;
}
/**
* @return Returns the issuerKeyName.
*/
public String getIssuerKeyName() {
return issuerKeyName;
}
/**
* @return Returns the issuerKeyPassword.
*/
public String getIssuerKeyPassword() {
return issuerKeyPassword;
}
/**
* @return Returns the senderVouches.
*/
public boolean isSenderVouches() {
return true;
}
/*
* ignored (non-Javadoc)
*
* @see
* org.apache.ws.security.saml.SAMLIssuer#setInstanceDoc(org.w3c.dom.Document
* )
*/
public void setInstanceDoc(Document instanceDoc) {
// ignored for sender vouches }
}
Invoking a web service using Axis2
To invoke the proxy, use the following example below. Basically the following data is needed:- Endpoint url of the web service
- Path to Axis2 repository
- Path to axis2 configuation file
- Name of the user to write into the SAML assertion
package call;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.ws.security.handler.WSHandlerConstants;
import proxy.WsseEchoStub;
public class CallProxy {
public static String callProxy(String input, String url, String repositoryDir, String axis2Path, String user)
throws Exception {
/*
* load configuration
*/
ConfigurationContext ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem(repositoryDir, axis2Path);
/*
* create proxy instance
*/
WsseEchoStub ws = new WsseEchoStub(ctx, url);
/*
* Set user to write into SAML assertion
*/
ws._getServiceClient().getOptions().setProperty(WSHandlerConstants.USER, user);
/*
* call web service
*/
proxy.WsseEchoStub.WSSE_ECHO a = new proxy.WsseEchoStub.WSSE_ECHO();
a.setINPUT(input);
WsseEchoStub.WSSE_ECHOResponse res = ws.WSSE_ECHO(a);
return res.getOUTPUT();
}
}
Example 1: Axis2 standalone
For illustration purposes, I'll first show how to invoke the proxy from a standalone Java application and authenticate the service call in the ABAP stack. As the standalone application does not support authentication itself, it should only be seen as a technical example and not used in realistic scenarios.More Here
Courtesy:http://wiki.sdn.sap.com/wiki/display/Security/Single+Sign+on+using+SAML+with+Apache+Axis2+%28Web+Service+Runtime%29