Peter Arockiaraj

Can you hear me now?…Good!

Developing CXF WS-Security with SAML


Introduction

In this article we are going to develop a web service by using Spring and CXF with WS-Security (SAML). This article provides steps (step by step) to create &  deploy web services by usingSpring and CXF with WS-Security (SAML). Please go through below to find sample web services.

Software Requirements

  1. EClipse (Java IDE)- Optional
  2. CXF Jars (Required for Compilation-Download from http://cxf.apache.org/download.html)

The Code

In this example, we are going to create a Hello service. In this example, we are going to use a code-first approach for this service using JAX-WS annotations.

Creating Server and Client Certificates

For the Signature and Encryption actions, you’ll need to create a public & private key for the entities involved. You can generate a key pair for the development environment via the following steps. Keep in mind these will not be signed by an external authority like Verisign

Keytool is inbuild tool which is comes with jdk.

Follow the steps to create client and server certificates (Refer following site)

  1. http://pa55word.wordpress.com/

When urgently you need some keystores and truststores to test out some security related java code this is a useful bat file to have. Copy the code below and create a bat file. run it and you got your stuff.

keytool -genkey -alias serverkeys -keyalg RSA -keystore server.keystore -storepass changeit -keypass changeit -dname “CN=localhost, OU=MYOU, O=MYORG, L=MYCITY, ST=MYSTATE, C=MY”


keytool -export -alias serverkeys -keystore server.keystore -storepass changeit -file server.cer


keytool -genkey -alias clientkeys -keyalg RSA -keystore client.keystore -storepass changeit -keypass changeit -dname “CN=localhost, OU=MYOU, O=MYORG, L=MYCITY, S=MY
STATE, C=MY”


keytool -export -alias clientkeys -keystore client.keystore -storepass changeit -file client.cer


keytool -import -v -keystore client.truststore -storepass changeit -file server.cer


keytool -import -v -keystore server.truststore -storepass changeit -file client.cer

It generates a keystore called server.keystore with password changeit. Then it creates server certificate server.cer.

Then it  generates a keystore called client.keystore with password changeit. Creates a client certificate named client.cer

Next it imports server certificate into client truststore and client certificate into server truststore.

These are self signed certificates. Good for internal use. You can use open ssl
and create certificates. But this bat file is short and sweet for immediate use.
When you paste it you do have to be careful about keywords not getting split up like wordpress does.

Creating Server Application

Step 1:   Download Following Jar files.

activation.jar

aopalliance-1.0.jar

commons-collections-3.2.jar

commons-lang-2.1.jar

commons-logging-1.1.jar

geronimo-activation-2.0.1.jar

geronimo-annotation_1.0_spec-1.1.jar

geronimo-javamail_1.4_mail-1.2.jar

geronimo-servlet_2.5_spec-1.1.jar

geronimo-ws-metadata_2.0_spec-1.1.1.jar

jaxb-api.jar

jaxb-api-2.0.jar

jaxb-impl-2.0.5.jar

jaxb-xjc.jar

jaxws-api.jar

mail.jar

neethi-2.0.jar

opensaml-1.0.1.jar

saaj-api.jar

saaj-impl.jar

spring-beans-2.0.6.jar

spring-context-2.0.6.jar

spring-core-2.0.6.jar

spring-web-2.0.6.jar

stax-api-1.0.1.jar

velocity-1.5.jar

wsdl4j-1.6.1.jar

wstx-asl-3.2.1.jar

xalan-2[1].6.0.jar

xalan-2[1].7.0.jar

xml-resolver-1.2.jar

cxf-bundle-2.0.4-incubator.jar

XmlSchema-1.3.2.jar

wss4j-1.5.1.jar

keyexport.jar

pkcs12import.jar

security-plugin.jar

wss-provider-update.jar

xws-security_jaxrpc.jar

xws-security.jar

xmlsec-1.3.0.jar

Step 2: Create New Java project in eclipse (CXFSAMLSecurity).

Step 3: Create WEB-INF folder inside project folder.

Step 4: Create classes folder inside WEB-INF folder.

Step 5: Create lib folder inside WEB-INF folder.

Step 6: Copy all the jar file into lib folder.

Step 7: Add all jar files into classpath (In Eclipse set java build path->Libraries). Add set Default output folder into CXFSAMLSecurity/WEB-INF/classes

Step 8: Create Remote Interface IHello.java

package com.sungard.cxf.example.server;

import javax.jws.WebService;

@WebService

public interface IHello {

public String sayHello(String value);

}

Step 9: Create Implementation Class IHello_Impl.java

package com.sungard.cxf.example.server;

import javax.jws.WebService;

@WebService(endpointInterface = “com.sungard.cxf.example.server.IHello”)

public class IHello_Impl implements IHello {

public String sayHello(String value) {

return “You Said” + value;

}

}

Step 10:  Create ServerSecurityEnvironmentHandler.java file to handle usernames and passwords. Here you have to give server certificate, server trust certificate alias name for checking. Password is alias password. Also you have to give client keystore file passwords also.

private String keyStorePassword = “changeit”;

private String trustStorePassword = “changeit”;

else if (callbacks[i] instanceof WSPasswordCallback) {

System.out.println(“handle::WSPasswordCallback”);

WSPasswordCallback cb = (WSPasswordCallback) callbacks[i];

cb.setPassword(“changeit”);

}

package com.sungard.cxf.example.server;

import java.io.IOException;

import java.math.BigInteger;

import java.net.URL;

import java.security.KeyStore;

import java.security.PrivateKey;

import java.security.cert.CertPathBuilder;

import java.security.cert.Certificate;

import java.security.cert.CertificateExpiredException;

import java.security.cert.CertificateNotYetValidException;

import java.security.cert.PKIXBuilderParameters;

import java.security.cert.PKIXCertPathBuilderResult;

import java.security.cert.X509CertSelector;

import java.security.cert.X509Certificate;

import java.text.SimpleDateFormat;

import java.util.Arrays;

import java.util.Calendar;

import java.util.Date;

import java.util.Enumeration;

import java.util.GregorianCalendar;

import javax.security.auth.callback.Callback;

import javax.security.auth.callback.CallbackHandler;

import javax.security.auth.callback.UnsupportedCallbackException;

import org.apache.ws.security.WSPasswordCallback;

//import com.sun.org.apache.xml.internal.security.utils.RFC2253Parser;

import com.sun.xml.wss.impl.callback.CertificateValidationCallback;

import com.sun.xml.wss.impl.callback.DecryptionKeyCallback;

import com.sun.xml.wss.impl.callback.EncryptionKeyCallback;

import com.sun.xml.wss.impl.callback.PasswordValidationCallback;

import com.sun.xml.wss.impl.callback.SignatureKeyCallback;

import com.sun.xml.wss.impl.callback.SignatureVerificationKeyCallback;

import com.sun.xml.wss.impl.callback.TimestampValidationCallback;

import com.sun.xml.wss.impl.misc.SecurityUtil;

/**

* A sample implementation of a CallbackHandler.

*/

public class ServerSecurityEnvironmentHandler implements CallbackHandler {

private KeyStore keyStore;

private KeyStore trustStore;

private String keyStorePassword = “changeit”;

private String trustStorePassword = “changeit”;

private static final UnsupportedCallbackException unsupported = new UnsupportedCallbackException(

null, “Unsupported Callback Type Encountered”);

public ServerSecurityEnvironmentHandler() throws Exception {

initTrustStore();

initKeyStore();

}

public void handle(Callback[] callbacks) throws IOException,

UnsupportedCallbackException {

System.out.println(“Entered::ServerSecurityEnvironmentHandler::handle”);

for (int i = 0; i < callbacks.length; i++) {

System.out.println(“handle::For-1”);

if (callbacks[i] instanceof PasswordValidationCallback) {

System.out.println(“handle::PasswordValidationCallback”);

PasswordValidationCallback cb = (PasswordValidationCallback) callbacks[i];

if (cb.getRequest() instanceof PasswordValidationCallback.PlainTextPasswordRequest) {

System.out.println(“handle::PlainTextPasswordRequest”);

cb.setValidator(new PlainTextPasswordValidator());

} else if (cb.getRequest() instanceof PasswordValidationCallback.DigestPasswordRequest) {

System.out.println(“handle::DigestPasswordRequest”);

PasswordValidationCallback.DigestPasswordRequest request = (PasswordValidationCallback.DigestPasswordRequest) cb

.getRequest();

String username = request.getUsername();

if (“Ron”.equals(username)) {

request.setPassword(“noR”);

cb

.setValidator(new PasswordValidationCallback.DigestPasswordValidator());

}

} else {

throw unsupported;

}

} else if (callbacks[i] instanceof TimestampValidationCallback) {

System.out.println(“handle::TimestampValidationCallback”);

TimestampValidationCallback cb = (TimestampValidationCallback) callbacks[i];

cb.setValidator(new DefaultTimestampValidator());

} else if (callbacks[i] instanceof SignatureVerificationKeyCallback) {

System.out.println(“handle::SignatureVerificationKeyCallback”);

SignatureVerificationKeyCallback cb = (SignatureVerificationKeyCallback) callbacks[i];

if (cb.getRequest() instanceof SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest) {

System.out.println(“handle::X509SubjectKeyIdentifierBasedRequest”);

// subject keyid request

SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest request = (SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest) cb

.getRequest();

X509Certificate cert = getCertificateFromTrustStore(request

.getSubjectKeyIdentifier());

request.setX509Certificate(cert);

} else if (cb.getRequest() instanceof SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest) {

// issuer serial request

System.out.println(“handle::X509IssuerSerialBasedRequest”);

SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest request = (SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest) cb

.getRequest();

X509Certificate cert = getCertificateFromTrustStore(request

.getIssuerName(), request.getSerialNumber());

request.setX509Certificate(cert);

} else {

throw unsupported;

}

} else if (callbacks[i] instanceof SignatureKeyCallback) {

System.out.println(“handle::SignatureKeyCallback”);

SignatureKeyCallback cb = (SignatureKeyCallback) callbacks[i];

if (cb.getRequest() instanceof SignatureKeyCallback.DefaultPrivKeyCertRequest) {

System.out.println(“handle::DefaultPrivKeyCertRequest”);

// default priv key cert req

SignatureKeyCallback.DefaultPrivKeyCertRequest request = (SignatureKeyCallback.DefaultPrivKeyCertRequest) cb

.getRequest();

getDefaultPrivKeyCert(request);

} else if (cb.getRequest() instanceof SignatureKeyCallback.AliasPrivKeyCertRequest) {

System.out.println(“handle::AliasPrivKeyCertRequest”);

SignatureKeyCallback.AliasPrivKeyCertRequest request = (SignatureKeyCallback.AliasPrivKeyCertRequest) cb

.getRequest();

String alias = request.getAlias();

try {

X509Certificate cert = (X509Certificate) keyStore

.getCertificate(alias);

request.setX509Certificate(cert);

// Assuming key passwords same as the keystore password

PrivateKey privKey = (PrivateKey) keyStore.getKey(

alias, keyStorePassword.toCharArray());

request.setPrivateKey(privKey);

} catch (Exception e) {

System.out.println(“handle::AliasPrivKeyCertRequest::Exception”);

throw new IOException(e.getMessage());

}

} else {

System.out.println(“handle::AliasPrivKeyCertRequest::Exception::own::1”);

throw unsupported;

}

} else if (callbacks[i] instanceof DecryptionKeyCallback) {

DecryptionKeyCallback cb = (DecryptionKeyCallback) callbacks[i];

System.out.println(“handle::DecryptionKeyCallback”);

if (cb.getRequest() instanceof DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest) {

System.out.println(“handle::X509SubjectKeyIdentifierBasedRequest”);

DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest request = (DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest) cb

.getRequest();

byte[] ski = request.getSubjectKeyIdentifier();

PrivateKey privKey = getPrivateKey(ski);

request.setPrivateKey(privKey);

} else if (cb.getRequest() instanceof DecryptionKeyCallback.X509IssuerSerialBasedRequest) {

System.out.println(“handle::X509IssuerSerialBasedRequest”);

DecryptionKeyCallback.X509IssuerSerialBasedRequest request = (DecryptionKeyCallback.X509IssuerSerialBasedRequest) cb

.getRequest();

String issuerName = request.getIssuerName();

BigInteger serialNumber = request.getSerialNumber();

PrivateKey privKey = getPrivateKey(issuerName, serialNumber);

request.setPrivateKey(privKey);

} else if (cb.getRequest() instanceof DecryptionKeyCallback.X509CertificateBasedRequest) {

System.out.println(“handle::X509CertificateBasedRequest”);

DecryptionKeyCallback.X509CertificateBasedRequest request = (DecryptionKeyCallback.X509CertificateBasedRequest) cb

.getRequest();

X509Certificate cert = request.getX509Certificate();

PrivateKey privKey = getPrivateKey(cert);

request.setPrivateKey(privKey);

} else {

System.out.println(“handle::X509CertificateBasedRequest::Exception::own:2”);

throw unsupported;

}

} else if (callbacks[i] instanceof EncryptionKeyCallback) {

EncryptionKeyCallback cb = (EncryptionKeyCallback) callbacks[i];

System.out.println(“handle::EncryptionKeyCallback”);

if (cb.getRequest() instanceof EncryptionKeyCallback.AliasX509CertificateRequest) {

System.out.println(“handle::AliasX509CertificateRequest”);

EncryptionKeyCallback.AliasX509CertificateRequest request = (EncryptionKeyCallback.AliasX509CertificateRequest) cb

.getRequest();

String alias = request.getAlias();

if (alias == null) {

System.out.println(“handle::AliasX509CertificateRequest::read”);

// plugin code here to read the cert from the

// ThreadLocal

} else {

try {

System.out.println(“handle::AliasX509CertificateRequest:try”);

X509Certificate cert = (X509Certificate) trustStore

.getCertificate(alias);

request.setX509Certificate(cert);

} catch (Exception e) {

System.out.println(“handle::AliasX509CertificateRequest::Exception”);

throw new IOException(e.getMessage());

}

}

} else {

System.out.println(“handle::AliasX509CertificateRequest::Exception::own::3”);

throw unsupported;

}

} else if (callbacks[i] instanceof CertificateValidationCallback) {

System.out.println(“handle::CertificateValidationCallback”);

CertificateValidationCallback cb = (CertificateValidationCallback) callbacks[i];

cb.setValidator(new X509CertificateValidatorImpl());

} else if (callbacks[i] instanceof CertificateValidationCallback) {

System.out.println(“handle::CertificateValidationCallback”);

CertificateValidationCallback cb = (CertificateValidationCallback) callbacks[i];

cb.setValidator(new X509CertificateValidatorImpl());

} else if (callbacks[i] instanceof WSPasswordCallback) {

System.out.println(“handle::WSPasswordCallback”);

WSPasswordCallback cb = (WSPasswordCallback) callbacks[i];

System.out.println(“handle::cb.getPassword()”+cb.getPassword());

cb.setPassword(“changeit”);

} else {

System.out.println(“handle::CallBack Class Name::”+callbacks[i].getClass().getName());

System.out.println(“handle::CertificateValidationCallback::Exception::own::4”);

throw unsupported;

}

}

System.out.println(“Leaving::ServerSecurityEnvironmentHandler::handle”);

}

private void initTrustStore() throws IOException {

System.out

.println(“Entered::ServerSecurityEnvironmentHandler::initTrustStore”);

try {

URL truststoreURL = SecurityUtil

.loadFromClasspath(“server-truststore.jks”);

trustStore = KeyStore.getInstance(“JKS”);

trustStore.load(truststoreURL.openStream(), trustStorePassword

.toCharArray());

} catch (Exception e) {

e.printStackTrace();

throw new IOException(e.getMessage());

}

System.out

.println(“Leaving::ServerSecurityEnvironmentHandler::initTrustStore”);

}

private void initKeyStore() throws IOException {

System.out

.println(“Entered::ServerSecurityEnvironmentHandler::initKeyStore”);

try {

URL keystoreURL = SecurityUtil

.loadFromClasspath(“server-keystore.jks”);

keyStore = KeyStore.getInstance(“JKS”);

keyStore.load(keystoreURL.openStream(), keyStorePassword

.toCharArray());

} catch (Exception e) {

throw new IOException(e.getMessage());

}

System.out

.println(“Leaving::ServerSecurityEnvironmentHandler::initKeyStore”);

}

private X509Certificate getCertificateFromTrustStore(byte[] ski)

throws IOException {

System.out

.println(“Entered::ServerSecurityEnvironmentHandler::getCertificateFromTrustStore”);

try {

Enumeration aliases = trustStore.aliases();

while (aliases.hasMoreElements()) {

String alias = (String) aliases.nextElement();

Certificate cert = trustStore.getCertificate(alias);

if (cert == null || !”X.509″.equals(cert.getType())) {

continue;

}

X509Certificate x509Cert = (X509Certificate) cert;

byte[] keyId = getSubjectKeyIdentifier(x509Cert);

if (keyId == null) {

// Cert does not contain a key identifier

continue;

}

if (Arrays.equals(ski, keyId)) {

System.out

.println(“Leaving::ServerSecurityEnvironmentHandler::getCertificateFromTrustStore::1”);

return x509Cert;

}

}

} catch (Exception e) {

throw new IOException(e.getMessage());

}

System.out

.println(“Leaving::ServerSecurityEnvironmentHandler::getCertificateFromTrustStore::2”);

return null;

}

private X509Certificate getCertificateFromTrustStore(String issuerName,

BigInteger serialNumber) throws IOException {

System.out

.println(“Entered::ServerSecurityEnvironmentHandler::getCertificateFromTrustStore::Multiple”);

try {

Enumeration aliases = trustStore.aliases();

while (aliases.hasMoreElements()) {

String alias = (String) aliases.nextElement();

Certificate cert = trustStore.getCertificate(alias);

if (cert == null || !”X.509″.equals(cert.getType())) {

continue;

}

X509Certificate x509Cert = (X509Certificate) cert;

String thisIssuerName = org.apache.xml.security.utils.RFC2253Parser.normalize(x509Cert

.getIssuerDN().getName());

BigInteger thisSerialNumber = x509Cert.getSerialNumber();

if (thisIssuerName.equals(issuerName)

&& thisSerialNumber.equals(serialNumber)) {

System.out

.println(“Leaving::ServerSecurityEnvironmentHandler::getCertificateFromTrustStore::Multiple::1”);

return x509Cert;

}

}

} catch (Exception e) {

throw new IOException(e.getMessage());

}

System.out

.println(“Leaving::ServerSecurityEnvironmentHandler::getCertificateFromTrustStore::Multiple::2”);

return null;

}

public PrivateKey getPrivateKey(byte[] ski) throws IOException {

System.out

.println(“Entered::ServerSecurityEnvironmentHandler::getPrivateKey”);

try {

Enumeration aliases = keyStore.aliases();

while (aliases.hasMoreElements()) {

String alias = (String) aliases.nextElement();

if (!keyStore.isKeyEntry(alias))

continue;

Certificate cert = keyStore.getCertificate(alias);

if (cert == null || !”X.509″.equals(cert.getType())) {

continue;

}

X509Certificate x509Cert = (X509Certificate) cert;

byte[] keyId = getSubjectKeyIdentifier(x509Cert);

if (keyId == null) {

// Cert does not contain a key identifier

continue;

}

if (Arrays.equals(ski, keyId)) {

// Asuumed key password same as the keystore password

System.out

.println(“Leaving::ServerSecurityEnvironmentHandler::getPrivateKey::2”);

return (PrivateKey) keyStore.getKey(alias, keyStorePassword

.toCharArray());

}

}

} catch (Exception e) {

throw new IOException(e.getMessage());

}

System.out

.println(“Leaving::ServerSecurityEnvironmentHandler::getPrivateKey::2”);

return null;

}

public PrivateKey getPrivateKey(String issuerName, BigInteger serialNumber)

throws IOException {

System.out

.println(“Entered::ServerSecurityEnvironmentHandler::getPrivateKey::multiple”);

try {

Enumeration aliases = keyStore.aliases();

while (aliases.hasMoreElements()) {

String alias = (String) aliases.nextElement();

if (!keyStore.isKeyEntry(alias))

continue;

Certificate cert = keyStore.getCertificate(alias);

if (cert == null || !”X.509″.equals(cert.getType())) {

continue;

}

X509Certificate x509Cert = (X509Certificate) cert;

String thisIssuerName = org.apache.xml.security.utils.RFC2253Parser.normalize(x509Cert

.getIssuerDN().getName());

BigInteger thisSerialNumber = x509Cert.getSerialNumber();

if (thisIssuerName.equals(issuerName)

&& thisSerialNumber.equals(serialNumber)) {

System.out

.println(“Leaving::ServerSecurityEnvironmentHandler::getPrivateKey::multiple::1”);

return (PrivateKey) keyStore.getKey(alias, keyStorePassword

.toCharArray());

}

}

} catch (Exception e) {

throw new IOException(e.getMessage());

}

System.out

.println(“Leaving::ServerSecurityEnvironmentHandler::getPrivateKey::multiple::1”);

return null;

}

public PrivateKey getPrivateKey(X509Certificate certificate)

throws IOException {

System.out

.println(“Entered::ServerSecurityEnvironmentHandler::getPrivateKey::certificate”);

try {

Enumeration aliases = keyStore.aliases();

while (aliases.hasMoreElements()) {

String alias = (String) aliases.nextElement();

if (!keyStore.isKeyEntry(alias))

continue;

Certificate cert = keyStore.getCertificate(alias);

if (cert != null && cert.equals(certificate))

System.out

.println(“Leaving::ServerSecurityEnvironmentHandler::getPrivateKey::certificate::1”);

return (PrivateKey) keyStore.getKey(alias, keyStorePassword

.toCharArray());

}

} catch (Exception e) {

throw new IOException(e.getMessage());

}

System.out

.println(“Leaving::ServerSecurityEnvironmentHandler::getPrivateKey::certificate::2”);

return null;

}

private void getDefaultPrivKeyCert(

SignatureKeyCallback.DefaultPrivKeyCertRequest request)

throws IOException {

System.out

.println(“Entered::ServerSecurityEnvironmentHandler::getDefaultPrivKeyCert”);

String uniqueAlias = null;

try {

Enumeration aliases = keyStore.aliases();

while (aliases.hasMoreElements()) {

String currentAlias = (String) aliases.nextElement();

if (keyStore.isKeyEntry(currentAlias)) {

Certificate thisCertificate = keyStore

.getCertificate(currentAlias);

if (thisCertificate != null) {

if (thisCertificate instanceof X509Certificate) {

if (uniqueAlias == null) {

uniqueAlias = currentAlias;

} else {

// Not unique!

uniqueAlias = null;

break;

}

}

}

}

}

if (uniqueAlias != null) {

request.setX509Certificate((X509Certificate) keyStore

.getCertificate(uniqueAlias));

request.setPrivateKey((PrivateKey) keyStore.getKey(uniqueAlias,

keyStorePassword.toCharArray()));

}

} catch (Exception e) {

throw new IOException(e.getMessage());

}

System.out

.println(“Leaving::ServerSecurityEnvironmentHandler::getDefaultPrivKeyCert”);

}

private static byte[] getSubjectKeyIdentifier(X509Certificate cert) {

System.out

.println(“Entered::ServerSecurityEnvironmentHandler::getSubjectKeyIdentifier”);

String SUBJECT_KEY_IDENTIFIER_OID = “2.5.29.14”;

byte[] subjectKeyIdentifier = cert

.getExtensionValue(SUBJECT_KEY_IDENTIFIER_OID);

if (subjectKeyIdentifier == null)

return null;

try {

sun.security.x509.KeyIdentifier keyId = null;

sun.security.util.DerValue derVal = new sun.security.util.DerValue(

new sun.security.util.DerInputStream(subjectKeyIdentifier)

.getOctetString());

keyId = new sun.security.x509.KeyIdentifier(derVal.getOctetString());

System.out

.println(“Leaving::ServerSecurityEnvironmentHandler::getSubjectKeyIdentifier::1”);

return keyId.getIdentifier();

} catch (NoClassDefFoundError ncde) {

if (subjectKeyIdentifier == null)

return null;

byte[] dest = new byte[subjectKeyIdentifier.length – 4];

System.arraycopy(subjectKeyIdentifier, 4, dest, 0,

subjectKeyIdentifier.length – 4);

System.out

.println(“Leaving::ServerSecurityEnvironmentHandler::getSubjectKeyIdentifier::2”);

return dest;

} catch (java.io.IOException ex) {

// ignore

System.out

.println(“Leaving::ServerSecurityEnvironmentHandler::getSubjectKeyIdentifier::3”);

return null;

}

}

private class PlainTextPasswordValidator implements

PasswordValidationCallback.PasswordValidator {

public boolean validate(PasswordValidationCallback.Request request)

throws PasswordValidationCallback.PasswordValidationException {

System.out.println(“Entered::PlainTextPasswordValidator::validate”);

PasswordValidationCallback.PlainTextPasswordRequest plainTextRequest = (PasswordValidationCallback.PlainTextPasswordRequest) request;

if (“Ron”.equals(plainTextRequest.getUsername())

&& “noR”.equals(plainTextRequest.getPassword())) {

System.out

.println(“Leaving::PlainTextPasswordValidator::validate::true”);

return true;

}

System.out

.println(“Leaving::PlainTextPasswordValidator::validate::false”);

return false;

}

}

private class DefaultTimestampValidator implements

TimestampValidationCallback.TimestampValidator {

public void validate(TimestampValidationCallback.Request request)

throws TimestampValidationCallback.TimestampValidationException {

System.out.println(“Entered::DefaultTimestampValidator::validate”);

// validate timestamp creation and expiration time.

TimestampValidationCallback.UTCTimestampRequest utcTimestampRequest = (TimestampValidationCallback.UTCTimestampRequest) request;

SimpleDateFormat calendarFormatter2 = new SimpleDateFormat(

“yyyy-MM-dd’T’HH:mm:ss’Z'”);

SimpleDateFormat calendarFormatter1 = new SimpleDateFormat(

“yyyy-MM-dd’T’HH:mm:ss’.’SSS’Z'”);

Date created = null;

Date expired = null;

try {

try {

created = calendarFormatter1.parse(utcTimestampRequest

.getCreated());

if (utcTimestampRequest.getExpired() != null)

expired = calendarFormatter1.parse(utcTimestampRequest

.getExpired());

} catch (java.text.ParseException pe) {

created = calendarFormatter2.parse(utcTimestampRequest

.getCreated());

if (utcTimestampRequest.getExpired() != null)

expired = calendarFormatter2.parse(utcTimestampRequest

.getExpired());

}

} catch (java.text.ParseException pe) {

throw new TimestampValidationCallback.TimestampValidationException(

pe.getMessage());

}

long maxClockSkew = utcTimestampRequest.getMaxClockSkew();

long timestampFreshnessLimit = utcTimestampRequest

.getTimestampFreshnessLimit();

// validate creation time

validateCreationTime(created, maxClockSkew, timestampFreshnessLimit);

// validate expiration time

if (expired != null)

validateExpirationTime(expired, maxClockSkew,

timestampFreshnessLimit);

System.out.println(“Leaving::DefaultTimestampValidator::validate”);

}

}

public void validateExpirationTime(Date expires, long maxClockSkew,

long timestampFreshnessLimit)

throws TimestampValidationCallback.TimestampValidationException {

System.out

.println(“Enterd::DefaultTimestampValidator::validateExpirationTime”);

Date currentTime = getGMTDateWithSkewAdjusted(new GregorianCalendar(),

maxClockSkew, false);

if (expires.before(currentTime)) {

throw new TimestampValidationCallback.TimestampValidationException(

“The current time is ahead of the expiration time in Timestamp”);

}

System.out

.println(“Leaving::DefaultTimestampValidator::validateExpirationTime”);

}

public void validateCreationTime(Date created, long maxClockSkew,

long timestampFreshnessLimit)

throws TimestampValidationCallback.TimestampValidationException {

System.out

.println(“Enterd::DefaultTimestampValidator::validateCreationTime”);

Date current = getFreshnessAndSkewAdjustedDate(maxClockSkew,

timestampFreshnessLimit);

System.out.println(“Validate Creation time called current=” + current);

System.out.println(“Validate Creation time called created=” + created);

if (created.before(current)) {

throw new TimestampValidationCallback.TimestampValidationException(

“The creation time is older than ”

+ ” currenttime – timestamp-freshness-limit – max-clock-skew”);

}

Date currentTime = getGMTDateWithSkewAdjusted(new GregorianCalendar(),

maxClockSkew, true);

System.out.println(“Validate Creation time called currentTime=”

+ currentTime);

System.out.println(“Validate Creation time called created=” + created);

if (currentTime.before(created)) {

throw new TimestampValidationCallback.TimestampValidationException(

“The creation time is ahead of the current time.”);

}

System.out

.println(“Leaving::DefaultTimestampValidator::validateCreationTime”);

}

private static Date getFreshnessAndSkewAdjustedDate(long maxClockSkew,

long timestampFreshnessLimit) {

System.out

.println(“Enterd::DefaultTimestampValidator::getFreshnessAndSkewAdjustedDate”);

Calendar c = new GregorianCalendar();

long offset = c.get(Calendar.ZONE_OFFSET);

if (c.getTimeZone().inDaylightTime(c.getTime())) {

offset += c.getTimeZone().getDSTSavings();

}

long beforeTime = c.getTimeInMillis();

long currentTime = beforeTime – offset;

System.out.println(“MaxSkew=” + maxClockSkew + ” freshness=”

+ timestampFreshnessLimit);

long adjustedTime = currentTime – maxClockSkew

– timestampFreshnessLimit;

c.setTimeInMillis(adjustedTime);

System.out

.println(“Leaving::DefaultTimestampValidator::getFreshnessAndSkewAdjustedDate”);

return c.getTime();

}

private static Date getGMTDateWithSkewAdjusted(Calendar c,

long maxClockSkew, boolean addSkew) {

System.out

.println(“Enterd::DefaultTimestampValidator::getGMTDateWithSkewAdjusted”);

long offset = c.get(Calendar.ZONE_OFFSET);

if (c.getTimeZone().inDaylightTime(c.getTime())) {

offset += c.getTimeZone().getDSTSavings();

}

long beforeTime = c.getTimeInMillis();

long currentTime = beforeTime – offset;

if (addSkew)

currentTime = currentTime + maxClockSkew;

else

currentTime = currentTime – maxClockSkew;

c.setTimeInMillis(currentTime);

System.out

.println(“Leaving::DefaultTimestampValidator::getGMTDateWithSkewAdjusted”);

return c.getTime();

}

private class X509CertificateValidatorImpl implements

CertificateValidationCallback.CertificateValidator {

public boolean validate(X509Certificate certificate)

throws CertificateValidationCallback.CertificateValidationException {

System.out

.println(“Enterd::X509CertificateValidatorImpl::validate”);

if (isSelfCert(certificate)) {

System.out

.println(“Leaving::X509CertificateValidatorImpl::validate::1”);

return true;

}

try {

certificate.checkValidity();

} catch (CertificateExpiredException e) {

e.printStackTrace();

throw new CertificateValidationCallback.CertificateValidationException(

“X509Certificate Expired”, e);

} catch (CertificateNotYetValidException e) {

e.printStackTrace();

throw new CertificateValidationCallback.CertificateValidationException(

“X509Certificate not yet valid”, e);

}

X509CertSelector certSelector = new X509CertSelector();

certSelector.setCertificate(certificate);

PKIXBuilderParameters parameters;

CertPathBuilder builder;

try {

parameters = new PKIXBuilderParameters(trustStore, certSelector);

parameters.setRevocationEnabled(false);

builder = CertPathBuilder.getInstance(“PKIX”);

} catch (Exception e) {

e.printStackTrace();

throw new CertificateValidationCallback.CertificateValidationException(

e.getMessage(), e);

}

try {

PKIXCertPathBuilderResult result = (PKIXCertPathBuilderResult) builder

.build(parameters);

} catch (Exception e) {

e.printStackTrace();

System.out

.println(“Leaving::X509CertificateValidatorImpl::validate::2”);

return false;

}

System.out

.println(“Leaving::X509CertificateValidatorImpl::validate::3”);

return true;

}

private boolean isSelfCert(X509Certificate cert)

throws CertificateValidationCallback.CertificateValidationException {

System.out

.println(“Entered::X509CertificateValidatorImpl::isSelfCert”);

try {

if (keyStore == null)

initKeyStore();

Enumeration aliases = keyStore.aliases();

while (aliases.hasMoreElements()) {

String alias = (String) aliases.nextElement();

if (keyStore.isKeyEntry(alias)) {

X509Certificate x509Cert = (X509Certificate) keyStore

.getCertificate(alias);

if (x509Cert != null) {

if (x509Cert.equals(cert))

System.out

.println(“Leaving::X509CertificateValidatorImpl::isSelfCert::1”);

return true;

}

}

}

System.out

.println(“Leaving::X509CertificateValidatorImpl::isSelfCert::2”);

return false;

} catch (Exception e) {

e.printStackTrace();

throw new CertificateValidationCallback.CertificateValidationException(

e.getMessage(), e);

}

}

}

private String getContainerHome() {

System.out

.println(“Entered::X509CertificateValidatorImpl::getContainerHome”);

String _home = “”;

String fileSeparator = System.getProperty(“file.separator”);

String contHome = System.getProperty(“catalina.home”);

if (contHome != null) {

String isAS = System.getProperty(“com.sun.aas.instanceRoot”);

if (isAS != null) {

_home = contHome + fileSeparator + “..” + fileSeparator + “..”;

} else {

_home = contHome;

}

} else {

_home = System.getProperty(“jwsdp.home”);

if (_home == null) {

_home = System.getProperty(“as.home”);

}

}

System.out

.println(“Leaving::X509CertificateValidatorImpl::getContainerHome”);

return _home;

}

}

Step 11: Create Interceptor class to handle soap requests ValidateUserTokenInterceptor.java.

package com.sungard.cxf.example.server;

import java.util.Vector;

import org.apache.cxf.message.Message;

import org.apache.cxf.phase.AbstractPhaseInterceptor;

import org.apache.cxf.phase.Phase;

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 ValidateUserTokenInterceptor extends AbstractPhaseInterceptor {

public ValidateUserTokenInterceptor(String s) {

super(s);

}

public ValidateUserTokenInterceptor() {

super(Phase.UNMARSHAL);

}

public void handleMessage(Message message) {

System.out

.println(“Enterd ValidateUserTokenInterceptor::handleMessage”);

boolean userTokenValidated = false;

Vector result = (Vector) message

.getContextualProperty(WSHandlerConstants.RECV_RESULTS);

for (int i = 0; i < result.size(); i++) {

WSHandlerResult res = (WSHandlerResult) result.get(i);

for (int j = 0; j < res.getResults().size(); j++) {

WSSecurityEngineResult secRes = (WSSecurityEngineResult) res

.getResults().get(j);

if (secRes.getPrincipal() != null) {

System.out

.println(“ValidateUserTokenInterceptor::handleMessage::Class”

+ secRes.getPrincipal().getClass());

System.out

.println(“ValidateUserTokenInterceptor::handleMessage::ClassName”

+ secRes.getPrincipal().getClass()

.getName());

System.out

.println(“ValidateUserTokenInterceptor::handleMessage::Name”

+ secRes.getPrincipal().getName());

if (secRes.getPrincipal().getClass().getName().equals(

“org.apache.ws.security.WSUsernameTokenPrincipal”)) {

System.out

.println(“ValidateUserTokenInterceptor::handleMessage::WSUsernameTokenPrincipal”

+ secRes.getPrincipal().getName());

WSUsernameTokenPrincipal principal = (WSUsernameTokenPrincipal) secRes

.getPrincipal();

System.out.println(“principal.isPasswordDigest”

+ principal.isPasswordDigest());

System.out.println(“principal.getNonce()”

+ principal.getNonce());

System.out.println(“principal.getPassword()”

+ principal.getPassword());

System.out.println(“principal.getCreatedTime()”

+ principal.getCreatedTime());

if (principal.getPassword() == null) {

throw new RuntimeException(

“Invalid Security Header”);

} else {

System.out

.println(“ValidateUserTokenInterceptor::handleMessage::userTokenValidated = true”);

userTokenValidated = true;

}

}

}

}

}

if (!userTokenValidated) {

throw new RuntimeException(“Security processing failed::Peter”);

}

System.out

.println(“Leaving ValidateUserTokenInterceptor::handleMessage”);

}

}

Step 12: Create beans.xml file to setup the application context for the server.

<?xml version=”1.0″ encoding=”UTF-8″?>

<beans xmlns=”http://www.springframework.org/schema/beans&#8221;

xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221;

xmlns:jaxws=”http://cxf.apache.org/jaxws&#8221;

xsi:schemaLocation=”

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd”&gt;

<import resource=”classpath:META-INF/cxf/cxf.xml” />

<import resource=”classpath:META-INF/cxf/cxf-extension-soap.xml” />

<import resource=”classpath:META-INF/cxf/cxf-servlet.xml” />

<jaxws:endpoint id=”helloWorld”

implementor=”com.sungard.cxf.example.server.IHello_Impl”

address=”/HelloService”>

<jaxws:inInterceptors>

<bean id=”logIn”

/>

<bean id=”logOut”

/>

<bean

/>

<bean

>

<property name=”properties”>

<map>

<entry key=”action”

value=”UsernameToken SAMLTokenUnsigned” />

<entry key=”passwordType” value=”PasswordText” />

<entry key=”enableNamespacePrefixOptimization”

value=”true” />

<entry key=”disablePrettyXML” value=”true” />

<entry key=”sendXsiTypes” value=”true” />

<entry key=”sendMultiRefs” value=”true” />

<entry key=”sendXMLDeclaration” value=”true” />

<entry key=”passwordCallbackClass”

value=”com.sungard.cxf.example.server.ServerSecurityEnvironmentHandler” />

<entry key=”signaturePropFile”

value=”server_sign.properties”>

</entry>

</map>

</property>

</bean>

<bean

/>

</jaxws:inInterceptors>

</jaxws:endpoint>

</beans>

Step 13: Create server_sign.properties under WEB-INF\classes folder to mention private keystore file details.

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=changeit

org.apache.ws.security.crypto.merlin.file=server-keystore.jks

Step 14: Copy all keystore and certificate files under WEB-INF\classes folder.

Step 15: Create web.xml file

<?xml version=”1.0″ encoding=”ISO-8859-1″?>

<!DOCTYPE web-app

PUBLIC “-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN”

http://java.sun.com/dtd/web-app_2_3.dtd”&gt;

<web-app>

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>WEB-INF/beans.xml</param-value>

</context-param>

<listener>

<listener-class>

org.springframework.web.context.ContextLoaderListener

</listener-class>

</listener>

<servlet>

<servlet-name>CXFServlet</servlet-name>

<display-name>CXF Servlet</display-name>

<servlet-class>

org.apache.cxf.transport.servlet.CXFServlet

</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>CXFServlet</servlet-name>

<url-pattern>/*</url-pattern>

</servlet-mapping>

</web-app>

Step 16: Create ant folder inside project. And Create build.xml file inside ant folder.

<?xml version=”1.0″ encoding=”UTF-8″?>

<project basedir=”../” default=”archive”>

<target name=”archive”>

<jar destfile=”samlnormalsecurity.war”>

<fileset dir=”${basedir}”>

<include name=”**/*.class” />

<include name=”**/*.jks*” />

<include name=”**/*.properties*” />

</fileset>

<fileset dir=”${basedir}”>

<include name=”**/*.jar” />

</fileset>

<fileset dir=”${basedir}”>

<include name=”**/*.xml” />

<exclude name=”**/*build*” />

</fileset>

</jar>

</target>

</project>

Step 17: Run build.xml using Ant.

Step 18: Deploy samlnormalsecurity.war into Web/Application Server (Tomcat/JBoss).

Step 19: Verify application deployed successfully or by using following url.
http://localhost:8080/samlnormalsecurity/HelloService?wsdl

Step 20: Browser will show wsdl file our web service.

 

Creating Client Application.

Step 1: Create New Java project in Eclipse

Step 2: Create folder Structure as like above application

Step 3: Use same jar files used for Server application.

Step 4: Set all the jars files into classpath.

Step 5: Create Remote Interface in client (IHello.java) (You can use wsdl2java for creating same)

package com.sungard.cxf.example.server;

import javax.jws.WebService;

@WebService

public interface IHello {

public String sayHello(String value);

}

Step 6: Create ClientSecurityEnvironmentHandler.java for handling soap request in client side. Here you have set the password what you are given client alias. You have tomention client ketstore passwords also here.

private String keyStorePassword = “changeit”;

private String trustStorePassword = “changeit”;

else if (callbacks[i] instanceof WSPasswordCallback) {

WSPasswordCallback cb = (WSPasswordCallback) callbacks[i];

System.out.println(“cb.getPassword()” + cb.getPassword());

cb.setPassword(“changeit”);

}

package com.sungard.cxf.example.server;

import java.io.IOException;

import java.math.BigInteger;

import java.net.URL;

import java.security.KeyStore;

import java.security.PrivateKey;

import java.security.cert.CertPathBuilder;

import java.security.cert.Certificate;

import java.security.cert.CertificateExpiredException;

import java.security.cert.CertificateNotYetValidException;

import java.security.cert.PKIXBuilderParameters;

import java.security.cert.PKIXCertPathBuilderResult;

import java.security.cert.X509CertSelector;

import java.security.cert.X509Certificate;

import java.text.SimpleDateFormat;

import java.util.Arrays;

import java.util.Calendar;

import java.util.Date;

import java.util.Enumeration;

import java.util.GregorianCalendar;

import javax.security.auth.callback.Callback;

import javax.security.auth.callback.CallbackHandler;

import javax.security.auth.callback.UnsupportedCallbackException;

import javax.xml.ws.BindingProvider;

import org.apache.ws.security.WSPasswordCallback;

import com.sun.xml.wss.impl.callback.CertificateValidationCallback;

import com.sun.xml.wss.impl.callback.DecryptionKeyCallback;

import com.sun.xml.wss.impl.callback.EncryptionKeyCallback;

import com.sun.xml.wss.impl.callback.PasswordCallback;

import com.sun.xml.wss.impl.callback.PasswordValidationCallback;

import com.sun.xml.wss.impl.callback.SignatureKeyCallback;

import com.sun.xml.wss.impl.callback.SignatureVerificationKeyCallback;

import com.sun.xml.wss.impl.callback.TimestampValidationCallback;

import com.sun.xml.wss.impl.callback.UsernameCallback;

import com.sun.xml.wss.impl.misc.SecurityUtil;

/**

* A sample implementation of a CallbackHandler.

*/

public class ClientSecurityEnvironmentHandler implements CallbackHandler {

private KeyStore keyStore;

private KeyStore trustStore;

private String keyStorePassword = “changeit”;

private String trustStorePassword = “changeit”;

private static final UnsupportedCallbackException unsupported = new UnsupportedCallbackException(

null, “Unsupported Callback Type Encountered”);

public ClientSecurityEnvironmentHandler() throws Exception {

System.out.println(“Entered::ClientSecurityEnvironmentHandler”);

initTrustStore();

initKeyStore();

System.out.println(“Leaving::ClientSecurityEnvironmentHandler”);

}

public void handle(Callback[] callbacks) throws IOException,

UnsupportedCallbackException {

System.out.println(“Entered::ClientSecurityEnvironmentHandler::handle”);

for (int i = 0; i < callbacks.length; i++) {

if (callbacks[i] instanceof PasswordValidationCallback) {

PasswordValidationCallback cb = (PasswordValidationCallback) callbacks[i];

if (cb.getRequest() instanceof PasswordValidationCallback.PlainTextPasswordRequest) {

cb.setValidator(new PlainTextPasswordValidator());

} else if (cb.getRequest() instanceof PasswordValidationCallback.DigestPasswordRequest) {

PasswordValidationCallback.DigestPasswordRequest request = (PasswordValidationCallback.DigestPasswordRequest) cb

.getRequest();

String username = request.getUsername();

if (“Ron”.equals(username)) {

request.setPassword(“noR”);

cb

.setValidator(new PasswordValidationCallback.DigestPasswordValidator());

}

} else {

System.out

.println(“ClientSecurityEnvironmentHandler::Handle::1”);

throw unsupported;

}

} else if (callbacks[i] instanceof TimestampValidationCallback) {

TimestampValidationCallback cb = (TimestampValidationCallback) callbacks[i];

cb.setValidator(new DefaultTimestampValidator());

} else if (callbacks[i] instanceof SignatureVerificationKeyCallback) {

SignatureVerificationKeyCallback cb = (SignatureVerificationKeyCallback) callbacks[i];

if (cb.getRequest() instanceof SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest) {

// subject keyid request

SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest request = (SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest) cb

.getRequest();

X509Certificate cert = getCertificateFromTrustStore(request

.getSubjectKeyIdentifier());

request.setX509Certificate(cert);

} else if (cb.getRequest() instanceof SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest) {

// issuer serial request

SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest request = (SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest) cb

.getRequest();

X509Certificate cert = getCertificateFromTrustStore(request

.getIssuerName(), request.getSerialNumber());

request.setX509Certificate(cert);

} else {

System.out

.println(“ClientSecurityEnvironmentHandler::Handle::2”);

throw unsupported;

}

} else if (callbacks[i] instanceof SignatureKeyCallback) {

SignatureKeyCallback cb = (SignatureKeyCallback) callbacks[i];

if (cb.getRequest() instanceof SignatureKeyCallback.DefaultPrivKeyCertRequest) {

// default priv key cert req

SignatureKeyCallback.DefaultPrivKeyCertRequest request = (SignatureKeyCallback.DefaultPrivKeyCertRequest) cb

.getRequest();

getDefaultPrivKeyCert(request);

} else if (cb.getRequest() instanceof SignatureKeyCallback.AliasPrivKeyCertRequest) {

SignatureKeyCallback.AliasPrivKeyCertRequest request = (SignatureKeyCallback.AliasPrivKeyCertRequest) cb

.getRequest();

String alias = request.getAlias();

try {

X509Certificate cert = (X509Certificate) keyStore

.getCertificate(alias);

request.setX509Certificate(cert);

// Assuming key passwords same as the keystore password

PrivateKey privKey = (PrivateKey) keyStore.getKey(

alias, keyStorePassword.toCharArray());

request.setPrivateKey(privKey);

} catch (Exception e) {

throw new IOException(e.getMessage());

}

} else {

System.out

.println(“ClientSecurityEnvironmentHandler::Handle::3”);

throw unsupported;

}

} else if (callbacks[i] instanceof DecryptionKeyCallback) {

DecryptionKeyCallback cb = (DecryptionKeyCallback) callbacks[i];

if (cb.getRequest() instanceof DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest) {

DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest request = (DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest) cb

.getRequest();

byte[] ski = request.getSubjectKeyIdentifier();

PrivateKey privKey = getPrivateKey(ski);

request.setPrivateKey(privKey);

} else if (cb.getRequest() instanceof DecryptionKeyCallback.X509IssuerSerialBasedRequest) {

DecryptionKeyCallback.X509IssuerSerialBasedRequest request = (DecryptionKeyCallback.X509IssuerSerialBasedRequest) cb

.getRequest();

String issuerName = request.getIssuerName();

BigInteger serialNumber = request.getSerialNumber();

PrivateKey privKey = getPrivateKey(issuerName, serialNumber);

request.setPrivateKey(privKey);

} else if (cb.getRequest() instanceof DecryptionKeyCallback.X509CertificateBasedRequest) {

DecryptionKeyCallback.X509CertificateBasedRequest request = (DecryptionKeyCallback.X509CertificateBasedRequest) cb

.getRequest();

X509Certificate cert = request.getX509Certificate();

PrivateKey privKey = getPrivateKey(cert);

request.setPrivateKey(privKey);

} else {

System.out

.println(“ClientSecurityEnvironmentHandler::Handle::4”);

throw unsupported;

}

} else if (callbacks[i] instanceof EncryptionKeyCallback) {

EncryptionKeyCallback cb = (EncryptionKeyCallback) callbacks[i];

if (cb.getRequest() instanceof EncryptionKeyCallback.AliasX509CertificateRequest) {

EncryptionKeyCallback.AliasX509CertificateRequest request = (EncryptionKeyCallback.AliasX509CertificateRequest) cb

.getRequest();

String alias = request.getAlias();

if (alias == null) {

// plugin code here to read the cert from the

// ThreadLocal

} else {

try {

X509Certificate cert = (X509Certificate) trustStore

.getCertificate(alias);

request.setX509Certificate(cert);

} catch (Exception e) {

throw new IOException(e.getMessage());

}

}

} else {

System.out

.println(“ClientSecurityEnvironmentHandler::Handle::5”);

throw unsupported;

}

} else if (callbacks[i] instanceof CertificateValidationCallback) {

CertificateValidationCallback cb = (CertificateValidationCallback) callbacks[i];

cb.setValidator(new X509CertificateValidatorImpl());

} else if (callbacks[i] instanceof UsernameCallback) {

UsernameCallback cb = (UsernameCallback) callbacks[i];

String username = (String) cb.getRuntimeProperties().get(

BindingProvider.USERNAME_PROPERTY);

System.out.println(“Got Username……… : ” + username);

cb.setUsername(username);

} else if (callbacks[i] instanceof PasswordCallback) {

PasswordCallback cb = (PasswordCallback) callbacks[i];

String password = (String) cb.getRuntimeProperties().get(

BindingProvider.PASSWORD_PROPERTY);

System.out.println(“Got Password……… : ” + password);

cb.setPassword(password);

} else if (callbacks[i] instanceof WSPasswordCallback) {

WSPasswordCallback cb = (WSPasswordCallback) callbacks[i];

System.out.println(“cb.getPassword()” + cb.getPassword());

cb.setPassword(“changeit”);

} else {

System.out.println(callbacks[i].getClass().getName());

System.out

.println(“ClientSecurityEnvironmentHandler::Handle::6”);

throw unsupported;

}

}

}

private void initTrustStore() throws IOException {

try {

URL truststoreURL = SecurityUtil

.loadFromClasspath(“client-truststore.jks”);

trustStore = KeyStore.getInstance(“JKS”);

trustStore.load(truststoreURL.openStream(), trustStorePassword

.toCharArray());

} catch (Exception e) {

throw new IOException(e.getMessage());

}

}

private void initKeyStore() throws IOException {

try {

URL keystoreURL = SecurityUtil

.loadFromClasspath(“client-keystore.jks”);

keyStore = KeyStore.getInstance(“JKS”);

keyStore.load(keystoreURL.openStream(), keyStorePassword

.toCharArray());

} catch (Exception e) {

throw new IOException(e.getMessage());

}

}

private X509Certificate getCertificateFromTrustStore(byte[] ski)

throws IOException {

try {

Enumeration aliases = trustStore.aliases();

while (aliases.hasMoreElements()) {

String alias = (String) aliases.nextElement();

Certificate cert = trustStore.getCertificate(alias);

if (cert == null || !”X.509″.equals(cert.getType())) {

continue;

}

X509Certificate x509Cert = (X509Certificate) cert;

byte[] keyId = getSubjectKeyIdentifier(x509Cert);

if (keyId == null) {

// Cert does not contain a key identifier

continue;

}

if (Arrays.equals(ski, keyId)) {

return x509Cert;

}

}

} catch (Exception e) {

throw new IOException(e.getMessage());

}

return null;

}

private X509Certificate getCertificateFromTrustStore(String issuerName,

BigInteger serialNumber) throws IOException {

try {

Enumeration aliases = trustStore.aliases();

while (aliases.hasMoreElements()) {

String alias = (String) aliases.nextElement();

Certificate cert = trustStore.getCertificate(alias);

if (cert == null || !”X.509″.equals(cert.getType())) {

continue;

}

X509Certificate x509Cert = (X509Certificate) cert;

String thisIssuerName = org.apache.xml.security.utils.RFC2253Parser

.normalize(x509Cert.getIssuerDN().getName());

BigInteger thisSerialNumber = x509Cert.getSerialNumber();

if (thisIssuerName.equals(issuerName)

&& thisSerialNumber.equals(serialNumber)) {

return x509Cert;

}

}

} catch (Exception e) {

throw new IOException(e.getMessage());

}

return null;

}

public PrivateKey getPrivateKey(byte[] ski) throws IOException {

try {

Enumeration aliases = keyStore.aliases();

while (aliases.hasMoreElements()) {

String alias = (String) aliases.nextElement();

if (!keyStore.isKeyEntry(alias))

continue;

Certificate cert = keyStore.getCertificate(alias);

if (cert == null || !”X.509″.equals(cert.getType())) {

continue;

}

X509Certificate x509Cert = (X509Certificate) cert;

byte[] keyId = getSubjectKeyIdentifier(x509Cert);

if (keyId == null) {

// Cert does not contain a key identifier

continue;

}

if (Arrays.equals(ski, keyId)) {

// Asuumed key password same as the keystore password

return (PrivateKey) keyStore.getKey(alias, keyStorePassword

.toCharArray());

}

}

} catch (Exception e) {

throw new IOException(e.getMessage());

}

return null;

}

public PrivateKey getPrivateKey(String issuerName, BigInteger serialNumber)

throws IOException {

try {

Enumeration aliases = keyStore.aliases();

while (aliases.hasMoreElements()) {

String alias = (String) aliases.nextElement();

if (!keyStore.isKeyEntry(alias))

continue;

Certificate cert = keyStore.getCertificate(alias);

if (cert == null || !”X.509″.equals(cert.getType())) {

continue;

}

X509Certificate x509Cert = (X509Certificate) cert;

String thisIssuerName = org.apache.xml.security.utils.RFC2253Parser

.normalize(x509Cert.getIssuerDN().getName());

BigInteger thisSerialNumber = x509Cert.getSerialNumber();

if (thisIssuerName.equals(issuerName)

&& thisSerialNumber.equals(serialNumber)) {

return (PrivateKey) keyStore.getKey(alias, keyStorePassword

.toCharArray());

}

}

} catch (Exception e) {

throw new IOException(e.getMessage());

}

return null;

}

public PrivateKey getPrivateKey(X509Certificate certificate)

throws IOException {

try {

Enumeration aliases = keyStore.aliases();

while (aliases.hasMoreElements()) {

String alias = (String) aliases.nextElement();

if (!keyStore.isKeyEntry(alias))

continue;

Certificate cert = keyStore.getCertificate(alias);

if (cert != null && cert.equals(certificate))

return (PrivateKey) keyStore.getKey(alias, keyStorePassword

.toCharArray());

}

} catch (Exception e) {

throw new IOException(e.getMessage());

}

return null;

}

private void getDefaultPrivKeyCert(

SignatureKeyCallback.DefaultPrivKeyCertRequest request)

throws IOException {

String uniqueAlias = null;

try {

Enumeration aliases = keyStore.aliases();

while (aliases.hasMoreElements()) {

String currentAlias = (String) aliases.nextElement();

if (keyStore.isKeyEntry(currentAlias)) {

Certificate thisCertificate = keyStore

.getCertificate(currentAlias);

if (thisCertificate != null) {

if (thisCertificate instanceof X509Certificate) {

if (uniqueAlias == null) {

uniqueAlias = currentAlias;

} else {

// Not unique!

uniqueAlias = null;

break;

}

}

}

}

}

if (uniqueAlias != null) {

request.setX509Certificate((X509Certificate) keyStore

.getCertificate(uniqueAlias));

request.setPrivateKey((PrivateKey) keyStore.getKey(uniqueAlias,

keyStorePassword.toCharArray()));

}

} catch (Exception e) {

throw new IOException(e.getMessage());

}

}

private static byte[] getSubjectKeyIdentifier(X509Certificate cert) {

String SUBJECT_KEY_IDENTIFIER_OID = “2.5.29.14”;

byte[] subjectKeyIdentifier = cert

.getExtensionValue(SUBJECT_KEY_IDENTIFIER_OID);

if (subjectKeyIdentifier == null)

return null;

try {

sun.security.x509.KeyIdentifier keyId = null;

sun.security.util.DerValue derVal = new sun.security.util.DerValue(

new sun.security.util.DerInputStream(subjectKeyIdentifier)

.getOctetString());

keyId = new sun.security.x509.KeyIdentifier(derVal.getOctetString());

return keyId.getIdentifier();

} catch (NoClassDefFoundError ncde) {

if (subjectKeyIdentifier == null)

return null;

byte[] dest = new byte[subjectKeyIdentifier.length – 4];

System.arraycopy(subjectKeyIdentifier, 4, dest, 0,

subjectKeyIdentifier.length – 4);

return dest;

} catch (java.io.IOException ex) {

// ignore

return null;

}

}

private class PlainTextPasswordValidator implements

PasswordValidationCallback.PasswordValidator {

public boolean validate(PasswordValidationCallback.Request request)

throws PasswordValidationCallback.PasswordValidationException {

PasswordValidationCallback.PlainTextPasswordRequest plainTextRequest = (PasswordValidationCallback.PlainTextPasswordRequest) request;

if (“Ron”.equals(plainTextRequest.getUsername())

&& “noR”.equals(plainTextRequest.getPassword())) {

return true;

}

return false;

}

}

private class DefaultTimestampValidator implements

TimestampValidationCallback.TimestampValidator {

public void validate(TimestampValidationCallback.Request request)

throws TimestampValidationCallback.TimestampValidationException {

// validate timestamp creation and expiration time.

TimestampValidationCallback.UTCTimestampRequest utcTimestampRequest = (TimestampValidationCallback.UTCTimestampRequest) request;

SimpleDateFormat calendarFormatter2 = new SimpleDateFormat(

“yyyy-MM-dd’T’HH:mm:ss’Z'”);

SimpleDateFormat calendarFormatter1 = new SimpleDateFormat(

“yyyy-MM-dd’T’HH:mm:ss’.’SSS’Z'”);

Date created = null;

Date expired = null;

try {

try {

created = calendarFormatter1.parse(utcTimestampRequest

.getCreated());

if (utcTimestampRequest.getExpired() != null)

expired = calendarFormatter1.parse(utcTimestampRequest

.getExpired());

} catch (java.text.ParseException pe) {

created = calendarFormatter2.parse(utcTimestampRequest

.getCreated());

if (utcTimestampRequest.getExpired() != null)

expired = calendarFormatter2.parse(utcTimestampRequest

.getExpired());

}

} catch (java.text.ParseException pe) {

throw new TimestampValidationCallback.TimestampValidationException(

pe.getMessage());

}

long maxClockSkew = utcTimestampRequest.getMaxClockSkew();

long timestampFreshnessLimit = utcTimestampRequest

.getTimestampFreshnessLimit();

// validate creation time

validateCreationTime(created, maxClockSkew, timestampFreshnessLimit);

// validate expiration time

if (expired != null)

validateExpirationTime(expired, maxClockSkew,

timestampFreshnessLimit);

}

}

public void validateExpirationTime(Date expires, long maxClockSkew,

long timestampFreshnessLimit)

throws TimestampValidationCallback.TimestampValidationException {

// System.out.println(“Validate Expiration time called”);

Date currentTime = getGMTDateWithSkewAdjusted(new GregorianCalendar(),

maxClockSkew, false);

if (expires.before(currentTime)) {

throw new TimestampValidationCallback.TimestampValidationException(

“The current time is ahead of the expiration time in Timestamp”);

}

}

public void validateCreationTime(Date created, long maxClockSkew,

long timestampFreshnessLimit)

throws TimestampValidationCallback.TimestampValidationException {

// System.out.println(“Validate Creation time called”);

Date current = getFreshnessAndSkewAdjustedDate(maxClockSkew,

timestampFreshnessLimit);

if (created.before(current)) {

throw new TimestampValidationCallback.TimestampValidationException(

“The creation time is older than ”

+ ” currenttime – timestamp-freshness-limit – max-clock-skew”);

}

Date currentTime = getGMTDateWithSkewAdjusted(new GregorianCalendar(),

maxClockSkew, true);

if (currentTime.before(created)) {

throw new TimestampValidationCallback.TimestampValidationException(

“The creation time is ahead of the current time.”);

}

}

private static Date getFreshnessAndSkewAdjustedDate(long maxClockSkew,

long timestampFreshnessLimit) {

Calendar c = new GregorianCalendar();

long offset = c.get(Calendar.ZONE_OFFSET);

if (c.getTimeZone().inDaylightTime(c.getTime())) {

offset += c.getTimeZone().getDSTSavings();

}

long beforeTime = c.getTimeInMillis();

long currentTime = beforeTime – offset;

long adjustedTime = currentTime – maxClockSkew

– timestampFreshnessLimit;

c.setTimeInMillis(adjustedTime);

return c.getTime();

}

private static Date getGMTDateWithSkewAdjusted(Calendar c,

long maxClockSkew, boolean addSkew) {

long offset = c.get(Calendar.ZONE_OFFSET);

if (c.getTimeZone().inDaylightTime(c.getTime())) {

offset += c.getTimeZone().getDSTSavings();

}

long beforeTime = c.getTimeInMillis();

long currentTime = beforeTime – offset;

if (addSkew)

currentTime = currentTime + maxClockSkew;

else

currentTime = currentTime – maxClockSkew;

c.setTimeInMillis(currentTime);

return c.getTime();

}

private class X509CertificateValidatorImpl implements

CertificateValidationCallback.CertificateValidator {

public boolean validate(X509Certificate certificate)

throws CertificateValidationCallback.CertificateValidationException {

if (isSelfCert(certificate)) {

return true;

}

try {

certificate.checkValidity();

} catch (CertificateExpiredException e) {

e.printStackTrace();

throw new CertificateValidationCallback.CertificateValidationException(

“X509Certificate Expired”, e);

} catch (CertificateNotYetValidException e) {

e.printStackTrace();

throw new CertificateValidationCallback.CertificateValidationException(

“X509Certificate not yet valid”, e);

}

X509CertSelector certSelector = new X509CertSelector();

certSelector.setCertificate(certificate);

PKIXBuilderParameters parameters;

CertPathBuilder builder;

try {

parameters = new PKIXBuilderParameters(trustStore, certSelector);

parameters.setRevocationEnabled(false);

builder = CertPathBuilder.getInstance(“PKIX”);

} catch (Exception e) {

e.printStackTrace();

throw new CertificateValidationCallback.CertificateValidationException(

e.getMessage(), e);

}

try {

PKIXCertPathBuilderResult result = (PKIXCertPathBuilderResult) builder

.build(parameters);

} catch (Exception e) {

e.printStackTrace();

return false;

}

return true;

}

private boolean isSelfCert(X509Certificate cert)

throws CertificateValidationCallback.CertificateValidationException {

try {

if (keyStore == null)

initKeyStore();

Enumeration aliases = keyStore.aliases();

while (aliases.hasMoreElements()) {

String alias = (String) aliases.nextElement();

if (keyStore.isKeyEntry(alias)) {

X509Certificate x509Cert = (X509Certificate) keyStore

.getCertificate(alias);

if (x509Cert != null) {

if (x509Cert.equals(cert))

return true;

}

}

}

return false;

} catch (Exception e) {

e.printStackTrace();

throw new CertificateValidationCallback.CertificateValidationException(

e.getMessage(), e);

}

}

}

private String getContainerHome() {

String _home = “”;

String fileSeparator = System.getProperty(“file.separator”);

String contHome = System.getProperty(“catalina.home”);

if (contHome != null) {

String isAS = System.getProperty(“com.sun.aas.instanceRoot”);

if (isAS != null) {

_home = contHome + fileSeparator + “..” + fileSeparator + “..”;

} else {

_home = contHome;

}

} else {

_home = System.getProperty(“jwsdp.home”);

if (_home == null) {

_home = System.getProperty(“as.home”);

}

}

return _home;

}

}

Step 7: Create the service factory (AuthServiceFactory.java), which is extremely easy since all the work was done in the Spring file:

package com.sungard.cxf.example.server;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public final class AuthServiceFactory {

private static final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(

new String[] { “cxfClient.xml” });

public AuthServiceFactory() {

}

public IHello getService() {

return (IHello) context.getBean(“client”);

}

}

Step 8: Create Client.java to invoke the service.

package com.sungard.cxf.example.server;

public final class Client {

private Client() {

}

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

AuthServiceFactory af = new AuthServiceFactory();

IHello client1 = af.getService();

String response1 = client1.sayHello(“Hello”);

System.out.println(“Response: ” + response1);

}

}

Step 9: Create cxfClient.xml to setup the application context for the client.

<?xml version=”1.0″ encoding=”UTF-8″?>

<beans xmlns=”http://www.springframework.org/schema/beans&#8221;

xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221;

xmlns:jaxws=”http://cxf.apache.org/jaxws&#8221;

xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd

http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd”&gt;

<bean id=”proxyFactory”

>

<property name=”serviceClass”

value=”com.sungard.cxf.example.server.IHello” />

<property name=”address”

value=”http://localhost:8080/samlnormalsecurity/HelloService&#8221; />

<property name=”inInterceptors”>

<list>

<ref bean=”logIn” />

</list>

</property>

<property name=”outInterceptors”>

<list>

<ref bean=”logOut” />

<ref bean=”saajOut” />

<ref bean=”wss4jOut” />

</list>

</property>

</bean>

<bean id=”client”

factory-bean=”proxyFactory” factory-method=”create” />

<bean id=”logIn”

/>

<bean id=”logOut”

/>

<bean id=”saajOut”

/>

<bean id=”wss4jOut”

>

<constructor-arg>

<map>

<entry key=”action” value=”UsernameToken SAMLTokenUnsigned” />

<entry key=”user” value=”xws-security-client” />

<entry key=”passwordType” value=”PasswordText” />

<entry key=”samlPropFile” value=”saml2.properties”/>

<entry key=”enableNamespacePrefixOptimization” value=”true”/>

<entry key=”disablePrettyXML” value=”true”/>

<entry key=”sendXsiTypes” value=”true”/>

<entry key=”sendMultiRefs” value=”true”/>

<entry key=”sendXMLDeclaration” value=”true”/>

<entry key=”passwordCallbackClass”

value=”com.sungard.cxf.example.server.ClientSecurityEnvironmentHandler” />

</map>

</constructor-arg>

</bean>

</beans>

Step 11:  Create client_sign.properties file under WEB-INF\classes folder. To give public keystore file details.

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=changeit

org.apache.ws.security.crypto.merlin.keystore.alias=xws-security-client

org.apache.ws.security.crypto.merlin.file=client-keystore.jks

Step 12:  Create saml2.properties file under WEB-INF\classes folder. To give public keystore file details.

org.apache.ws.security.saml.issuerClass=org.apache.ws.security.saml.SAMLIssuerImpl

org.apache.ws.security.saml.issuer.cryptoProp.file=client_sign.properties

org.apache.ws.security.saml.issuer=www.example.com

org.apache.ws.security.saml.subjectNameId.name=xws-security-client

org.apache.ws.security.saml.subjectNameId.qualifier=www.example.com

org.apache.ws.security.saml.authenticationMethod=password

org.apache.ws.security.saml.confirmationMethod=senderVouches

org.apache.ws.security.saml.issuer.key.name=xws-security-client

org.apache.ws.security.saml.issuer.key.password=changeit

Step 13:  Copy keystore and certificates in WEB-INF\classes folder. (Or set it in classpath)

Step 14:  Run Client.java

You will get response like as follows.

Response: You SaidHello

Note:

Client Side:

We Set User name in client cxfClient.xml file. That is public alias name.  (We can set the same through program also and we can read it xml/properties files. We can pass the same in runtime also)

<entry key=”user” value=”xws-security-client” />

We Set password in ClientSecurityEnvironmentHandler.java class (We can pass same in runtime also)

// set the password for our message.

pc.setPassword(“changeit”);

You can see the In & Outbound Messages in Client Side. As like as follows. This will go with signature.

INFO: Outbound Message

—————————

Encoding: UTF-8

Headers: {SOAPAction=[“”], Accept=[*]}

Messages:

Payload: <soap:Envelope xmlns:soap=”http://schemas.xmlsoap.org/soap/envelope/”&gt;

<soap:Header>

<wsse:Security xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd&#8221; soap:mustUnderstand=”1″><Assertion xmlns=”urn:oasis:names:tc:SAML:1.0:assertion” xmlns:saml=”urn:oasis:names:tc:SAML:1.0:assertion” xmlns:samlp=”urn:oasis:names:tc:SAML:1.0:protocol” AssertionID=”b58cef8ed07e7a8c1be2d099e73ba075″ IssueInstant=”2008-04-04T05:13:59.068Z” Issuer=”www.example.com” MajorVersion=”1″ MinorVersion=”1″><AuthenticationStatement AuthenticationInstant=”2008-04-04T05:13:58.896Z” AuthenticationMethod=”urn:oasis:names:tc:SAML:1.0:am:password”><Subject><NameIdentifier NameQualifier=”www.example.com”>xws-security-client</NameIdentifier><SubjectConfirmation><ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:sender-vouches</ConfirmationMethod></SubjectConfirmation></Subject></AuthenticationStatement></Assertion><wsse:UsernameToken xmlns:wsu=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd&#8221; wsu:Id=”UsernameToken-24451742″ xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”><wsse:Username xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”>xws-security-client</wsse:Username><wsse:Password Type=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText&#8221; xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”>changeit</wsse:Password></wsse:UsernameToken></wsse:Security></soap:Header><soap:Body><ns1:sayHello xmlns:ns1=”http://server.example.cxf.sungard.com/”><arg0>Hello</arg0></ns1:sayHello></soap:Body></soap:Envelope&gt;

————————————–

Apr 4, 2008 10:44:10 AM org.apache.cxf.interceptor.LoggingInInterceptor logging

INFO: Inbound Message

—————————-

Encoding: UTF-8

Headers: {Content-Length=[230], Date=[Fri, 04 Apr 2008 05:14:10 GMT], SOAPAction=[“”], Server=[Apache-Coyote/1.1], content-type=[text/xml;charset=UTF-8]}

Messages:

Message:

Payload: <soap:Envelope xmlns:soap=”http://schemas.xmlsoap.org/soap/envelope/”><soap:Body><ns1:sayHelloResponse xmlns:ns1=”http://server.example.cxf.sungard.com/”><return>You SaidHello</return></ns1:sayHelloResponse></soap:Body></soap:Envelope>

————————————–

September 4, 2009 - Posted by | Web Services

5 Comments »

  1. Hi Peter,

    Excellent Article, good work….

    Can u able to share the working source code for me ?…….

    Thanks & Regards,
    Ibrahim

    Comment by Ibrahim | November 26, 2010 | Reply

  2. Hi Peter,

    Good Article!!

    Can you send me the source code?
    Regards,
    Gerard

    Comment by Gerard | March 11, 2011 | Reply

  3. Dude I got this finally working the links that were helpful to me was not your blog actually but the following :
    http://coheigea.blogspot.com/2011/04/saml-support-in-cxf-240.html

    if you plan on providing any code in future please consider releasing it in the form of Jar or a war or a zip file at a location it could save grey hair for many

    Comment by Naga | May 9, 2011 | Reply

  4. it’s impossible to read this post. can you format the code, please?

    Comment by andrej | August 24, 2011 | Reply

  5. thanks for creating a blog on this…. consider using a code formatter to help your blog readers and a link to the repo…

    Comment by Balaji Krishnan | July 13, 2014 | Reply


Leave a comment