--- /dev/null
+CLASSPATH:=${shell echo `find lib -type f | tr '\n' ':'`build}
+
+all: wsdl build
+
+wsdl: build/org/glite/wsdl/services/lb/stubs
+
+build: build/org/glite/wsdl/services/lb/example
+
+run:
+ if test -z "${FILE}" -o -z "${PASS}"; then echo 'Specify FILE and PASS variables.'; exit 1; fi
+ java -classpath $(CLASSPATH) org.glite.wsdl.services.lb.example.LBClientExample ${FILE} ${PASS} ${ENDPOINT}
+
+clean:
+ rm -rvf build/
+
+build/org/glite/wsdl/services/lb/stubs:
+ java -classpath $(CLASSPATH) org.apache.axis.wsdl.WSDL2Java -v \
+ --buildFile \
+ --package org.glite.wsdl.services.lb.stubs \
+ --output build \
+ http://egee.cesnet.cz/cms/export/sites/egee/en/WSDL/HEAD/LB.wsdl
+
+build/org/glite/wsdl/services/lb/example:
+ -mkdir build
+ javac -classpath $(CLASSPATH) -d build src/*.java build/org/glite/wsdl/services/lb/{stubs,stubs/holders}/*.java
+
+.PHONY: all wsdl run clean
--- /dev/null
+How to build
+============
+
+1) copy following files to lib/ directory:
+
+axis-ant.jar
+axis.jar
+commons-discovery-0.2.jar
+commons-logging-1.0.4.jar
+jaxrpc.jar
+log4j.properties
+log4j-1.2.13.jar
+saaj.jar
+wsdl4j-1.5.1.jar
+
+2) generate source stubs and build the example by:
+
+ make
+
+
+Launch
+======
+
+ make run FILE=file.p12 PASS=passphrase ENDPOINT=https://host:9003
+
+or:
+
+ java -cp `find lib -type f | tr '\n' ':'`:build org.glite.wsdl.services.lb.example.LBClientExample <file.p12> <passphrase> https://host:9003
--- /dev/null
+package org.glite.wsdl.services.lb.example;
+
+import org.apache.axis.components.net.BooleanHolder;
+import org.apache.axis.components.net.DefaultSocketFactory;
+import org.apache.axis.components.net.SecureSocketFactory;
+import org.apache.log4j.Logger;
+
+import javax.net.ssl.*;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Hashtable;
+
+/**
+ * Factory for SSLSockets for Axis, which creates sockets for SSLv3 connection.
+ * Globus SSL libraries don't support SSLv2 initial packet, so SSLv2Hello protocol
+ * on SSLSocket must be disabled.
+ *
+ * @author Martin Kuba makub@ics.muni.cz
+ */
+public class ExampleSSLSocketFactory extends DefaultSocketFactory implements SecureSocketFactory {
+
+ static Logger log = Logger.getLogger(ExampleSSLSocketFactory.class);
+
+ static Certificate[] cChain = null;
+ static PrivateKey pKey = null;
+ static X509Certificate[] certAuths = null;
+
+ static void registerForAxis(Certificate[] certs, PrivateKey privateKey, X509Certificate[] certificateAuthorities) {
+ log.debug("registering as Axis SecureSocketFactory");
+ cChain = certs;
+ pKey = privateKey;
+ certAuths = certificateAuthorities;
+ System.setProperty("org.apache.axis.components.net.SecureSocketFactory", ExampleSSLSocketFactory.class.getName());
+ }
+
+ protected SSLSocketFactory sslFactory = null;
+
+ public ExampleSSLSocketFactory(Hashtable attributes) throws Exception {
+ super(attributes);
+ SSLContext sctx = SSLContext.getInstance("SSL");
+ KeyManager[] myKeys = new KeyManager[]{new MyX509KeyManager(cChain, pKey)};
+ TrustManager[] myTrust = new TrustManager[]{new MyX509TrustManager(certAuths)};
+ //init SSLContext with our keymanager and trustmanager, and default random device
+ sctx.init(myKeys, myTrust, null);
+ if (log.isDebugEnabled()) {
+ log.debug("attributes: " + attributes);
+ log.debug("SSLContext.provider: " + sctx.getProvider().getInfo());
+ }
+ sslFactory = sctx.getSocketFactory();
+ }
+
+
+ public Socket create(String host, int port, StringBuffer otherHeaders, BooleanHolder useFullURL) throws IOException, SocketException {
+ int i;
+
+ log.debug("create(" + host + ":" + port + ")");
+ //create SSL socket
+ SSLSocket socket = (SSLSocket) sslFactory.createSocket();
+ //enable only SSLv3
+ socket.setEnabledProtocols(new String[]{"SSLv3"}); // SSLv2Hello, SSLv3,TLSv1
+ //enable only ciphers without RC4 (some bug, probably in older globus)
+ String[] ciphers = socket.getEnabledCipherSuites();
+ ArrayList al = new ArrayList(ciphers.length);
+ for (i = 0; i < ciphers.length; i++) {
+ if (ciphers[i].indexOf("RC4") == -1) al.add(ciphers[i]);
+ }
+ socket.setEnabledCipherSuites((String [])al.toArray(new String[al.size()]));
+ //connect as client
+ socket.setUseClientMode(true);
+ socket.setSoTimeout(30000); //read timeout
+ socket.connect(new InetSocketAddress(host, port), 3000); //connect timeout
+ //create or join a SSL session
+ SSLSession sess = socket.getSession();
+ if (sess == null) {
+ log.debug("sess is null");
+ return socket;
+ }
+
+ if (log.isDebugEnabled()) {
+ //print all we know
+ byte[] id = sess.getId();
+ StringBuffer sb = new StringBuffer(id.length * 2);
+ for (i = 0; i < id.length; i++) {
+ sb.append(Integer.toHexString(id[i] < 0 ? 256 - id[i] : id[i]));
+ }
+ log.debug("SSLSession.id = " + sb.toString());
+// log.debug("peerHost:Port = " + sess.getPeerHost() + ":" + sess.getPeerPort());
+ log.debug("cipherSuite = " + sess.getCipherSuite());
+ log.debug("protocol = " + sess.getProtocol());
+// log.debug("isValid = " + sess.isValid());
+ log.debug("creationTime = " + (new Date(sess.getCreationTime())));
+ log.debug("lastAccessedTime= " + (new Date(sess.getLastAccessedTime())));
+// log.debug("applicationBufferSize= " + sess.getApplicationBufferSize());
+// log.debug("packetBufferSize= " + sess.getPacketBufferSize());
+// log.debug("localPrincipal= " + sess.getLocalPrincipal());
+// log.debug("peerPrincipal= " + sess.getPeerPrincipal());
+ }
+ return socket;
+ }
+
+}
--- /dev/null
+package org.glite.wsdl.services.lb.example;
+
+import org.apache.log4j.Logger;
+import org.glite.wsdl.services.lb.stubs.LoggingAndBookkeepingPortType;
+import org.glite.wsdl.services.lb.stubs.LoggingAndBookkeeping_ServiceLocator;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Enumeration;
+
+/**
+ * Example client of LoggingAndBookkeeping web service. Please note that the client depends
+ * only on Axis and Log4j libraries, it uses cryptography included in the JDK.
+ *
+ * @author Martin Kuba makub@ics.muni.cz
+ * @version $Id$
+ */
+public class LBClientExample {
+ static Logger log = Logger.getLogger(LBClientExample.class);
+
+ public static void main(String[] args) throws Exception {
+ if(args.length<2) {
+ System.out.println("usage: java LBClientExample <keystore.p12> <password> [<url>]");
+ System.exit(-1);
+ }
+ File keyfile = new File(args[0]);
+ String password = args[1];
+ URL url = new URL("https://localhost:9003/");
+ if(args.length==3) {
+ url = new URL(args[2]);
+ }
+
+ //read in a keystore file
+ KeyStore ks = readKeyStoreFile(keyfile, password);
+ //find key alias (name)
+ String alias = null;
+ for (Enumeration en = ks.aliases(); en.hasMoreElements();) {
+ alias = (String)en.nextElement();
+ if (ks.isKeyEntry(alias)) break;
+ else alias = null;
+ }
+ if (alias == null) throw new RuntimeException("the keystore contains no keys");
+ //get my private key and certificates
+ Certificate[] certs = ks.getCertificateChain(alias);
+ PrivateKey key = (PrivateKey) ks.getKey(alias, password.toCharArray());
+ //use my CA as the only trusted certificate authority
+ X509Certificate[] trustedCertAuths = new X509Certificate[]{(X509Certificate) certs[certs.length - 1]};
+
+ //register our SSL handling
+ ExampleSSLSocketFactory.registerForAxis(certs, key, trustedCertAuths);
+
+ //get client stub
+ LoggingAndBookkeepingPortType lb = new LoggingAndBookkeeping_ServiceLocator().getLoggingAndBookkeeping(url);
+
+ //call the service
+ String version = lb.getVersion(null);
+ System.out.println("LB version: " + version);
+ }
+
+ public static KeyStore readKeyStoreFile(File ksfile, String password) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
+ String kstype;
+ if (ksfile.getName().endsWith("ks")) kstype = "JKS";
+ else if (ksfile.getName().endsWith(".p12")) kstype = "PKCS12";
+ else throw new IOException("Only JKS (*ks) and PKCS12 (*.p12) files are supported ");
+ KeyStore store = KeyStore.getInstance(kstype);
+ store.load(new FileInputStream(ksfile), password != null ? password.toCharArray() : null);
+ return store;
+ }
+
+}
--- /dev/null
+package org.glite.wsdl.services.lb.example;
+
+import org.apache.log4j.Logger;
+
+import javax.net.ssl.X509KeyManager;
+import java.net.Socket;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+
+/**
+ * Implementation of X509KeyManager, which always returns one pair of a private key and certificate chain.
+ */
+public class MyX509KeyManager implements X509KeyManager {
+ static Logger log = Logger.getLogger(MyX509KeyManager.class);
+ private final X509Certificate[] certChain;
+ private final PrivateKey key;
+
+ public MyX509KeyManager(Certificate[] cchain, PrivateKey key) {
+ this.certChain = new X509Certificate[cchain.length];
+ System.arraycopy(cchain, 0, this.certChain, 0, cchain.length);
+ this.key = key;
+ }
+
+ //not used
+ public String[] getClientAliases(String string, Principal[] principals) {
+ log.debug("getClientAliases()");
+ return null;
+ }
+
+
+ // Intented to be implemented by GUI for user interaction, but we have only one key.
+ public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
+ if (log.isDebugEnabled()) {
+ log.debug("chooseClientAlias()");
+ for (int i = 0; i < keyType.length; i++) log.debug("keyType[" + i + "]=" + keyType[i]);
+ for (int i = 0; i < issuers.length; i++) log.debug("issuers[" + i + "]=" + issuers[i]);
+ }
+ return "thealias";
+ }
+
+ //not used on a client
+ public String[] getServerAliases(String string, Principal[] principals) {
+ log.debug("getServerAliases()");
+ return null;
+ }
+
+ //not used on a client
+ public String chooseServerAlias(String string, Principal[] principals, Socket socket) {
+ log.debug("chooseServerAlias()");
+ return null;
+ }
+
+ public X509Certificate[] getCertificateChain(String alias) {
+ log.debug("getCertificateChain()");
+ return certChain;
+ }
+
+ public PrivateKey getPrivateKey(String alias) {
+ log.debug("getPrivateKey()");
+ return key;
+ }
+}
--- /dev/null
+package org.glite.wsdl.services.lb.example;
+
+import org.apache.log4j.Logger;
+
+import javax.net.ssl.X509TrustManager;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.*;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Simple trust manager validating server certificates against supplied trusted CAs.
+ *
+ * @author Martin Kuba makub@ics.muni.cz
+ * @version $Id$
+ */
+public class MyX509TrustManager implements X509TrustManager {
+ static Logger log = Logger.getLogger(MyX509TrustManager.class);
+ private final X509Certificate[] certificateAuthorities;
+ private final Set trustAnchors;
+
+ /**
+ * Creates an instance with supplied trusted root CAs.
+ * @param certificateAuthorities
+ */
+ public MyX509TrustManager(X509Certificate[] certificateAuthorities) {
+ int i;
+
+ this.certificateAuthorities = certificateAuthorities;
+ this.trustAnchors = new HashSet();
+ for (i = 0; i < certificateAuthorities.length; i++) {
+ this.trustAnchors.add(new TrustAnchor(certificateAuthorities[i], null));
+ }
+ }
+
+ //not used on a client
+ public X509Certificate[] getAcceptedIssuers() {
+ log.debug("getAcceptedIssuers()");
+ return this.certificateAuthorities;
+ }
+
+ //not used on a client
+ public void checkClientTrusted(X509Certificate[] certs, String authType) {
+ log.debug("checkClientTrusted()");
+ }
+
+ /**
+ * Validates certificate chain sent by a server against trusted CAs.
+ * @param certs
+ * @param authType
+ * @throws CertificateException
+ */
+ public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
+ if (log.isDebugEnabled()) {
+ log.debug("checkServerTrusted(certs: "+ certs.length + ", authType=" + authType+")");
+ for (int i = 0; i < certs.length; i++) {
+ log.debug("cert[" + i + "]=" + certs[i].getSubjectX500Principal().toString());
+ }
+ }
+ //validate server certificate
+ try {
+ PKIXParameters pkixParameters = new PKIXParameters(this.trustAnchors);
+ pkixParameters.setRevocationEnabled(false);
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509");
+ CertPath path = certFact.generateCertPath(Arrays.asList(certs));
+ CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX");
+ certPathValidator.validate(path, pkixParameters);
+ } catch (NoSuchAlgorithmException e) {
+ log.error(e.getMessage(), e);
+ } catch (InvalidAlgorithmParameterException e) {
+ log.error(e.getMessage(), e);
+ } catch (CertPathValidatorException e) {
+ CertificateException ce;
+ log.error(e.getMessage(), e);
+ ce = new CertificateException(e.getMessage());
+ ce.setStackTrace(e.getStackTrace());
+ throw ce;
+ }
+ log.debug("server is trusted");
+ }
+}
--- /dev/null
+# Set root category priority to INFO and its only appender to CONSOLE.
+# names CONSOLE, R, F are arbitrary
+log4j.rootCategory=INFO, CONSOLE
+
+# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
+log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
+log4j.logger.org.apache.axis.utils.JavaUtils=FATAL
+log4j.logger.org.glite.wsdl.services.lb=DEBUG
+
+# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
+log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
+log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
+#viz http://logging.apache.org/log4j/docs/api/org/apache/log4j/PatternLayout.html
+# %d - date
+# %t - thread
+# %p - priority
+# %c{1} - category (jmeno loggeru) s poctem zobrazovanych casti oddelenych teckou
+# %m - message
+# %n - line separator
+log4j.appender.CONSOLE.layout.ConversionPattern=%d [%t] %-5p %c{1} - %m%n
+
+log4j.appender.F=org.apache.log4j.FileAppender
+log4j.appender.F.File=txt.log
+log4j.appender.F.layout=org.apache.log4j.PatternLayout
+log4j.appender.F.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
+
+log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.R.File=xml.log
+log4j.appender.R.layout=org.apache.log4j.xml.XMLLayout
+log4j.appender.R.DatePattern='.'yyyy-MM-dd