From ece7d18cf35374bf4e26d041799cda8f791c89f8 Mon Sep 17 00:00:00 2001 From: gregor Date: Mon, 7 Jul 2003 10:58:37 +0000 Subject: Initial commit git-svn-id: https://joinup.ec.europa.eu/svn/moa-idspss/trunk@2 d688527b-c9ab-4aba-bd8d-4036d912da1d --- .../src/at/gv/egovernment/moa/logging/LogMsg.java | 43 ++ .../src/at/gv/egovernment/moa/logging/Logger.java | 175 +++++ .../gv/egovernment/moa/logging/LoggingContext.java | 46 ++ .../moa/logging/LoggingContextManager.java | 56 ++ .../at/gv/egovernment/moa/util/Base64Utils.java | 109 +++ .../src/at/gv/egovernment/moa/util/BoolUtils.java | 24 + .../gv/egovernment/moa/util/CollectionUtils.java | 36 + .../src/at/gv/egovernment/moa/util/Constants.java | 218 ++++++ .../src/at/gv/egovernment/moa/util/DOMUtils.java | 806 +++++++++++++++++++++ .../at/gv/egovernment/moa/util/DateTimeUtils.java | 326 +++++++++ .../egovernment/moa/util/EntityResolverChain.java | 52 ++ .../src/at/gv/egovernment/moa/util/FileUtils.java | 87 +++ .../at/gv/egovernment/moa/util/KeyStoreUtils.java | 134 ++++ .../gv/egovernment/moa/util/MOADefaultHandler.java | 82 +++ .../gv/egovernment/moa/util/MOAEntityResolver.java | 103 +++ .../gv/egovernment/moa/util/MOAErrorHandler.java | 85 +++ .../src/at/gv/egovernment/moa/util/MOATimer.java | 110 +++ .../gv/egovernment/moa/util/MessageProvider.java | 63 ++ .../src/at/gv/egovernment/moa/util/Messages.java | 117 +++ .../egovernment/moa/util/NodeIteratorAdapter.java | 87 +++ .../gv/egovernment/moa/util/NodeListAdapter.java | 44 ++ .../egovernment/moa/util/ResourceBundleChain.java | 66 ++ .../src/at/gv/egovernment/moa/util/SSLUtils.java | 222 ++++++ .../egovernment/moa/util/StreamEntityResolver.java | 64 ++ .../at/gv/egovernment/moa/util/StreamUtils.java | 116 +++ .../src/at/gv/egovernment/moa/util/URLDecoder.java | 60 ++ .../src/at/gv/egovernment/moa/util/URLEncoder.java | 63 ++ .../at/gv/egovernment/moa/util/XPathException.java | 58 ++ .../src/at/gv/egovernment/moa/util/XPathUtils.java | 415 +++++++++++ .../src/test/at/gv/egovernment/moa/AllTests.java | 38 + .../test/at/gv/egovernment/moa/MOATestCase.java | 75 ++ .../at/gv/egovernment/moa/util/DOMUtilsTest.java | 137 ++++ .../gv/egovernment/moa/util/DateTimeUtilsTest.java | 104 +++ .../gv/egovernment/moa/util/KeyStoreUtilsTest.java | 90 +++ .../at/gv/egovernment/moa/util/SSLUtilsTest.java | 160 ++++ .../at/gv/egovernment/moa/util/URLDecoderTest.java | 29 + .../at/gv/egovernment/moa/util/URLEncoderTest.java | 43 ++ .../moa/util/XMLGrammarBuilderTest.java | 99 +++ .../at/gv/egovernment/moa/util/XPathUtilsTest.java | 51 ++ 39 files changed, 4693 insertions(+) create mode 100644 common/src/at/gv/egovernment/moa/logging/LogMsg.java create mode 100644 common/src/at/gv/egovernment/moa/logging/Logger.java create mode 100644 common/src/at/gv/egovernment/moa/logging/LoggingContext.java create mode 100644 common/src/at/gv/egovernment/moa/logging/LoggingContextManager.java create mode 100644 common/src/at/gv/egovernment/moa/util/Base64Utils.java create mode 100644 common/src/at/gv/egovernment/moa/util/BoolUtils.java create mode 100644 common/src/at/gv/egovernment/moa/util/CollectionUtils.java create mode 100644 common/src/at/gv/egovernment/moa/util/Constants.java create mode 100644 common/src/at/gv/egovernment/moa/util/DOMUtils.java create mode 100644 common/src/at/gv/egovernment/moa/util/DateTimeUtils.java create mode 100644 common/src/at/gv/egovernment/moa/util/EntityResolverChain.java create mode 100644 common/src/at/gv/egovernment/moa/util/FileUtils.java create mode 100644 common/src/at/gv/egovernment/moa/util/KeyStoreUtils.java create mode 100644 common/src/at/gv/egovernment/moa/util/MOADefaultHandler.java create mode 100644 common/src/at/gv/egovernment/moa/util/MOAEntityResolver.java create mode 100644 common/src/at/gv/egovernment/moa/util/MOAErrorHandler.java create mode 100644 common/src/at/gv/egovernment/moa/util/MOATimer.java create mode 100644 common/src/at/gv/egovernment/moa/util/MessageProvider.java create mode 100644 common/src/at/gv/egovernment/moa/util/Messages.java create mode 100644 common/src/at/gv/egovernment/moa/util/NodeIteratorAdapter.java create mode 100644 common/src/at/gv/egovernment/moa/util/NodeListAdapter.java create mode 100644 common/src/at/gv/egovernment/moa/util/ResourceBundleChain.java create mode 100644 common/src/at/gv/egovernment/moa/util/SSLUtils.java create mode 100644 common/src/at/gv/egovernment/moa/util/StreamEntityResolver.java create mode 100644 common/src/at/gv/egovernment/moa/util/StreamUtils.java create mode 100644 common/src/at/gv/egovernment/moa/util/URLDecoder.java create mode 100644 common/src/at/gv/egovernment/moa/util/URLEncoder.java create mode 100644 common/src/at/gv/egovernment/moa/util/XPathException.java create mode 100644 common/src/at/gv/egovernment/moa/util/XPathUtils.java create mode 100644 common/src/test/at/gv/egovernment/moa/AllTests.java create mode 100644 common/src/test/at/gv/egovernment/moa/MOATestCase.java create mode 100644 common/src/test/at/gv/egovernment/moa/util/DOMUtilsTest.java create mode 100644 common/src/test/at/gv/egovernment/moa/util/DateTimeUtilsTest.java create mode 100644 common/src/test/at/gv/egovernment/moa/util/KeyStoreUtilsTest.java create mode 100644 common/src/test/at/gv/egovernment/moa/util/SSLUtilsTest.java create mode 100644 common/src/test/at/gv/egovernment/moa/util/URLDecoderTest.java create mode 100644 common/src/test/at/gv/egovernment/moa/util/URLEncoderTest.java create mode 100644 common/src/test/at/gv/egovernment/moa/util/XMLGrammarBuilderTest.java create mode 100644 common/src/test/at/gv/egovernment/moa/util/XPathUtilsTest.java (limited to 'common/src') diff --git a/common/src/at/gv/egovernment/moa/logging/LogMsg.java b/common/src/at/gv/egovernment/moa/logging/LogMsg.java new file mode 100644 index 000000000..4d04fc72d --- /dev/null +++ b/common/src/at/gv/egovernment/moa/logging/LogMsg.java @@ -0,0 +1,43 @@ +package at.gv.egovernment.moa.logging; + +/** + * A unified message type to log messages from inside the MOA subsystem. + * + * @author Patrick Peck + * @version $Id$ + */ +public class LogMsg { + /** The message to log. */ + private Object message; + + /** + * Create a LogMsg object. + * + * @param message The actual message to log. May be null. + */ + public LogMsg(Object message) { + this.message = message; + } + + /** + * Convert this log message to a String. + * + * @return The String representation of this log message. + */ + public String toString() { + StringBuffer msg = new StringBuffer(); + LoggingContext ctx = + LoggingContextManager.getInstance().getLoggingContext(); + String tid = ctx != null ? ctx.getTransactionID() : null; + String nodeId = ctx != null ? ctx.getNodeID() : null; + + msg.append("TID="); + msg.append(tid != null ? tid : ""); + msg.append(" NID="); + msg.append(nodeId != null ? nodeId : ""); + msg.append(" MSG="); + msg.append(message != null ? message.toString() : ""); + + return msg.toString(); + } +} diff --git a/common/src/at/gv/egovernment/moa/logging/Logger.java b/common/src/at/gv/egovernment/moa/logging/Logger.java new file mode 100644 index 000000000..eb7aa5634 --- /dev/null +++ b/common/src/at/gv/egovernment/moa/logging/Logger.java @@ -0,0 +1,175 @@ +package at.gv.egovernment.moa.logging; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * A utility class acting as a facade to the logging subsystem. + * + * Configure the logging defaultHierarchy that the Logger uses by + * calling setHierarchy once before calling any of the logging + * output functions. + * + * @author Patrick Peck + * @version $Id$ + */ +public class Logger { + + /** The default logging hierarchy. */ + private static String defaultHierarchy = ""; + + /** + * Get the Log object for the default hierarchy. + * + * @return The Log object to write log messages to. + */ + private static Log getLog() { + return LogFactory.getLog(defaultHierarchy); + } + + /** + * Get the Log object for a given hierarchy. + * + * @param hierarchy The logging hierarchy for which to return the logger. + * @return The Log object to write log messages to. + */ + private static Log getLog(String hierarchy) { + return LogFactory.getLog(hierarchy); + } + + /** + * Set the default hierarchy to which the Logger should send its + * logging output. + * @param hierarchy The logging defaultHierarchy. + */ + public static void setHierarchy(String hierarchy) { + defaultHierarchy = hierarchy; + } + + /** + * Test, if the trace log level is enabled. + * + * @return boolean true, if tracing output is enabled + * false otherwise. + */ + public static boolean isTraceEnabled() { + return getLog().isTraceEnabled(); + } + + /** + * Test, if the trace log level is enabled for a given hierarchy. + * + * @param hierarchy requested log hierarchy + * @return boolean true, if tracing output is enabled + * false otherwise. + */ + public static boolean isTraceEnabled(String hierarchy) { + return getLog(hierarchy).isTraceEnabled(); + } + + /** + * Trace a message. + * + * @param message The message to trace. + */ + public static void trace(Object message) { + getLog().trace(message); + } + + /** + * Test, if the debug log level is enabled. + * + * @return boolean true, if debug output is enabled + * false otherwise. + */ + public static boolean isDebugEnabled() { + return getLog().isDebugEnabled(); + } + + /** + * Test, if the debug log level is enabled for a given hierarchy. + * + * @param hierarchy requested log hierarchy + * @return boolean true, if debug output is enabled + * false otherwise. + */ + public static boolean isDebugEnabled(String hierarchy) { + return getLog(hierarchy).isDebugEnabled(); + } + + /** + * Log a debug message. + * + * @param message The message to log. + */ + public static void debug(Object message) { + getLog().debug(message); + } + + /** + * Log an info message. + * + * @param message The message to log. + */ + public static void info(Object message) { + getLog().info(message); + } + + /** + * Log a warning message. + * + * @param message The message to log. + */ + public static void warn(Object message) { + getLog().warn(message); + } + + /** + * Log a warning message. + * + * @param message The message to log. + * @param t An exception that may be the cause of the warning. + */ + public static void warn(Object message, Throwable t) { + getLog().warn(message, t); + } + + /** + * Log an error message. + * + * @param message The message to log. + */ + public static void error(Object message) { + getLog().error(message); + } + + /** + * Log an error message. + * + * @param message The message to log. + * @param t An exception that may be the cause of the error. + */ + public static void error(Object message, Throwable t) { + getLog().error(message, t); + } + + /** + * Log a fatal error message. + * + * @param message The message to log. + */ + public static void fatal(Object message) { + getLog().fatal(message); + } + + /** + * Log a fatal error message. + * + * @param message The message to log. + * @param t An exception that may be the cause of the error. + */ + public static void fatal(Object message, Throwable t) { + getLog().fatal(message, t); + } + +} diff --git a/common/src/at/gv/egovernment/moa/logging/LoggingContext.java b/common/src/at/gv/egovernment/moa/logging/LoggingContext.java new file mode 100644 index 000000000..42d8db06e --- /dev/null +++ b/common/src/at/gv/egovernment/moa/logging/LoggingContext.java @@ -0,0 +1,46 @@ +package at.gv.egovernment.moa.logging; + +/** + * Encapsulates contextual information (i.e. per request information) for + * logging purposes. + * + * @author Patrick Peck + * @version $Id$ + */ +public class LoggingContext { + /** The name of the node ID system property. */ + public static final String NODE_ID_PROPERTY = "moa.node-id"; + + /** The current transaction ID. */ + private String transactionID; + /** The node ID. */ + private String nodeID; + + /** + * Create a new LoggingContext. + * + * @param transactionID The transaction ID. May be null. + */ + public LoggingContext(String transactionID) { + this.transactionID = transactionID; + this.nodeID = System.getProperty(NODE_ID_PROPERTY); + } + + /** + * Return the transaction ID. + * + * @return The transaction ID. + */ + public String getTransactionID() { + return transactionID; + } + + /** + * Return the node ID. + * + * @return The node ID. + */ + public String getNodeID() { + return nodeID; + } +} diff --git a/common/src/at/gv/egovernment/moa/logging/LoggingContextManager.java b/common/src/at/gv/egovernment/moa/logging/LoggingContextManager.java new file mode 100644 index 000000000..2bbe6caa1 --- /dev/null +++ b/common/src/at/gv/egovernment/moa/logging/LoggingContextManager.java @@ -0,0 +1,56 @@ +package at.gv.egovernment.moa.logging; + +/** + * Provides each thread with a single instance of LoggingContext. + * + * @author Patrick Peck + * @version $Id$ + */ +public class LoggingContextManager { + /** The single instance of this class. */ + private static LoggingContextManager instance = null; + + /** The LoggingContext for each thread. */ + private ThreadLocal context; + + /** + * Get the single instance of the LoggingContextManager class. + * + * @return LoggingContextManager The single instance. + */ + public static synchronized LoggingContextManager getInstance() { + if (instance == null) { + instance = new LoggingContextManager(); + } + return instance; + } + + /** + * Creates a new LoggingContextManager. + * + * Protected to disallow direct instantiation. + */ + protected LoggingContextManager() { + context = new ThreadLocal(); + } + + /** + * Set the LoggingContext context for the current thread. + * + * @param ctx The LoggingContext for the current thread. + */ + public void setLoggingContext(LoggingContext ctx) { + context.set(ctx); + } + + /** + * Return the LoggingContext for the current thread. + * + * @return LoggingContext The LoggingContext for the current + * thread, or null if none has been set. + */ + public LoggingContext getLoggingContext() { + return (LoggingContext) context.get(); + } + +} diff --git a/common/src/at/gv/egovernment/moa/util/Base64Utils.java b/common/src/at/gv/egovernment/moa/util/Base64Utils.java new file mode 100644 index 000000000..ba2c4fb0e --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/Base64Utils.java @@ -0,0 +1,109 @@ +package at.gv.egovernment.moa.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; + +import iaik.utils.Base64InputStream; +import iaik.utils.Base64OutputStream; + +/** + * Utitility functions for encoding/decoding Base64 strings. + * + * @author Patrick Peck + * @version $Id$ + */ +public class Base64Utils { + + /** + * Read the bytes encoded in a Base64 encoded String. + * + * @param base64String The String containing the Base64 encoded + * bytes. + * @param ignoreInvalidChars Whether to ignore invalid Base64 characters. + * @return byte[] The raw bytes contained in the base64String. + * @throws IOException Failed to read the Base64 data. + */ + public static byte[] decode(String base64String, boolean ignoreInvalidChars) + throws IOException { + + Base64InputStream in = + new Base64InputStream( + new ByteArrayInputStream(base64String.getBytes("UTF-8")), + ignoreInvalidChars); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] bytes = new byte[256]; + int bytesRead; + + while ((bytesRead = in.read(bytes)) > 0) { + out.write(bytes, 0, bytesRead); + } + + return out.toByteArray(); + } + + /** + * Read the bytes encoded in a Base64 encoded String and provide + * them via an InputStream. + * + * @param base64String The String containing the Base64 encoded + * bytes. + * @param ignoreInvalidChars Whether to ignore invalid Base64 characters. + * @return The InputStream from which the binary content of the + * base64String can be read. + */ + public static InputStream decodeToStream( + String base64String, + boolean ignoreInvalidChars) { + + try { + ByteArrayInputStream bin = + new ByteArrayInputStream(base64String.getBytes("UTF-8")); + Base64InputStream in = new Base64InputStream(bin, ignoreInvalidChars); + + return in; + } catch (UnsupportedEncodingException e) { + // cannot occur, since UTF-8 is required to be supported by every JRE + return null; + } + } + + /** + * Convert a byte array to a Base64 encoded String. + * + * @param bytes The bytes to encode. + * @return String The Base64 encoded representation of the bytes. + * @throws IOException Failed to write the bytes as Base64 data. + */ + public static String encode(byte[] bytes) throws IOException { + return encode(new ByteArrayInputStream(bytes)); + } + + /** + * Convert the data contained in the given stream to a Base64 encoded + * String. + * + * @param inputStream The stream containing the data to encode. + * @return The Base64 encoded data of inputStream, as a + * String. + * @throws IOException Failed to convert the data in the stream. + */ + public static String encode(InputStream inputStream) throws IOException { + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + Base64OutputStream base64Stream = new Base64OutputStream(byteStream); + byte[] bytes = new byte[256]; + int bytesRead; + + while ((bytesRead = inputStream.read(bytes)) > 0) { + base64Stream.write(bytes, 0, bytesRead); + } + base64Stream.flush(); + base64Stream.close(); + inputStream.close(); + + return byteStream.toString("UTF-8"); + } + +} diff --git a/common/src/at/gv/egovernment/moa/util/BoolUtils.java b/common/src/at/gv/egovernment/moa/util/BoolUtils.java new file mode 100644 index 000000000..fcd39b4dd --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/BoolUtils.java @@ -0,0 +1,24 @@ +package at.gv.egovernment.moa.util; + +/** + * Utility class for parsing XML schema boolean values. + * + * @author Patrick Peck + * @version $Id$ + */ +public class BoolUtils { + + /** + * Return the boolean value of an xsd:boolean type of DOM + * element/attribute. + * + * @param boolStr The value of the xsd:boolean element/attribute. + * @return true, if boolStr equals + * "true" or "1;". Otherwise, + * false is returned. + */ + public static boolean valueOf(String boolStr) { + return "true".equals(boolStr) || "1".equals(boolStr); + } + +} diff --git a/common/src/at/gv/egovernment/moa/util/CollectionUtils.java b/common/src/at/gv/egovernment/moa/util/CollectionUtils.java new file mode 100644 index 000000000..5329dcbd2 --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/CollectionUtils.java @@ -0,0 +1,36 @@ +package at.gv.egovernment.moa.util; + +import java.util.Iterator; +import java.util.List; + +/** + * Various utility methods for dealing with java.util.Collection + * classes. + * + * @author Patrick Peck + * @version $Id$ + */ +public class CollectionUtils { + + /** + * Convert a List of Number objects to an + * int array. + * + * @param nums The List containing the numbers whose integer + * value to put into the result. + * @return The int values of the Numbers contained + * in nums. + */ + public static int[] toIntArray(List nums) { + int[] result = new int[nums.size()]; + Iterator iter; + int i; + + for (i = 0, iter = nums.iterator(); iter.hasNext(); i++) { + Number num = (Number) iter.next(); + result[i] = num.intValue(); + } + + return result; + } +} diff --git a/common/src/at/gv/egovernment/moa/util/Constants.java b/common/src/at/gv/egovernment/moa/util/Constants.java new file mode 100644 index 000000000..681bed55b --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/Constants.java @@ -0,0 +1,218 @@ +package at.gv.egovernment.moa.util; + +/** + * Contains various constants used throughout the system. + * + * @author Patrick Peck + * @version $Id$ + */ +public interface Constants { + /** Root location of the schema files. */ + public static final String SCHEMA_ROOT = "/resources/schemas/"; + + /** URI of the MOA XML namespace. */ + public static final String MOA_NS_URI = + "http://reference.e-government.gv.at/namespace/moa/20020822#"; + + /** Prefix used for the MOA XML namespace */ + public static final String MOA_PREFIX = "moa"; + + /** Local location of the MOA XML schema definition. */ + public static final String MOA_SCHEMA_LOCATION = + SCHEMA_ROOT + "MOA-SPSS-1.1.xsd"; + + /** URI of the MOA configuration XML namespace. */ + public static final String MOA_CONFIG_NS_URI = + "http://reference.e-government.gv.at/namespace/moaconfig/20021122#"; + + /** URI of the MOA ID configuration XML namespace. */ + public static final String MOA_ID_CONFIG_NS_URI = + "http://www.buergerkarte.at/namespaces/moaconfig#"; + + /** Prefix used for the MOA configuration XML namespace */ + public static final String MOA_CONFIG_PREFIX = "conf"; + + /** Prefix used for the MOA configuration XML namespace */ + public static final String MOA_ID_CONFIG_PREFIX = "confID"; + + /** Local location of the MOA configuration XML schema definition. */ + public static final String MOA_CONFIG_SCHEMA_LOCATION = + SCHEMA_ROOT + "MOA-SPSS-Configuration-1.0.xsd"; + + /** Local location of the MOA ID configuration XML schema definition. */ + public static final String MOA_ID_CONFIG_SCHEMA_LOCATION = + SCHEMA_ROOT + "MOA-ID-Configuration-1.1.xsd"; + + /** URI of the Security Layer 1.0 namespace. */ + public static final String SL10_NS_URI = + "http://www.buergerkarte.at/namespaces/securitylayer/20020225#"; + + /** Prefix used for the Security Layer 1.0 XML namespace */ + public static final String SL10_PREFIX = "sl10"; + + /** Local location of the Security Layer 1.0 XML schema definition */ + public static final String SL10_SCHEMA_LOCATION = + SCHEMA_ROOT + "Core.20020225.xsd"; + + /** URI of the Security Layer 1.1 XML namespace */ + public static final String SL11_NS_URI = + "http://www.buergerkarte.at/namespaces/securitylayer/20020831#"; + + /** Prefix used for the Security Layer 1.1 XML namespace */ + public static final String SL11_PREFIX = "sl11"; + + /** Local location of the Security Layer 1.1 XML schema definition */ + public static final String SL11_SCHEMA_LOCATION = + SCHEMA_ROOT + "Core.20020831.xsd"; + + /** URI of the ECDSA XML namespace */ + public static final String ECDSA_NS_URI = + "http://www.buergerkarte.at/namespaces/ecdsa/200206030#"; + + /** Prefix used for ECDSA namespace */ + public static final String ECDSA_PREFIX = "ecdsa"; + + /** Local location of ECDSA XML schema definition */ + public static final String ECDSA_SCHEMA_LOCATION = + SCHEMA_ROOT + "ECDSAKeyValue.xsd"; + + /** URI of the PersonData XML namespace. */ + public static final String PD_NS_URI = + "http://reference.e-government.gv.at/namespace/persondata/20020228#"; + + /** Prefix used for the PersonData XML namespace */ + public static final String PD_PREFIX = "pr"; + + /** Local location of the PersonData XML schema definition */ + public static final String PD_SCHEMA_LOCATION = + SCHEMA_ROOT + "PersonData.xsd"; + + /** URI of the SAML namespace. */ + public static final String SAML_NS_URI = + "urn:oasis:names:tc:SAML:1.0:assertion"; + + /** Prefix used for the SAML XML namespace */ + public static final String SAML_PREFIX = "saml"; + + /** Local location of the SAML XML schema definition. */ + public static final String SAML_SCHEMA_LOCATION = + SCHEMA_ROOT + "cs-sstc-schema-assertion-01.xsd"; + + /** URI of the SAML request-response protocol namespace. */ + public static final String SAMLP_NS_URI = + "urn:oasis:names:tc:SAML:1.0:protocol"; + + /** Prefix used for the SAML request-response protocol namespace */ + public static final String SAMLP_PREFIX = "samlp"; + + /** Local location of the SAML request-response protocol schema definition. */ + public static final String SAMLP_SCHEMA_LOCATION = + SCHEMA_ROOT + "cs-sstc-schema-protocol-01.xsd"; + + /** URI of the XML namespace. */ + public static final String XML_NS_URI = + "http://www.w3.org/XML/1998/namespace"; + + /** Prefix used for the XML namespace */ + public static final String XML_PREFIX = "xml"; + + /** Local location of the XML schema definition. */ + public static final String XML_SCHEMA_LOCATION = SCHEMA_ROOT + "xml.xsd"; + + /** URI of the XMLNS namespace */ + public static final String XMLNS_NS_URI = "http://www.w3.org/2000/xmlns/"; + + /** Prefix used for the XSI namespace */ + public static final String XSI_PREFIX = "xsi"; + + /** Local location of the XSI schema definition. */ + public static final String XSI_SCHEMA_LOCATION = + SCHEMA_ROOT + "XMLSchema-instance.xsd"; + + /** URI of the XSI XMLNS namespace */ + public static final String XSI_NS_URI = + "http://www.w3.org/2001/XMLSchema-instance"; + + /** URI of the XSLT XML namespace */ + public static final String XSLT_NS_URI = + "http://www.w3.org/1999/XSL/Transform"; + + /** Prefix used for the XSLT XML namespace */ + public static final String XSLT_PREFIX = "xsl"; + + /** URI of the XMLDSig XML namespace. */ + public static final String DSIG_NS_URI = "http://www.w3.org/2000/09/xmldsig#"; + + /** Prefix used for the XMLDSig XML namespace */ + public static final String DSIG_PREFIX = "dsig"; + + /** Local location of the XMLDSig XML schema. */ + public static final String DSIG_SCHEMA_LOCATION = + SCHEMA_ROOT + "xmldsig-core-schema.xsd"; + + /** URI of the XMLDSig XPath Filter XML namespace. */ + public static final String DSIG_FILTER2_NS_URI = + "http://www.w3.org/2002/06/xmldsig-filter2"; + + /** Prefix used for the XMLDSig XPath Filter XML namespace */ + public static final String DSIG_FILTER2_PREFIX = "dsig-filter2"; + + /** Local location of the XMLDSig XPath Filter XML schema definition. */ + public static final String DSIG_FILTER2_SCHEMA_LOCATION = + SCHEMA_ROOT + "xmldsig-filter2.xsd"; + + /** URI of the Exclusive Canonicalization XML namespace */ + public static final String DSIG_EC_NS_URI = + "http://www.w3.org/2001/10/xml-exc-c14n#"; + + /** Prefix used for the Exclusive Canonicalization XML namespace */ + public static final String DSIG_EC_PREFIX = "ec"; + + /** Local location of the Exclusive Canonicalizaion XML schema definition */ + public static final String DSIG_EC_SCHEMA_LOCATION = + SCHEMA_ROOT + "exclusive-canonicalization.xsd"; + + /** + * Contains all namespaces and local schema locations for XML schema + * definitions relevant for MOA. For use in validating XML parsers. + */ + public static final String ALL_SCHEMA_LOCATIONS = + (MOA_NS_URI + " " + MOA_SCHEMA_LOCATION + " ") + + (MOA_CONFIG_NS_URI + " " + MOA_CONFIG_SCHEMA_LOCATION + " ") + + (MOA_ID_CONFIG_NS_URI + " " + MOA_ID_CONFIG_SCHEMA_LOCATION + " ") + + (SL10_NS_URI + " " + SL10_SCHEMA_LOCATION + " ") + + (SL11_NS_URI + " " + SL11_SCHEMA_LOCATION + " ") + + (ECDSA_NS_URI + " " + ECDSA_SCHEMA_LOCATION + " ") + + (PD_NS_URI + " " + PD_SCHEMA_LOCATION + " ") + + (SAML_NS_URI + " " + SAML_SCHEMA_LOCATION + " ") + + (SAMLP_NS_URI + " " + SAMLP_SCHEMA_LOCATION + " ") + + (XML_NS_URI + " " + XML_SCHEMA_LOCATION + " ") + + (XSI_NS_URI + " " + XSI_SCHEMA_LOCATION + " ") + + (DSIG_NS_URI + " " + DSIG_SCHEMA_LOCATION + " ") + + (DSIG_FILTER2_NS_URI + " " + DSIG_FILTER2_SCHEMA_LOCATION + " ") + + (DSIG_EC_NS_URI + " " + DSIG_EC_SCHEMA_LOCATION); + + /** Security Layer manifest type URI. */ + public static final String SL_MANIFEST_TYPE_URI = + "http://www.buergerkarte.at/specifications/Security-Layer/20020225#SignatureManifest"; + + /** URI of the SHA1 digest algorithm */ + public static final String SHA1_URI = + "http://www.w3.org/2000/09/xmldsig#sha1"; + + /** URI of the Canonical XML algorithm */ + public static final String C14N_URI = + "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"; + + /** URI of the Canoncial XML with comments algorithm */ + public static final String C14N_WITH_COMMENTS_URI = + "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"; + + /** URI of the Exclusive Canonical XML algorithm */ + public static final String EXC_C14N_URI = + "http://www.w3.org/2001/10/xml-exc-c14n#"; + + /** URI of the Exclusive Canonical XML with commments algorithm */ + public static final String EXC_C14N_WITH_COMMENTS_URI = + "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"; +} diff --git a/common/src/at/gv/egovernment/moa/util/DOMUtils.java b/common/src/at/gv/egovernment/moa/util/DOMUtils.java new file mode 100644 index 000000000..6da99037e --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/DOMUtils.java @@ -0,0 +1,806 @@ +package at.gv.egovernment.moa.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import org.apache.xerces.parsers.DOMParser; +import org.apache.xerces.parsers.SAXParser; +import org.apache.xerces.parsers.XMLGrammarPreparser; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLGrammarPoolImpl; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * Various utility functions for handling XML DOM trees. + * + * The parsing methods in this class make use of some features internal to the + * Xerces DOM parser, mainly for performance reasons. As soon as JAXP + * (currently at version 1.2) is better at schema handling, it should be used as + * the parser interface. + * + * @author Patrick Peck + * @version $Id$ + */ +public class DOMUtils { + + /** Feature URI for namespace aware parsing. */ + private static final String NAMESPACES_FEATURE = + "http://xml.org/sax/features/namespaces"; + /** Feature URI for validating parsing. */ + private static final String VALIDATION_FEATURE = + "http://xml.org/sax/features/validation"; + /** Feature URI for schema validating parsing. */ + private static final String SCHEMA_VALIDATION_FEATURE = + "http://apache.org/xml/features/validation/schema"; + /** Feature URI for normalization of element/attribute values. */ + private static final String NORMALIZED_VALUE_FEATURE = + "http://apache.org/xml/features/validation/schema/normalized-value"; + /** Feature URI for parsing ignorable whitespace. */ + private static final String INCLUDE_IGNORABLE_WHITESPACE_FEATURE = + "http://apache.org/xml/features/dom/include-ignorable-whitespace"; + /** Feature URI for creating EntityReference nodes in the DOM tree. */ + private static final String CREATE_ENTITY_REF_NODES_FEATURE = + "http://apache.org/xml/features/dom/create-entity-ref-nodes"; + /** Property URI for providing external schema locations. */ + private static final String EXTERNAL_SCHEMA_LOCATION_PROPERTY = + "http://apache.org/xml/properties/schema/external-schemaLocation"; + /** Property URI for providing the external schema location for elements + * without a namespace. */ + private static final String EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY = + "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation"; + /** Property URI for the Xerces grammar pool. */ + private static final String GRAMMAR_POOL = + org.apache.xerces.impl.Constants.XERCES_PROPERTY_PREFIX + + org.apache.xerces.impl.Constants.XMLGRAMMAR_POOL_PROPERTY; + /** A prime number for initializing the symbol table. */ + private static final int BIG_PRIME = 2039; + /** Symbol table for the grammar pool. */ + private static SymbolTable symbolTable = new SymbolTable(BIG_PRIME); + /** Xerces schema grammar pool. */ + private static XMLGrammarPool grammarPool = new XMLGrammarPoolImpl(); + + /** + * Preparse a schema and add it to the schema pool. + * + * @param inputStream An InputStream providing the contents of + * the schema. + * @param systemId The systemId to use for the schema. + * @throws IOException An error occurred reading the schema. + */ + public static void addSchemaToPool(InputStream inputStream, String systemId) + throws IOException { + XMLGrammarPreparser preparser; + + // unlock the pool so that we can add another grammar + grammarPool.unlockPool(); + + // prepare the preparser + preparser = new XMLGrammarPreparser(symbolTable); + preparser.registerPreparser(XMLGrammarDescription.XML_SCHEMA, null); + preparser.setProperty(GRAMMAR_POOL, grammarPool); + preparser.setFeature(NAMESPACES_FEATURE, true); + preparser.setFeature(VALIDATION_FEATURE, true); + + // add the grammar to the pool + preparser.preparseGrammar( + XMLGrammarDescription.XML_SCHEMA, + new XMLInputSource(null, systemId, null, inputStream, null)); + + // lock the pool again so that schemas are not added automatically + grammarPool.lockPool(); + } + + /** + * Parse an XML document from an InputStream. + * + * @param inputStream The InputStream containing the XML + * document. + * @param validating If true, parse validating. + * @param externalSchemaLocations A String containing namespace + * URI to schema location pairs, the same way it is accepted by the xsi: + * schemaLocation attribute. + * @param externalNoNamespaceSchemaLocation The schema location of the + * schema for elements without a namespace, the same way it is accepted by the + * xsi:noNamespaceSchemaLocation attribute. + * @param entityResolver An EntityResolver to resolve external + * entities (schemas and DTDs). If null, it will not be set. + * @param errorHandler An ErrorHandler to decide what to do + * with parsing errors. If null, it will not be set. + * @return The parsed XML document as a DOM tree. + * @throws SAXException An error occurred parsing the document. + * @throws IOException An error occurred reading the document. + * @throws ParserConfigurationException An error occurred configuring the XML + * parser. + */ + public static Document parseDocument( + InputStream inputStream, + boolean validating, + String externalSchemaLocations, + String externalNoNamespaceSchemaLocation, + EntityResolver entityResolver, + ErrorHandler errorHandler) + throws SAXException, IOException, ParserConfigurationException { + + DOMParser parser; + + // create the DOM parser + if (symbolTable != null) { + parser = new DOMParser(symbolTable, grammarPool); + } else { + parser = new DOMParser(); + } + + // set parser features and properties + parser.setFeature(NAMESPACES_FEATURE, true); + parser.setFeature(VALIDATION_FEATURE, validating); + parser.setFeature(SCHEMA_VALIDATION_FEATURE, validating); + parser.setFeature(NORMALIZED_VALUE_FEATURE, false); + parser.setFeature(INCLUDE_IGNORABLE_WHITESPACE_FEATURE, true); + parser.setFeature(CREATE_ENTITY_REF_NODES_FEATURE, false); + + if (validating) { + if (externalSchemaLocations != null) { + parser.setProperty( + EXTERNAL_SCHEMA_LOCATION_PROPERTY, + externalSchemaLocations); + } + if (externalNoNamespaceSchemaLocation != null) { + parser.setProperty( + EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY, + externalNoNamespaceSchemaLocation); + } + } + + // set entity resolver and error handler + if (entityResolver != null) { + parser.setEntityResolver(entityResolver); + } + if (errorHandler != null) { + parser.setErrorHandler(errorHandler); + } + + // parse the document and return it + parser.parse(new InputSource(inputStream)); + + return parser.getDocument(); + } + + /** + * Parse an XML document from an InputStream. + * + * It uses a MOAEntityResolver as the EntityResolver + * and a MOAErrorHandler as the ErrorHandler. + * + * @param inputStream The InputStream containing the XML + * document. + * @param validating If true, parse validating. + * @param externalSchemaLocations A String containing namespace + * URI to schema location pairs, the same way it is accepted by the xsi: + * schemaLocation attribute. + * @param externalNoNamespaceSchemaLocation The schema location of the + * schema for elements without a namespace, the same way it is accepted by the + * xsi:noNamespaceSchemaLocation attribute. + * @return The parsed XML document as a DOM tree. + * @throws SAXException An error occurred parsing the document. + * @throws IOException An error occurred reading the document. + * @throws ParserConfigurationException An error occurred configuring the XML + * parser. + */ + public static Document parseDocument( + InputStream inputStream, + boolean validating, + String externalSchemaLocations, + String externalNoNamespaceSchemaLocation) + throws SAXException, IOException, ParserConfigurationException { + + return parseDocument( + inputStream, + validating, + externalSchemaLocations, + externalNoNamespaceSchemaLocation, + new MOAEntityResolver(), + new MOAErrorHandler()); + } + + /** + * Parse an XML document from a String. + * + * It uses a MOAEntityResolver as the EntityResolver + * and a MOAErrorHandler as the ErrorHandler. + * + * @param xmlString The String containing the XML document. + * @param encoding The encoding of the XML document. + * @param validating If true, parse validating. + * @param externalSchemaLocations A String containing namespace + * URI to schema location pairs, the same way it is accepted by the xsi: + * schemaLocation attribute. + * @param externalNoNamespaceSchemaLocation The schema location of the + * schema for elements without a namespace, the same way it is accepted by the + * xsi:noNamespaceSchemaLocation attribute. + * @return The parsed XML document as a DOM tree. + * @throws SAXException An error occurred parsing the document. + * @throws IOException An error occurred reading the document. + * @throws ParserConfigurationException An error occurred configuring the XML + * parser. + */ + public static Document parseDocument( + String xmlString, + String encoding, + boolean validating, + String externalSchemaLocations, + String externalNoNamespaceSchemaLocation) + throws SAXException, IOException, ParserConfigurationException { + + InputStream in = new ByteArrayInputStream(xmlString.getBytes(encoding)); + return parseDocument( + in, + validating, + externalSchemaLocations, + externalNoNamespaceSchemaLocation); + } + + /** + * Parse an UTF-8 encoded XML document from a String. + * + * @param xmlString The String containing the XML document. + * @param validating If true, parse validating. + * @param externalSchemaLocations A String containing namespace + * URI to schema location pairs, the same way it is accepted by the xsi: + * schemaLocation attribute. + * @param externalNoNamespaceSchemaLocation The schema location of the + * schema for elements without a namespace, the same way it is accepted by the + * xsi:noNamespaceSchemaLocation attribute. + * @return The parsed XML document as a DOM tree. + * @throws SAXException An error occurred parsing the document. + * @throws IOException An error occurred reading the document. + * @throws ParserConfigurationException An error occurred configuring the XML + * parser. + */ + public static Document parseDocument( + String xmlString, + boolean validating, + String externalSchemaLocations, + String externalNoNamespaceSchemaLocation) + throws SAXException, IOException, ParserConfigurationException { + + return parseDocument( + xmlString, + "UTF-8", + validating, + externalSchemaLocations, + externalNoNamespaceSchemaLocation); + } + + /** + * A convenience method to parse an XML document validating. + * + * @param inputStream The InputStream containing the XML + * document. + * @return The root element of the parsed XML document. + * @throws SAXException An error occurred parsing the document. + * @throws IOException An error occurred reading the document. + * @throws ParserConfigurationException An error occurred configuring the XML + * parser. + */ + public static Element parseXmlValidating(InputStream inputStream) + throws ParserConfigurationException, SAXException, IOException { + return DOMUtils + .parseDocument(inputStream, true, Constants.ALL_SCHEMA_LOCATIONS, null) + .getDocumentElement(); + } + + /** + * Schema validate a given DOM element. + * + * @param element The element to validate. + * @param externalSchemaLocations A String containing namespace + * URI to schema location pairs, the same way it is accepted by the xsi: + * schemaLocation attribute. + * @param externalNoNamespaceSchemaLocation The schema location of the + * schema for elements without a namespace, the same way it is accepted by the + * xsi:noNamespaceSchemaLocation attribute. + * @return true, if the element validates against + * the schemas declared in it. + * @throws SAXException An error occurred parsing the document. + * @throws IOException An error occurred reading the document from its + * serialized representation. + * @throws ParserConfigurationException An error occurred configuring the XML + * @throws TransformerException An error occurred serializing the element. + */ + public static boolean validateElement( + Element element, + String externalSchemaLocations, + String externalNoNamespaceSchemaLocation) + throws + ParserConfigurationException, + IOException, + SAXException, + TransformerException { + + byte[] docBytes; + SAXParser parser; + + // create the SAX parser + if (symbolTable != null) { + parser = new SAXParser(symbolTable, grammarPool); + } else { + parser = new SAXParser(); + } + + // serialize the document + docBytes = serializeNode(element, "UTF-8"); + + // set up parser features and attributes + parser.setFeature(NAMESPACES_FEATURE, true); + parser.setFeature(VALIDATION_FEATURE, true); + parser.setFeature(SCHEMA_VALIDATION_FEATURE, true); + if (externalSchemaLocations != null) { + parser.setProperty( + EXTERNAL_SCHEMA_LOCATION_PROPERTY, + externalSchemaLocations); + } + if (externalNoNamespaceSchemaLocation != null) { + parser.setProperty( + EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY, + "externalNoNamespaceSchemaLocation"); + } + + // set up entity resolver and error handler + parser.setEntityResolver(new MOAEntityResolver()); + parser.setErrorHandler(new MOAErrorHandler()); + + // parse validating + parser.parse(new InputSource(new ByteArrayInputStream(docBytes))); + return true; + } + + /** + * Serialize the given DOM node. + * + * The node will be serialized using the UTF-8 encoding. + * + * @param node The node to serialize. + * @return String The String representation of the given DOM + * node. + * @throws TransformerException An error occurred transforming the + * node to a String. + * @throws IOException An IO error occurred writing the node to a byte array. + */ + public static String serializeNode(Node node) + throws TransformerException, IOException { + return new String(serializeNode(node, "UTF-8"), "UTF-8"); + } + + /** + * Serialize the given DOM node to a byte array. + * + * @param node The node to serialize. + * @param xmlEncoding The XML encoding to use. + * @return The serialized node, as a byte array. Using a compatible encoding + * this can easily be converted into a String. + * @throws TransformerException An error occurred transforming the node to a + * byte array. + * @throws IOException An IO error occurred writing the node to a byte array. + */ + public static byte[] serializeNode(Node node, String xmlEncoding) + throws TransformerException, IOException { + + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer = transformerFactory.newTransformer(); + ByteArrayOutputStream bos = new ByteArrayOutputStream(16384); + + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); + transformer.setOutputProperty(OutputKeys.ENCODING, xmlEncoding); + transformer.transform(new DOMSource(node), new StreamResult(bos)); + + bos.flush(); + bos.close(); + + return bos.toByteArray(); + } + + /** + * Return the text that a node contains. + * + * This routine: + *
    + *
  • Ignores comments and processing instructions.
  • + *
  • Concatenates TEXT nodes, CDATA nodes, and the results recursively + * processing EntityRef nodes.
  • + *
  • Ignores any element nodes in the sublist. (Other possible options are + * to recurse into element sublists or throw an exception.)
  • + *
