From 28a12ad95c925738b65080ee0edfb693c1e2405c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Franti=C5=A1ek=20Dvo=C5=99=C3=A1k?= Date: Mon, 29 Sep 2008 16:44:18 +0000 Subject: [PATCH] Copy "pure Java" web services example to the CVS. --- .../examples/webservices/java/Makefile | 27 ++++++ .../examples/webservices/java/README | 28 ++++++ .../java/src/ExampleSSLSocketFactory.java | 108 +++++++++++++++++++++ .../webservices/java/src/LBClientExample.java | 79 +++++++++++++++ .../webservices/java/src/MyX509KeyManager.java | 64 ++++++++++++ .../webservices/java/src/MyX509TrustManager.java | 83 ++++++++++++++++ .../examples/webservices/java/src/log4j.properties | 30 ++++++ 7 files changed, 419 insertions(+) create mode 100644 org.glite.lb.client/examples/webservices/java/Makefile create mode 100644 org.glite.lb.client/examples/webservices/java/README create mode 100644 org.glite.lb.client/examples/webservices/java/src/ExampleSSLSocketFactory.java create mode 100644 org.glite.lb.client/examples/webservices/java/src/LBClientExample.java create mode 100644 org.glite.lb.client/examples/webservices/java/src/MyX509KeyManager.java create mode 100644 org.glite.lb.client/examples/webservices/java/src/MyX509TrustManager.java create mode 100644 org.glite.lb.client/examples/webservices/java/src/log4j.properties diff --git a/org.glite.lb.client/examples/webservices/java/Makefile b/org.glite.lb.client/examples/webservices/java/Makefile new file mode 100644 index 0000000..4a24541 --- /dev/null +++ b/org.glite.lb.client/examples/webservices/java/Makefile @@ -0,0 +1,27 @@ +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 diff --git a/org.glite.lb.client/examples/webservices/java/README b/org.glite.lb.client/examples/webservices/java/README new file mode 100644 index 0000000..0af4d6b --- /dev/null +++ b/org.glite.lb.client/examples/webservices/java/README @@ -0,0 +1,28 @@ +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 https://host:9003 diff --git a/org.glite.lb.client/examples/webservices/java/src/ExampleSSLSocketFactory.java b/org.glite.lb.client/examples/webservices/java/src/ExampleSSLSocketFactory.java new file mode 100644 index 0000000..f06b6ad --- /dev/null +++ b/org.glite.lb.client/examples/webservices/java/src/ExampleSSLSocketFactory.java @@ -0,0 +1,108 @@ +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; + } + +} diff --git a/org.glite.lb.client/examples/webservices/java/src/LBClientExample.java b/org.glite.lb.client/examples/webservices/java/src/LBClientExample.java new file mode 100644 index 0000000..07d4fcc --- /dev/null +++ b/org.glite.lb.client/examples/webservices/java/src/LBClientExample.java @@ -0,0 +1,79 @@ +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 []"); + 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; + } + +} diff --git a/org.glite.lb.client/examples/webservices/java/src/MyX509KeyManager.java b/org.glite.lb.client/examples/webservices/java/src/MyX509KeyManager.java new file mode 100644 index 0000000..96e4a40 --- /dev/null +++ b/org.glite.lb.client/examples/webservices/java/src/MyX509KeyManager.java @@ -0,0 +1,64 @@ +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; + } +} diff --git a/org.glite.lb.client/examples/webservices/java/src/MyX509TrustManager.java b/org.glite.lb.client/examples/webservices/java/src/MyX509TrustManager.java new file mode 100644 index 0000000..c88f96f --- /dev/null +++ b/org.glite.lb.client/examples/webservices/java/src/MyX509TrustManager.java @@ -0,0 +1,83 @@ +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"); + } +} diff --git a/org.glite.lb.client/examples/webservices/java/src/log4j.properties b/org.glite.lb.client/examples/webservices/java/src/log4j.properties new file mode 100644 index 0000000..cfdcee3 --- /dev/null +++ b/org.glite.lb.client/examples/webservices/java/src/log4j.properties @@ -0,0 +1,30 @@ +# 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 -- 1.8.2.3