aboutsummaryrefslogtreecommitdiff
path: root/id.server/src/at/gv/egovernment/moa/id/util
diff options
context:
space:
mode:
Diffstat (limited to 'id.server/src/at/gv/egovernment/moa/id/util')
-rw-r--r--id.server/src/at/gv/egovernment/moa/id/util/AxisSecureSocketFactory.java213
-rw-r--r--id.server/src/at/gv/egovernment/moa/id/util/MOAIDMessageProvider.java58
-rw-r--r--id.server/src/at/gv/egovernment/moa/id/util/Random.java22
-rw-r--r--id.server/src/at/gv/egovernment/moa/id/util/SSLUtils.java156
4 files changed, 449 insertions, 0 deletions
diff --git a/id.server/src/at/gv/egovernment/moa/id/util/AxisSecureSocketFactory.java b/id.server/src/at/gv/egovernment/moa/id/util/AxisSecureSocketFactory.java
new file mode 100644
index 000000000..8967bdbba
--- /dev/null
+++ b/id.server/src/at/gv/egovernment/moa/id/util/AxisSecureSocketFactory.java
@@ -0,0 +1,213 @@
+package at.gv.egovernment.moa.id.util;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.Socket;
+import java.security.GeneralSecurityException;
+import java.util.Hashtable;
+
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+import org.apache.axis.components.net.BooleanHolder;
+import org.apache.axis.components.net.DefaultSocketFactory;
+import org.apache.axis.components.net.SecureSocketFactory;
+import org.apache.axis.components.net.TransportClientProperties;
+import org.apache.axis.components.net.TransportClientPropertiesFactory;
+import org.apache.axis.utils.Messages;
+import org.apache.axis.utils.XMLUtils;
+
+import at.gv.egovernment.moa.logging.Logger;
+
+/**
+ * Secure socket factory for Axis webs service clients of the MOA-ID component,
+ * which are the MOA-SP calls from MOA-ID Auth,
+ * and the MOA-ID Auth calls from MOA-ID Proxy.
+ * <br/>Use this initialization code:<br/>
+ * <code> // ConnectionParameter connParam = ... get from ConfigurationProvider
+ * AxisSecureSocketFactory.initialize(connParam);</code>
+ * <br/>See the Apache Axis documentation on how to configure this class
+ * as the default secure socket factory to be used by Axis.
+ * <br/>
+ * This code has been copied from <code>JSSESocketFactory</code>, the
+ * method <code>initialize()</code> has been added.
+ *
+ *
+ * @author Paul Ivancsics
+ * @version $Id$
+ */
+public class AxisSecureSocketFactory
+ extends DefaultSocketFactory implements SecureSocketFactory {
+
+ /** Field sslFactory */
+ private static SSLSocketFactory sslFactory;
+
+ /**
+ * Constructor for AxisSecureSocketFactory.
+ * @param attributes ???
+ */
+ public AxisSecureSocketFactory(Hashtable attributes) {
+ super(attributes);
+ }
+ /**
+ * Initializes the factory by setting the connection parameters to be used for
+ * setting the secure socket factory, and by setting the system property
+ * <code>axis.socketSecureFactory</code>.
+ * @param connParam <code>ConnectionParameter</code> to derive the
+ * secure socket factory from
+ */
+ public static void initialize(SSLSocketFactory ssf)
+ throws IOException, GeneralSecurityException {
+
+ Logger.debug("Initialize AxisSecureSocketFactory");
+ sslFactory = ssf;
+ }
+
+ /**
+ * creates a secure socket
+ *
+ * @param host
+ * @param port
+ * @param otherHeaders
+ * @param useFullURL
+ *
+ * @return Socket
+ * @throws Exception
+ */
+ public Socket create(
+ String host,
+ int port,
+ StringBuffer otherHeaders,
+ BooleanHolder useFullURL)
+ throws Exception {
+ if (port == -1) {
+ port = 443;
+ }
+
+ TransportClientProperties tcp =
+ TransportClientPropertiesFactory.create("https");
+
+ boolean hostInNonProxyList =
+ isHostInNonProxyList(host, tcp.getNonProxyHosts());
+
+ Socket sslSocket = null;
+ if (tcp.getProxyHost().length() == 0 || hostInNonProxyList) {
+ // direct SSL connection
+ sslSocket = sslFactory.createSocket(host, port);
+ }
+ else {
+
+ // Default proxy port is 80, even for https
+ int tunnelPort =
+ (tcp.getProxyPort().length() != 0)
+ ? Integer.parseInt(tcp.getProxyPort())
+ : 80;
+ if (tunnelPort < 0)
+ tunnelPort = 80;
+
+ // Create the regular socket connection to the proxy
+ Socket tunnel = new Socket(tcp.getProxyHost(), tunnelPort);
+
+ // The tunnel handshake method (condensed and made reflexive)
+ OutputStream tunnelOutputStream = tunnel.getOutputStream();
+ PrintWriter out =
+ new PrintWriter(
+ new BufferedWriter(new OutputStreamWriter(tunnelOutputStream)));
+
+ // More secure version... engage later?
+ // PasswordAuthentication pa =
+ // Authenticator.requestPasswordAuthentication(
+ // InetAddress.getByName(tunnelHost),
+ // tunnelPort, "SOCK", "Proxy","HTTP");
+ // if(pa == null){
+ // printDebug("No Authenticator set.");
+ // }else{
+ // printDebug("Using Authenticator.");
+ // tunnelUser = pa.getUserName();
+ // tunnelPassword = new String(pa.getPassword());
+ // }
+ out.print(
+ "CONNECT "
+ + host
+ + ":"
+ + port
+ + " HTTP/1.0\r\n"
+ + "User-Agent: AxisClient");
+ if (tcp.getProxyUser().length() != 0
+ && tcp.getProxyPassword().length() != 0) {
+
+ // add basic authentication header for the proxy
+ String encodedPassword =
+ XMLUtils.base64encode(
+ (tcp.getProxyUser() + ":" + tcp.getProxyPassword()).getBytes());
+
+ out.print("\nProxy-Authorization: Basic " + encodedPassword);
+ }
+ out.print("\nContent-Length: 0");
+ out.print("\nPragma: no-cache");
+ out.print("\r\n\r\n");
+ out.flush();
+ InputStream tunnelInputStream = tunnel.getInputStream();
+
+ if (log.isDebugEnabled()) {
+ log.debug(
+ Messages.getMessage(
+ "isNull00",
+ "tunnelInputStream",
+ "" + (tunnelInputStream == null)));
+ }
+ String replyStr = "";
+
+ // Make sure to read all the response from the proxy to prevent SSL negotiation failure
+ // Response message terminated by two sequential newlines
+ int newlinesSeen = 0;
+ boolean headerDone = false; /* Done on first newline */
+
+ while (newlinesSeen < 2) {
+ int i = tunnelInputStream.read();
+
+ if (i < 0) {
+ throw new IOException("Unexpected EOF from proxy");
+ }
+ if (i == '\n') {
+ headerDone = true;
+ ++newlinesSeen;
+ }
+ else if (i != '\r') {
+ newlinesSeen = 0;
+ if (!headerDone) {
+ replyStr += String.valueOf((char) i);
+ }
+ }
+ }
+ if (!replyStr.startsWith("HTTP/1.0 200")
+ && !replyStr.startsWith("HTTP/1.1 200")) {
+ throw new IOException(
+ Messages.getMessage(
+ "cantTunnel00",
+ new String[] { tcp.getProxyHost(), "" + tunnelPort, replyStr }));
+ }
+
+ // End of condensed reflective tunnel handshake method
+ sslSocket = sslFactory.createSocket(tunnel, host, port, true);
+ if (log.isDebugEnabled()) {
+ log.debug(
+ Messages.getMessage(
+ "setupTunnel00",
+ tcp.getProxyHost(),
+ "" + tunnelPort));
+ }
+ }
+
+ ((SSLSocket) sslSocket).startHandshake();
+ if (log.isDebugEnabled()) {
+ log.debug(Messages.getMessage("createdSSL00"));
+ }
+ return sslSocket;
+ }
+
+}
diff --git a/id.server/src/at/gv/egovernment/moa/id/util/MOAIDMessageProvider.java b/id.server/src/at/gv/egovernment/moa/id/util/MOAIDMessageProvider.java
new file mode 100644
index 000000000..d31aa6ec1
--- /dev/null
+++ b/id.server/src/at/gv/egovernment/moa/id/util/MOAIDMessageProvider.java
@@ -0,0 +1,58 @@
+package at.gv.egovernment.moa.id.util;
+
+import java.util.Locale;
+
+import at.gv.egovernment.moa.util.Messages;
+
+/**
+ * A singleton wrapper around a <code>Message</code> object, providing the messages used in MOA-ID.
+ *
+ * @author Paul Ivancsics
+ * @version $Id$
+ */
+public class MOAIDMessageProvider {
+
+ /** DEFAULT_MESSAGE_RESOURCES are resources/properties/id_messages */
+ private static final String[] DEFAULT_MESSAGE_RESOURCES =
+ { "resources/properties/id_messages" };
+ /** DEFAULT_MESSAGE_LOCALES are "de", "AT" */
+ private static final Locale[] DEFAULT_MESSAGE_LOCALES =
+ new Locale[] { new Locale("de", "AT") };
+ /** The instance for our singleton */
+ private static MOAIDMessageProvider instance;
+ /** The Messages */
+ private Messages messages;
+
+ /**
+ * Returns the single instance of <code>MOAIDMessageProvider</code>.
+ *
+ * @return the single instance of <code>MOAIDMessageProvider</code>
+ */
+ public static MOAIDMessageProvider getInstance() {
+ if (instance == null)
+ instance = new MOAIDMessageProvider(DEFAULT_MESSAGE_RESOURCES, DEFAULT_MESSAGE_LOCALES);
+ return instance;
+ }
+
+ /**
+ * Create a <code>MOAIDMessageProvider</code>.
+ *
+ * @param resourceNames The names of the resources containing the messages.
+ * @param locales The corresponding locales.
+ */
+ protected MOAIDMessageProvider(String[] resourceNames, Locale[] locales) {
+ this.messages = new Messages(resourceNames, locales);
+ }
+
+ /**
+ * Get the message corresponding to a given message ID.
+ *
+ * @param messageId The ID of the message.
+ * @param parameters The parameters to fill in into the message arguments.
+ * @return The formatted message.
+ */
+ public String getMessage(String messageId, Object[] parameters) {
+ return messages.getMessage(messageId, parameters);
+ }
+
+}
diff --git a/id.server/src/at/gv/egovernment/moa/id/util/Random.java b/id.server/src/at/gv/egovernment/moa/id/util/Random.java
new file mode 100644
index 000000000..da75b4213
--- /dev/null
+++ b/id.server/src/at/gv/egovernment/moa/id/util/Random.java
@@ -0,0 +1,22 @@
+package at.gv.egovernment.moa.id.util;
+
+import java.util.Date;
+
+/**
+ * Random number generator used to generate ID's
+ * @author Paul Ivancsics
+ * @version $Id$
+ */
+public class Random {
+
+ /** random number generator used */
+ private static java.util.Random random = new java.util.Random(new Date().getTime());
+ /**
+ * Creates a new random number, to be used as an ID.
+ *
+ * @return random long as a String
+ */
+ public static String nextRandom() {
+ return "" + random.nextLong();
+ }
+}
diff --git a/id.server/src/at/gv/egovernment/moa/id/util/SSLUtils.java b/id.server/src/at/gv/egovernment/moa/id/util/SSLUtils.java
new file mode 100644
index 000000000..f21b0880e
--- /dev/null
+++ b/id.server/src/at/gv/egovernment/moa/id/util/SSLUtils.java
@@ -0,0 +1,156 @@
+package at.gv.egovernment.moa.id.util;
+
+import iaik.pki.PKIConfiguration;
+import iaik.pki.PKIException;
+import iaik.pki.PKIFactory;
+import iaik.pki.PKIProfile;
+import iaik.pki.jsse.IAIKX509TrustManager;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.security.Security;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.net.ssl.SSLSocketFactory;
+
+import at.gv.egovernment.moa.id.config.ConfigurationException;
+import at.gv.egovernment.moa.id.config.ConfigurationProvider;
+import at.gv.egovernment.moa.id.config.ConnectionParameter;
+import at.gv.egovernment.moa.id.iaik.config.PKIConfigurationImpl;
+import at.gv.egovernment.moa.id.iaik.pki.PKIProfileImpl;
+import at.gv.egovernment.moa.id.iaik.pki.jsse.MOAIDTrustManager;
+import at.gv.egovernment.moa.logging.Logger;
+import at.gv.egovernment.moa.util.StreamUtils;
+
+import com.sun.net.ssl.HttpsURLConnection;
+import com.sun.net.ssl.KeyManager;
+import com.sun.net.ssl.SSLContext;
+import com.sun.net.ssl.TrustManager;
+
+/**
+ * Utility for a obtaining a secure socket factory using <code>IAIKX509TrustManager</code>.
+ * This <code>TrustManager</code> implementation features CRL checking.<br/>
+ * <code>SSLUtils</code> caches secure socket factories for given <code>ConnectionParameter</code>s.
+ *
+ * @author Paul Ivancsics
+ * @version $Id$
+ */
+public class SSLUtils {
+
+ /** SSLSocketFactory store, mapping URL->SSLSocketFactory **/
+ private static Map sslSocketFactories = new HashMap();
+
+ /**
+ * Initializes the SSLSocketFactory store.
+ */
+ public static void initialize() {
+ sslSocketFactories = new HashMap();
+ Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
+ System.setProperty("java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol");
+ }
+
+ /**
+ * Creates an <code>SSLSocketFactory</code> which utilizes an
+ * <code>IAIKX509TrustManager</code> for the given trust store,
+ * and the given key store.
+ *
+ * @param conf configuration provider providing a generic properties pointing
+ * to trusted CA store and certificate store root
+ * @param connParam connection parameter containing the client key store settings
+ * to be used in case of client authentication;
+ * if <code>connParam.getClientKeyStore() == null</code>, client authentication
+ * is assumed to be disabled
+ * @return <code>SSLSocketFactory</code> to be used by an <code>HttpsURLConnection</code>
+ * @throws IOException thrown while reading key store file
+ * @throws GeneralSecurityException thrown while creating the socket factory
+ * @throws ConfigurationException on invalid configuration data
+ * @throws PKIException while initializing the <code>IAIKX509TrustManager</code>
+ */
+ public static SSLSocketFactory getSSLSocketFactory(
+ ConfigurationProvider conf,
+ ConnectionParameter connParam)
+ throws IOException, GeneralSecurityException, ConfigurationException, PKIException {
+
+ Logger.debug("Get SSLSocketFactory for " + connParam.getUrl());
+ // retrieve SSLSocketFactory if already created
+ SSLSocketFactory ssf = (SSLSocketFactory)sslSocketFactories.get(connParam.getUrl());
+ if (ssf != null)
+ return ssf;
+ // else create new SSLSocketFactory
+ String trustStoreURL = conf.getTrustedCACertificates();
+ if (trustStoreURL == null)
+ throw new ConfigurationException(
+ "config.08", new Object[] {"TrustedCACertificates"});
+ String acceptedServerCertURL = connParam.getAcceptedServerCertificates();
+ TrustManager[] tms = getTrustManagers(conf, trustStoreURL, acceptedServerCertURL);
+ KeyManager[] kms = at.gv.egovernment.moa.util.SSLUtils.getKeyManagers(
+ "pkcs12", connParam.getClientKeyStore(), connParam.getClientKeyStorePassword());
+ SSLContext ctx = SSLContext.getInstance("TLS");
+ ctx.init(kms, tms, null);
+ ssf = ctx.getSocketFactory();
+ // store SSLSocketFactory
+ sslSocketFactories.put(connParam.getUrl(), ssf);
+ return ssf;
+ }
+
+ /**
+ * Initializes an <code>IAIKX509TrustManager</code> for a given trust store,
+ * using configuration data.
+ *
+ * @param conf MOA-ID configuration provider
+ * @param trustStoreURL trust store URL
+ * @param acceptedServerCertURL file URL pointing to directory containing accepted server SSL certificates
+ * @return <code>TrustManager</code> array containing the <code>IAIKX509TrustManager</code>
+ * @throws ConfigurationException on invalid configuration data
+ * @throws IOException on data-reading problems
+ * @throws PKIException while initializing the <code>IAIKX509TrustManager</code>
+ */
+ public static TrustManager[] getTrustManagers(
+ ConfigurationProvider conf, String trustStoreURL, String acceptedServerCertURL)
+ throws ConfigurationException, PKIException, IOException, GeneralSecurityException {
+
+ PKIConfiguration cfg = null;
+ if (! PKIFactory.getInstance().isAlreadyConfigured())
+ cfg = new PKIConfigurationImpl(conf);
+ PKIProfile profile = new PKIProfileImpl(trustStoreURL);
+ // This call fixes a bug occuring when PKIConfiguration is
+ // initialized by the MOA-SP initialization code, in case
+ // MOA-SP is called by API
+ MOAIDTrustManager.initializeLoggingContext();
+ IAIKX509TrustManager tm = new MOAIDTrustManager(acceptedServerCertURL);
+ tm.init(cfg, profile);
+ return new TrustManager[] {tm};
+ }
+ /**
+ * Reads a file, given by URL, into a byte array,
+ * securing the connection by IAIKX509TrustManager.
+ * @param connParam containing URL and accepted server certificates
+ * @param conf ConfigurationProvider for reading
+ * @return file content
+ * @throws ConfigurationException on invalid configuration data
+ * @throws PKIException on invalid configuration data
+ * @throws IOException on data-reading problems
+ * @throws GeneralSecurityException on security issues
+ */
+ public static byte[] readHttpsURL(ConfigurationProvider conf, ConnectionParameter connParam)
+ throws ConfigurationException, PKIException, IOException, GeneralSecurityException {
+
+ URL url = new URL(connParam.getUrl());
+ HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
+ conn.setRequestMethod("GET");
+ conn.setDoInput(true);
+ SSLSocketFactory sslSocketFactory = getSSLSocketFactory(conf, connParam);
+ conn.setSSLSocketFactory(sslSocketFactory);
+ conn.connect();
+ InputStream in = new BufferedInputStream(conn.getInputStream());
+ byte[] content = StreamUtils.readStream(in);
+ in.close();
+ conn.disconnect();
+ return content;
+ }
+
+}