+ * + * @param node A DOM node from which to extract text. + * @return A String representing its contents. + */ + public static String getText(Node node) { + if (!node.hasChildNodes()) { + return ""; + } + + StringBuffer result = new StringBuffer(); + NodeList list = node.getChildNodes(); + + for (int i = 0; i < list.getLength(); i++) { + Node subnode = list.item(i); + if (subnode.getNodeType() == Node.TEXT_NODE) { + result.append(subnode.getNodeValue()); + } else if (subnode.getNodeType() == Node.CDATA_SECTION_NODE) { + result.append(subnode.getNodeValue()); + } else if (subnode.getNodeType() == Node.ENTITY_REFERENCE_NODE) { + // Recurse into the subtree for text + // (and ignore comments) + result.append(getText(subnode)); + } + } + return result.toString(); + } + + /** + * Build the namespace prefix to namespace URL mapping in effect for a given + * node. + * + * @param node The context node for which build the map. + * @return The namespace prefix to namespace URL mapping ( + * a String value to String value mapping). + */ + public static Map getNamespaceDeclarations(Node node) { + Map nsDecls = new HashMap(); + int i; + + do { + if (node.hasAttributes()) { + NamedNodeMap attrs = node.getAttributes(); + + for (i = 0; i < attrs.getLength(); i++) { + Attr attr = (Attr) attrs.item(i); + + // add prefix mapping if none exists + if ("xmlns".equals(attr.getPrefix()) + || "xmlns".equals(attr.getName())) { + + String nsPrefix = + attr.getPrefix() != null ? attr.getLocalName() : ""; + + if (nsDecls.get(nsPrefix) == null) { + nsDecls.put(nsPrefix, attr.getValue()); + } + } + } + } + } while ((node = node.getParentNode()) != null); + + return nsDecls; + } + + /** + * Add all namespace declarations declared in the parent(s) of a given + * element and used in the subtree of the given element to the given element. + * + * @param context The element to which to add the namespaces. + */ + public static void localizeNamespaceDeclarations(Element context) { + Node parent = context.getParentNode(); + + if (parent != null) { + Map namespaces = getNamespaceDeclarations(context.getParentNode()); + Set nsUris = collectNamespaceURIs(context); + Iterator iter; + + for (iter = namespaces.entrySet().iterator(); iter.hasNext();) { + Map.Entry e = (Map.Entry) iter.next(); + + if (nsUris.contains(e.getValue())) { + String prefix = (String) e.getKey(); + String nsUri = (String) e.getValue(); + String nsAttrName = "".equals(prefix) ? "xmlns" : "xmlns:" + prefix; + + context.setAttributeNS(Constants.XMLNS_NS_URI, nsAttrName, nsUri); + } + } + } + } + + /** + * Collect all the namespace URIs used in the subtree of a given element. + * + * @param context The element that should be searched for namespace URIs. + * @return All namespace URIs used in the subtree of context, + * including the ones used in context itself. + */ + public static Set collectNamespaceURIs(Element context) { + Set result = new HashSet(); + + collectNamespaceURIsImpl(context, result); + return result; + } + + /** + * A recursive method to do the work of collectNamespaceURIs. + * + * @param context The context element to evaluate. + * @param result The result, passed as a parameter to avoid unnecessary + * instantiations of Set. + */ + private static void collectNamespaceURIsImpl(Element context, Set result) { + NamedNodeMap attrs = context.getAttributes(); + NodeList childNodes = context.getChildNodes(); + String nsUri; + int i; + + // add the namespace of the context element + nsUri = context.getNamespaceURI(); + if (nsUri != null && nsUri != Constants.XMLNS_NS_URI) { + result.add(nsUri); + } + + // add all namespace URIs from attributes + for (i = 0; i < attrs.getLength(); i++) { + nsUri = attrs.item(i).getNamespaceURI(); + if (nsUri != null && nsUri != Constants.XMLNS_NS_URI) { + result.add(nsUri); + } + } + + // add all namespaces from subelements + for (i = 0; i < childNodes.getLength(); i++) { + Node node = childNodes.item(i); + + if (node.getNodeType() == Node.ELEMENT_NODE) { + collectNamespaceURIsImpl((Element) node, result); + } + } + } + + /** + * Check, that each attribute node in the given NodeList has its + * parent in the NodeList as well. + * + * @param nodes The NodeList to check. + * @return true, if each attribute node in nodes + * has its parent in nodes as well. + */ + public static boolean checkAttributeParentsInNodeList(NodeList nodes) { + Set nodeSet = new HashSet(); + int i; + + // put the nodes into the nodeSet + for (i = 0; i < nodes.getLength(); i++) { + nodeSet.add(nodes.item(i)); + } + + // check that each attribute node's parent is in the node list + for (i = 0; i < nodes.getLength(); i++) { + Node n = nodes.item(i); + + if (n.getNodeType() == Node.ATTRIBUTE_NODE) { + Attr attr = (Attr) n; + Element owner = attr.getOwnerElement(); + + if (owner == null) { + if (!isNamespaceDeclaration(attr)) { + return false; + } + } + + if (!nodeSet.contains(owner) && !isNamespaceDeclaration(attr)) { + return false; + } + } + } + + return true; + } + + /** + * Convert an unstructured NodeList into a + * DocumentFragment. + * + * @param nodeList Contains the node list to be converted into a DOM + * DocumentFragment. + * @return the resulting DocumentFragment. The DocumentFragment will be + * backed by a new DOM Document, i.e. all noded of the node list will be + * cloned. + * @throws ParserConfigurationException An error occurred creating the + * DocumentFragment. + * @precondition The nodes in the node list appear in document order. + * @precondition For each Attr node in the node list, the owning Element is + * in the node list as well. + * @precondition Each Element or Attr node in the node list is namespace + * aware. + */ + public static DocumentFragment nodeList2DocumentFragment(NodeList nodeList) + throws ParserConfigurationException { + + DocumentBuilder builder = + DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document doc = builder.newDocument(); + DocumentFragment result = doc.createDocumentFragment(); + + if (null == nodeList || nodeList.getLength() == 0) { + return result; + } + + int currPos = 0; + currPos = + nodeList2DocumentFragment(nodeList, currPos, result, null, null) + 1; + + while (currPos < nodeList.getLength()) { + currPos = + nodeList2DocumentFragment(nodeList, currPos, result, null, null) + 1; + } + return result; + } + + /** + * Helper method for the nodeList2DocumentFragment. + * + * @param nodeList The NodeList to convert. + * @param currPos The current position in the nodeList. + * @param result The resulting DocumentFragment. + * @param currOrgElem The current original element. + * @param currClonedElem The current cloned element. + * @return The current position. + */ + private static int nodeList2DocumentFragment( + NodeList nodeList, + int currPos, + DocumentFragment result, + Element currOrgElem, + Element currClonedElem) { + + while (currPos < nodeList.getLength()) { + Node currentNode = nodeList.item(currPos); + switch (currentNode.getNodeType()) { + case Node.COMMENT_NODE : + case Node.PROCESSING_INSTRUCTION_NODE : + case Node.TEXT_NODE : + { + // Append current node either to resulting DocumentFragment or to + // current cloned Element + if (null == currClonedElem) { + result.appendChild( + result.getOwnerDocument().importNode(currentNode, false)); + } else { + // Stop processing if current Node is not a descendant of + // current Element + if (!isAncestor(currOrgElem, currentNode)) { + return --currPos; + } + + currClonedElem.appendChild( + result.getOwnerDocument().importNode(currentNode, false)); + } + break; + } + + case Node.ELEMENT_NODE : + { + Element nextCurrOrgElem = (Element) currentNode; + Element nextCurrClonedElem = + result.getOwnerDocument().createElementNS( + nextCurrOrgElem.getNamespaceURI(), + nextCurrOrgElem.getNodeName()); + + // Append current Node either to resulting DocumentFragment or to + // current cloned Element + if (null == currClonedElem) { + result.appendChild(nextCurrClonedElem); + currOrgElem = nextCurrOrgElem; + currClonedElem = nextCurrClonedElem; + } else { + // Stop processing if current Node is not a descendant of + // current Element + if (!isAncestor(currOrgElem, currentNode)) { + return --currPos; + } + + currClonedElem.appendChild(nextCurrClonedElem); + } + + // Process current Node (of type Element) recursively + currPos = + nodeList2DocumentFragment( + nodeList, + ++currPos, + result, + nextCurrOrgElem, + nextCurrClonedElem); + + break; + } + + case Node.ATTRIBUTE_NODE : + { + Attr currAttr = (Attr) currentNode; + + // GK 20030411: Hack to overcome problems with IAIK IXSIL + if (currAttr.getOwnerElement() == null) + break; + if (currClonedElem == null) + break; + + // currClonedElem must be the owner Element of currAttr if + // preconditions are met + currClonedElem.setAttributeNS( + currAttr.getNamespaceURI(), + currAttr.getNodeName(), + currAttr.getValue()); + break; + } + + default : + { + // All other nodes will be ignored + } + } + + currPos++; + } + + return currPos; + } + + /** + * Check, if the given attribute is a namespace declaration. + * + * @param attr The attribute to check. + * @return true, if the attribute is a namespace declaration, + * false otherwise. + */ + private static boolean isNamespaceDeclaration(Attr attr) { + return Constants.XMLNS_NS_URI.equals(attr.getNamespaceURI()); + } + + /** + * Check, if a given DOM element is an ancestor of a given node. + * + * @param candAnc The DOM element to check for being the ancestor. + * @param cand The node to check for being the child. + * @return true, if candAnc is an (indirect) + * ancestor of cand; false otherwise. + */ + public static boolean isAncestor(Element candAnc, Node cand) { + Node currPar = cand.getParentNode(); + + while (currPar != null) { + if (candAnc == currPar) + return true; + currPar = currPar.getParentNode(); + } + return false; + } + +} diff --git a/common/src/at/gv/egovernment/moa/util/DateTimeUtils.java b/common/src/at/gv/egovernment/moa/util/DateTimeUtils.java new file mode 100644 index 000000000..58cc04c4c --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/DateTimeUtils.java @@ -0,0 +1,326 @@ +package at.gv.egovernment.moa.util; + +import java.io.StringWriter; +import java.text.ParseException; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +/** + * Utility for parsing and building XML type dateTime, + * according to ISO 8601. + * + * @author Patrick Peck + * @version $Id$ + * @see http://www.w3.org/2001/XMLSchema-datatypes" + */ +public class DateTimeUtils { + /** Error messages. */ + private static MessageProvider msg = MessageProvider.getInstance(); + + /** + * Builds a dateTime value from a Calendar value. + * @param cal the Calendar value + * @return the dateTime value + */ + public static String buildDateTime(Calendar cal) { + StringWriter out = new StringWriter(); + out.write("" + cal.get(Calendar.YEAR)); + out.write("-"); + out.write(to2DigitString(cal.get(Calendar.MONTH) + 1)); + out.write("-"); + out.write(to2DigitString(cal.get(Calendar.DAY_OF_MONTH))); + out.write("T"); + out.write(to2DigitString(cal.get(Calendar.HOUR_OF_DAY))); + out.write(":"); + out.write(to2DigitString(cal.get(Calendar.MINUTE))); + out.write(":"); + out.write(to2DigitString(cal.get(Calendar.SECOND))); + int tzOffsetMilliseconds = + cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET); + if (tzOffsetMilliseconds != 0) { + int tzOffsetMinutes = tzOffsetMilliseconds / (1000 * 60); + int tzOffsetHours = tzOffsetMinutes / 60; + tzOffsetMinutes -= tzOffsetHours * 60; + if (tzOffsetMilliseconds > 0) { + out.write("+"); + out.write(to2DigitString(tzOffsetHours)); + out.write(":"); + out.write(to2DigitString(tzOffsetMinutes)); + } else { + out.write("-"); + out.write(to2DigitString(-tzOffsetHours)); + out.write(":"); + out.write(to2DigitString(-tzOffsetMinutes)); + } + } + return out.toString(); + } + + /** + * Converts month, day, hour, minute, or second value + * to a 2 digit String. + * @param number the month, day, hour, minute, or second value + * @return 2 digit String + */ + private static String to2DigitString(int number) { + if (number < 10) + return "0" + number; + else + return "" + number; + } + + /** + * Parse a String containing a date and time instant, given in + * ISO 8601 format. + * + * @param dateTime The String to parse. + * @return The Date representation of the contents of + * dateTime. + * @throws ParseException Parsing the dateTime failed. + */ + public static Date parseDateTime(String dateTime) throws ParseException { + GregorianCalendar calendar; + long time; + int yearSign = 1, year, month, day; + int hour, minute, second; + double fraction = 0.0; + int tzSign = 1, tzHour = 0, tzMinute = 0; + int curPos = 0; + String fractStr; + boolean localTime = false; + char c; + + // parse year sign + ensureChars(dateTime, curPos, 1); + c = dateTime.charAt(curPos); + if (c == '+' || c == '-') { + yearSign = c == '+' ? 1 : -1; + curPos++; + } + + // parse year + year = parseInt(dateTime, curPos, 4); + curPos += 4; + + // parse '-' + ensureChar(dateTime, curPos, '-'); + curPos++; + + // parse month + month = parseInt(dateTime, curPos, 2); + ensureValue(month, 1, 12, curPos); + curPos += 2; + + // parse '-' + ensureChar(dateTime, curPos, '-'); + curPos++; + + // parse day + day = parseInt(dateTime, curPos, 2); + ensureValue(day, 1, 31, curPos); + curPos += 2; + + // parse 'T' + ensureChar(dateTime, curPos, 'T'); + curPos++; + + // parse hour + hour = parseInt(dateTime, curPos, 2); + ensureValue(hour, 0, 23, curPos); + curPos += 2; + + // parse ':' + ensureChar(dateTime, curPos, ':'); + curPos++; + + // parse minute + minute = parseInt(dateTime, curPos, 2); + ensureValue(minute, 0, 59, curPos); + curPos += 2; + + // parse ':' + ensureChar(dateTime, curPos, ':'); + curPos++; + + // parse second + second = parseInt(dateTime, curPos, 2); + ensureValue(second, 0, 59, curPos); + curPos += 2; + + // parse a fraction + if (dateTime.length() > curPos && dateTime.charAt(curPos) == '.') { + curPos++; + ensureDigits(dateTime, curPos, 1); + fractStr = "0."; + fractStr + += dateTime.substring(curPos, curPos + countDigits(dateTime, curPos)); + fraction = Double.parseDouble(fractStr); + curPos += countDigits(dateTime, curPos); + } + + // parse a time zone + if (dateTime.length() > curPos) { + c = dateTime.charAt(curPos); + if (c == 'Z') { + curPos++; + } else if (c == '+' || c == '-') { + // parse time zone sign + tzSign = c == '+' ? 1 : -1; + curPos++; + + // parse time zone hour + tzHour = parseInt(dateTime, curPos, 2); + ensureValue(tzHour, 0, 14, curPos); + curPos += 2; + + // parse ':' + ensureChar(dateTime, curPos, ':'); + curPos++; + + // parse time zone minute + tzMinute = parseInt(dateTime, curPos, 2); + ensureValue(tzMinute, 0, 59, curPos); + curPos += 2; + } + } else { + localTime = true; + } + + // if we have characters left, it's an error + if (dateTime.length() != curPos) { + throw new ParseException(msg.getMessage("datetime.00", null), curPos); + } + + // build the Date object + year = year * yearSign; + try { + calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT")); + calendar.set(year, month - 1, day, hour, minute, second); + calendar.set(Calendar.MILLISECOND, 0); + time = calendar.getTime().getTime(); + time += (long) (fraction * 1000.0); + time -= tzSign * ((tzHour * 60) + tzMinute) * 60 * 1000; + if (localTime) { + time -= TimeZone.getDefault().getRawOffset(); + } + return new Date(time); + } catch (IllegalArgumentException e) { + throw new ParseException(msg.getMessage("datetime.00", null), curPos); + } + + } + + /** + * Parse an integer value. + * + * @param str The String containing the digits. + * @param curPos The starting position. + * @param digits The number of digist making up the integer value. + * @return int The integer representation of the digits contained in + * str. + * @throws ParseException Parsing the integer value failed. + */ + private static int parseInt(String str, int curPos, int digits) + throws ParseException { + + ensureDigits(str, curPos, digits); + return Integer.parseInt(str.substring(curPos, curPos + digits)); + } + + /** + * Count the number of digits following curPos. + * + * @param str The String in which to count digits. + * @param curPos The starting position. + * @return int The number of digits. + */ + private static int countDigits(String str, int curPos) { + int i; + + for (i = curPos; i < str.length() && Character.isDigit(str.charAt(i)); i++); + return i - curPos; + } + + /** + * Ensure that a value falls in a given min/max range. + * + * @param value The value to check. + * @param min The minimum allowed value. + * @param max The maximum allowed value. + * @param curPos To indicate the parsing position in the + * ParseException. + * @throws ParseException Thrown, if value < min || value > + * max + */ + private static void ensureValue(int value, int min, int max, int curPos) + throws ParseException { + + if (value < min || value > max) { + throw new ParseException(msg.getMessage("datetime.00", null), curPos); + } + } + + /** + * Ensure that the given String has a number of characters left. + * + * @param str The String to check for its length. + * @param curPos The starting position. + * @param count The minimum number of characters that str must + * contain, starting at from curPos. + * @throws ParseException Thrown, if + * curPos + count > str.length(). + */ + private static void ensureChars(String str, int curPos, int count) + throws ParseException { + if (curPos + count > str.length()) { + throw new ParseException(msg.getMessage("datetime.00", null), curPos); + } + } + + /** + * Ensure that a given String contains a certain character at a + * certain position. + * + * @param str The String in which to look up the character. + * @param curPos The position in str that must contain the + * character. + * @param c The character value that must be contained at position + * curPos. + * @throws ParseException Thrown, if the characters do not match or + * curPos is out of range. + */ + private static void ensureChar(String str, int curPos, char c) + throws ParseException { + + ensureChars(str, curPos, 1); + if (str.charAt(curPos) != c) { + throw new ParseException(msg.getMessage("datetime.00", null), curPos); + } + } + + /** + * Ensure that a given String contains a number of digits, + * starting at a given position. + * + * @param str The String to scan for digits. + * @param curPos The starting postion. + * @param count The number of digits that must be contained in + * str, starting at curPos. + * @throws ParseException Thrown, if str is not long enough, or + * one of the characters following curPos in str is + * not a digit. + */ + private static void ensureDigits(String str, int curPos, int count) + throws ParseException { + + ensureChars(str, curPos, count); + for (int i = curPos; i < curPos + count; i++) { + if (!Character.isDigit(str.charAt(i))) { + throw new ParseException(msg.getMessage("datetime.00", null), curPos); + } + } + } + +} diff --git a/common/src/at/gv/egovernment/moa/util/EntityResolverChain.java b/common/src/at/gv/egovernment/moa/util/EntityResolverChain.java new file mode 100644 index 000000000..e7008a701 --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/EntityResolverChain.java @@ -0,0 +1,52 @@ +package at.gv.egovernment.moa.util; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * Implementation of the org.xml.sax.EntityResolver, + * for use by a org.apache.xerces.parsers.DOMParser. + * + * @author Patrick Peck + * @version $Id$ + */ +public class EntityResolverChain implements EntityResolver { + /** The EntityResolvers in the chain. */ + private List resolvers = new ArrayList(); + + /** + * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String, java.lang.String) + */ + public InputSource resolveEntity(String publicId, String systemId) + throws SAXException, IOException { + + Iterator iter; + + for (iter = resolvers.iterator(); iter.hasNext(); ) { + EntityResolver resolver = (EntityResolver) iter.next(); + InputSource is = resolver.resolveEntity(publicId, systemId); + + if (is != null) { + return is; + } + } + + return null; + } + + /** + * Add an EntityResolver to the chain. + * + * @param entityResolver The EntityResolver to add. + */ + public void addEntityResolver(EntityResolver entityResolver) { + resolvers.add(entityResolver); + } + +} diff --git a/common/src/at/gv/egovernment/moa/util/FileUtils.java b/common/src/at/gv/egovernment/moa/util/FileUtils.java new file mode 100644 index 000000000..f8941568d --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/FileUtils.java @@ -0,0 +1,87 @@ +package at.gv.egovernment.moa.util; + +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +/** + * Utility for accessing files on the file system, and for reading from input streams. + * @author Paul Ivancsics + * @version $Id$ + */ +public class FileUtils { + + /** + * Reads a file, given by URL, into a byte array. + * @param urlString file URL + * @return file content + * @throws IOException on any exception thrown + */ + public static byte[] readURL(String urlString) throws IOException { + URL url = new URL(urlString); + InputStream in = new BufferedInputStream(url.openStream()); + byte[] content = StreamUtils.readStream(in); + in.close(); + return content; + } + /** + * Reads a file, given by URL, into a String. + * @param urlString file URL + * @param encoding character encoding + * @return file content + * @throws IOException on any exception thrown + */ + public static String readURL(String urlString, String encoding) throws IOException { + byte[] content = readURL(urlString); + return new String(content, encoding); + } + /** + * Reads a file, given by filename, into a byte array. + * @param filename filename + * @return file content + * @throws IOException on any exception thrown + */ + public static byte[] readFile(String filename) throws IOException { + BufferedInputStream in = new BufferedInputStream(new FileInputStream(filename)); + byte[] content = StreamUtils.readStream(in); + in.close(); + return content; + } + /** + * Reads a file, given by filename, into a String. + * @param filename filename + * @param encoding character encoding + * @return file content + * @throws IOException on any exception thrown + */ + public static String readFile(String filename, String encoding) throws IOException { + byte[] content = readFile(filename); + return new String(content, encoding); + } + /** + * Reads a file from a resource. + * @param name resource name + * @return file content as a byte array + * @throws IOException on any exception thrown + */ + public static byte[] readResource(String name) throws IOException { + ClassLoader cl = FileUtils.class.getClassLoader(); + BufferedInputStream in = new BufferedInputStream(cl.getResourceAsStream(name)); + byte[] content = StreamUtils.readStream(in); + in.close(); + return content; + } + /** + * Reads a file from a resource. + * @param name filename + * @param encoding character encoding + * @return file content + * @throws IOException on any exception thrown + */ + public static String readResource(String name, String encoding) throws IOException { + byte[] content = readResource(name); + return new String(content, encoding); + } +} diff --git a/common/src/at/gv/egovernment/moa/util/KeyStoreUtils.java b/common/src/at/gv/egovernment/moa/util/KeyStoreUtils.java new file mode 100644 index 000000000..d6a34a7b2 --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/KeyStoreUtils.java @@ -0,0 +1,134 @@ +package at.gv.egovernment.moa.util; + +import iaik.x509.X509Certificate; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.cert.Certificate; + +/** + * Utility for creating and loading key stores. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class KeyStoreUtils { + + /** + * Loads a key store from file. + * + * @param keystoreType key store type + * @param urlString URL of key store + * @param password password protecting the key store + * @return key store loaded + * @throws IOException thrown while reading the key store from file + * @throws GeneralSecurityException thrown while creating the key store + */ + public static KeyStore loadKeyStore( + String keystoreType, + String urlString, + String password) + throws IOException, GeneralSecurityException { + + URL keystoreURL = new URL(urlString); + InputStream in = keystoreURL.openStream(); + return loadKeyStore(keystoreType, in, password); + } + /** + * Loads a key store from an InputStream, and + * closes the InputStream. + * + * @param keystoreType key store type + * @param in input stream + * @param password password protecting the key store + * @return key store loaded + * @throws IOException thrown while reading the key store from the stream + * @throws GeneralSecurityException thrown while creating the key store + */ + public static KeyStore loadKeyStore( + String keystoreType, + InputStream in, + String password) + throws IOException, GeneralSecurityException { + + char[] chPassword = null; + if (password != null) + chPassword = password.toCharArray(); + KeyStore ks = KeyStore.getInstance(keystoreType); + ks.load(in, chPassword); + in.close(); + return ks; + } + /** + * Creates a key store from X509 certificate files, aliasing them with + * the index in the String[], starting with "0". + * + * @param keyStoreType key store type + * @param certFilenames certificate filenames + * @return key store created + * @throws IOException thrown while reading the certificates from file + * @throws GeneralSecurityException thrown while creating the key store + */ + public static KeyStore createKeyStore( + String keyStoreType, + String[] certFilenames) + throws IOException, GeneralSecurityException { + + KeyStore ks = KeyStore.getInstance(keyStoreType); + ks.load(null, null); + for (int i = 0; i < certFilenames.length; i++) { + Certificate cert = loadCertificate(certFilenames[i]); + ks.setCertificateEntry("" + i, cert); + } + return ks; + } + /** + * Creates a key store from a directory containg X509 certificate files, + * aliasing them with the index in the String[], starting with "0". + * All the files in the directory are considered to be certificates. + * + * @param keyStoreType key store type + * @param certDirURLString file URL of directory containing certificate filenames + * @return key store created + * @throws IOException thrown while reading the certificates from file + * @throws GeneralSecurityException thrown while creating the key store + */ + public static KeyStore createKeyStoreFromCertificateDirectory( + String keyStoreType, + String certDirURLString) + throws IOException, GeneralSecurityException { + + URL certDirURL = new URL(certDirURLString); + String certDirname = certDirURL.getFile(); + File certDir = new File(certDirname); + String[] certFilenames = certDir.list(); + String separator = + (certDirname.endsWith(File.separator) ? "" : File.separator); + for (int i = 0; i < certFilenames.length; i++) { + certFilenames[i] = certDirname + separator + certFilenames[i]; + } + return createKeyStore(keyStoreType, certFilenames); + } + + /** + * Loads an X509 certificate from file. + * @param certFilename filename + * @return the certificate loaded + * @throws IOException thrown while reading the certificate from file + * @throws GeneralSecurityException thrown while creating the certificate + */ + private static Certificate loadCertificate(String certFilename) + throws IOException, GeneralSecurityException { + + FileInputStream in = new FileInputStream(certFilename); + Certificate cert = new X509Certificate(in); + in.close(); + return cert; + } + +} diff --git a/common/src/at/gv/egovernment/moa/util/MOADefaultHandler.java b/common/src/at/gv/egovernment/moa/util/MOADefaultHandler.java new file mode 100644 index 000000000..0474d92cd --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/MOADefaultHandler.java @@ -0,0 +1,82 @@ +package at.gv.egovernment.moa.util; + +import java.io.IOException; + +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * A DefaultHandler that uses a MOAEntityResolver and + * a MOAErrorHandler. + * + * @author Patrick Peck + * @version $Id$ + */ +public class MOADefaultHandler extends DefaultHandler { + /** The EntityResolver to use. */ + private EntityResolver entityResolver; + /** The ErrorHandler to use. */ + private ErrorHandler errorHandler; + + /** + * Create a new MOADefaultHandler. + */ + public MOADefaultHandler() { + entityResolver = new MOAEntityResolver(); + errorHandler = new MOAErrorHandler(); + } + + /** + * Create a new MOADefaultHandler. + * + * @param entityResolver The EntityResolver to use for resolving + * external entities. + * @param errorHandler The ErrorHandler to use for reporting + * parsing errors. + */ + public MOADefaultHandler( + EntityResolver entityResolver, + ErrorHandler errorHandler) { + + this.entityResolver = entityResolver; + this.errorHandler = errorHandler; + } + + /** + * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String, java.lang.String) + */ + public InputSource resolveEntity(String publicId, String systemId) + throws SAXException { + try { + return entityResolver.resolveEntity(publicId, systemId); + } catch (IOException e) { + return null; + } + } + + /** + * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException) + */ + public void warning(SAXParseException exception) throws SAXException { + errorHandler.warning(exception); + } + + /** + * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException) + */ + public void error(SAXParseException exception) throws SAXException { + errorHandler.error(exception); + } + + /** + * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException) + */ + public void fatalError(SAXParseException exception) throws SAXException { + errorHandler.fatalError(exception); + } + +} diff --git a/common/src/at/gv/egovernment/moa/util/MOAEntityResolver.java b/common/src/at/gv/egovernment/moa/util/MOAEntityResolver.java new file mode 100644 index 000000000..9406612e2 --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/MOAEntityResolver.java @@ -0,0 +1,103 @@ +package at.gv.egovernment.moa.util; + +import java.io.InputStream; + +import org.apache.xerces.util.URI; +import org.apache.xerces.util.URI.MalformedURIException; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; + +import at.gv.egovernment.moa.logging.LogMsg; +import at.gv.egovernment.moa.logging.Logger; + +/** + * An EntityResolver that looks up entities stored as + * local resources. + * + *

The following DTDs are mapped to local resources: + *

    + *
  • The XMLSchema.dtd
  • + *
  • The datatypes.dtd
  • + *
+ *

+ *

For all other resources, an attempt is made to resolve them as resources, + * either absolute or relative to Constants.SCHEMA_ROOT. + * + * @author Patrick Peck + * @author Sven Aigner + */ +public class MOAEntityResolver implements EntityResolver { + + /** + * Resolve an entity. + * + * The systemId parameter is used to perform the lookup of the + * entity as a resource, either by interpreting the systemId as + * an absolute resource path, or by appending the last path component of + * systemId to Constants.SCHEMA_ROOT. + * + * @param publicId The public ID of the resource. + * @param systemId The system ID of the resource. + * @return An InputSource from which the entity can be read, or + * null, if the entity could not be found. + * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String, java.lang.String) + */ + public InputSource resolveEntity(String publicId, String systemId) { + InputStream stream; + int slashPos; + + if (Logger.isDebugEnabled()) { + Logger.debug( + new LogMsg("resolveEntity: p=" + publicId + " s=" + systemId)); + } + + if (publicId != null) { + // check if we can resolve some standard dtd's + if (publicId.equalsIgnoreCase("-//W3C//DTD XMLSchema 200102//EN")) { + return new InputSource( + getClass().getResourceAsStream( + Constants.SCHEMA_ROOT + "XMLSchema.dtd")); + } else if (publicId.equalsIgnoreCase("datatypes")) { + return new InputSource( + getClass().getResourceAsStream( + Constants.SCHEMA_ROOT + "datatypes.dtd")); + } + } else if (systemId != null) { + // get the URI path + try { + URI uri = new URI(systemId); + systemId = uri.getPath(); + if (!"file".equals(uri.getScheme()) || "".equals(systemId.trim())) { + return null; + } + } catch (MalformedURIException e) { + return null; + } + + // try to get the resource from the full path + stream = getClass().getResourceAsStream(systemId); + if (stream != null) { + InputSource source = new InputSource(stream); + + source.setSystemId(systemId); + return source; + } + + // try to get the resource from the last path component + slashPos = systemId.lastIndexOf('/'); + if (slashPos >= 0 && systemId.length() > slashPos) { + systemId = systemId.substring(slashPos + 1, systemId.length()); + stream = + getClass().getResourceAsStream(Constants.SCHEMA_ROOT + systemId); + if (stream != null) { + InputSource source = new InputSource(stream); + + source.setSystemId(systemId); + return source; + } + } + } + + return null; // nothing found - let the parser handle the entity + } +} \ No newline at end of file diff --git a/common/src/at/gv/egovernment/moa/util/MOAErrorHandler.java b/common/src/at/gv/egovernment/moa/util/MOAErrorHandler.java new file mode 100644 index 000000000..1f7757c8f --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/MOAErrorHandler.java @@ -0,0 +1,85 @@ +package at.gv.egovernment.moa.util; + +import org.apache.xml.utils.DefaultErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import at.gv.egovernment.moa.logging.LogMsg; +import at.gv.egovernment.moa.logging.Logger; + +/** + * An ErrorHandler that logs a message and throws a + * SAXException upon error and fatal + * parsing errors. + * + * @author Patrick Peck + * @author Sven Aigner + */ +public class MOAErrorHandler extends DefaultErrorHandler { + + /** + * Logs a warning message. + * + * @see org.xml.sax.ErrorHandler#warning(SAXParseException) + */ + public void warning(SAXParseException exception) throws SAXException { + warn("parser.00", messageParams(exception), null); + } + + /** + * Logs a warning and rethrows the exception. + * + * @see org.xml.sax.ErrorHandler#error(SAXParseException) + */ + public void error(SAXParseException exception) throws SAXException { + warn("parser.01", messageParams(exception), null); + throw exception; + } + + /** + * Logs a warning and rethrows the exception. + * + * @see org.xml.sax.ErrorHandler#fatalError(SAXParseException) + */ + public void fatalError(SAXParseException exception) throws SAXException { + warn("parser.02", messageParams(exception), null); + throw exception; + } + + /** + * Log a warning message. + * + * @param messageId The message ID to log. + * @param parameters Additional message parameters. + * @param t The Throwable to log; usually the cause of this + * warning. + */ + private static void warn( + String messageId, + Object[] parameters, + Throwable t) { + + MessageProvider msg = MessageProvider.getInstance(); + Logger.warn(new LogMsg(msg.getMessage(messageId, parameters)), t); + } + + /** + * Put the system id, line and column number information from the exception + * into an Object array, to provide it as a + * MessageFormat parameter. + * + * @param e The SAXParseException containing the + * source system id and line/column numbers. + * @return An array containing the system id (a String) as well + * as line/column numbers (2 Integer objects) from the + * SAXParseException. + */ + private static Object[] messageParams(SAXParseException e) { + return new Object[] { + e.getMessage(), + e.getSystemId(), + new Integer(e.getLineNumber()), + new Integer(e.getColumnNumber())}; + } + +} \ No newline at end of file diff --git a/common/src/at/gv/egovernment/moa/util/MOATimer.java b/common/src/at/gv/egovernment/moa/util/MOATimer.java new file mode 100644 index 000000000..d8bf64fc3 --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/MOATimer.java @@ -0,0 +1,110 @@ +package at.gv.egovernment.moa.util; + +import java.util.Map; +import java.util.WeakHashMap; + +/** + * A timer utility for named timers. + * + * @author Sven Aigner + */ +public class MOATimer { + + /** The single instance of this class. */ + private static MOATimer instance = null; + /** The starting points of single timings. */ + private static Map timemapstart = new WeakHashMap(); + /** The end points of single timings. */ + private static Map timemapend = new WeakHashMap(); + + /** + * Return the single instance of this class. + * + * @return The single instance of this class. + */ + public static MOATimer getInstance() { + if (instance == null) { + instance = new MOATimer(); + } + return instance; + } + + /** + * Create a new MOATimer. + * + * Protected to disallow multiple instances. + */ + protected MOATimer() { + super(); + } + + /** + * Start timing a certain action. + * + * The timing belonging to the action ID is garbage collected as soon as there + * exists no other reference to the action ID. + * + * @param id The action ID. + */ + public void startTiming(Object id) { + timemapstart.put(id, new Long(System.currentTimeMillis())); + } + + /** + * Stop timing an action. + * + * @param id The action ID. + */ + public void stopTiming(Object id) { + timemapend.put(id, new Long(System.currentTimeMillis())); + } + + /** + * Get the duration of an action. + * + * @param id The action ID for which to compute the duration. + * @return long The duration in milliseconds between calls to + * startTiming() and stopTiming(). If + * only startTiming() has been called for the action, then + * current difference to the system time is returned. If no timing exists for + * the action, - 1 is returned. + */ + public long duration(Object id) { + if (timemapstart.containsKey(id)) { + long start = ((Long) timemapstart.get(id)).longValue(); + if (timemapend.containsKey(id)) { + long end = ((Long) timemapend.get(id)).longValue(); + return end - start; + } else { + return System.currentTimeMillis() - start; + } + } else + return -1; + } + + /** + * Get the duration of an action, as a nicely formatted String. + * + * @param id The action ID. + * @return String The duration() as a String. + */ + public String durationAsString(Object id) { + long dur = duration(id); + long second = dur / 1000; + long mil = (dur) - (second * 1000); + return "Duration: " + second + "." + mil + " seconds"; + } + + /** + * Remove a timing. + * + * @param id The action ID. + */ + public void clearTiming(String id) { + if (timemapstart.containsKey(id)) + timemapstart.remove(id); + if (timemapend.containsKey(id)) + timemapend.remove(id); + } + +} diff --git a/common/src/at/gv/egovernment/moa/util/MessageProvider.java b/common/src/at/gv/egovernment/moa/util/MessageProvider.java new file mode 100644 index 000000000..f5117e390 --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/MessageProvider.java @@ -0,0 +1,63 @@ +package at.gv.egovernment.moa.util; + +import java.util.Locale; + +/** + * A singleton wrapper around a Message object. + * + * Provides the messages used in the common project. + * + * @author Patrick Peck + * @version $Id$ + */ +public class MessageProvider { + /** The location of the default message resources. */ + private static final String[] DEFAULT_MESSAGE_RESOURCES = + { "resources/properties/common_messages" }; + /** The locale of the default message resources. */ + private static final Locale[] DEFAULT_MESSAGE_LOCALES = + new Locale[] { new Locale("de", "AT") }; + /** The single instance of this class. */ + private static MessageProvider instance; + + /** The messages provided by this MessageProvider. */ + private Messages messages; + + /** + * Return the single instance of the MessageProvider. + * + * Intialilizes the MessageProvider with the default message + * locations: /resources/properties/common_messages. + * + * @return The single MessageProvider. + */ + public static synchronized MessageProvider getInstance() { + if (instance == null) { + instance = + new MessageProvider(DEFAULT_MESSAGE_RESOURCES, DEFAULT_MESSAGE_LOCALES); + } + return instance; + } + + /** + * Create a MessageProvider. + * + * @param resourceNames The names of the resources containing the messages. + * @param locales The corresponding locales. + */ + protected MessageProvider(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/common/src/at/gv/egovernment/moa/util/Messages.java b/common/src/at/gv/egovernment/moa/util/Messages.java new file mode 100644 index 000000000..a0139ae93 --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/Messages.java @@ -0,0 +1,117 @@ +package at.gv.egovernment.moa.util; + +import java.text.MessageFormat; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.PropertyResourceBundle; + +import at.gv.egovernment.moa.logging.Logger; + +/** + * Provides access to the system messages resource used for exception handling + * and logging messages. + * + * Messages must be provided as a resource bundle at the path. + * + * @author Patrick Peck + * @version $Id$ + */ +public class Messages { + /** Error message indicating that no messages are avaiable. */ + private static final String ERROR_MESSAGES_UNAVAILABLE = + "Fehler in der Server-Konfiguration. " + + "Die Fehlertexte konnten nicht geladen werden."; + /** Error message indicating that the message is not available. */ + private static final String ERROR_NO_MESSAGE = + "Keine Fehlermeldung für Fehler-Nr.={0}"; + + /** The names of the resources containing the messages. */ + private String[] resourceNames; + /** The corresponding Locales of the resources. */ + private Locale[] locales; + /** The ResourceBundles containing the messages. */ + private ResourceBundleChain messages; + + /** + * Create a new Message object containing the messages + * in the given resources. + * + * @param resourceNames The names of the resources containing the messages. + * @param locales The corresponding locales. + */ + public Messages(String[] resourceNames, Locale[] locales) { + this.resourceNames = resourceNames; + this.locales = locales; + this.messages = null; + } + + /** + * 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) { + // initialize messages + if (messages == null) { + initMessages(); + } + + // create the message + if (messages == null) { + return ERROR_MESSAGES_UNAVAILABLE; + } else { + try { + String rawMessage = messages.getString(messageId); + return MessageFormat.format(rawMessage, parameters); + } catch (MissingResourceException e2) { + // couldn't find any message -> set to default error message + return MessageFormat.format( + ERROR_NO_MESSAGE, + new Object[] { messageId }); + } + } + } + + /** + * Return the names of the resources containing the messages. + * + * @return String[] The names of the resource bundles containing the messages. + */ + private String[] getResourceNames() { + return resourceNames; + } + + /** + * Return the Locales of the resources containing the messages. + * + * @return Locale[] The Locales of the resource bundles + * containing the messages. + */ + private Locale[] getLocales() { + return locales; + } + + /** + * Initialize the messages ResourceBundle containing + * the MOA error messages. + */ + private void initMessages() { + messages = new ResourceBundleChain(); + int i; + + // initialize the message resources + for (i = 0; i < resourceNames.length; i++) { + try { + messages.addResourceBundle( + PropertyResourceBundle.getBundle( + getResourceNames()[i], + getLocales()[i])); + } catch (MissingResourceException e) { + Logger.error(ERROR_MESSAGES_UNAVAILABLE, e); + } + } + } + +} diff --git a/common/src/at/gv/egovernment/moa/util/NodeIteratorAdapter.java b/common/src/at/gv/egovernment/moa/util/NodeIteratorAdapter.java new file mode 100644 index 000000000..f71aa472d --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/NodeIteratorAdapter.java @@ -0,0 +1,87 @@ +package at.gv.egovernment.moa.util; + +import java.util.ListIterator; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; + +/** + * A NodeIterator implementation based on a + * ListIterator. + * + * @see java.util.ListIterator + * @see org.w3c.dom.traversal.NodeIterator + * + * @author Patrick Peck + * @version $Id$ + */ +public class NodeIteratorAdapter implements NodeIterator { + + /** The ListIterator to wrap. */ + private ListIterator nodeIterator; + + /** + * Create a new NodeIteratorAdapter. + * @param nodeIterator The ListIterator to iterate over. + */ + public NodeIteratorAdapter(ListIterator nodeIterator) { + this.nodeIterator = nodeIterator; + } + + /** + * @see org.w3c.dom.traversal.NodeIterator#getRoot() + */ + public Node getRoot() { + return null; + } + + /** + * @see org.w3c.dom.traversal.NodeIterator#getWhatToShow() + */ + public int getWhatToShow() { + return NodeFilter.SHOW_ALL; + } + + /** + * @see org.w3c.dom.traversal.NodeIterator#getFilter() + */ + public NodeFilter getFilter() { + return null; + } + + /** + * @see org.w3c.dom.traversal.NodeIterator#getExpandEntityReferences() + */ + public boolean getExpandEntityReferences() { + return false; + } + + /** + * @see org.w3c.dom.traversal.NodeIterator#nextNode() + */ + public Node nextNode() throws DOMException { + if (nodeIterator.hasNext()) { + return (Node) nodeIterator.next(); + } + return null; + } + + /** + * @see org.w3c.dom.traversal.NodeIterator#previousNode() + */ + public Node previousNode() throws DOMException { + if (nodeIterator.hasPrevious()) { + return (Node) nodeIterator.previous(); + } + return null; + } + + /** + * @see org.w3c.dom.traversal.NodeIterator#detach() + */ + public void detach() { + } + +} diff --git a/common/src/at/gv/egovernment/moa/util/NodeListAdapter.java b/common/src/at/gv/egovernment/moa/util/NodeListAdapter.java new file mode 100644 index 000000000..7102cadca --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/NodeListAdapter.java @@ -0,0 +1,44 @@ +package at.gv.egovernment.moa.util; + +import java.util.List; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * A NodeList implementation based on a List. + * + * @see java.util.List + * @see org.w3c.dom.NodeList + * + * @author Patrick Peck + * @version $Id$ + */ +public class NodeListAdapter implements NodeList { + /** The List to wrap. */ + private List nodeList; + + /** + * Create a new NodeListAdapter. + * + * @param nodeList The List containing the nodes. + */ + public NodeListAdapter(List nodeList) { + this.nodeList = nodeList; + } + + /** + * @see org.w3c.dom.NodeList#item(int) + */ + public Node item(int index) { + return (Node) nodeList.get(index); + } + + /** + * @see org.w3c.dom.NodeList#getLength() + */ + public int getLength() { + return nodeList.size(); + } + +} diff --git a/common/src/at/gv/egovernment/moa/util/ResourceBundleChain.java b/common/src/at/gv/egovernment/moa/util/ResourceBundleChain.java new file mode 100644 index 000000000..90b28548a --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/ResourceBundleChain.java @@ -0,0 +1,66 @@ +package at.gv.egovernment.moa.util; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * A class to chain ResourceBundles. + * + * @author Patrick Peck + * @version $Id$ + */ +public class ResourceBundleChain { + /** Error message indicating the resource is not available. */ + private static final String ERROR_MISSING_RESOURCE = "Missing resource"; + /** The ResourceBundles contained in this chain. */ + private List resourceBundles = new ArrayList(); + + /** + * Add a ResourceBundle to the chain. + * + * @param resourceBundle The ResourceBundle to add. + */ + public void addResourceBundle(ResourceBundle resourceBundle) { + resourceBundles.add(resourceBundle); + } + + /** + * Return the value of the resource. + * + * @param key The key to access the String resource. + * @return The resource value. All the registered ResourceBundles + * are searched in the order in which they have previously been added to this + * ResourceBundleChain. + * @throws MissingResourceException The resource coult not be found in any of + * the bundles. + */ + public String getString(String key) throws MissingResourceException { + MissingResourceException lastException = null; + Iterator iter; + + // handle case where no resource bundles have been added + if (resourceBundles.size() == 0) { + throw new MissingResourceException( + ERROR_MISSING_RESOURCE, + this.getClass().getName(), + key); + } + + // try to find the resource in one of the bundles; if it cannot be found, + // return the exception thrown by the last bundle in the list + for (iter = resourceBundles.iterator(); iter.hasNext();) { + ResourceBundle resourceBundle = (ResourceBundle) iter.next(); + try { + String value = resourceBundle.getString(key); + return value; + } catch (MissingResourceException e) { + lastException = e; + } + } + throw lastException; + } + +} diff --git a/common/src/at/gv/egovernment/moa/util/SSLUtils.java b/common/src/at/gv/egovernment/moa/util/SSLUtils.java new file mode 100644 index 000000000..621562e2d --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/SSLUtils.java @@ -0,0 +1,222 @@ +package at.gv.egovernment.moa.util; + +import java.io.IOException; +import java.io.InputStream; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import javax.net.ssl.SSLSocketFactory; + +import com.sun.net.ssl.KeyManager; +import com.sun.net.ssl.KeyManagerFactory; +import com.sun.net.ssl.SSLContext; +import com.sun.net.ssl.TrustManager; +import com.sun.net.ssl.TrustManagerFactory; + +/** + * Utility for connecting to server applications via SSL. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class SSLUtils { + + /** + * Creates an SSLSocketFactory which utilizes the given trust store. + * + * @param trustStoreType key store type of trust store + * @param trustStoreInputStream input stream for reading JKS trust store containing + * trusted server certificates; if null, the default + * trust store will be utilized + * @param trustStorePassword if provided, it will be used to check + * the integrity of the trust store; if omitted, it will not be checked + * @return SSLSocketFactory to be used by an HttpsURLConnection + * @throws IOException thrown while reading from the input stream + * @throws GeneralSecurityException thrown while creating the socket factory + */ + public static SSLSocketFactory getSSLSocketFactory( + String trustStoreType, + InputStream trustStoreInputStream, + String trustStorePassword) + throws IOException, GeneralSecurityException { + + TrustManager[] tms = getTrustManagers(trustStoreType, trustStoreInputStream, trustStorePassword); + SSLContext ctx = SSLContext.getInstance("TLS"); + ctx.init(null, tms, null); + + SSLSocketFactory sf = ctx.getSocketFactory(); + return sf; + } + /** + * Creates an SSLSocketFactory which utilizes the + * given trust store and keystore. + * + * @param trustStore trust store containing trusted server certificates; + * if null, the default trust store will be utilized + * @param clientKeyStoreType key store type of clientKeyStore + * @param clientKeyStoreURL URL of key store containing keys to be used for + * client authentication; if null, the default key store will be utilized + * @param clientKeyStorePassword if provided, it will be used to check + * the integrity of the client key store; if omitted, it will not be checked + * @return SSLSocketFactory to be used by an HttpsURLConnection + * @throws IOException thrown while reading key store file + * @throws GeneralSecurityException thrown while creating the socket factory + */ + public static SSLSocketFactory getSSLSocketFactory( + KeyStore trustStore, + String clientKeyStoreType, + String clientKeyStoreURL, + String clientKeyStorePassword) + throws IOException, GeneralSecurityException { + + SSLContext ctx = getSSLContext( + trustStore, clientKeyStoreType, clientKeyStoreURL, clientKeyStorePassword); + SSLSocketFactory sf = ctx.getSocketFactory(); + return sf; + } + /** + * Creates an SSLContext initialized for the + * given trust store and keystore. + * + * @param trustStore trust store containing trusted server certificates; + * if null, the default trust store will be utilized + * @param clientKeyStoreType key store type of clientKeyStore + * @param clientKeyStoreURL URL of key store containing keys to be used for + * client authentication; if null, the default key store will be utilized + * @param clientKeyStorePassword if provided, it will be used to check + * the integrity of the client key store; if omitted, it will not be checked + * @return SSLContext to be used for creating an SSLSocketFactory + * @throws IOException thrown while reading key store file + * @throws GeneralSecurityException thrown while creating the SSL context + */ + public static SSLContext getSSLContext( + KeyStore trustStore, + String clientKeyStoreType, + String clientKeyStoreURL, + String clientKeyStorePassword) + throws IOException, GeneralSecurityException { + + //System.setProperty("javax.net.debug", "all"); + TrustManager[] tms = getTrustManagers(trustStore); + KeyManager[] kms = getKeyManagers(clientKeyStoreType, clientKeyStoreURL, clientKeyStorePassword); + SSLContext ctx = SSLContext.getInstance("TLS"); + ctx.init(kms, tms, null); + return ctx; + } + /** + * Loads the trust store from an input stream and gets the + * TrustManagers from a default TrustManagerFactory, + * initialized from the given trust store. + * @param trustStoreType key store type of trust store + * @param trustStoreInputStream input stream for reading JKS trust store containing + * trusted server certificates; if null, the default + * trust store will be utilized + * @param trustStorePassword if provided, it will be used to check + * the integrity of the trust store; if omitted, it will not be checked + * @return TrustManagers to be used for creating an + * SSLSocketFactory utilizing the given trust store + * @throws IOException thrown while reading from the input stream + * @throws GeneralSecurityException thrown while initializing the + * default TrustManagerFactory + */ + protected static TrustManager[] getTrustManagers( + String trustStoreType, + InputStream trustStoreInputStream, + String trustStorePassword) + throws IOException, GeneralSecurityException { + + if (trustStoreInputStream == null) + return null; + + // Set up the TrustStore to use. We need to load the file into + // a KeyStore instance. + KeyStore trustStore = KeyStoreUtils.loadKeyStore(trustStoreType, trustStoreInputStream, trustStorePassword); + return getTrustManagers(trustStore); + } + /** + * Gets the TrustManagers from a default TrustManagerFactory, + * initialized from the given trust store. + * + * @param trustStore the trust store to use + * @param trustStorePassword password protecting the given trust store + * @return TrustManagers to be used for creating an + * SSLSocketFactory utilizing the given trust store + * @throws GeneralSecurityException thrown while initializing the + * default TrustManagerFactory + */ + protected static TrustManager[] getTrustManagers(KeyStore trustStore) + throws GeneralSecurityException { + + if (trustStore == null) + return null; + + // Initialize the default TrustManagerFactory with this KeyStore + String alg=TrustManagerFactory.getDefaultAlgorithm(); + TrustManagerFactory tmFact=TrustManagerFactory.getInstance(alg); + tmFact.init(trustStore); + + // And now get the TrustManagers + TrustManager[] tms=tmFact.getTrustManagers(); + return tms; + } + /** + * Loads the client key store from file and gets the + * KeyManagers from a default KeyManagerFactory, + * initialized from the given client key store. + * @param clientKeyStoreType key store type of clientKeyStore + * @param clientKeyStoreURL URL of key store containing keys to be used for + * client authentication; if null, the default key store will be utilized + * @param clientKeyStorePassword password used to check the integrity of the client key store; + * if null, it will not be checked + * @return KeyManagers to be used for creating an + * SSLSocketFactory utilizing the given client key store + * @throws IOException thrown while reading from the key store file + * @throws GeneralSecurityException thrown while initializing the + * default KeyManagerFactory + */ + public static KeyManager[] getKeyManagers ( + String clientKeyStoreType, + String clientKeyStoreURL, + String clientKeyStorePassword) + throws IOException, GeneralSecurityException { + + if (clientKeyStoreURL == null) + return null; + + // Set up the KeyStore to use. We need to load the file into + // a KeyStore instance. + KeyStore clientKeyStore = KeyStoreUtils.loadKeyStore( + clientKeyStoreType, clientKeyStoreURL, clientKeyStorePassword); + return getKeyManagers(clientKeyStore, clientKeyStorePassword); + } + /** + * Gets the KeyManagers from a default KeyManagerFactory, + * initialized from the given client key store. + * @param clientKeyStore client key store + * @param clientKeyStorePassword if provided, it will be used to check + * the integrity of the client key store; if omitted, it will not be checked + * @return KeyManagers to be used for creating an + * SSLSocketFactory utilizing the given client key store + * @throws GeneralSecurityException thrown while initializing the + * default KeyManagerFactory + */ + public static KeyManager[] getKeyManagers ( + KeyStore clientKeyStore, + String clientKeyStorePassword) + throws GeneralSecurityException { + + if (clientKeyStore == null) + return null; + + // Now we initialize the default KeyManagerFactory with this KeyStore + String alg=KeyManagerFactory.getDefaultAlgorithm(); + KeyManagerFactory kmFact=KeyManagerFactory.getInstance(alg); + char[] password = null; + if (clientKeyStorePassword != null) + password = clientKeyStorePassword.toCharArray(); + kmFact.init(clientKeyStore, password); + + // And now get the KeyManagers + KeyManager[] kms=kmFact.getKeyManagers(); + return kms; + } +} diff --git a/common/src/at/gv/egovernment/moa/util/StreamEntityResolver.java b/common/src/at/gv/egovernment/moa/util/StreamEntityResolver.java new file mode 100644 index 000000000..38c4e863c --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/StreamEntityResolver.java @@ -0,0 +1,64 @@ +package at.gv.egovernment.moa.util; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * An EntityResolver that maps system IDs to + * InputStreams. + * + * @author Patrick Peck + * @version $Id$ + */ +public class StreamEntityResolver implements EntityResolver { + + /** A mapping from Public ID or System ID to an InputStream + * containing the entity. */ + private Map mappedEntities; + + /** + * Create a StreamEntityResolver. + * + * @param mappedEntities A mapping from public or system IDs + * (String objects) to InputStreams. + */ + public StreamEntityResolver(Map mappedEntities) { + this.mappedEntities = mappedEntities; + } + + /** + * Resolve an entity by looking it up in the mapped entities. + * + * First, the public ID is looked up in the mapping, then the system ID. + * + * @param publicId The public ID of the entity. + * @param systemId The system ID of the entity. + * @return An InputStream containing the entity or + * null if no entity could be found. + * @throws SAXException Signalling a parsing exception. + * @throws IOException Error reading the entity. + */ + public InputSource resolveEntity(String publicId, String systemId) + throws SAXException, IOException { + + InputSource src = null; + + if (publicId != null && mappedEntities.get(publicId) != null) { + src = new InputSource((InputStream) mappedEntities.get(publicId)); + } else if (systemId != null && mappedEntities.get(systemId) != null) { + src = new InputSource((InputStream) mappedEntities.get(systemId)); + } + + if (src != null) { + src.setPublicId(publicId); + src.setSystemId(systemId); + } + + return src; + } +} diff --git a/common/src/at/gv/egovernment/moa/util/StreamUtils.java b/common/src/at/gv/egovernment/moa/util/StreamUtils.java new file mode 100644 index 000000000..88db24504 --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/StreamUtils.java @@ -0,0 +1,116 @@ +package at.gv.egovernment.moa.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Utility methods for streams. + * + * @author Patrick Peck + * @version $Id$ + */ +public class StreamUtils { + + /** + * Compare the contents of two InputStreams. + * + * @param is1 The 1st InputStream to compare. + * @param is2 The 2nd InputStream to compare. + * @return boolean true, if both streams contain the exactly the + * same content, false otherwise. + * @throws IOException An error occurred reading one of the streams. + */ + public static boolean compareStreams(InputStream is1, InputStream is2) + throws IOException { + + byte[] buf1 = new byte[256]; + byte[] buf2 = new byte[256]; + int length1; + int length2; + + try { + while (true) { + length1 = is1.read(buf1); + length2 = is2.read(buf2); + + if (length1 != length2) { + return false; + } + if (length1 <= 0) { + return true; + } + if (!compareBytes(buf1, buf2, length1)) { + return false; + } + } + } catch (IOException e) { + throw e; + } finally { + // close both streams + try { + is1.close(); + is2.close(); + } catch (IOException e) { + // ignore this + } + } + } + + /** + * Compare two byte arrays, up to a given maximum length. + * + * @param b1 1st byte array to compare. + * @param b2 2nd byte array to compare. + * @param length The maximum number of bytes to compare. + * @return true, if the byte arrays are equal, false + * otherwise. + */ + private static boolean compareBytes(byte[] b1, byte[] b2, int length) { + if (b1.length != b2.length) { + return false; + } + + for (int i = 0; i < b1.length && i < length; i++) { + if (b1[i] != b2[i]) { + return false; + } + } + + return true; + } + + /** + * Reads a byte array from a stream. + * @param in The InputStream to read. + * @return The bytes contained in the given InputStream. + * @throws IOException on any exception thrown + */ + public static byte[] readStream(InputStream in) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int b; + while ((b = in.read()) >= 0) + out.write(b); + in.close(); + return out.toByteArray(); + } + + /** + * Reads a String from a stream, using given encoding. + * @param in The InputStream to read. + * @param encoding The character encoding to use for converting the bytes + * of the InputStream into a String. + * @return The content of the given InputStream converted into + * a String. + * @throws IOException on any exception thrown + */ + public static String readStream(InputStream in, String encoding) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int b; + while ((b = in.read()) >= 0) + out.write(b); + in.close(); + return out.toString(encoding); + } + +} diff --git a/common/src/at/gv/egovernment/moa/util/URLDecoder.java b/common/src/at/gv/egovernment/moa/util/URLDecoder.java new file mode 100644 index 000000000..a20820f7e --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/URLDecoder.java @@ -0,0 +1,60 @@ +package at.gv.egovernment.moa.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; + +/** + * Decodes an URL encoded String using a specified character encoding. + * Provides a function missing in JDK 1.3. + * @author Paul Ivancsics + * @version $Id$ + */ +public class URLDecoder { + + /** + * Decodes an application/x-www-form-urlencoded string using a specific encoding scheme. + * @param s the string to decode + * @param encoding name of character encoding + * @return the newly decoded string + * @throws UnsupportedEncodingException if the encoding is not supported + */ + public static String decode(String s, String encoding) throws UnsupportedEncodingException { + StringReader in = new StringReader(s); + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + for (int b = read(in); b >= 0; b = read(in)) + bout.write(b); + return bout.toString(encoding); + } + /** + * Decodes the next byte from the string reader. + * @param in string reader + * @return the next byte decoded; + * -1 upon end of string, on erroneous data, and on any exception caught + * @todo syntax check on string + */ + private static int read(StringReader in) { + try { + int b = in.read(); + if (b == '+') + return ' '; + if (b == '%') { + char[] hex = new char[2]; + if (in.read(hex, 0, 2) >= 0) { + String hexString = new String(hex); + return Integer.valueOf(hexString, 16).intValue(); + } + else + return -1; + } + return b; + } + catch (IOException ex) { + return -1; + } + catch (NumberFormatException ex) { + return -1; + } + } +} diff --git a/common/src/at/gv/egovernment/moa/util/URLEncoder.java b/common/src/at/gv/egovernment/moa/util/URLEncoder.java new file mode 100644 index 000000000..840c0c3bc --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/URLEncoder.java @@ -0,0 +1,63 @@ +package at.gv.egovernment.moa.util; + +import java.io.ByteArrayInputStream; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; + +/** + * Translates a string into mime format "x-www-form-urlencoded". + * Provides a function missing in JDK 1.3. + * @author Paul Ivancsics + * @version $Id$ + */ +public class URLEncoder { + + /** + * Translates a string into x-www-form-urlencoded format. + * @param s the string to be translated + * @param encoding the encoding to use + * @return the translated string + * @throws UnsupportedEncodingException when the desired encoding is not supported + */ + public static String encode(String s, String encoding) throws UnsupportedEncodingException { + byte[] barr = s.getBytes(encoding); + ByteArrayInputStream bin = new ByteArrayInputStream(barr); + StringWriter out = new StringWriter(); + for (int b = bin.read(); b >= 0; b = bin.read()) + encode(b, out); + return out.toString(); + } + + /** + * Encode a character. + * @param ch The character to encode. + * @param out The StringWriter containing the result. + */ + private static void encode(int ch, StringWriter out) { + if ((ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z') + || (ch >= '0' && ch <= '9') + || ch == '.' || ch == '-' || ch == '*' || ch == '_') + out.write(ch); + else if (ch == ' ') + out.write('+'); + else + encodeHex(ch, out); + } + + /** + * Encode a character as an escaped hex value. + * @param ch The character to encode. + * @param out The StringWriter containing the result. + */ + private static void encodeHex(int ch, StringWriter out) { + out.write('%'); + String hex = Integer.toHexString(ch).toUpperCase(); + if (hex.length() < 2) + out.write('0'); + else + out.write(hex.charAt(hex.length() - 2)); + out.write(hex.charAt(hex.length() - 1)); + } + +} diff --git a/common/src/at/gv/egovernment/moa/util/XPathException.java b/common/src/at/gv/egovernment/moa/util/XPathException.java new file mode 100644 index 000000000..e10c882e5 --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/XPathException.java @@ -0,0 +1,58 @@ +package at.gv.egovernment.moa.util; + +import java.io.PrintStream; +import java.io.PrintWriter; + +/** + * An exception occurred evaluating an XPath. + * + * @author Patrick Peck + * @version $Id$ + */ +public class XPathException extends RuntimeException { + /** The wrapped exception. */ + private Throwable wrapped; + + /** + * Create a XPathException. + * + * @param message The exception message. + * @param wrapped The exception being the likely cause of this exception. + */ + public XPathException(String message, Throwable wrapped) { + super(message); + this.wrapped = wrapped; + } + + /** + * Return the wrapped exception. + * + * @return The wrapped exception being the likely cause of this exception. + */ + public Throwable getWrapped() { + return wrapped; + } + + /** + * @see java.lang.Throwable#printStackTrace(java.io.PrintStream) + */ + public void printStackTrace(PrintStream s) { + super.printStackTrace(s); + if (getWrapped() != null) { + s.print("Caused by: "); + getWrapped().printStackTrace(s); + } + } + + /** + * @see java.lang.Throwable#printStackTrace(java.io.PrintWriter) + */ + public void printStackTrace(PrintWriter s) { + super.printStackTrace(s); + if (getWrapped() != null) { + s.print("Caused by: "); + getWrapped().printStackTrace(s); + } + } + +} diff --git a/common/src/at/gv/egovernment/moa/util/XPathUtils.java b/common/src/at/gv/egovernment/moa/util/XPathUtils.java new file mode 100644 index 000000000..0ed4fcda3 --- /dev/null +++ b/common/src/at/gv/egovernment/moa/util/XPathUtils.java @@ -0,0 +1,415 @@ +package at.gv.egovernment.moa.util; + +import java.util.List; +import java.util.Map; + +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.traversal.NodeIterator; + +import org.jaxen.JaxenException; +import org.jaxen.NamespaceContext; +import org.jaxen.SimpleNamespaceContext; +import org.jaxen.dom.DOMXPath; +import org.jaxen.dom.DocumentNavigator; + +/** + * Utility methods to evaluate XPath expressions on DOM nodes. + * + * @author Patrick Peck + * @version $Id$ + */ +public class XPathUtils { + + /** + * The XPath expression selecting all nodes under a given root (including the + * root node itself). + */ + public static final String ALL_NODES_XPATH = + "(.//. | .//@* | .//namespace::*)"; + + /** The DocumentNavigator to use for navigating the document. */ + private static DocumentNavigator documentNavigator = + DocumentNavigator.getInstance(); + /** The default namespace prefix to namespace URI mappings. */ + private static NamespaceContext NS_CONTEXT; + + static { + SimpleNamespaceContext ctx = new SimpleNamespaceContext(); + ctx.addNamespace(Constants.MOA_PREFIX, Constants.MOA_NS_URI); + ctx.addNamespace(Constants.MOA_CONFIG_PREFIX, Constants.MOA_CONFIG_NS_URI); + ctx.addNamespace( + Constants.MOA_ID_CONFIG_PREFIX, + Constants.MOA_ID_CONFIG_NS_URI); + ctx.addNamespace(Constants.SL10_PREFIX, Constants.SL10_NS_URI); + ctx.addNamespace(Constants.SL11_PREFIX, Constants.SL11_NS_URI); + ctx.addNamespace(Constants.ECDSA_PREFIX, Constants.ECDSA_NS_URI); + ctx.addNamespace(Constants.PD_PREFIX, Constants.PD_NS_URI); + ctx.addNamespace(Constants.SAML_PREFIX, Constants.SAML_NS_URI); + ctx.addNamespace(Constants.SAMLP_PREFIX, Constants.SAMLP_NS_URI); + ctx.addNamespace(Constants.DSIG_PREFIX, Constants.DSIG_NS_URI); + ctx.addNamespace(Constants.XSLT_PREFIX, Constants.XSLT_NS_URI); + ctx.addNamespace(Constants.XSI_PREFIX, Constants.XSI_NS_URI); + ctx.addNamespace( + Constants.DSIG_FILTER2_PREFIX, + Constants.DSIG_FILTER2_NS_URI); + ctx.addNamespace(Constants.DSIG_EC_PREFIX, Constants.DSIG_EC_NS_URI); + NS_CONTEXT = ctx; + } + + /** + * Return a NodeIterator over the nodes matching the XPath + * expression. + * + * All namespace URIs and prefixes declared in the Constants + * interface are used for resolving namespaces. + * + * @param contextNode The root node from which to evaluate the XPath + * expression. + * @param exp The XPath expression to evaluate. + * @return An iterator over the resulting nodes. + * @throws XPathException An error occurred evaluating the XPath expression. + */ + public static NodeIterator selectNodeIterator(Node contextNode, String exp) + throws XPathException { + + return selectNodeIterator(contextNode, NS_CONTEXT, exp); + } + + /** + * Return a NodeIterator over the nodes matching the XPath + * expression. + * + * @param contextNode The root node from which to evaluate the XPath + * expression. + * @param namespaceElement An element from which to build the + * namespace mapping for evaluating the XPath expression + * @param exp The XPath expression to evaluate. + * @return An iterator over the resulting nodes. + * @throws XPathException An error occurred evaluating the XPath expression. + */ + public static NodeIterator selectNodeIterator( + Node contextNode, + Element namespaceElement, + String exp) + throws XPathException { + + try { + SimpleNamespaceContext ctx = new SimpleNamespaceContext(); + ctx.addElementNamespaces(documentNavigator, namespaceElement); + return selectNodeIterator(contextNode, ctx, exp); + } catch (JaxenException e) { + MessageProvider msg = MessageProvider.getInstance(); + String message = msg.getMessage("xpath.00", new Object[] { exp }); + throw new XPathException(message, e); + } + } + + /** + * Return a NodeIterator over the nodes matching the XPath + * expression. + * + * @param contextNode The root node from which to evaluate the XPath + * expression. + * @param namespaceMapping A namespace prefix to namespace URI mapping + * (String to String) for evaluating the XPath + * expression. + * @param exp The XPath expression to evaluate. + * @return An iterator over the resulting nodes. + * @throws XPathException An error occurred evaluating the XPath expression. + */ + public static NodeIterator selectNodeIterator( + Node contextNode, + Map namespaceMapping, + String exp) + throws XPathException { + + SimpleNamespaceContext ctx = new SimpleNamespaceContext(namespaceMapping); + + return selectNodeIterator(contextNode, ctx, exp); + } + + /** + * Return a NodeIterator over the nodes matching the XPath + * expression. + * + * @param contextNode The root node from which to evaluate the XPath + * expression. + * @param nsContext The NamespaceContext for resolving namespace + * prefixes to namespace URIs for evaluating the XPath expression. + * @param exp The XPath expression to evaluate. + * @return An iterator over the resulting nodes. + * @throws XPathException An error occurred evaluating the XPath expression. + */ + private static NodeIterator selectNodeIterator( + Node contextNode, + NamespaceContext nsContext, + String exp) + throws XPathException { + + try { + DOMXPath xpath = new DOMXPath(exp); + List nodes; + + xpath.setNamespaceContext(nsContext); + nodes = xpath.selectNodes(contextNode); + return new NodeIteratorAdapter(nodes.listIterator()); + } catch (JaxenException e) { + MessageProvider msg = MessageProvider.getInstance(); + String message = msg.getMessage("xpath.00", new Object[] { exp }); + throw new XPathException(message, e); + } + } + + /** + * Return a NodeList of all the nodes matching the XPath + * expression. + * + * All namespace URIs and prefixes declared in the Constants + * interface are used for resolving namespaces. + * + * @param contextNode The root node from which to evaluate the XPath + * expression. + * @param exp The XPath expression to evaluate. + * @return A NodeList containing the matching nodes. + * @throws XPathException An error occurred evaluating the XPath expression. + */ + public static NodeList selectNodeList(Node contextNode, String exp) + throws XPathException { + + return selectNodeList(contextNode, NS_CONTEXT, exp); + } + + /** + * Return a NodeList of all the nodes matching the XPath + * expression. + * + * @param contextNode The root node from which to evaluate the XPath + * expression. + * @param namespaceElement An element from which to build the + * namespace mapping for evaluating the XPath expression + * @param exp The XPath expression to evaluate. + * @return A NodeList containing the matching nodes. + * @throws XPathException An error occurred evaluating the XPath expression. + */ + public static NodeList selectNodeList( + Node contextNode, + Element namespaceElement, + String exp) + throws XPathException { + + try { + SimpleNamespaceContext ctx = new SimpleNamespaceContext(); + + ctx.addElementNamespaces(documentNavigator, namespaceElement); + return selectNodeList(contextNode, ctx, exp); + } catch (JaxenException e) { + MessageProvider msg = MessageProvider.getInstance(); + String message = msg.getMessage("xpath.00", new Object[] { exp }); + throw new XPathException(message, e); + } + } + + /** + * Return a NodeList of all the nodes matching the XPath + * expression. + * + * @param contextNode The root node from which to evaluate the XPath + * expression. + * @param namespaceMapping A namespace prefix to namespace URI mapping + * (String to String) for evaluating the XPath + * expression. + * @param exp The XPath expression to evaluate. + * @return A NodeList containing the matching nodes. + * @throws XPathException An error occurred evaluating the XPath expression. + */ + public static NodeList selectNodeList( + Node contextNode, + Map namespaceMapping, + String exp) + throws XPathException { + + SimpleNamespaceContext ctx = new SimpleNamespaceContext(namespaceMapping); + + return selectNodeList(contextNode, ctx, exp); + } + + /** + * Return a NodeList of all the nodes matching the XPath + * expression. + * + * @param contextNode The root node from which to evaluate the XPath + * expression. + * @param nsContext The NamespaceContext for resolving namespace + * prefixes to namespace URIs for evaluating the XPath expression. + * @param exp The XPath expression to evaluate. + * @return A NodeList containing the matching nodes. + * @throws XPathException An error occurred evaluating the XPath expression. + */ + private static NodeList selectNodeList( + Node contextNode, + NamespaceContext nsContext, + String exp) + throws XPathException { + + try { + DOMXPath xpath = new DOMXPath(exp); + List nodes; + + xpath.setNamespaceContext(nsContext); + nodes = xpath.selectNodes(contextNode); + return new NodeListAdapter(nodes); + } catch (JaxenException e) { + MessageProvider msg = MessageProvider.getInstance(); + String message = msg.getMessage("xpath.00", new Object[] { exp }); + throw new XPathException(message, e); + } + } + + /** + * Select the first node matching an XPath expression. + * + * All namespace URIs and prefixes declared in the Constants + * interface are used for resolving namespaces. + * + * @param contextNode The root node from which to evaluate the XPath + * expression. + * @param exp The XPath expression to evaluate. + * @return Node The first node matching the XPath expression, or + * null, if no node matched. + * @throws XPathException An error occurred evaluating the XPath expression. + */ + public static Node selectSingleNode(Node contextNode, String exp) + throws XPathException { + + return selectSingleNode(contextNode, NS_CONTEXT, exp); + } + + /** + * Select the first node matching an XPath expression. + * + * @param contextNode The root node from which to evaluate the XPath + * expression. + * @param namespaceElement An element from which to build the + * namespace mapping for evaluating the XPath expression + * @param exp The XPath expression to evaluate. + * @return Node The first node matching the XPath expression, or + * null, if no node matched. + * @throws XPathException An error occurred evaluating the XPath expression. + */ + public static Node selectSingleNode( + Node contextNode, + Element namespaceElement, + String exp) + throws XPathException { + + try { + SimpleNamespaceContext ctx = new SimpleNamespaceContext(); + ctx.addElementNamespaces(documentNavigator, namespaceElement); + + return selectSingleNode(contextNode, ctx, exp); + } catch (JaxenException e) { + MessageProvider msg = MessageProvider.getInstance(); + String message = msg.getMessage("xpath.00", new Object[] { exp }); + throw new XPathException(message, e); + } + } + + /** + * Select the first node matching an XPath expression. + * + * @param contextNode The root node from which to evaluate the XPath + * expression. + * @param namespaceMapping A namespace prefix to namespace URI mapping + * (String to String) for evaluating the XPath + * expression. + * @param exp The XPath expression to evaluate. + * @return Node The first node matching the XPath expression, or + * null, if no node matched. + * @throws XPathException An error occurred evaluating the XPath expression. + */ + public static Node selectSingleNode( + Node contextNode, + Map namespaceMapping, + String exp) + throws XPathException { + + SimpleNamespaceContext ctx = new SimpleNamespaceContext(namespaceMapping); + + return selectSingleNode(contextNode, ctx, exp); + } + + /** + * Select the first node matching an XPath expression. + * + * @param contextNode The root node from which to evaluate the XPath + * expression. + * @param nsContext The NamespaceContext for resolving namespace + * prefixes to namespace URIs for evaluating the XPath expression. + * @param exp The XPath expression to evaluate. + * @return Node The first node matching the XPath expression, or + * null, if no node matched. + * @throws XPathException An error occurred evaluating the XPath expression. + */ + private static Node selectSingleNode( + Node contextNode, + NamespaceContext nsContext, + String exp) + throws XPathException { + + try { + DOMXPath xpath = new DOMXPath(exp); + xpath.setNamespaceContext(nsContext); + return (Node) xpath.selectSingleNode(contextNode); + } catch (JaxenException e) { + MessageProvider msg = MessageProvider.getInstance(); + String message = msg.getMessage("xpath.00", new Object[] { exp }); + throw new XPathException(message, e); + } + } + + /** + * Return the value of a DOM element whose location is given by an XPath + * expression. + * + * @param root The root element from which to evaluate the XPath. + * @param xpath The XPath expression pointing to the element whose value + * to return. + * @param def The default value to return, if no element can be found using + * the given xpath. + * @return The element value, if it can be located using the + * xpath. Otherwise, def is returned. + */ + public static String getElementValue( + Element root, + String xpath, + String def) { + + Element elem = (Element) XPathUtils.selectSingleNode(root, xpath); + return elem != null ? DOMUtils.getText(elem) : def; + } + + /** + * Return the value of a DOM attribute whose location is given by an XPath + * expression. + * + * @param root The root element from which to evaluate the XPath. + * @param xpath The XPath expression pointing to the attribute whose value to + * return. + * @param def The default value to return, if no attribute can be found using + * the given xpath. + * @return The element value, if it can be located using the + * xpath. Otherwise, def is returned. + */ + public static String getAttributeValue( + Element root, + String xpath, + String def) { + + Attr attr = (Attr) XPathUtils.selectSingleNode(root, xpath); + return attr != null ? attr.getValue() : def; + } + +} diff --git a/common/src/test/at/gv/egovernment/moa/AllTests.java b/common/src/test/at/gv/egovernment/moa/AllTests.java new file mode 100644 index 000000000..00e2c505f --- /dev/null +++ b/common/src/test/at/gv/egovernment/moa/AllTests.java @@ -0,0 +1,38 @@ +package test.at.gv.egovernment.moa; + +import test.at.gv.egovernment.moa.util.DOMUtilsTest; +import test.at.gv.egovernment.moa.util.DateTimeUtilsTest; +import test.at.gv.egovernment.moa.util.KeyStoreUtilsTest; +import test.at.gv.egovernment.moa.util.SSLUtilsTest; +import test.at.gv.egovernment.moa.util.XPathUtilsTest; + +import junit.awtui.TestRunner; +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * @author patrick + * @version $Id$ + */ +public class AllTests { + + public static Test suite() { + TestSuite suite = new TestSuite(); + + suite.addTestSuite(DOMUtilsTest.class); + suite.addTestSuite(DateTimeUtilsTest.class); + suite.addTestSuite(XPathUtilsTest.class); + suite.addTestSuite(KeyStoreUtilsTest.class); + suite.addTestSuite(SSLUtilsTest.class); + + return suite; + } + + public static void main(String[] args) { + try { + TestRunner.run(AllTests.class); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/common/src/test/at/gv/egovernment/moa/MOATestCase.java b/common/src/test/at/gv/egovernment/moa/MOATestCase.java new file mode 100644 index 000000000..86ea2ee6c --- /dev/null +++ b/common/src/test/at/gv/egovernment/moa/MOATestCase.java @@ -0,0 +1,75 @@ +package test.at.gv.egovernment.moa; + +import java.io.FileInputStream; +import java.io.StringReader; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; + +import org.xml.sax.InputSource; + +import junit.framework.TestCase; + +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.DOMUtils; + +/** + * Base class for MOA test cases. + * + * Provides some utility functions. + * + * @author Patrick Peck + * @version $Id$ + */ +public class MOATestCase extends TestCase { + + protected static final String TESTDATA_ROOT = "data/test/"; + + /** + * Constructor for MOATestCase. + * @param arg0 + */ + public MOATestCase(String name) { + super(name); + } + + /** + * Parse an XML file non-validating. + */ + public static Document parseXml(String fileName) throws Exception { + return DOMUtils.parseDocument( + new FileInputStream(fileName), + false, + null, + null); + } + + /** + * Parse an XML validating with a given file name. + * + * Uses the local schema resources. + */ + public static Document parseXmlValidating(String fileName) throws Exception { + return DOMUtils.parseDocument( + new FileInputStream(fileName), + true, + Constants.ALL_SCHEMA_LOCATIONS, + null); + } + + /** + * Parse an XML from a String. + */ + public static Document parseXmlString(String xml) throws Exception { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder; + + factory.setNamespaceAware(true); + builder = factory.newDocumentBuilder(); + + return builder.parse(new InputSource(new StringReader(xml))); + } + +} diff --git a/common/src/test/at/gv/egovernment/moa/util/DOMUtilsTest.java b/common/src/test/at/gv/egovernment/moa/util/DOMUtilsTest.java new file mode 100644 index 000000000..eb3ad1a5c --- /dev/null +++ b/common/src/test/at/gv/egovernment/moa/util/DOMUtilsTest.java @@ -0,0 +1,137 @@ +package test.at.gv.egovernment.moa.util; +import java.io.FileInputStream; +import java.util.Map; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import test.at.gv.egovernment.moa.*; + +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.DOMUtils; + +/** + * @author Patrick Peck + * @version $Id$ + */ +public class DOMUtilsTest extends MOATestCase { + private static final String TESTDATA_BASE = TESTDATA_ROOT + "xml/"; + private static boolean grammarsInitialized = false; + + /** + * Constructor for DOMUtilsTest. + * @param name + */ + public DOMUtilsTest(String name) { + super(name); + } + + protected void setUp() throws Exception { + if (!grammarsInitialized) { + // preparse XML schema + DOMUtils.addSchemaToPool( + getClass().getResourceAsStream(Constants.XML_SCHEMA_LOCATION), + Constants.XML_NS_URI); + // preparse XMLDsig Filter2 schema + DOMUtils.addSchemaToPool( + getClass().getResourceAsStream(Constants.DSIG_FILTER2_SCHEMA_LOCATION), + Constants.DSIG_FILTER2_NS_URI); + // preparse XMLDsig schema + DOMUtils.addSchemaToPool( + getClass().getResourceAsStream(Constants.DSIG_SCHEMA_LOCATION), + Constants.DSIG_NS_URI); + // preparse MOA schema + DOMUtils.addSchemaToPool( + getClass().getResourceAsStream(Constants.MOA_SCHEMA_LOCATION), + Constants.MOA_NS_URI); + grammarsInitialized = true; + } + } + + private Document parse(String fileName) throws Exception { + return DOMUtils.parseDocument( + new FileInputStream(fileName), + true, + Constants.ALL_SCHEMA_LOCATIONS, + null); + } + + public void testParseCreateXMLSignature() throws Exception { + parse(TESTDATA_BASE + "CreateXMLSignature/TestGeneratorCX2.005.Req.xml"); + parse(TESTDATA_BASE + "CreateXMLSignature/Req000.xml"); + parse(TESTDATA_BASE + "CreateXMLSignature/Req001.xml"); + parse(TESTDATA_BASE + "CreateXMLSignature/Req002.xml"); + parse(TESTDATA_BASE + "CreateXMLSignature/Req004.xml"); + } + + public void testParseVerifyCMSSignature() throws Exception { + parse(TESTDATA_BASE + "VerifyCMSSignature/Req000.xml"); + } + + public void testParseVerifyXMLSignature() throws Exception { + parse(TESTDATA_BASE + "VerifyXMLSignature/Req000.xml"); + parse(TESTDATA_BASE + "VerifyXMLSignature/Req001.xml"); + parse(TESTDATA_BASE + "VerifyXMLSignature/Req002.xml"); + parse(TESTDATA_BASE + "VerifyXMLSignature/TestGeneratorVX.002.Req.xml"); + //parse(TESTDATA_BASE + "VerifyXMLSignature/TestGeneratorVX.006.Req.xml"); + parse(TESTDATA_BASE + "VerifyXMLSignature/VerifySAMLRequest.xml"); + } + + public void testParseInfobox() throws Exception { + parse(TESTDATA_BASE + "Infobox/InfoboxReadResponseMOA4.xml"); + parse(TESTDATA_BASE + "Infobox/InfoboxReadResponse.xml"); + } + + + private Document parsePlain(String fileName) throws Exception { + return DOMUtils.parseDocument( + new FileInputStream(fileName), + false, + null, + null); + } + + public void testValidateCreateXMLSignature() throws Exception { + Document doc; + boolean valid; + + // test a valid request + doc = parsePlain(TESTDATA_BASE + "CreateXMLSignature/Req000.xml"); + valid = + DOMUtils.validateElement( + doc.getDocumentElement(), + Constants.ALL_SCHEMA_LOCATIONS, + null); + assertTrue(valid); + + // test an invalid request + doc = parsePlain(TESTDATA_BASE + "CreateXMLSignature/invalid.xml"); + try { + valid = + DOMUtils.validateElement( + doc.getDocumentElement(), + Constants.ALL_SCHEMA_LOCATIONS, + null); + fail(); + } catch (Exception e) { + } + } + + public void testGetNamespaceDeclarations() throws Exception { + Document doc; + NodeList nl; + Element elem; + Map nsDecls; + + doc = parse(TESTDATA_BASE + "VerifyXMLSignature/Req002.xml"); + nl = doc.getElementsByTagNameNS(Constants.DSIG_NS_URI, "Reference"); + elem = (Element) nl.item(0); + nsDecls = DOMUtils.getNamespaceDeclarations(elem); + + assertEquals(2, nsDecls.size()); + assertEquals(Constants.DSIG_NS_URI, nsDecls.get("dsig")); + assertEquals(Constants.MOA_NS_URI, nsDecls.get("")); + } + +} diff --git a/common/src/test/at/gv/egovernment/moa/util/DateTimeUtilsTest.java b/common/src/test/at/gv/egovernment/moa/util/DateTimeUtilsTest.java new file mode 100644 index 000000000..da6b29b1c --- /dev/null +++ b/common/src/test/at/gv/egovernment/moa/util/DateTimeUtilsTest.java @@ -0,0 +1,104 @@ +package test.at.gv.egovernment.moa.util; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +import junit.framework.TestCase; + +import at.gv.egovernment.moa.util.DateTimeUtils; + +/** + * @author Patrick Peck + * @version $Id$ + */ +public class DateTimeUtilsTest extends TestCase { + + /** + * Constructor for DateTimeUtilsTest. + * @param arg0 + */ + public DateTimeUtilsTest(String arg0) { + super(arg0); + } + + public void testParseDateTimeValid() throws Exception { + Date date; + DateFormat format = SimpleDateFormat.getDateTimeInstance(); + String dateStr; + + format.setTimeZone(TimeZone.getTimeZone("GMT")); + date = DateTimeUtils.parseDateTime("+1971-12-12T06:30:15"); + date.setTime(date.getTime() + TimeZone.getDefault().getRawOffset()); + dateStr = format.format(date); + assertEquals("12.12.1971 06:30:15", dateStr); + + date = DateTimeUtils.parseDateTime("2000-01-01T23:59:59.012Z"); + dateStr = format.format(date); + assertEquals("01.01.2000 23:59:59", dateStr); + + date = DateTimeUtils.parseDateTime("2003-05-20T12:17:30-05:00"); + dateStr = format.format(date); + assertEquals("20.05.2003 17:17:30", dateStr); + + + date = DateTimeUtils.parseDateTime("2002-02-02T02:02:02.33+04:30"); + dateStr = format.format(date); + assertEquals("01.02.2002 21:32:02", dateStr); + } + + public void testParseDateTimeInvalid() { + try { + DateTimeUtils.parseDateTime("+1971-12-12T6:30:15"); + fail(); + } catch (ParseException e) { + } + + try { + DateTimeUtils.parseDateTime("2000-01-0123:59:59.999999Z"); + fail(); + } catch (ParseException e) { + } + + try { + DateTimeUtils.parseDateTime("2003-05-20T12:17:3005:00"); + fail(); + } catch (ParseException e) { + } + + try { + DateTimeUtils.parseDateTime(" 2002-02-02T02:02:02.33+04:00"); + fail(); + } catch (ParseException e) { + } + + } + + public void testBuildDateTimeGMTMinus3() { + String should = "2002-01-01T01:01:01-03:00"; + doTestBuildDateTime(2002, 1, 1, 1, 1, 1, "GMT-03:00", should); + } + public void testBuildDateTimeMEZSommerzeit() { + String should = "2002-07-31T23:59:59+02:00"; + doTestBuildDateTime(2002, 7, 31, 23, 59, 59, "GMT+01:00", should); + } + public void testBuildDateTimeGMT() { + String should = "2002-01-01T01:01:01"; + doTestBuildDateTime(2002, 1, 1, 1, 1, 1, "GMT+00:00", should); + } + private void doTestBuildDateTime( + int year, int month, int day, + int hour, int min, int sec, + String timeZone, String dateTimeShould) { + + Calendar cal = new GregorianCalendar(TimeZone.getTimeZone(timeZone)); + cal.set(year,month, day, hour, min, sec); + cal.set(Calendar.MILLISECOND, 0); + String dateTimeBuilt = DateTimeUtils.buildDateTime(cal); + assertEquals(dateTimeShould, dateTimeBuilt); + } + +} diff --git a/common/src/test/at/gv/egovernment/moa/util/KeyStoreUtilsTest.java b/common/src/test/at/gv/egovernment/moa/util/KeyStoreUtilsTest.java new file mode 100644 index 000000000..06a72c570 --- /dev/null +++ b/common/src/test/at/gv/egovernment/moa/util/KeyStoreUtilsTest.java @@ -0,0 +1,90 @@ +package test.at.gv.egovernment.moa.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyStore; +import java.security.Security; +import java.security.cert.X509Certificate; +import java.util.Enumeration; + +import at.gv.egovernment.moa.util.KeyStoreUtils; + +import junit.framework.TestCase; + +/** + * @author Paul Ivancsics + * @version $Id$ + */ +public class KeyStoreUtilsTest extends TestCase { + private String tmpDir = "tmp/KeyStoreUtilsTest"; + private String tmpDirURL = "file:" + tmpDir; + + public KeyStoreUtilsTest(String arg0) { + super(arg0); + } + + protected void setUp() throws Exception { + Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider()); + new File(tmpDir).mkdirs(); + } + protected void tearDown() throws Exception { + new File(tmpDir).delete(); + } + public void testCreateKeyStoreJKS() throws Exception { + String[] certFilenames = new String[] { + "data/test/security/server-certs/baltimore.cer" + }; + KeyStore ks = KeyStoreUtils.createKeyStore("jks", certFilenames); + assertEquals(1, ks.size()); + X509Certificate cert = (X509Certificate)ks.getCertificate("0"); + assertEquals(3424, cert.getSerialNumber().intValue()); + } + public void testCreateKeyStorePKCS12() throws Exception { + String[] certFilenames = new String[] { + "data/test/security/server-certs/baltimore.cer" + }; + KeyStore ks = KeyStoreUtils.createKeyStore("pkcs12", certFilenames); + assertEquals(1, ks.size()); + X509Certificate cert = (X509Certificate)ks.getCertificate("0"); + assertEquals(3424, cert.getSerialNumber().intValue()); + } + public void testCreateKeyStoreFromCertificateDirectory() throws Exception { + // copy certificate files to a temporary directory, + // omitting the "CVS" directory in the source directory + copyCertificates("data/test/security/server-certs", tmpDir); + KeyStore ks = KeyStoreUtils.createKeyStoreFromCertificateDirectory("jks", tmpDirURL); + assertEquals(2, ks.size()); + X509Certificate cert0 = (X509Certificate)ks.getCertificate("0"); + X509Certificate cert1 = (X509Certificate)ks.getCertificate("1"); + assertTrue(3424 == cert0.getSerialNumber().intValue() || 3424 == cert1.getSerialNumber().intValue()); + } + private void copyCertificates(String from, String to) throws IOException { + String[] fromList = new File(from).list(); + for (int i = 0; i < fromList.length; i++) { + File fromFile = new File(from + File.separator + fromList[i]); + if (fromFile.isFile()) { + String toFile = to + "/" + fromList[i]; + FileInputStream in = new FileInputStream(fromFile); + FileOutputStream out = new FileOutputStream(toFile); + for (int ch = in.read(); ch >= 0; ch = in.read()) + out.write(ch); + out.close(); + in.close(); + } + } + + } + public void testLoadKeyStore() throws Exception { + String keyStoreURL = "file:data/test/security/client-certs/sicher-demo(buergerkarte).p12"; + KeyStore ks = KeyStoreUtils.loadKeyStore("pkcs12", keyStoreURL, "buergerkarte"); + assertEquals(1, ks.size()); + Enumeration enum = ks.aliases(); + String alias = (String)enum.nextElement(); + X509Certificate cert = (X509Certificate)ks.getCertificate(alias); + assertEquals(new BigInteger("1044289238331").intValue(), cert.getSerialNumber().intValue()); + } + +} diff --git a/common/src/test/at/gv/egovernment/moa/util/SSLUtilsTest.java b/common/src/test/at/gv/egovernment/moa/util/SSLUtilsTest.java new file mode 100644 index 000000000..7e55cb7d0 --- /dev/null +++ b/common/src/test/at/gv/egovernment/moa/util/SSLUtilsTest.java @@ -0,0 +1,160 @@ +package test.at.gv.egovernment.moa.util; + +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.security.KeyStore; +import java.security.Security; + +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSocketFactory; + +import com.sun.net.ssl.HostnameVerifier; +import com.sun.net.ssl.HttpsURLConnection; + +import at.gv.egovernment.moa.util.KeyStoreUtils; +import at.gv.egovernment.moa.util.SSLUtils; + +import junit.framework.TestCase; + +/** + * @author Paul Ivancsics + * @version $Id$ + */ +public class SSLUtilsTest extends TestCase { + + public SSLUtilsTest(String arg0) { + super(arg0); + } + + + protected void setUp() throws Exception { + //System.setProperty("javax.net.debug", "all"); + Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider()); + System.setProperty("java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol"); + System.setProperty("https.cipherSuites", "SSL_DHE_DSS_WITH_DES_CBC_SHA,SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA,SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,SSL_RSA_WITH_DES_CBC_SHA,SSL_RSA_WITH_3DES_EDE_CBC_SHA,SSL_RSA_EXPORT_WITH_RC4_40_MD5"); + } + + public void testGetSSLSocketFactoryBaltimoreOK() throws Exception { + doTestGetSSLSocketFactory( + "GET", + "https://www.baltimore.com/", + false, + "file:data/test/security/cacerts+gt_cybertrust_root", + "changeit", + true); + } + public void testGetSSLSocketFactoryBaltimoreNOK() throws Exception { + doTestGetSSLSocketFactory( + "GET", + "https://www.baltimore.com/", + false, + "file:data/test/security/cacerts", + "changeit", + false); + } + public void testGetSSLSocketFactoryVerisignOK() throws Exception { + doTestGetSSLSocketFactory( + "GET", + "https://www.verisign.com/", + false, + "file:data/test/security/cacerts", + "changeit", + true); + } + public void testGetSSLSocketFactoryVerisignNoTruststoreOK() throws Exception { + doTestGetSSLSocketFactory( + "GET", + "https://www.verisign.com/", + false, + null, + null, + true); + } + public void testGetSSLSocketFactoryLocalhostOK() throws Exception { + String urlString = "https://localhost:8443/moa-id-auth/index.jsp"; + doTestGetSSLSocketFactory( + "GET", + urlString, + true, + "file:data/test/security/server.keystore.tomcat", + "changeit", + true); + } + public void testGetSSLSocketFactoryLocalhostNOK() throws Exception { + String urlString = "https://localhost:8443/moa-id-auth/index.jsp"; + doTestGetSSLSocketFactory( + "GET", + urlString, + true, + null, + null, + false); + } + + public void doTestGetSSLSocketFactory( + String requestMethod, + String urlString, + boolean useHostnameVerifierHack, + String truststoreurl, + String trustpassword, + boolean shouldOk + ) throws Exception { + + doTestGetSSLSocketFactory( + requestMethod, urlString, useHostnameVerifierHack, truststoreurl, trustpassword, null, null, null, shouldOk); + } + public void doTestGetSSLSocketFactory( + String requestMethod, + String urlString, + boolean useHostnameVerifierHack, + String truststoreurl, + String trustpassword, + String keystoretype, + String keystoreurl, + String keypassword, + boolean shouldOk + ) throws Exception { + + KeyStore truststore = null; + if (truststoreurl != null) + truststore = KeyStoreUtils.loadKeyStore("jks", truststoreurl, trustpassword); + SSLSocketFactory sf = SSLUtils.getSSLSocketFactory( + truststore, keystoretype, keystoreurl, keypassword); + System.out.println(requestMethod + " " + urlString); + + URL url = new URL(urlString); + HttpsURLConnection conn = (HttpsURLConnection)url.openConnection(); + conn.setRequestMethod(requestMethod); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setUseCaches(false); + conn.setAllowUserInteraction(false); + conn.setSSLSocketFactory(sf); + if (useHostnameVerifierHack) + conn.setHostnameVerifier(new HostnameVerifierHack()); + try { + conn.connect(); + assertTrue(shouldOk); + assertEquals(200, conn.getResponseCode()); + conn.disconnect(); + } + catch (SSLException ex) { + assertFalse(shouldOk); + } + } + private byte[] readTruststore(String filename) throws IOException { + if (filename == null) + return null; + FileInputStream in = new FileInputStream(filename); + byte[] buffer = new byte[in.available()]; + in.read(buffer); + in.close(); + return buffer; + } + private class HostnameVerifierHack implements HostnameVerifier { + public boolean verify(String arg0, String arg1) { + return true; + } + } +} diff --git a/common/src/test/at/gv/egovernment/moa/util/URLDecoderTest.java b/common/src/test/at/gv/egovernment/moa/util/URLDecoderTest.java new file mode 100644 index 000000000..b6ea0e152 --- /dev/null +++ b/common/src/test/at/gv/egovernment/moa/util/URLDecoderTest.java @@ -0,0 +1,29 @@ +package test.at.gv.egovernment.moa.util; + +import java.net.URLEncoder; + +import at.gv.egovernment.moa.util.FileUtils; +import at.gv.egovernment.moa.util.URLDecoder; + +import junit.framework.TestCase; + +/* + * @author Paul Ivancsics + * @version $Id$ + */ +public class URLDecoderTest extends TestCase { + + public void test() throws Exception { + String s = "immerZUA0129<>%==$$%&/()@?{()=} \\\"äöüÄÖÜ?§"; + String senc = URLEncoder.encode(s); + String sdec = URLDecoder.decode(senc, "ISO-8859-1"); + assertEquals(s, sdec); + } + public void testUTF8() throws Exception { + String s = new String(FileUtils.readFile("data/test/xml/CreateXMLSignature/CreateXMLSignatureResponse.xml")); + String senc = URLEncoder.encode(s); + String sdec = URLDecoder.decode(senc, "UTF-8"); + String sutf8 = FileUtils.readFile("data/test/xml/CreateXMLSignature/CreateXMLSignatureResponse.xml", "UTF-8"); + assertEquals(sutf8, sdec); + } +} diff --git a/common/src/test/at/gv/egovernment/moa/util/URLEncoderTest.java b/common/src/test/at/gv/egovernment/moa/util/URLEncoderTest.java new file mode 100644 index 000000000..43238c51f --- /dev/null +++ b/common/src/test/at/gv/egovernment/moa/util/URLEncoderTest.java @@ -0,0 +1,43 @@ +package test.at.gv.egovernment.moa.util; + +import at.gv.egovernment.moa.util.FileUtils; +import at.gv.egovernment.moa.util.URLDecoder; +import at.gv.egovernment.moa.util.URLEncoder; +import junit.framework.TestCase; + +/* + * @author Paul Ivancsics + * @version $Id$ + */ +public class URLEncoderTest extends TestCase { + + public void testUnchangedString() throws Exception { + String s = "AZaz0123456789.-*_"; + String senc = URLEncoder.encode(s, "UTF-8"); + assertEquals(s, senc); + } + public void testAumlUTF8() throws Exception { + String s = "ä"; + String senc = URLEncoder.encode(s, "UTF-8"); + assertEquals("%C3%A4", senc); + } + public void testEncodeDecode() throws Exception { + String s = "AZaz09.-*_ <>%=$%&/()@?{}[]\\\"'äöüÄÖÜߧ"; + String senc = URLEncoder.encode(s, "UTF-8"); + String sdec = URLDecoder.decode(senc, "UTF-8"); + assertEquals(s, sdec); + } + public void testCertInfo() throws Exception { + String s = new String(FileUtils.readFile("data/test/xml/VerifyXMLSignature/CertInfoVerifyXMLSignatureRequest.xml", "UTF-8")); + String senc = URLEncoder.encode(s, "UTF-8"); + String sdec = URLDecoder.decode(senc, "UTF-8"); + assertEquals(s, sdec); + } + /*public void testJDK14() throws Exception { + String s = new String(FileUtils.readFile("data/test/xml/VerifyXMLSignature/CertInfoVerifyXMLSignatureRequest.xml", "UTF-8")); + String senc = URLEncoder.encode(s, "UTF-8"); + String senc14 = java.net.URLEncoder.encode(s, "UTF-8"); + assertEquals(senc, senc14); + }*/ + +} diff --git a/common/src/test/at/gv/egovernment/moa/util/XMLGrammarBuilderTest.java b/common/src/test/at/gv/egovernment/moa/util/XMLGrammarBuilderTest.java new file mode 100644 index 000000000..7986fe540 --- /dev/null +++ b/common/src/test/at/gv/egovernment/moa/util/XMLGrammarBuilderTest.java @@ -0,0 +1,99 @@ +package test.at.gv.egovernment.moa.util; +import java.io.FileInputStream; +import java.io.InputStream; + +import org.apache.xerces.parsers.DOMParser; +import org.apache.xerces.parsers.XMLGrammarPreparser; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLGrammarPoolImpl; +import org.apache.xerces.xni.grammars.Grammar; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.xml.sax.InputSource; + +import test.at.gv.egovernment.moa.MOATestCase; + +import at.gv.egovernment.moa.util.Constants; + + +/** + * Experimentation with Xerces grammar caching. + * + * Used the Xerces sample 'XMLGrammarBuilder' as a starting point. + * + * @author Patrick Peck + * @version $Id$ + */ +public class XMLGrammarBuilderTest extends MOATestCase { + + private static final String GRAMMAR_POOL = + org.apache.xerces.impl.Constants.XERCES_PROPERTY_PREFIX + + org.apache.xerces.impl.Constants.XMLGRAMMAR_POOL_PROPERTY; + + protected static final String NAMESPACES_FEATURE_ID = + "http://xml.org/sax/features/namespaces"; + protected static final String VALIDATION_FEATURE_ID = + "http://xml.org/sax/features/validation"; + protected static final String SCHEMA_VALIDATION_FEATURE_ID = + "http://apache.org/xml/features/validation/schema"; + protected static final String SCHEMA_FULL_CHECKING_FEATURE_ID = + "http://apache.org/xml/features/validation/schema-full-checking"; + + private static final int BIG_PRIME = 2039; + private SymbolTable symbolTable; + private XMLGrammarPoolImpl grammarPool; + + /** + * Constructor for XMLGrammarBuilderTest. + * @param name + */ + public XMLGrammarBuilderTest(String name) { + super(name); + } + + protected void setUp() throws Exception { + XMLGrammarPreparser preparser; + + // set up symbol table and grammar pool + symbolTable = new SymbolTable(BIG_PRIME); + grammarPool = new XMLGrammarPoolImpl(); + preparser = new XMLGrammarPreparser(symbolTable); + preparser.registerPreparser(XMLGrammarDescription.XML_SCHEMA, null); + preparser.setProperty(GRAMMAR_POOL, grammarPool); + preparser.setFeature(NAMESPACES_FEATURE_ID, true); + preparser.setFeature(VALIDATION_FEATURE_ID, true); + // now we can still do schema features just in case, + // so long as it's our configuraiton...... + preparser.setFeature(SCHEMA_VALIDATION_FEATURE_ID, true); + preparseSchemaResource( + preparser, + Constants.DSIG_SCHEMA_LOCATION, + "/resources/schemas/xmldsig-core-schema.xsd"); + } + + private static Grammar preparseSchemaResource( + XMLGrammarPreparser preparser, + String systemId, + String resource) + throws Exception { + + InputStream is = XMLGrammarBuilderTest.class.getResourceAsStream(resource); + return preparser.preparseGrammar( + XMLGrammarDescription.XML_SCHEMA, + new XMLInputSource(null, systemId, null, is, null)); + } + + public void testParseValidating() throws Exception { + DOMParser parser = new DOMParser(symbolTable, grammarPool); + + parser.setFeature(NAMESPACES_FEATURE_ID, true); + parser.setFeature(VALIDATION_FEATURE_ID, true); + parser.setFeature(SCHEMA_VALIDATION_FEATURE_ID, true); + + parser.parse( + new InputSource( + new FileInputStream(TESTDATA_ROOT + "xml/dsigTransform/base64.xml"))); + parser.getDocument(); + } + +} diff --git a/common/src/test/at/gv/egovernment/moa/util/XPathUtilsTest.java b/common/src/test/at/gv/egovernment/moa/util/XPathUtilsTest.java new file mode 100644 index 000000000..559494300 --- /dev/null +++ b/common/src/test/at/gv/egovernment/moa/util/XPathUtilsTest.java @@ -0,0 +1,51 @@ +package test.at.gv.egovernment.moa.util; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; + +import test.at.gv.egovernment.moa.MOATestCase; + +import at.gv.egovernment.moa.util.XPathUtils; + + +/** + * @author Patrick Peck + * @version $Id$ + */ +public class XPathUtilsTest extends MOATestCase { + + private Document doc1; + + /** + * Constructor for XPathUtilsTest. + * @param name + */ + public XPathUtilsTest(String name) { + super(name); + } + + /** + * @see TestCase#setUp() + */ + protected void setUp() throws Exception { + super.setUp(); + doc1 = + parseXml(TESTDATA_ROOT + "xml/VerifyXMLSignature/Req000.xml"); + } + + public void testSelectNodeList() throws Exception { + NodeList nodes; + + nodes = + XPathUtils.selectNodeList( + doc1.getDocumentElement(), + doc1.getDocumentElement(), + "/VerifyXMLSignatureRequest"); + assertEquals(1, nodes.getLength()); + nodes = + XPathUtils.selectNodeList( + doc1.getDocumentElement(), + "//dsig:Signature"); + assertEquals(1, nodes.getLength()); + } + +} -- cgit v1.2.3