diff options
Diffstat (limited to 'spss.slinterface/src/at')
26 files changed, 3231 insertions, 0 deletions
diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/Constants.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/Constants.java new file mode 100644 index 000000000..419f1fb9b --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/Constants.java @@ -0,0 +1,90 @@ +/* + * Created on 18.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class Constants +{ + // System properties + public static final String SP_INIT_PROPS_LOC_ = + "at.gv.egovernment.moa.spss.slinterface.PropertiesLocation"; + + // Init properties + + // TODO Revisit if constants can be removed + // public static final String IP_SL2MOA_STYLESHEET_ = "location.stylesheet.sl2moa"; + // public static final String IP_MOA2SL_STYLESHEET_ = "location.stylesheet.moa2sl"; + public static final String IP_SL_SCHEMA_ = "location.schema.sl"; + public static final String IP_MOA_SCHEMA_ = "location.schema.moa"; + public static final String IP_SLXHTML_SCHEMA_ = "location.schema.slxhtml"; + public static final String IP_TEMP_DIR_ = "location.tempdir"; + public static final String IP_SP_ENDPOINT_ = "service.sp.endpoint"; + public static final String IP_SP_TRUSTPROFILEID_ = "service.sp.trustProfileId"; + public static final String IP_RES_SHOWETSI_ = "result.showetsi"; + public static final String IP_RES_SHOWSLMAN_ = "result.showslmanifest"; + + public static final String IP_REW_ = "rewrite"; + public static final String IP_REW_PROXYURL_ = "rewrite.proxyURL"; + public static final String IP_REW_PROXYURL_HOSTDUMMY_ = "rewrite.proxyURL.proxyhostDummy"; + public static final String IP_REW_DNS_LOOKUP_PREFIX_ = "rewrite.dn."; + public static final String IP_REW_DNS_LOOKUP_DEFAULT_ = "rewrite.dn.default"; + public static final String IP_REW_MOASL_URLPARAMNAME_ = "rewrite.MOASLUrlParamName"; + public static final String IP_REW_MOASL_WEBAPPSERV_URL_ = "rewrite.MOASLWebAppServUrl"; + + // Logging hierarchies + + public static final String LH_BASE_ = "slinterface"; + public static final String LH_LISTENERS_ = LH_BASE_ + ".listeners"; + public static final String LH_LISTENERS_XMLPARSER_ = LH_LISTENERS_ + ".xmlparser"; + public static final String LH_FILTERS_ = LH_BASE_ + ".filters"; + public static final String LH_SERVLETS_ = LH_BASE_ + ".servlets"; + public static final String LH_BEANS_ = LH_BASE_ + ".beans"; + public static final String LH_TEST_ = LH_BASE_ + ".test"; + + // Web service context parameters + + public static final String WSCP_INIT_PROPS_ = "initProperties"; + public static final String WSCP_INITPROPS_BEAN_ = "initPropertiesBean"; + // TODO Revisit if constants can be removed + // public static final String WSCP_SL2MOA_TRANSFORMER_ = "sl2MoaTransformer"; + // public static final String WSCP_MOA2SL_TRANSFORMER_ = "moa2SlTransformer"; + public static final String WSCP_XMLPARSER_ = "xmlParser"; + public static final String WSCP_URL_REWRITER_ = "urlRewriter"; + + // Security-Layer constants + + public static final String SLC_NAME_HTTP_REQUEST_ = "http-security-layer-request"; + public static final String SLC_NAME_XML_REQUEST_ = "XMLRequest"; + public static final String SLC_NAME_DATA_URL_ = "DataURL"; + public static final String SLC_NAME_STYLESHEET_URL_ = "StylesheetURL"; + public static final String SLC_NAME_REDIRECT_URL_ = "RedirectURL"; + + // Namespace URIs + + public static final String NSURI_SL_10_ = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#"; + public static final String NSURI_SL_11_ = "http://www.buergerkarte.at/namespaces/securitylayer/20020831#"; + // TODO Change Namespace to final SL 1.2 + public static final String NSURI_SL_12_ = "http://www.buergerkarte.at/namespaces/securitylayer/20031231#"; + public static final String NSURI_MOA_12_ = "http://reference.e-government.gv.at/namespace/moa/20020822#"; + public static final String NSURI_NAMESPACES_ = "http://www.w3.org/2000/xmlns/"; + public static final String NSURI_XML_ = "http://www.w3.org/XML/1998/namespace"; + public static final String NSURI_DSIG_ = "http://www.w3.org/2000/09/xmldsig#"; + public static final String NSURI_XHTML_ = "http://www.w3.org/1999/xhtml"; + + // Namespace prefixes + public static final String NSPRE_SL_10_ = "sl10"; + public static final String NSPRE_SL_11_ = "sl11"; + public static final String NSPRE_SL_12_ = "sl12"; + public static final String NSPRE_MOA_12_ = "moa"; + public static final String NSPRE_DSIG_ = "dsig"; + public static final String NSPRE_XHTML_ = "xhtml"; + + // MOA invoker constants + + public static final String MI_SP_QNAME_ = "SignatureVerification"; +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/DOMUtils.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/DOMUtils.java new file mode 100644 index 000000000..814d7832e --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/DOMUtils.java @@ -0,0 +1,169 @@ +/* + * Created on 28.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import org.apache.xerces.parsers.DOMParser; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import at.gv.egovernment.moa.spss.slinterface.listeners.XMLParserErrorHandler; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class DOMUtils +{ + private static final String SAX_NAMESPACES_FEATURE = "http://xml.org/sax/features/namespaces"; + private static final String XERCES_CREATE_ENTITY_REF_NODES_FEATURE = + "http://apache.org/xml/features/dom/create-entity-ref-nodes"; + protected static final String XERCES_DEFER_NODE_EXPANSION_ = + "http://apache.org/xml/features/dom/defer-node-expansion"; + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * Gets the first text node of the specified element. + * + * @param elem The element. + * + * @return the first text node of the specified element, or <code>null</code> if <code>element</code> + * equals <code>null</code>, or if the element has no text node. + */ + public static String getText(Element elem) + { + if (elem == null) return null; + NodeList childNodes = elem.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) + { + Node currNode = childNodes.item(i); + if (currNode.getNodeType() == Node.TEXT_NODE) return currNode.getNodeValue(); + } + return null; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * Gets the first text node of the specified child element from the specified parent element. + * + * @param parent The parent. + * + * @param childNS The namespace of the child element. + * + * @param childLocName The local name of the child element. + * + * @return the first text node of the specified child, or <code>null</code> if <code>parent</code> equals + * <code>null</code> or has no child element with the specified namespace and local name, or if + * the child element has no text node. + */ + public static String getChildText(Element parent, String childNS, String childLocName) + { + if (parent == null) return null; + Element child = getChildElem(parent, childNS, childLocName); + if (child == null) return null; + return getText(child); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * Gets the first child element of the specified parent with the specified namspace and local name. + * + * @param parent The parent. + * + * @param childNS The namespace of the child element to be searched for. + * + * @param childLocName The local name of the child element to be searched for. + * + * @return the first child element as described above, or <code>null</code> if <code>parent</code> is + * null or has no child elements with for the specified namespace and local name. + */ + public static Element getChildElem(Element parent, String childNS, String childLocName) + { + List childElems = getChildElems(parent, childNS, childLocName, true); + return (childElems == null) ? null : (Element) childElems.get(0); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * Gets all or the first child element(s) of the specified parent with the specified namspace and local + * name. + * + * @param parent The parent. + * + * @param childNS The namespace of the child elements to be searched for. + * + * @param childLocName The local name of the child elements to be searched for. + * + * @param firstOnly Specifies wheter only the first or all child elements with the specified namespace and + * local name should be returned. + * + * @return a <code>java.util.List</code> with objects of type <code>org.w3c.dom.Element</code>; each + * element in the list represents a child element as specified above. If <code>parent</code> + * equals <code>null</code>, or if there are no child elements as specified above, <code>null + * </code> will be returned. + */ + public static List getChildElems(Element parent, String childNS, String childLocName, boolean firstOnly) + { + if (parent == null) return null; + + ArrayList childElems = new ArrayList(); + NodeList childNodes = parent.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) + { + Node currNode = childNodes.item(i); + if (currNode.getNodeType() == Node.ELEMENT_NODE) + { + Element currElem = (Element) currNode; + if (childNS.equals(currElem.getNamespaceURI()) && childLocName.equals(currElem.getLocalName())) + { + childElems.add(currElem); + if (firstOnly) break; + } + } + } + return (childElems.size() == 0) ? null : childElems; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public static Document parseWellFormed(InputStream is) throws Exception + { + DOMParser xmlParser = new DOMParser(); + try + { + xmlParser.setFeature(SAX_NAMESPACES_FEATURE, true); + xmlParser.setFeature(XERCES_CREATE_ENTITY_REF_NODES_FEATURE, false); + xmlParser.setFeature(XERCES_DEFER_NODE_EXPANSION_, false); + xmlParser.setErrorHandler(new XMLParserErrorHandler(false, true, true)); + + } + catch (SAXException e) + { + String message = "Initialization of XML parser failed."; + throw new Exception(message, e); + } + try + { + xmlParser.parse(new InputSource(is)); + return xmlParser.getDocument(); + } + catch (Exception e) + { + String message = "Wellformed parsing failed."; + throw new Exception(message, e); + } + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/URLRewriter.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/URLRewriter.java new file mode 100644 index 000000000..683851ff9 --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/URLRewriter.java @@ -0,0 +1,157 @@ +/* + * Created on 15.12.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Properties; + +import javax.servlet.http.HttpSession; + +import org.apache.log4j.Logger; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class URLRewriter +{ + private static Logger logger_ = Logger.getLogger(Constants.LH_LISTENERS_); + + Properties initProps_; + + /** + * Flag indicating whether rewriting should take place or not. + */ + boolean doRewrite_; + + /** + * Class that manges the rewriting of URLs for the result pages. Necessary as workaround for the deploy- + * ment in the Federal Chancellory. + */ + public URLRewriter(Properties initProps) + { + initProps_ = initProps; + doRewrite_ = Boolean.valueOf(initProps_.getProperty(Constants.IP_REW_)).booleanValue(); + } + + /** + * Rewrites the specified URL. + * + * @param url A URL relative to the root of the web application server containing MOA SL. + * + * @param session The session which will be considered in the rewritten URL. + * + * @return A URL fitting for the proxy component running at the Federal Chancellory. + */ + public String rewrite(String url, HttpSession session) + { + if (doRewrite_) + { + // Get remote IP address and resolve to remote to remote domain name + String remoteAddr = (String)session.getAttribute("remoteAddr"); + String remoteName = null; + if (remoteAddr != null) + { + remoteName = initProps_.getProperty(Constants.IP_REW_DNS_LOOKUP_PREFIX_ + remoteAddr); + logger_.debug("Remote address lookup succeeded for IP " + remoteAddr + ", using " + remoteName); + } + if (remoteName == null) + { + remoteName = initProps_.getProperty(Constants.IP_REW_DNS_LOOKUP_DEFAULT_); + logger_.debug("Remote address lookup failed for IP " + remoteAddr + ", using default: " + remoteName); + } + + // Get proxy URL and replace proxy URL hostname placeholder with remote domain name + String proxyURLStr = initProps_.getProperty(Constants.IP_REW_PROXYURL_); + int pHStartIndex = proxyURLStr.indexOf(initProps_.getProperty(Constants.IP_REW_PROXYURL_HOSTDUMMY_)); + proxyURLStr = proxyURLStr.substring(0, pHStartIndex) + + remoteName + + proxyURLStr.substring(pHStartIndex + + initProps_.getProperty(Constants.IP_REW_PROXYURL_HOSTDUMMY_).length()); + + String slInterfaceURLParamName = initProps_.getProperty(Constants.IP_REW_MOASL_URLPARAMNAME_); + String slInterfaceWebAppServURLStr = initProps_.getProperty(Constants.IP_REW_MOASL_WEBAPPSERV_URL_); + + if (proxyURLStr == null || + slInterfaceURLParamName == null || + slInterfaceWebAppServURLStr == null || + "".equals(proxyURLStr.trim()) || + "".equals(slInterfaceURLParamName.trim()) || + "".equals(slInterfaceWebAppServURLStr.trim())) + { + logger_.warn("Some params for URL rewriting are not available; rewriting disabled:" + + " proxyURL: \"" + proxyURLStr + "\"," + + " slInterfaceURLParamName: \"" + slInterfaceURLParamName + "\"," + + " slInterfaceWebAppServURLStr: \"" + slInterfaceWebAppServURLStr + "\""); + return url; + } + + URL slInterfaceURL = null; + try + { + slInterfaceURL = new URL(slInterfaceWebAppServURLStr + url); + } + catch (MalformedURLException e) + { + logger_.warn("Parameter \"slInterfaceURL\" is not a valid URL: \"" + slInterfaceWebAppServURLStr + url + "\""); + return url; + } + URL proxyURL = null; + try + { + proxyURL = new URL(proxyURLStr); + } + catch (MalformedURLException e) + { + logger_.warn("Parameter \"proxyURL\" is not a valid URL: \"" + proxyURLStr + "\""); + return url; + } + + String sessionId = session.getId(); + String sessionIdParam = (sessionId != null) ? (";" + "jsessionid=" + sessionId) : ""; + String returnValue = + proxyURL.getProtocol() + + "://" + + proxyURL.getHost() + + ((proxyURL.getPort() != -1) ? (":" + proxyURL.getPort()) : "") + + proxyURL.getPath() + + ((proxyURL.getQuery() != null) ? "?" + proxyURL.getQuery() + "&" : "?") + + slInterfaceURLParamName + "=" + + slInterfaceURL.getProtocol() + + "://" + + slInterfaceURL.getHost() + + ((slInterfaceURL.getPort() != -1) ? (":" + slInterfaceURL.getPort()) : "") + + slInterfaceURL.getPath() + + sessionIdParam + + ((slInterfaceURL.getQuery() != null) ? "?" + escapeQueryPart(slInterfaceURL.getQuery()) : ""); + + logger_.debug("Rewritten URL: " + returnValue); + return returnValue; + } + else + { + logger_.debug("URL rewriting disabled via configuration. URL \"" + url + "\" remains unchanged."); + return url; + } + } + + private String escapeQueryPart(String query) + { + StringBuffer querySB = new StringBuffer(); + for (int i = 0; i < query.length(); i++) + { + if (query.charAt(i) == '&') + { + querySB.append("%26"); + } + else + { + querySB.append(query.charAt(i)); + } + } + return querySB.toString(); + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/Utils.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/Utils.java new file mode 100644 index 000000000..50ae5dc03 --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/Utils.java @@ -0,0 +1,51 @@ +/* + * Created on 25.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class Utils +{ + public static byte[] readFromInputStream(InputStream inputStream) throws IOException + { + byte[] currentBytes = new byte[500]; + int bytesRead; + ByteArrayOutputStream result = new ByteArrayOutputStream(); + do + { + bytesRead = inputStream.read(currentBytes); + if (bytesRead > 0) + { + result.write(currentBytes, 0, bytesRead); + } + } + while (bytesRead != -1); + return result.toByteArray(); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public static void transferStreams(InputStream in, OutputStream out) throws IOException + { + byte[] currentBytes = new byte[500]; + int bytesRead; + do + { + bytesRead = in.read(currentBytes); + if (bytesRead > 0) + { + out.write(currentBytes, 0, bytesRead); + } + } + while (bytesRead != -1); + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/XPathUtils.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/XPathUtils.java new file mode 100644 index 000000000..16e4938ed --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/XPathUtils.java @@ -0,0 +1,162 @@ +/* + * Created on 02.12.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface; + +import java.util.HashMap; +import java.util.StringTokenizer; + +import org.apache.xml.utils.PrefixResolverDefault; +import org.apache.xpath.XPath; +import org.apache.xpath.XPathContext; +import org.apache.xpath.objects.XObject; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class XPathUtils +{ + /** + * The XPath context for the XPath engine. + */ + protected XPathContext xPathContext_; + + /** + * The prefix resolver for the XPath engine. + */ + protected PrefixResolver prefixResolver_; + + /** + * The XPath engine. + */ + protected XPath xPath_; + + /* ==================================================================================================== */ + + public void setupContext(String xPathExpr, Node namespaceNode, String additionalNSPrefixes) + throws Exception + { + + try + { + // Set up a new evaluation context + xPathContext_ = new XPathContext(); + + // Set up the namespace prefix resolver for the XPath engine + prefixResolver_ = new PrefixResolver(namespaceNode, additionalNSPrefixes); + + // Initialize XPath engine + xPath_ = new XPath(xPathExpr, null, prefixResolver_, XPath.SELECT, null); + } + catch (Exception e) + { + throw new Exception("Setting up XPath evaluation context failed.", e); + } + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public NodeList selectNodeSet(Node contextNode) throws Exception + { + XObject xObject; + try + { + xObject = xPath_.execute(xPathContext_, contextNode, prefixResolver_); + return xObject.nodelist(); + } + catch (Exception e) + { + throw new Exception("Executing XPath expression failed.", e); + } + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public boolean selectBoolean(Node contextNode) throws Exception + { + XObject xObject; + try + { + xObject = xPath_.execute(xPathContext_, contextNode, prefixResolver_); + return xObject.bool(); + } + catch (Exception e) + { + throw new Exception("Executing XPath expression failed.", e); + } + } + + /* ==================================================================================================== */ + + /** + * Special extension of the {@link org.apache.xml.utils.PrefixResolverDefault} interface. Used to + * configure the Apache Xalan XPath engine which is employed as the backbone of this class. + */ + protected class PrefixResolver extends PrefixResolverDefault + { + + /** + * Contains the additionally specified namespace prefix (key) to namespace URI (value) attributions. + */ + protected HashMap additionalNSPrefixesMap_; + + /* ================================================================================================== */ + + /** + * Basic constructor. + * + * @param xpathExpressionContext The namespace declarations in scope for this node will be used to get + * the namespace uri for a prefix specified in the XPath expression. + * + * @param additionalNSPrefixes Allows the specification of additional prefix to uri attributions apart + * from the declarations in scope for the parameter <code> + * xpathExpressionContext</code>. May be <code>null</code>. + */ + public PrefixResolver(Node xpathExpressionContext, String additionalNSPrefixes) throws Exception + { + super(xpathExpressionContext); + additionalNSPrefixesMap_ = new HashMap(); + + // Register the specified additional namespace prefix to namespace uri attributions + if (additionalNSPrefixes != null) + { + StringTokenizer tokenizer = new StringTokenizer(additionalNSPrefixes, " "); + while (tokenizer.hasMoreTokens()) + { + String prefix = tokenizer.nextToken(); + if (!tokenizer.hasMoreTokens()) + { + + // There must be an even number of tokens in the string + throw new Exception("Parameter \"additionalNSPrefixes\" must have an even number of tokens."); + } + String uri = tokenizer.nextToken(); + additionalNSPrefixesMap_.put(prefix, uri); + } + } + } + + /* -------------------------------------------------------------------------------------------------- */ + + /** + * Gets the namespace uri for the specified namespace prefix. The additionally specified prefixes + * overrule the prefixes found in the specified namespace node. + * + * @param prefix The namespace prefix for which a namespace uri should be found. + * + * @return the namespace uri for the specified namespace prefix. + */ + public String getNamespaceForPrefix(String prefix) + { + String additionalURI = (String) additionalNSPrefixesMap_.get(prefix); + return (additionalURI != null) + ? additionalURI + : super.getNamespaceForPrefix(prefix); + } + } +} + diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/beans/ChecksInfoBean.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/beans/ChecksInfoBean.java new file mode 100644 index 000000000..00c9fd517 --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/beans/ChecksInfoBean.java @@ -0,0 +1,165 @@ +/* + * Created on 27.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.beans; + +import java.util.List; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import at.gv.egovernment.moa.spss.slinterface.Constants; +import at.gv.egovernment.moa.spss.slinterface.DOMUtils; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class ChecksInfoBean +{ + private static final String SIG_CHECK_ELEM_ = "SignatureCheck"; + private static final String SIGMF_CHECK_ELEM_ = "SignatureManifestCheck"; + private static final String XMLDSIGMF_CHECK_ELEM_ = "XMLDSIGManifestCheck"; + private static final String CERT_CHECK_ELEM_ = "CertificateCheck"; + private static final String CODE_ELEM_ = "Code"; + private static final String INFO_ELEM_ = "Info"; + private static final String FAILEDREF_ELEM_ = "FailedReference"; + private static final String REFSIGREF_ELEM_ = "ReferringSigReference"; + + private Element sigCheckElem_; + private int sigCheckFaildRefCount_; + + private Element sigMFCheckElem_; + private int sigMFCheckFaildRefCount_; + + private List xmldsigMFCheckElems_; + private int xmldsigMFCheckCount_; + private int xmldsigMFCheckFaildRefCount_; + + private Element certCheckElem_; + + /** + * Creates a bean with information about the checks executed for the verified xml signature. + * + * @pre slResponseDoc has been validated. + */ + public ChecksInfoBean(Document slResponseDoc) + { + Element verifyXMLResponseElem = slResponseDoc.getDocumentElement(); + sigCheckElem_ = DOMUtils.getChildElem( + verifyXMLResponseElem, Constants.NSURI_SL_11_, SIG_CHECK_ELEM_); + sigMFCheckElem_ = DOMUtils.getChildElem( + verifyXMLResponseElem, Constants.NSURI_SL_11_, SIGMF_CHECK_ELEM_); + xmldsigMFCheckElems_ = DOMUtils.getChildElems( + verifyXMLResponseElem, Constants.NSURI_SL_11_, XMLDSIGMF_CHECK_ELEM_, false); + certCheckElem_ = DOMUtils.getChildElem( + verifyXMLResponseElem, Constants.NSURI_SL_11_, CERT_CHECK_ELEM_); + + sigCheckFaildRefCount_ = 0; + sigMFCheckFaildRefCount_ = 0; + xmldsigMFCheckFaildRefCount_ = 0; + xmldsigMFCheckCount_ = 0; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public String getSigCheckCode() + { + return DOMUtils.getChildText(sigCheckElem_, Constants.NSURI_SL_11_, CODE_ELEM_); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public void setSigCheckFailedRefCount(int count) + { + sigCheckFaildRefCount_ = count; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public String getSigCheckFailedRef() + { + Element info = DOMUtils.getChildElem(sigCheckElem_, Constants.NSURI_SL_11_, INFO_ELEM_); + if (info == null) return null; + List failedRefElems = DOMUtils.getChildElems(info, Constants.NSURI_SL_11_, FAILEDREF_ELEM_, false); + if (failedRefElems == null || failedRefElems.size() <= sigCheckFaildRefCount_) return null; + return DOMUtils.getText((Element)failedRefElems.get(sigCheckFaildRefCount_)); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public String getSigMFCheckCode() + { + return DOMUtils.getChildText(sigMFCheckElem_, Constants.NSURI_SL_11_, CODE_ELEM_); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public void setSigMFCheckFailedRefCount(int count) + { + sigMFCheckFaildRefCount_ = count; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public String getSigMFCheckFailedRef() + { + Element info = DOMUtils.getChildElem(sigMFCheckElem_, Constants.NSURI_SL_11_, INFO_ELEM_); + if (info == null) return null; + List failedRefElems = DOMUtils.getChildElems(info, Constants.NSURI_SL_11_, FAILEDREF_ELEM_, false); + if (failedRefElems == null || failedRefElems.size() <= sigMFCheckFaildRefCount_) return null; + return DOMUtils.getText((Element)failedRefElems.get(sigMFCheckFaildRefCount_)); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public void setXmldsigMFCheckCount(int count) + { + xmldsigMFCheckCount_ = count; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public void setXmldsigMFCheckFailedRefCount(int count) + { + xmldsigMFCheckFaildRefCount_ = count; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public String getXmldsigMFCheckCode() + { + Element xmldsigMFCheckElem = (Element)xmldsigMFCheckElems_.get(xmldsigMFCheckCount_); + return DOMUtils.getChildText(xmldsigMFCheckElem, Constants.NSURI_SL_11_, CODE_ELEM_); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public String getXmldsigMFCheckFailedRef() + { + Element xmldsigMFCheckElem = (Element)xmldsigMFCheckElems_.get(xmldsigMFCheckCount_); + Element info = DOMUtils.getChildElem(xmldsigMFCheckElem, Constants.NSURI_SL_11_, INFO_ELEM_); + if (info == null) return null; + List failedRefElems = DOMUtils.getChildElems(info, Constants.NSURI_SL_11_, FAILEDREF_ELEM_, false); + if (failedRefElems == null || failedRefElems.size() <= xmldsigMFCheckFaildRefCount_) return null; + return DOMUtils.getText((Element)failedRefElems.get(xmldsigMFCheckFaildRefCount_)); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public String getXmldsigMFCheckReferringSigRef() + { + Element xmldsigMFCheckElem = (Element)xmldsigMFCheckElems_.get(xmldsigMFCheckCount_); + Element info = DOMUtils.getChildElem(xmldsigMFCheckElem, Constants.NSURI_SL_11_, INFO_ELEM_); + if (info == null) return null; + return DOMUtils.getChildText(info, Constants.NSURI_SL_11_, REFSIGREF_ELEM_); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public String getCertCheckCode() + { + return DOMUtils.getChildText(certCheckElem_, Constants.NSURI_SL_10_, CODE_ELEM_); + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/beans/DataInfoBean.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/beans/DataInfoBean.java new file mode 100644 index 000000000..570f3fb15 --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/beans/DataInfoBean.java @@ -0,0 +1,541 @@ +/* + * Created on 27.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.beans; + +import iaik.utils.Util; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Random; +import java.util.Set; +import java.util.StringTokenizer; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionBindingEvent; +import javax.servlet.http.HttpSessionBindingListener; + +import org.apache.log4j.Logger; +import org.apache.xerces.parsers.DOMParser; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +import at.gv.egovernment.moa.spss.slinterface.Constants; +import at.gv.egovernment.moa.spss.slinterface.DOMUtils; +import at.gv.egovernment.moa.spss.slinterface.URLRewriter; +import at.gv.egovernment.moa.spss.slinterface.XPathUtils; +import at.gv.egovernment.moa.spss.slinterface.moainvoker.MOAInvoker; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class DataInfoBean implements HttpSessionBindingListener +{ + private static Logger logger_ = Logger.getLogger(Constants.LH_BEANS_); + + // MOA + private static final String HID_ELEM_ = "HashInputData"; + private static final String B64CONT_ELEM_ = "Base64Content"; + private static final String XMLCONT_ELEM_ = "XMLContent"; + private static final String SIGLOC_ELEM_ = "VerifySignatureLocation"; + + // XMLDSIG + private static final String TYPE_ATTR_ = "Type"; + private static final String URI_ATTR_ = "URI"; + + // XHTML + private static final String SRC_ATTR_ = "src"; + private static final String HTML_ELEM_ = "html"; + + private static final String HID_URL_PREFIX_ = "/showdata?hidCount="; + + private static final String XPATH_ALL_IMG_ = "//" + Constants.NSPRE_XHTML_ + ":img"; + private static final String XPATH_ALL_REF_ = "./" + Constants.NSPRE_DSIG_ + ":SignedInfo/" + + Constants.NSPRE_DSIG_ + ":Reference"; + private static final String XPATH_SIG_ENV_CONTENT_ = "/" + Constants.NSPRE_MOA_12_ + ":VerifyXMLSignatureRequest/" + + Constants.NSPRE_MOA_12_ + ":VerifySignatureInfo/" + Constants.NSPRE_MOA_12_ + ":VerifySignatureEnvironment/*"; + + private static final String SLXHTML_TYPE_PREFIX_ = "http://www.buergerkarte.at/specifications/" + + "Security-Layer/20031113?Name=SignedImage&InstanceDocRef="; + + private static final String ETSI_TYPE_ = "http://uri.etsi.org/01903/v1.1.1#SignedProperties"; + private static final String SLMANIFEST_TYPE_ = + "http://www.buergerkarte.at/specifications/Securitylayer/20020225#SignatureManifest"; + + ServletContext context_; + String contextPath_; + HttpSession session_; + + Properties initProps_; + + /** + * Contains objects of type {@link HashInputDataInfo}. + */ + List hashInputDataInfos_; + + int hashInputDataCount_; + + /* ---------------------------------------------------------------------------------------------------- */ + + public DataInfoBean(Document moaRequestDoc, Document moaResponseDoc, String contextPath, HttpSession session, + ServletContext context) throws Exception + { + context_ = context; + contextPath_ = contextPath; + session_ = session; + initProps_ = (Properties) context_.getAttribute(Constants.WSCP_INIT_PROPS_); + + hashInputDataInfos_ = new ArrayList(); + int hashInputDataCount_ = 0; + + Element moaResponseElem = moaResponseDoc.getDocumentElement(); + List hidElems = DOMUtils.getChildElems(moaResponseElem, Constants.NSURI_MOA_12_, HID_ELEM_, false); + + String tempDir = initProps_.getProperty(Constants.IP_TEMP_DIR_); + if (tempDir == null) + { + String message = "Init property \"" + Constants.IP_TEMP_DIR_ + "\" not set."; + logger_.error(message); + throw new IOException(message); + } + + Random random = new Random(); + for (int i = 0; i < hidElems.size(); i++) + { + // Open file for current hash input data + String currHidFileNameStr = tempDir + session_.getId() + "_" + System.currentTimeMillis() + "_" + + random.nextLong(); + currHidFileNameStr = context_.getRealPath(currHidFileNameStr); + FileOutputStream currHidFOS; + try + { + currHidFOS = new FileOutputStream(currHidFileNameStr); + } + catch (IOException e) + { + String message = "Cannot open file \"" + currHidFileNameStr + "\"."; + logger_.error(message); + throw new IOException(message); + } + + // Write HID to file + Element currHidElem = (Element) hidElems.get(i); + Element base64ContentElem = DOMUtils.getChildElem(currHidElem, Constants.NSURI_MOA_12_, B64CONT_ELEM_); + if (base64ContentElem != null) + { + // HID is base64 + + String base64ContentText = DOMUtils.getText(base64ContentElem); + byte[] content = Util.Base64Decode(base64ContentText.getBytes()); + try + { + currHidFOS.write(content); + currHidFOS.close(); + } + catch (IOException e) + { + String message = "Cannot write to file \"" + currHidFileNameStr + "\"."; + logger_.error(message); + throw new IOException(message); + } + } + else + { + // HID is XML + + // TODO treatment of XML content + throw new RuntimeException("XML content not support yet."); + } + + hashInputDataInfos_.add(new HashInputDataInfo(currHidFileNameStr)); + } + logger_.debug("Finnished writing hash input data to files."); + + // Check if hids are slxhtml documents; mark them appropriately + try + { + Map signedImages = getSignedImages(moaRequestDoc, hashInputDataInfos_); + for (int i = 0; i < hashInputDataInfos_.size(); i++) + { + HashInputDataInfo currHid = (HashInputDataInfo) hashInputDataInfos_.get(i); + FileInputStream currHidIS = new FileInputStream(currHid.filename_); + checkImages(currHidIS, currHid, signedImages); + } + } + catch (Exception e) + { + String message = "Performing SLXHTML checks failed."; + logger_.error(message, e); + throw new Exception(message, e); + } + logger_.debug("Finnished checking hash input data for slxhtml conformity."); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public void valueBound(HttpSessionBindingEvent event) + { + // Do nothing. + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public void valueUnbound(HttpSessionBindingEvent event) + { + // Delete all temporary hash input data files + for (int i = 0; i < hashInputDataInfos_.size(); i++) + { + String currFileStr = ((HashInputDataInfo) hashInputDataInfos_.get(i)).filename_; + File currFile = new File(currFileStr); + currFile.delete(); + } + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public void setHashInputDataCount(int count) + { + hashInputDataCount_ = count; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public String getHashInputDataFilename() + { + HashInputDataInfo currHid = (HashInputDataInfo) hashInputDataInfos_.get(hashInputDataCount_); + return (currHid == null) ? null : currHid.filename_; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public String getHashInputDataURL() + { + return (hashInputDataInfos_.size() > hashInputDataCount_) + ? HID_URL_PREFIX_ + hashInputDataCount_ + : null; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public boolean getShowHashInputData() + { + HashInputDataInfo currHid = (HashInputDataInfo) hashInputDataInfos_.get(hashInputDataCount_); + return (currHid == null) ? false : currHid.doShow_; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public boolean getIsSLXHTMLDocument() + { + HashInputDataInfo currHid = (HashInputDataInfo) hashInputDataInfos_.get(hashInputDataCount_); + return (currHid == null) ? false : currHid.isSLXHTMLDocument_; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + private Document parseSLXHTMLDocument(InputStream docIS) + { + DOMParser xmlParser = (DOMParser) context_.getAttribute(Constants.WSCP_XMLPARSER_); + InputSource docInputSource = new InputSource(docIS); + Document parsedDoc = null; + try + { + xmlParser.parse(docInputSource); + parsedDoc = xmlParser.getDocument(); + } + catch (Exception e) + { + // Exception shows that document is not a valid SLXHTML document; return null in that case + logger_.debug("HashInputData is not a valid SLXHTML document.", e); + return null; + } + + Element docElem = parsedDoc.getDocumentElement(); + if (docElem.getNamespaceURI() != Constants.NSURI_XHTML_ || docElem.getLocalName() != HTML_ELEM_) + { + return null; + } + + return parsedDoc; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + private void checkImages(InputStream hidIS, HashInputDataInfo hid, Map signedImages) throws Exception + { + // Parse hidIS + Document slxhtmlDoc = parseSLXHTMLDocument(hidIS); + if (slxhtmlDoc == null) return; + + // Get all img elements of slxhtml document + XPathUtils xpUtils = new XPathUtils(); + String additionalNSPrefixes = Constants.NSPRE_XHTML_ + " " + Constants.NSURI_XHTML_; + xpUtils.setupContext(XPATH_ALL_IMG_, slxhtmlDoc.getDocumentElement(), additionalNSPrefixes); + NodeList imgTags = xpUtils.selectNodeSet(slxhtmlDoc); + + // Check if all img elements have corresponding slxhtml signed images + boolean allImgsSigned = true; + for (int i = 0; i < imgTags.getLength(); i++) + { + Element currImgElem = (Element) imgTags.item(i); + String uri = currImgElem.getAttribute(SRC_ATTR_); + if (!signedImages.containsKey(uri)) + { + allImgsSigned = false; + break; + } + } + + // Mark all corresponding slxhtml signed images as not to be shown + if (allImgsSigned) + { + for (int i = 0; i < imgTags.getLength(); i++) + { + Element currImgElem = (Element) imgTags.item(i); + String uri = currImgElem.getAttribute(SRC_ATTR_); + HashInputDataInfo currHidi = (HashInputDataInfo) signedImages.get(uri); + currHidi.doShow_ = false; + } + } + + if (allImgsSigned) + { + // Change the src attributes of all img tags so that they refer to the temporary names + for (int i = 0; i < imgTags.getLength(); i++) + { + Element currImgElem = (Element) imgTags.item(i); + String uri = currImgElem.getAttribute(SRC_ATTR_); + HashInputDataInfo currHidi = (HashInputDataInfo) signedImages.get(uri); + + Attr srcAttr = currImgElem.getAttributeNode(SRC_ATTR_); + int slashPos = currHidi.filename_.lastIndexOf(System.getProperty("file.separator")); + +// Properties initProps = (Properties) context_.getAttribute(Constants.WSCP_INIT_PROPS_); +// String tempDir = initProps.getProperty(Constants.IP_TEMP_DIR_); +// String newSrcAttrValue = "." + tempDir + currHidi.filename_.substring(slashPos + 1); + + Properties initProps = (Properties) context_.getAttribute(Constants.WSCP_INIT_PROPS_); + String tempDir = initProps.getProperty(Constants.IP_TEMP_DIR_); + URLRewriter urlRewriter = (URLRewriter) context_.getAttribute(Constants.WSCP_URL_REWRITER_); + String newSrcAttrValue = urlRewriter.rewrite( + contextPath_ + tempDir + currHidi.filename_.substring(slashPos + 1), session_); + + srcAttr.setNodeValue(newSrcAttrValue); + } + + // Mark hid as slxhtml document + hid.isSLXHTMLDocument_ = true; + + // Serialize modified slxhtml document to temporary file location + FileOutputStream slxhtmlFOS = new FileOutputStream(hid.filename_); + MOAInvoker.serializeDocument(slxhtmlDoc, slxhtmlFOS); + slxhtmlFOS.close(); + } + } + + /* ---------------------------------------------------------------------------------------------------- */ + + private Map getSignedImages(Document moaRequestDoc, List hashInputDataInfos) throws Exception + { + // Get signature from MOA request + Element signatureElem = getSignature(moaRequestDoc); + + // Get all signature references from MOA request + XPathUtils xpUtils = new XPathUtils(); + String additionalNSPrefixes = Constants.NSPRE_DSIG_ + " " + Constants.NSURI_DSIG_; + xpUtils.setupContext(XPATH_ALL_REF_, signatureElem, additionalNSPrefixes); + NodeList dsigRefs = xpUtils.selectNodeSet(signatureElem); + + // Check signature references for slxhtml images + HashMap imgHids = new HashMap(dsigRefs.getLength()); + for (int i = 0; i < dsigRefs.getLength(); i++) + { + Element currRef = (Element) dsigRefs.item(i); + String type = currRef.getAttribute(TYPE_ATTR_); + if (type != null && type.startsWith(SLXHTML_TYPE_PREFIX_)) + { + String uri = currRef.getAttribute(URI_ATTR_); + Set referredHids = createReferredHidsSet(type); + HashInputDataInfo currHidi = (HashInputDataInfo)hashInputDataInfos.get(i); + currHidi.uri_ = uri; + currHidi.referredHids_ = referredHids; + currHidi.isSLXHTMLImage_ = true; + imgHids.put(uri, currHidi); + } + } + + // Check signature references if they refer to etsi attributes or to a SL manifest + for (int i = 0; i < dsigRefs.getLength(); i++) + { + Element currRef = (Element) dsigRefs.item(i); + String type = currRef.getAttribute(TYPE_ATTR_); + if (type != null && type.equals(ETSI_TYPE_)) + { + HashInputDataInfo currHidi = (HashInputDataInfo)hashInputDataInfos.get(i); + currHidi.doShow_ = new Boolean(initProps_.getProperty(Constants.IP_RES_SHOWETSI_).trim()).booleanValue(); + } + if (type != null && type.equals(SLMANIFEST_TYPE_)) + { + HashInputDataInfo currHidi = (HashInputDataInfo)hashInputDataInfos.get(i); + currHidi.doShow_ = new Boolean(initProps_.getProperty(Constants.IP_RES_SHOWSLMAN_).trim()).booleanValue(); + } + } + + return imgHids; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + private Set createReferredHidsSet(String type) throws Exception + { + HashSet set = new HashSet(); + String typeSuffix = type.substring(SLXHTML_TYPE_PREFIX_.length()); + StringTokenizer tokenizer = new StringTokenizer(typeSuffix, ","); + while (tokenizer.hasMoreTokens()) + { + try + { + set.add(new Integer(tokenizer.nextToken())); + } + catch (NumberFormatException e) + { + String message = "Signed image type attribute \"" + type + "\" is malformed."; + logger_.error(message, e); + throw new Exception(message, e); + } + } + return set; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + private Element getSignature(Document moaRequestDoc) throws Exception + { + // Get signature environment content + NodeList contentNL; + try + { + XPathUtils xpUtils = new XPathUtils(); + String addNSPrefixes = Constants.NSPRE_MOA_12_ + " " + Constants.NSURI_MOA_12_; + xpUtils.setupContext(XPATH_SIG_ENV_CONTENT_, moaRequestDoc, addNSPrefixes); + contentNL = xpUtils.selectNodeSet(moaRequestDoc); + } + catch (Exception e) + { + String message = "Cannot find signature environment content."; + logger_.error(message); + throw new Exception(message, e); + } + if (contentNL.getLength() == 0) + { + String message = "Cannot find signature environment content."; + logger_.error(message); + throw new Exception(message); + } + Element contentElem = (Element) contentNL.item(0); + + // Get signature environment document from signature environment content + String contentElemLocName = contentElem.getLocalName(); + Element sigEnvElem = null; + Element oldDocElem = null; + if (XMLCONT_ELEM_.equals(contentElemLocName)) + { + // XML content + NodeList contentNodes = contentElem.getChildNodes(); + for (int i = 0; i < contentNodes.getLength(); i++) + { + Node currContNode = (Node) contentNodes.item(i); + if (currContNode.getNodeType() == Node.ELEMENT_NODE) + { + sigEnvElem = (Element) currContNode; + oldDocElem = (Element) moaRequestDoc.replaceChild(sigEnvElem, moaRequestDoc.getDocumentElement()); + break; + } + } + } + else if (B64CONT_ELEM_.equals(contentElemLocName)) + { + // Base64 content + String base64ContStr = DOMUtils.getText(contentElem); + byte[] contBytes = Util.Base64Decode(base64ContStr.getBytes()); + ByteArrayInputStream contBIS = new ByteArrayInputStream(contBytes); + Document sigEnvDoc; + try + { + sigEnvDoc = DOMUtils.parseWellFormed(contBIS); + } + catch (Exception e) + { + String message = "Cannot parse signature environment from base64 content."; + logger_.error(message); + throw new Exception(message, e); + } + sigEnvElem = sigEnvDoc.getDocumentElement(); + } + else + { + // LocRef content + String locRef = DOMUtils.getText(contentElem); + URL locRefURL = new URL(locRef); + InputStream contentIS = locRefURL.openStream(); + Document sigEnvDoc; + try + { + sigEnvDoc = DOMUtils.parseWellFormed(contentIS); + } + catch (Exception e) + { + String message = "Cannot parse signature environment from location reference content."; + logger_.error(message); + throw new Exception(message, e); + } + sigEnvElem = sigEnvDoc.getDocumentElement(); + } + + // Get signature form signature environment document + Element sigInfoElem = (Element) contentElem.getParentNode().getParentNode(); + Element sigLocElem = DOMUtils.getChildElem(sigInfoElem, Constants.NSURI_MOA_12_, SIGLOC_ELEM_); + String sigLocXPath = DOMUtils.getText(sigLocElem); + NodeList sigElemNL; + try + { + XPathUtils xpUtils = new XPathUtils(); + xpUtils.setupContext(sigLocXPath, sigLocElem, null); + sigElemNL = xpUtils.selectNodeSet(sigEnvElem); + } + catch (Exception e) + { + String message = "Cannot get signature at location \"" + sigLocXPath + "\" from signature environment."; + logger_.error(message); + throw new Exception(message, e); + } + if (sigElemNL.getLength() != 1 || ((Node) sigElemNL.item(0)).getNodeType() != Node.ELEMENT_NODE) + { + String message = "Cannot get signature at location \"" + sigLocXPath + "\" from signature environment."; + logger_.error(message); + throw new Exception(message); + } + + if (oldDocElem != null) moaRequestDoc.replaceChild(oldDocElem, moaRequestDoc.getDocumentElement()); + + return (Element) sigElemNL.item(0); + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/beans/HashInputDataInfo.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/beans/HashInputDataInfo.java new file mode 100644 index 000000000..e2cb27ab3 --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/beans/HashInputDataInfo.java @@ -0,0 +1,55 @@ +/* + * Created on 02.12.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.beans; + +import java.util.Set; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class HashInputDataInfo +{ + /** + * The name of the temporary file in which this data is stored. + */ + public String filename_; + + /** + * Is this HID a SLXHTML document? + */ + public boolean isSLXHTMLDocument_; + + /** + * Is this HID a SLXHTML signed image? + */ + public boolean isSLXHTMLImage_; + + /** + * Show HID in result presentation? + */ + public boolean doShow_; + + /** + * The URI attribute value of the dsig:Reference corresponding with this HID. + */ + public String uri_; + + /** + * In case that this ID is a SLXHTML signed image, this set contains objects of type <code>Integer</code>, + * indicating the SLXHTML HIDs where this image is referenced. + */ + public Set referredHids_; + + public HashInputDataInfo(String filename) + { + filename_ = filename; + isSLXHTMLDocument_ = false; + isSLXHTMLImage_ = false; + doShow_ = true; + uri_ = null; + referredHids_ = null; + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/beans/InitPropertiesBean.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/beans/InitPropertiesBean.java new file mode 100644 index 000000000..8cb7e0a41 --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/beans/InitPropertiesBean.java @@ -0,0 +1,36 @@ +package at.gv.egovernment.moa.spss.slinterface.beans; + +import java.util.Properties; + +import org.apache.log4j.Logger; + +import at.gv.egovernment.moa.spss.slinterface.Constants; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@siemens.com) + */ +public class InitPropertiesBean +{ + private Properties initProps_; + + private static Logger logger_ = Logger.getLogger(Constants.LH_BEANS_); + + public InitPropertiesBean(Properties props) + { + initProps_ = props; + } + + public String getMOASLWebAppURL() + { + String webAppServerURLProp = initProps_.getProperty(Constants.IP_REW_MOASL_WEBAPPSERV_URL_); + logger_.debug("MOA SL Web application server URL property: " + webAppServerURLProp); + if (webAppServerURLProp == null || webAppServerURLProp.trim().length() == 0) + { + String defaultWebAppServerURL = "http://localhost:8080"; + logger_.info("MOA SL Web application server URL property not available, using default (" + defaultWebAppServerURL + ")"); + return defaultWebAppServerURL; + } + else return webAppServerURLProp; + + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/beans/SignerInfoBean.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/beans/SignerInfoBean.java new file mode 100644 index 000000000..2893b2ac3 --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/beans/SignerInfoBean.java @@ -0,0 +1,127 @@ +/* + * Created on 27.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.beans; + +import iaik.asn1.ObjectID; +import iaik.asn1.structures.Name; +import iaik.utils.RFC2253NameParser; +import iaik.utils.RFC2253NameParserException; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import at.gv.egovernment.moa.spss.slinterface.Constants; +import at.gv.egovernment.moa.spss.slinterface.DOMUtils; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class SignerInfoBean +{ + private static final String SIGNERINFO_ELEM_ = "SignerInfo"; + private static final String X509DATA_ELEM_ = "X509Data"; + private static final String X509SUBJNAME_ELEM_ = "X509SubjectName"; + private static final String X509ISSUERSERIAL_ELEM_ = "X509IssuerSerial"; + private static final String SERIAL_ELEM_ = "X509SerialNumber"; + private static final String ISSUER_ELEM_ = "X509IssuerName"; + private static final String QUALCERT_ELEM_ = "QualifiedCertificate"; + + private Element signerInfoElem_; + + private String subjectNameItemSel_; + private String issuerNameItemSel_; + + /* ---------------------------------------------------------------------------------------------------- */ + + public SignerInfoBean(Document slResponseDoc) + { + Element verifyXMLResponseElem = slResponseDoc.getDocumentElement(); + signerInfoElem_ = DOMUtils.getChildElem( + verifyXMLResponseElem, Constants.NSURI_SL_11_, SIGNERINFO_ELEM_); + + subjectNameItemSel_ = "2.5.4.3"; + issuerNameItemSel_ = "2.5.4.3"; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public void setSubjectNameItemSel(String selector) + { + subjectNameItemSel_ = selector; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public String getSubjectNameItem() + { + Element x509DataElem = DOMUtils.getChildElem(signerInfoElem_, Constants.NSURI_DSIG_, X509DATA_ELEM_); + String subjectNameStr = DOMUtils.getChildText(x509DataElem, Constants.NSURI_DSIG_, X509SUBJNAME_ELEM_); + if (subjectNameStr == null) return null; + return getRDN(subjectNameStr, subjectNameItemSel_); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public String getSerial() + { + Element x509DataElem = DOMUtils.getChildElem(signerInfoElem_, Constants.NSURI_DSIG_, X509DATA_ELEM_); + Element iSElem = DOMUtils.getChildElem(x509DataElem, Constants.NSURI_DSIG_, X509ISSUERSERIAL_ELEM_); + return DOMUtils.getChildText(iSElem, Constants.NSURI_DSIG_, SERIAL_ELEM_); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public void setIssuerNameItemSel(String selector) + { + issuerNameItemSel_ = selector; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public String getIssuerNameItem() + { + Element x509DataElem = DOMUtils.getChildElem(signerInfoElem_, Constants.NSURI_DSIG_, X509DATA_ELEM_); + Element iSElem = DOMUtils.getChildElem(x509DataElem, Constants.NSURI_DSIG_, X509ISSUERSERIAL_ELEM_); + String issuerNameStr = DOMUtils.getChildText(iSElem, Constants.NSURI_DSIG_, ISSUER_ELEM_); + if (issuerNameStr == null) return null; + return getRDN(issuerNameStr, issuerNameItemSel_); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public boolean getIsQualified() + { + Element x509DataElem = DOMUtils.getChildElem(signerInfoElem_, Constants.NSURI_DSIG_, X509DATA_ELEM_); + Element qCElem = DOMUtils.getChildElem(x509DataElem, Constants.NSURI_SL_11_, QUALCERT_ELEM_); + return (qCElem != null); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + private String getRDN(String nameStr, String oidStr) + { + try + { + RFC2253NameParser nameParser = new RFC2253NameParser(nameStr); + Name name = nameParser.parse(); + ObjectID oid = ObjectID.getObjectID(oidStr); + if (oid == null) return null; + String[] rdns = name.getRDNs(oid); + if (rdns == null) return null; + StringBuffer rdnsStr = new StringBuffer(); + for (int i = 0; i < rdns.length; i++) + { + if (i > 0) rdnsStr.append(", "); + rdnsStr.append(rdns[i]); + } + return rdnsStr.toString(); + } + catch (RFC2253NameParserException e) + { + return null; + } + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/filters/RequestWrapper.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/filters/RequestWrapper.java new file mode 100644 index 000000000..a6652a56e --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/filters/RequestWrapper.java @@ -0,0 +1,57 @@ +/* + * Created on 19.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.filters; + +import java.io.ByteArrayInputStream; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class RequestWrapper extends HttpServletRequestWrapper +{ + + private ServletInputStream inputStream_; + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * Generates a request wrapper around a particular request. + * + * @param request The request to be wrapped. + * + * @param inputStream The new inputstream, which will be returned by method {@link #getInputStream}, and + * whose length will be returned by method {@link #getContentLength}. + */ + public RequestWrapper(HttpServletRequest request, ByteArrayInputStream inputStream) + { + super(request); + inputStream_ = new ServletInputStream(inputStream); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * @see #RequestWrapper(HttpServletRequest, ByteArrayInputStream) + */ + public javax.servlet.ServletInputStream getInputStream() + { + return inputStream_; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * @see #RequestWrapper(HttpServletRequest, ByteArrayInputStream) + */ + public int getContentLength() + { + return inputStream_.getContentLength(); + } + +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/filters/ResponseWrapper.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/filters/ResponseWrapper.java new file mode 100644 index 000000000..420723abb --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/filters/ResponseWrapper.java @@ -0,0 +1,44 @@ +/* + * Created on 18.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.filters; + +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class ResponseWrapper extends HttpServletResponseWrapper +{ + private ServletOutputStream outputStream_; + + /* ---------------------------------------------------------------------------------------------------- */ + + public ResponseWrapper(HttpServletResponse response) + { + super(response); + outputStream_ = new ServletOutputStream(); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public javax.servlet.ServletOutputStream getOutputStream() + { + return outputStream_; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * Returns the wrapped response as a byte array. + * + * @return the response as a byte array. + */ + public byte[] toByteArray() + { + return outputStream_.toByteArray(); + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/filters/SL2MOAFilter.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/filters/SL2MOAFilter.java new file mode 100644 index 000000000..0ff14551f --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/filters/SL2MOAFilter.java @@ -0,0 +1,381 @@ +/* + * Created on 18.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.filters; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.CharArrayReader; +import java.io.IOException; +import java.io.Reader; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.commons.fileupload.DiskFileUpload; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileUpload; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.xerces.parsers.DOMParser; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import at.gv.egovernment.moa.spss.slinterface.Constants; +import at.gv.egovernment.moa.spss.slinterface.beans.ChecksInfoBean; +import at.gv.egovernment.moa.spss.slinterface.beans.DataInfoBean; +import at.gv.egovernment.moa.spss.slinterface.beans.SignerInfoBean; +import at.gv.egovernment.moa.spss.slinterface.moainvoker.MOAInvoker; +import at.gv.egovernment.moa.spss.slinterface.servlets.SLRequest; +import at.gv.egovernment.moa.spss.slinterface.transformers.MOA2SL; +import at.gv.egovernment.moa.spss.slinterface.transformers.SL2MOA; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class SL2MOAFilter implements Filter +{ + private static Logger logger_ = Logger.getLogger(Constants.LH_FILTERS_); + + private FilterConfig config_; + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) + */ + public void init(FilterConfig config) throws ServletException + { + // Store filter configuration + config_ = config; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, + * javax.servlet.FilterChain) + */ + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException + { + // It is necessary to set the content type header already here, because for any unknown reason setting + // it in the response JSP page has no effects at all. Perhaps any of the filters or the like already + // writes to the response output stream. + HttpServletResponse httpResponse = (HttpServletResponse) response; + httpResponse.setHeader("Content-Type", "text/html; charset='ISO-8859-1'"); + + // Create session + HttpSession session = ((HttpServletRequest) request).getSession(true); + + // Check if request is HTTP-POST + checkHttpPost((HttpServletRequest) request); + + // Remember remote IP address for later URL rewriting + session.setAttribute("remoteAddr", request.getRemoteAddr()); + + // Get SL request from content of request + SLRequest slRequest = parseRequest((HttpServletRequest) request); + session.setAttribute("slRequest", slRequest); + + // Schema validate SL request + CharArrayReader slXmlRequestCAR = new CharArrayReader(slRequest.xmlRequest_.toCharArray()); + Document slXMLRequestDoc = parseSlXmlRequest(slXmlRequestCAR); + logger_.debug("Finnished schema validating SL request."); + + // Transform SL request into a MOA SPSS request + Properties initProps = (Properties)config_.getServletContext().getAttribute(Constants.WSCP_INIT_PROPS_); + String trustProfileId = initProps.getProperty(Constants.IP_SP_TRUSTPROFILEID_); + Document moaXMLRequestDoc = SL2MOA.toMoaVerifyXMLSignatureRequest(slXMLRequestDoc, trustProfileId); + ByteArrayOutputStream moaRequestBOS = new ByteArrayOutputStream(); + MOAInvoker.serializeDocument(moaXMLRequestDoc, moaRequestBOS); + logger_.debug("SL request transformed into MOA request:\n" + moaRequestBOS); + ByteArrayInputStream moaRequestIS = new ByteArrayInputStream(moaRequestBOS.toByteArray()); + logger_.debug("Finnished transforming SL request into a MOA SP request."); + + // Invoke MOA SPSS + RequestWrapper requestWrapper = new RequestWrapper((HttpServletRequest) request, moaRequestIS); + ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) response); + chain.doFilter(requestWrapper, responseWrapper); + logger_.debug("Finnished invoking MOA SP service."); + + // Parse MOA response + DOMParser xmlParser = (DOMParser) config_.getServletContext().getAttribute(Constants.WSCP_XMLPARSER_); + ServletOutputStream moaResponseSOS = (ServletOutputStream) responseWrapper.getOutputStream(); + ByteArrayInputStream moaResponseBIS = new ByteArrayInputStream(moaResponseSOS.toByteArray()); + InputSource responseSource = new InputSource(moaResponseBIS); + Document moaResponseDoc; + try + { + xmlParser.parse(responseSource); + moaResponseDoc = xmlParser.getDocument(); + } + catch (SAXException e) + { + String message = "Parsing MOA XML response failed."; + logger_.error(message, e); + throw new ServletException(message, e); + } + logger_.debug("Finnished parsing MOA SP response."); + + // Create bean with info about signed data + try + { + DataInfoBean dataInfo = new DataInfoBean( + moaXMLRequestDoc, + moaResponseDoc, + ((HttpServletRequest) request).getContextPath(), + session, + config_.getServletContext()); + session.setAttribute("dataInfo", dataInfo); + } + catch (Exception e) + { + String message = "Creating DataInfobean failed."; + logger_.error(message, e); + throw new ServletException(message, e); + } + logger_.debug("Finnished creating bean with info about signed data."); + + // Transform MOA response into a SL response + Document slResponseDoc; + slResponseDoc = MOA2SL.toSlVerifyXMLSignatureResponse(moaResponseDoc); + session.setAttribute("slResponseDoc", slResponseDoc); + logger_.debug("Finnished transforming MOA SP response into a SL response."); + + // Create bean with info about signer + SignerInfoBean signerInfo = new SignerInfoBean(slResponseDoc); + request.setAttribute("signerInfo", signerInfo); + logger_.debug("Finnished creating bean with info about signer."); + + // Create bean with info about checks + ChecksInfoBean checksInfo = new ChecksInfoBean(slResponseDoc); + request.setAttribute("checksInfo", checksInfo); + logger_.debug("Finnished creating bean with info about checks."); + + // Include jsp page, which writes the overview information about the verified signature + try + { + RequestDispatcher dispatcher = request.getRequestDispatcher("/pages/resultOverview.jsp"); + dispatcher.include(request, response); + } + catch (IOException e) + { + String message = "Failed to create result overview page."; + logger_.error(message, e); + throw new ServletException(message, e); + } + logger_.debug("Finnished SL2MOAFilter."); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * @see javax.servlet.Filter#destroy() + */ + public void destroy() + { + // Nothing to do here at the moment. + } + + /* ---------------------------------------------------------------------------------------------------- */ + + // TODO Revisit if method can be removed + /* private void initTransformer(ServletContext context, String initPropStylesheetLoc) throws ServletException + { + String stylesheetName = + (Constants.IP_SL2MOA_STYLESHEET_.equals(initPropStylesheetLoc)) + ? "sl2Moa" + : "moa2Sl"; + + String contextAttrName = + (Constants.IP_SL2MOA_STYLESHEET_.equals(initPropStylesheetLoc)) + ? Constants.WSCP_SL2MOA_TRANSFORMER_ + : Constants.WSCP_MOA2SL_TRANSFORMER_; + + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Properties initProps = (Properties) context.getAttribute(Constants.WSCP_INIT_PROPS_); + String stylesheetLoc = initProps.getProperty(initPropStylesheetLoc); + InputStream stylesheetIS = context.getResourceAsStream(stylesheetLoc); + if (stylesheetIS == null) + { + String message = + "Cannot load " + stylesheetName + " stylesheet from location \"" + stylesheetLoc + "\"."; + logger_.error(message); + throw new ServletException(message); + } + Transformer transformer; + try + { + StreamSource stylesheetSS = new StreamSource(stylesheetIS); + transformer = transformerFactory.newTransformer(stylesheetSS); + } + catch (TransformerConfigurationException e) + { + String message = "Cannot create XSLT transformer with " + stylesheetName + " stylesheet."; + logger_.error(message, e); + throw new ServletException(message, e); + } + context.setAttribute(contextAttrName, transformer); + }*/ + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * Parses the http request. + */ + private SLRequest parseRequest(HttpServletRequest request) throws IOException + { + SLRequest slRequest = new SLRequest(); + + // Check if request URL ends with "http-security-layer-request" + // @TODO Don't know if this check is sufficient - spec says request URL must have this value as path + String requestURI = request.getRequestURI(); + if (!requestURI.endsWith(Constants.SLC_NAME_HTTP_REQUEST_)) + { + String message = "Request does not end with \"" + Constants.SLC_NAME_HTTP_REQUEST_ + "\"."; + logger_.error(message); + throw new IOException(message); + } + + if (FileUpload.isMultipartContent(request)) + { + // Request is encoded as mulitpart/form-data + List items; + try + { + DiskFileUpload upload = new DiskFileUpload(); + items = upload.parseRequest(request); + } + catch (FileUploadException e) + { + String message = "Cannot parse multipart/form-data request."; + logger_.error(message); + throw new IOException(message); + } + + Iterator itemsIt = items.iterator(); + while (itemsIt.hasNext()) + { + FileItem currItem = (FileItem) itemsIt.next(); + String currItemName = currItem.getFieldName(); + if (Constants.SLC_NAME_XML_REQUEST_.equals(currItemName)) + slRequest.xmlRequest_ = currItem.getString(); + else if (Constants.SLC_NAME_DATA_URL_.equals(currItemName)) + slRequest.dataUrl_ = currItem.getString(); + else if (Constants.SLC_NAME_STYLESHEET_URL_.equals(currItemName)) + slRequest.stylesheetUrl_ = currItem.getString(); + else if (Constants.SLC_NAME_REDIRECT_URL_.equals(currItemName)) + slRequest.redirectUrl_ = currItem.getString(); + else + continue; // @TODO Do not evaluate other params at the moment + } + } + else + { + // Request is encoded as application/x-www-form-urlencoded + Map paramsMap = request.getParameterMap(); + Iterator paramNames = paramsMap.keySet().iterator(); + while (paramNames.hasNext()) + { + String currName = (String) paramNames.next(); + String[] currValues = (String[]) paramsMap.get(currName); + if (Constants.SLC_NAME_XML_REQUEST_.equals(currName)) + slRequest.xmlRequest_ = currValues[0]; + else if (Constants.SLC_NAME_DATA_URL_.equals(currName)) + slRequest.dataUrl_ = currValues[0]; + else if (Constants.SLC_NAME_STYLESHEET_URL_.equals(currName)) + slRequest.stylesheetUrl_ = currValues[0]; + else if (Constants.SLC_NAME_REDIRECT_URL_.equals(currName)) + slRequest.redirectUrl_ = currValues[0]; + else + continue; // @TODO Do not evaluate other params at the moment + } + } + + if (slRequest.xmlRequest_ == null || slRequest.dataUrl_ == null || + slRequest.stylesheetUrl_ != null || slRequest.redirectUrl_ != null) + { + // @TODO Only combination of XMLRequest and DataURL allowed at the moment + String message = "Currently only (XMLRequest + DataURL) is supported."; + logger_.error(message); + throw new IOException(message); + } + + return slRequest; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + private Document parseSlXmlRequest(Reader slXmlRequest) throws ServletException + { + // Parse sl request + InputSource slXMLRequestIS = new InputSource(slXmlRequest); + Document slXmlRequestDoc = null; + try + { + DOMParser xmlParser = (DOMParser) config_.getServletContext().getAttribute(Constants.WSCP_XMLPARSER_); + xmlParser.parse(slXMLRequestIS); + slXmlRequestDoc = xmlParser.getDocument(); + } + catch (Exception e) + { + String message = "Parsing Security-Layer request failed."; + logger_.error(message, e); + throw new ServletException(message, e); + } + if (logger_.getEffectiveLevel().isGreaterOrEqual(Level.DEBUG)) + { + ByteArrayOutputStream debugOutputStream = new ByteArrayOutputStream(); + try + { + MOAInvoker.serializeDocument(slXmlRequestDoc, debugOutputStream); + logger_.debug("XML-Request received:\n" + debugOutputStream); + } + catch (IOException e) + { + // No debug output if this fails + } + } + + // Check if namespace is correct + String namespaceURI = slXmlRequestDoc.getDocumentElement().getNamespaceURI(); + if (!Constants.NSURI_SL_11_.equals(namespaceURI) && !Constants.NSURI_SL_12_.equals(namespaceURI)) + { + String message = "XML request has invalid namespace: \"" + namespaceURI + "\"."; + logger_.error(message); + throw new ServletException(message); + } + + return slXmlRequestDoc; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + private void checkHttpPost(HttpServletRequest request) throws ServletException + { + String method = request.getMethod(); + if (!"POST".equals(method)) + { + String message = "HTTP method \"" + method + "\" not supported. Must be \"POST\"."; + logger_.error(message); + throw new ServletException(message); + } + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/filters/ServletInputStream.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/filters/ServletInputStream.java new file mode 100644 index 000000000..b0609c2f8 --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/filters/ServletInputStream.java @@ -0,0 +1,55 @@ +/* + * Created on 19.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.filters; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class ServletInputStream extends javax.servlet.ServletInputStream +{ + private ByteArrayInputStream inputStream_; + private int length_; + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * Generates a new <code>ServletInputStram</code> from the specified stream. + * + * @param inputStream See above. + */ + public ServletInputStream(ByteArrayInputStream inputStream) + { + super(); + inputStream_ = inputStream; + length_ = inputStream_.available(); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * Reads a single byte from the underlying <code>ByteArrayInputStream</code>. + * + * @see java.io.InputStream#read() + */ + public int read() throws IOException + { + return inputStream_.read(); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * Gets the length of the content from this input stream. This equals to the number of bytes which where + * available at the time of creating this <code>ServletInputStream</code>. + */ + public int getContentLength() + { + return length_; + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/filters/ServletOutputStream.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/filters/ServletOutputStream.java new file mode 100644 index 000000000..b790ee55c --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/filters/ServletOutputStream.java @@ -0,0 +1,50 @@ +/* + * Created on 18.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.filters; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class ServletOutputStream extends javax.servlet.ServletOutputStream +{ + private ByteArrayOutputStream outputStream_; + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * Default constructor. + */ + public ServletOutputStream() + { + super(); + outputStream_ = new ByteArrayOutputStream(); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * @see java.io.OutputStream#write(int) + */ + public void write(int b) throws IOException + { + outputStream_.write(b); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * Returns the content of this stream as a byte array. + * + * @return the content of this stream as a byte array. + */ + public byte[] toByteArray() + { + return outputStream_.toByteArray(); + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/listeners/ContextListener.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/listeners/ContextListener.java new file mode 100644 index 000000000..8b8befb1c --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/listeners/ContextListener.java @@ -0,0 +1,214 @@ +/* + * Created on 18.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.listeners; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import org.apache.log4j.Logger; +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.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.xml.sax.SAXException; + +import at.gv.egovernment.moa.spss.slinterface.Constants; +import at.gv.egovernment.moa.spss.slinterface.URLRewriter; +import at.gv.egovernment.moa.spss.slinterface.beans.InitPropertiesBean; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class ContextListener implements ServletContextListener +{ + private static final String SAX_NAMESPACES_FEATURE = "http://xml.org/sax/features/namespaces"; + private static final String SAX_VALIDATION_FEATURE = "http://xml.org/sax/features/validation"; + + private static final String XERCES_SCHEMA_VALIDATION_FEATURE = + "http://apache.org/xml/features/validation/schema"; + private static final String XERCES_NORMALIZED_VALUE_FEATURE = + "http://apache.org/xml/features/validation/schema/normalized-value"; + private static final String XERCES_INCLUDE_IGNORABLE_WHITESPACE_FEATURE = + "http://apache.org/xml/features/dom/include-ignorable-whitespace"; + private static final String XERCES_CREATE_ENTITY_REF_NODES_FEATURE = + "http://apache.org/xml/features/dom/create-entity-ref-nodes"; + protected static final String XERCES_DEFER_NODE_EXPANSION_ = + "http://apache.org/xml/features/dom/defer-node-expansion"; + protected static final String XERCES_AUGMENT_PSI_ = + "http://apache.org/xml/features/validation/schema/augment-psvi"; + + private static final int BIG_PRIME = 2039; + + private static Logger logger_ = Logger.getLogger(Constants.LH_LISTENERS_); + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * Initializes the web application. + * @throws Exception + * + * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent) + */ + public void contextInitialized(ServletContextEvent event) + { + logger_.debug("Context is being initialized."); + + ServletContext context = event.getServletContext(); + + String initPropsLoc = System.getProperty(Constants.SP_INIT_PROPS_LOC_); + if (initPropsLoc == null) + { + logger_.fatal("System property \"" + Constants.SP_INIT_PROPS_LOC_ + "\" not set."); + logger_.fatal("Web application initialization failed."); + return; + } + + // Load init properties + try + { + logger_.debug("Init properties location \"" + initPropsLoc + "\" will be used."); + + // Try to interpret init properties location as relative to the web application root + InputStream initPropsIS = context.getResourceAsStream(initPropsLoc); + + if (initPropsIS == null) + { + // If this does not work, try to interpret init properties location as an absolute file system path + initPropsIS = new FileInputStream(initPropsLoc); + } + + Properties initProps = new Properties(); + initProps.load(initPropsIS); + context.setAttribute(Constants.WSCP_INIT_PROPS_, initProps); + + // Prepare application bean knowing about init properties + InitPropertiesBean initPropsBean = new InitPropertiesBean(initProps); + context.setAttribute(Constants.WSCP_INITPROPS_BEAN_, initPropsBean); + } + catch (IOException e) + { + logger_.fatal("Cannot load initialization properties from location \"" + initPropsLoc + "\".", e); + logger_.fatal("Web application initialization failed."); + return; + } + + // Put helper object for rewriting URLs in the result page into the context + URLRewriter urlRewriter = new URLRewriter((Properties)context.getAttribute(Constants.WSCP_INIT_PROPS_)); + context.setAttribute(Constants.WSCP_URL_REWRITER_, urlRewriter); + + // Initialize XML parser + SymbolTable symbolTable = new SymbolTable(BIG_PRIME); + XMLGrammarPool grammarPool = new XMLGrammarPoolImpl(); + + XMLGrammarPreparser preparser = new XMLGrammarPreparser(symbolTable); + preparser.registerPreparser(XMLGrammarDescription.XML_SCHEMA, null); + preparser.setProperty(org.apache.xerces.impl.Constants.XERCES_PROPERTY_PREFIX + + org.apache.xerces.impl.Constants.XMLGRAMMAR_POOL_PROPERTY, grammarPool); + preparser.setFeature(SAX_NAMESPACES_FEATURE, true); + preparser.setFeature(SAX_VALIDATION_FEATURE, true); + + // Schema for Security-Layer 1.2 alpha (including LocRefContent) + Properties initProps = (Properties) context.getAttribute(Constants.WSCP_INIT_PROPS_); + String slSchemaLoc = initProps.getProperty(Constants.IP_SL_SCHEMA_); + if (!preparseSchema(context, preparser, slSchemaLoc)) + { + logger_.fatal("Web application initialization failed."); + return; + } + + // Schema for MOA 1.2 + String moaSchemaLoc = initProps.getProperty(Constants.IP_MOA_SCHEMA_); + if (!preparseSchema(context, preparser, moaSchemaLoc)) + { + logger_.fatal("Web application initialization failed."); + return; + } + + // Schema for SLXHTML 1.0 + String slxhtmlSchemaLoc = initProps.getProperty(Constants.IP_SLXHTML_SCHEMA_); + if (!preparseSchema(context, preparser, slxhtmlSchemaLoc)) + { + logger_.fatal("Web application initialization failed."); + return; + } + + + // TODO parser is not threadsafe + DOMParser xmlParser = new DOMParser(symbolTable, grammarPool); + try + { + xmlParser.setFeature(SAX_NAMESPACES_FEATURE, true); + xmlParser.setFeature(SAX_VALIDATION_FEATURE, true); + xmlParser.setFeature(XERCES_SCHEMA_VALIDATION_FEATURE, true); + xmlParser.setFeature(XERCES_NORMALIZED_VALUE_FEATURE, false); + xmlParser.setFeature(XERCES_INCLUDE_IGNORABLE_WHITESPACE_FEATURE, true); + xmlParser.setFeature(XERCES_CREATE_ENTITY_REF_NODES_FEATURE, false); + xmlParser.setFeature(XERCES_DEFER_NODE_EXPANSION_, true); + xmlParser.setFeature(XERCES_AUGMENT_PSI_, false); + xmlParser.setErrorHandler(new XMLParserErrorHandler(false, true, true)); + } + catch (SAXException e) + { + String message = "Initialization of XML parser failed."; + logger_.fatal(message, e); + logger_.fatal("Web application initialization failed."); + return; + } + context.setAttribute(Constants.WSCP_XMLPARSER_, xmlParser); + + String message = "Web application initialization succeeded."; + logger_.info(message); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * Does some clean up at finalization of the web application. + * + * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent) + */ + public void contextDestroyed(ServletContextEvent event) + { + // Remove init properties from web service context + Properties initProps = (Properties) event.getServletContext().getAttribute(Constants.WSCP_INIT_PROPS_); + if (initProps != null) event.getServletContext().removeAttribute(Constants.WSCP_INIT_PROPS_); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + private boolean preparseSchema(ServletContext context, XMLGrammarPreparser preparser, String schemaLoc) + { + InputStream schemaIS = context.getResourceAsStream(schemaLoc); + if (schemaIS == null) + { + String message = "Cannot load schema from location \"" + schemaLoc + "\"."; + logger_.fatal(message); + return false; + } + try + { + String schemaSystemId = context.getResource(schemaLoc).toExternalForm(); + preparser.preparseGrammar(XMLGrammarDescription.XML_SCHEMA, + new XMLInputSource(null, schemaSystemId, null, schemaIS, null)); + } + catch (Exception e) + { + String message = "Parsing schema loaded from location \"" + schemaLoc + "\" failed."; + logger_.fatal(message, e); + return false; + } + return true; + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/listeners/XMLParserErrorHandler.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/listeners/XMLParserErrorHandler.java new file mode 100644 index 000000000..496d0aadb --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/listeners/XMLParserErrorHandler.java @@ -0,0 +1,65 @@ +/* + * Created on 02.12.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.listeners; + +import org.apache.log4j.Logger; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import at.gv.egovernment.moa.spss.slinterface.Constants; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class XMLParserErrorHandler implements ErrorHandler +{ + private static Logger logger_ = Logger.getLogger(Constants.LH_LISTENERS_XMLPARSER_); + + private boolean reportWarning_, reportError_, reportFatal_; + + /* ---------------------------------------------------------------------------------------------------- */ + + public XMLParserErrorHandler(boolean reportWarning, boolean reportError, boolean reportFatal) + { + reportWarning_ = reportWarning; + reportError_ = reportError; + reportFatal_ = reportFatal; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException) + */ + public void warning(SAXParseException exception) throws SAXException + { + logger_.warn("XML parser reported a warning.", exception); + if (reportWarning_) throw exception; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException) + */ + public void error(SAXParseException exception) throws SAXException + { + logger_.error("XML parser reported an error.", exception); + if (reportError_) throw exception; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + /** + * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException) + */ + public void fatalError(SAXParseException exception) throws SAXException + { + logger_.error("XML parser reported a fatal error.", exception); + if (reportFatal_) throw exception; + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/moainvoker/MOAInvoker.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/moainvoker/MOAInvoker.java new file mode 100644 index 000000000..e89d255f0 --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/moainvoker/MOAInvoker.java @@ -0,0 +1,92 @@ +/* + * Created on 19.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.moainvoker; + +import java.io.IOException; +import java.io.OutputStream; +import java.rmi.RemoteException; +import java.util.Vector; + +import javax.xml.namespace.QName; +import javax.xml.rpc.Call; +import javax.xml.rpc.Service; +import javax.xml.rpc.ServiceException; +import javax.xml.rpc.ServiceFactory; + +import org.apache.axis.message.SOAPBodyElement; +import org.apache.xml.serialize.OutputFormat; +import org.apache.xml.serialize.XMLSerializer; +import org.w3c.dom.Document; + +import at.gv.egovernment.moa.spss.slinterface.Constants; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class MOAInvoker +{ + /** + * Invokes MOA SP. + * + * @param request The XML request to be sent to MOA SP. + * + * @param endpoint The endpoint of the SOAP service where to send the XML request to. + * + * @return the XML response from the service. + * + * @throws Exception if getting the XML response from the SOAP response body fails. + * + * @throws RemoteException if MOA SP signals an error. + * + * @throws ServiceException if the SOAP client invoking MOA SP signals an error. + */ + public static Document invokeSP(Document request, String endpoint) + throws Exception, RemoteException, ServiceException + { + QName serviceQName = new QName(Constants.MI_SP_QNAME_); + return invoke(request, endpoint, serviceQName); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + private static Document invoke(Document request, String endpoint, QName serviceQName) throws Exception + { + // Instantiate AXIS service + Service service = ServiceFactory.newInstance().createService(serviceQName); + + // Create and configure service call + Call call = service.createCall(); + call.setTargetEndpointAddress(endpoint); + + // Create SOAP body + SOAPBodyElement body = new SOAPBodyElement(request.getDocumentElement()); + SOAPBodyElement[] params = new SOAPBodyElement[] {body}; + + // Make call + Vector responses = (Vector) call.invoke(params); + + // Get response + SOAPBodyElement responseBody = (SOAPBodyElement) responses.get(0); + Document response = responseBody.getAsDocument(); + return response; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public static void serializeDocument(Document doc, OutputStream out) throws IOException + { + OutputFormat format = new OutputFormat(doc); + + format.setLineSeparator("\n"); + format.setIndenting(false); + format.setPreserveSpace(true); + format.setOmitXMLDeclaration(false); + format.setEncoding("UTF-8"); + + XMLSerializer serializer = new XMLSerializer(out, format); + serializer.serialize(doc); + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/servlets/HashInputDataServlet.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/servlets/HashInputDataServlet.java new file mode 100644 index 000000000..f7cfb7e6c --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/servlets/HashInputDataServlet.java @@ -0,0 +1,93 @@ +/* + * Created on 01.12.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.servlets; + +import java.io.FileInputStream; +import java.io.OutputStream; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.log4j.Logger; + +import at.gv.egovernment.moa.spss.slinterface.Constants; +import at.gv.egovernment.moa.spss.slinterface.Utils; +import at.gv.egovernment.moa.spss.slinterface.beans.DataInfoBean; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class HashInputDataServlet extends HttpServlet +{ + private static Logger logger_ = Logger.getLogger(Constants.LH_SERVLETS_); + + /** + * Default constructor. + */ + public HashInputDataServlet() + { + super(); + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException + { + // Get DataInfoBean object from session + HttpSession session = request.getSession(false); + if (session == null) + { + String message = "No session available."; + logger_.error(message); + throw new ServletException(message); + } + DataInfoBean dataInfo = (DataInfoBean) session.getAttribute("dataInfo"); + + // Get parameter inicating which hash input data file to show + String hidCountStr = request.getParameter("hidCount"); + if (hidCountStr == null) + { + String message = "Parameter \"hidCount\" not available in request."; + logger_.error(message); + throw new ServletException(message); + } + int hidCount = -1; + try + { + hidCount = Integer.parseInt(hidCountStr); + } + catch (NumberFormatException e) + { + String message = "Parameter \"hidCount\" (\"" + hidCount + "\") is not a valid string representation of an integer."; + logger_.error(message, e); + throw new ServletException(message, e); + } + + // Get file name of temporary HID file + dataInfo.setHashInputDataCount(hidCount); + String hidFilename = dataInfo.getHashInputDataFilename(); + + // Set content type + boolean isSLXHTML = dataInfo.getIsSLXHTMLDocument(); + String contenType = (isSLXHTML) ? "text/html" : "application/octet-stream"; + response.setContentType(contenType); + + // Write content from temporary HID file to response OS + try + { + FileInputStream hidFIS = new FileInputStream(hidFilename); + OutputStream responseOS = response.getOutputStream(); + Utils.transferStreams(hidFIS, responseOS); + } + catch (Exception e) + { + String message = "Writing hash input data to response stream failed."; + logger_.error(message, e); + throw new ServletException(message, e); + } + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/servlets/MOAServlet.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/servlets/MOAServlet.java new file mode 100644 index 000000000..362793064 --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/servlets/MOAServlet.java @@ -0,0 +1,113 @@ +/* + * Created on 19.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.servlets; + +import java.io.IOException; +import java.rmi.RemoteException; +import java.util.Properties; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.rpc.ServiceException; + +import org.apache.log4j.Logger; +import org.apache.xerces.parsers.DOMParser; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import at.gv.egovernment.moa.spss.slinterface.Constants; +import at.gv.egovernment.moa.spss.slinterface.moainvoker.MOAInvoker; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class MOAServlet extends HttpServlet +{ + private static Logger logger_ = Logger.getLogger(Constants.LH_SERVLETS_); + + /** + * Default constructor. + */ + public MOAServlet() + { + super(); + } + + public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException + { + // Get moa request form http request + Document moaXmlRequest = null; + DOMParser xmlParser = (DOMParser) this.getServletContext().getAttribute(Constants.WSCP_XMLPARSER_); + try + { + InputSource requestIS = new InputSource(request.getInputStream()); + xmlParser.parse(requestIS); + moaXmlRequest = xmlParser.getDocument(); + } + catch (IOException ioe) + { + String message = "Getting MOA XML request from http request input failed."; + logger_.error(message, ioe); + throw new ServletException(message, ioe); + } + catch (SAXException se) + { + String message = "Parsing MOA XML request got from http request failed."; + logger_.error(message, se); + throw new ServletException(message, se); + } + + // Send request to MOA SP + Properties initProps = (Properties) this.getServletContext().getAttribute(Constants.WSCP_INIT_PROPS_); + String endPoint = initProps.getProperty(Constants.IP_SP_ENDPOINT_); + if (endPoint == null) + { + String message = "No endpoint configured for MOA SP service."; + logger_.error(message); + throw new ServletException(message); + } + Document moaXMLResponseDoc = null; + try + { + moaXMLResponseDoc = MOAInvoker.invokeSP(moaXmlRequest, endPoint); + } + catch (Exception e) + { + String message; + if (e instanceof RemoteException) + { + message = "MOA SP service indicated an error at request execution."; + } + else if (e instanceof ServiceException) + { + message = "MOA SP client indicated an error at request execution."; + } + else + { + message = "Could not create DOM Document from MOA SP service response."; + } + logger_.error(message, e); + throw new ServletException(message, e); + } + logger_.debug("Got response from MOA SP service."); + + // Write moa response to http response + try + { + MOAInvoker.serializeDocument(moaXMLResponseDoc, response.getOutputStream()); + } + catch (IOException e) + { + String message = "Writing MOA SP XML response to http response failed."; + logger_.error(message, e); + throw new ServletException(message, e); + } + logger_.debug("Wrote response from MOA SP service to http response outputstream."); + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/servlets/ReturnServlet.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/servlets/ReturnServlet.java new file mode 100644 index 000000000..84ce26be0 --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/servlets/ReturnServlet.java @@ -0,0 +1,129 @@ +/* + * Created on 25.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.servlets; + +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.net.URLConnection; + +import javax.servlet.ServletException; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; + +import at.gv.egovernment.moa.spss.slinterface.Constants; +import at.gv.egovernment.moa.spss.slinterface.Utils; +import at.gv.egovernment.moa.spss.slinterface.moainvoker.MOAInvoker; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class ReturnServlet extends HttpServlet +{ + + private static Logger logger_ = Logger.getLogger(Constants.LH_SERVLETS_); + + /** + * Default constructor. + */ + public ReturnServlet() + { + super(); + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException + { + // Get session + HttpSession session = request.getSession(false); + if (session == null) + { + String message = "No session available."; + logger_.error(message); + throw new ServletException(message); + } + + // Get original SL request from session + SLRequest slRequest = (SLRequest) session.getAttribute("slRequest"); + if (slRequest == null) + { + String message = "Session object \"slRequest\" not available."; + logger_.error(message); + throw new ServletException(message); + } + + // Get SL response from session + Document slResponseDoc = (Document) session.getAttribute("slResponseDoc"); + if (slResponseDoc == null) + { + String message = "Session object \"slResponseDoc\" not available."; + logger_.error(message); + throw new ServletException(message); + } + + URLConnection dataURLConn; + try + { + // TODO Does not conform to SL/Bindings/sec. 3.3.2.2 + + // Open connection to DataURL + URL dataURL = new URL(slRequest.dataUrl_); + dataURLConn = dataURL.openConnection(); + dataURLConn.setDoOutput(true); + OutputStream dataURLOS = dataURLConn.getOutputStream(); + MOAInvoker.serializeDocument(slResponseDoc, dataURLOS); + dataURLOS.flush(); + } + catch (Exception e) + { + String message = "Sending SL XML response to DataURL failed."; + logger_.error(message, e); + throw new ServletException(message, e); + } + + // Forward response from DataURL to client + forwardResponse(dataURLConn, response); + + session.invalidate(); + } + + /* ---------------------------------------------------------------------------------------------------- */ + + private void forwardResponse(URLConnection dataURLConn, ServletResponse response) throws ServletException + { + // TODO Does not conform to SL/Bindings/sec. 3.3.2.1 + + // Make sure that content type of DataURL response is text/html + String dataURLContentType = dataURLConn.getContentType(); + if (dataURLContentType == null || !dataURLContentType.startsWith("text/html")) + { + String message = "Unsupported content type of DataURL response: \"" + dataURLContentType + "\"."; + logger_.error(message); + throw new ServletException(message); + } + + try + { + InputStream dataURLIS = dataURLConn.getInputStream(); + byte[] dataURLResponse = Utils.readFromInputStream(dataURLIS); + response.setContentType("text/html"); + OutputStream responseOS = response.getOutputStream(); + responseOS.write(dataURLResponse); + responseOS.flush(); + } + catch (Exception e) + { + String message = "Forwarding DataURL response to client failed."; + logger_.error(message, e); + throw new ServletException(message, e); + } + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/servlets/SLRequest.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/servlets/SLRequest.java new file mode 100644 index 000000000..3c19d5ff6 --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/servlets/SLRequest.java @@ -0,0 +1,19 @@ +/* + * Created on 25.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.servlets; + +/** + * Helper class, representing the fields of a Security-Layer request. + * + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class SLRequest +{ + public String xmlRequest_; + public String dataUrl_; + public String stylesheetUrl_; + public String redirectUrl_; +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/transformers/MOA2SL.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/transformers/MOA2SL.java new file mode 100644 index 000000000..2e82d4d32 --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/transformers/MOA2SL.java @@ -0,0 +1,93 @@ +/* + * Created on 20.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.transformers; + +import java.util.ArrayList; +import java.util.HashMap; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import at.gv.egovernment.moa.spss.slinterface.Constants; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class MOA2SL +{ + /** + * Transforms an MOA VerifyXMLSignatureResponse into a SL VerifyXMLSignatureResponse. + * + * @param moaVerifyXMLSignatureResponse The MOA VerifyXMLSignatureResponse to be transformed. + * + * @return the specified response document, transformed into a SL VerifyXMLSignatureResponse. Please note + * that <code>moaVerifyXMLSignatureResponse</code> is modified into the sl response. + * + * @pre moaVerifyXMLSignatureResponse is a valid instance of the SL Schema (version 1.2 or 1.1). + */ + public static Document toSlVerifyXMLSignatureResponse(Document moaVerifyXMLSignatureResponse) + { + // Namespace to namespace prefix mapping + HashMap prefixMap = new HashMap(4); + prefixMap.put(Constants.NSURI_SL_10_, Constants.NSPRE_SL_10_); + prefixMap.put(Constants.NSURI_SL_11_, Constants.NSPRE_SL_11_); + prefixMap.put(Constants.NSURI_SL_12_, Constants.NSPRE_SL_12_); + prefixMap.put(Constants.NSURI_MOA_12_, Constants.NSPRE_MOA_12_); + + // Namespaces to be changed + HashMap nsTransforms = new HashMap(); + nsTransforms.put(Constants.NSURI_MOA_12_, Constants.NSURI_SL_11_); + + // Names to be changed + HashMap nameTransforms = new HashMap(); + nameTransforms.put( + new QName(Constants.NSURI_MOA_12_, "PublicAuthority"), + new QName(Constants.NSURI_MOA_12_,"PublicAuthority")); + + Element verifyResponseElem = moaVerifyXMLSignatureResponse.getDocumentElement(); + verifyResponseElem.setAttributeNS(Constants.NSURI_NAMESPACES_, + "xmlns:" + Constants.NSPRE_SL_10_, Constants.NSURI_SL_10_); + verifyResponseElem.setAttributeNS(Constants.NSURI_NAMESPACES_, + "xmlns:" + Constants.NSPRE_SL_11_, Constants.NSURI_SL_11_); + + // Convert SL request into MOA request + verifyResponseElem = + Utils.transformDeep(verifyResponseElem, prefixMap, nsTransforms, nameTransforms); + + // Add SignatureManifestCheck element (Code = 98) + Element signatureMFCheckElem = moaVerifyXMLSignatureResponse.createElementNS( + Constants.NSURI_SL_11_, Constants.NSPRE_SL_11_ + ":SignatureManifestCheck"); + Element smfCodeElem = moaVerifyXMLSignatureResponse.createElementNS( + Constants.NSURI_SL_11_, Constants.NSPRE_SL_11_ + ":Code"); + signatureMFCheckElem.appendChild(smfCodeElem); + smfCodeElem.appendChild(moaVerifyXMLSignatureResponse.createTextNode("98")); + Element signatureCheckElem = (Element) verifyResponseElem.getElementsByTagNameNS( + Constants.NSURI_SL_11_, "SignatureCheck").item(0); + verifyResponseElem.insertBefore(signatureMFCheckElem, signatureCheckElem.getNextSibling()); + + // Siblings of Certificate check must be in sl10 namespace + nsTransforms.clear(); + nsTransforms.put(Constants.NSURI_SL_11_, Constants.NSURI_SL_10_); + nameTransforms.clear(); + Element certCheckElem = (Element) verifyResponseElem.getElementsByTagNameNS( + Constants.NSURI_SL_11_, "CertificateCheck").item(0); + NodeList certCheckChildren = certCheckElem.getChildNodes(); + ArrayList certCheckChildElemsList = new ArrayList(certCheckChildren.getLength()); + for (int i = 0; i < certCheckChildren.getLength(); i++) + { + Node currentNode = certCheckChildren.item(i); + if (currentNode.getNodeType() == Node.ELEMENT_NODE) + certCheckChildElemsList.add(certCheckChildren.item(i)); + } + for (int i = 0; i < certCheckChildElemsList.size(); i++) + Utils.transformDeep((Element) certCheckChildElemsList.get(i), prefixMap, nsTransforms, + nameTransforms); + + return moaVerifyXMLSignatureResponse; + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/transformers/QName.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/transformers/QName.java new file mode 100644 index 000000000..6da0c433f --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/transformers/QName.java @@ -0,0 +1,51 @@ +/* + * Created on 20.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.transformers; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class QName +{ + public String nsUrl_; + public String localName_; + + /* ---------------------------------------------------------------------------------------------------- */ + + public QName(String nsUrl, String localName) + { + nsUrl_ = nsUrl; + localName_ = localName; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public boolean equals(Object o) + { + if (o == null) return false; + if (o instanceof QName) + { + QName toBeCompared = (QName) o; + + boolean nsURLEquals = (nsUrl_ == null) + ? toBeCompared.nsUrl_ == null + : nsUrl_.equals(toBeCompared.nsUrl_); + boolean localNameEquals = (localName_ == null) + ? toBeCompared.localName_ == null + : localName_.equals(toBeCompared.localName_); + + return nsURLEquals && localNameEquals; + } + return false; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + public int hashCode() + { + return new String(nsUrl_ + localName_).hashCode(); + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/transformers/SL2MOA.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/transformers/SL2MOA.java new file mode 100644 index 000000000..6c476e9ce --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/transformers/SL2MOA.java @@ -0,0 +1,93 @@ +/* + * Created on 20.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.transformers; + +import java.util.HashMap; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import at.gv.egovernment.moa.spss.slinterface.Constants; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class SL2MOA +{ + /** + * Transforms an SL VerifyXMLSignatureRequest into a MOA VerifyXMLSignatureRequest. + * + * @param slVerifyXMLSignatureRequest The SL VerifyXMLSignatureRequest to be transformed. + * + * @return the specified request document, transformed into a MOA VerifyXMLSignatureRequest. Please note + * that <code>slVerifyXMLSignatureRequest</code> is modified into the moa request. + * + * @pre slVerifyXMLSignatureRequest is a valid instance of the SL Schema (version 1.2 or 1.1). + */ + public static Document toMoaVerifyXMLSignatureRequest(Document slVerifyXMLSignatureRequest, + String trustProfileID) + { + // Namespace to namespace prefix mapping + HashMap prefixMap = new HashMap(4); + prefixMap.put(Constants.NSURI_SL_10_, Constants.NSPRE_SL_10_); + prefixMap.put(Constants.NSURI_SL_11_, Constants.NSPRE_SL_11_); + prefixMap.put(Constants.NSURI_SL_12_, Constants.NSPRE_SL_12_); + prefixMap.put(Constants.NSURI_MOA_12_, Constants.NSPRE_MOA_12_); + + // Namespaces to be changed + HashMap nsTransforms = new HashMap(); + nsTransforms.put(Constants.NSURI_SL_10_, Constants.NSURI_MOA_12_); + nsTransforms.put(Constants.NSURI_SL_11_, Constants.NSURI_MOA_12_); + nsTransforms.put(Constants.NSURI_SL_12_, Constants.NSURI_MOA_12_); + + // Names to be changed + HashMap nameTransforms = new HashMap(); + nameTransforms.put( + new QName(Constants.NSURI_SL_11_, "SignatureInfo"), + new QName(Constants.NSURI_MOA_12_,"VerifySignatureInfo")); + nameTransforms.put( + new QName(Constants.NSURI_SL_12_, "SignatureInfo"), + new QName(Constants.NSURI_MOA_12_,"VerifySignatureInfo")); + nameTransforms.put( + new QName(Constants.NSURI_SL_11_, "SignatureEnvironment"), + new QName(Constants.NSURI_MOA_12_,"VerifySignatureEnvironment")); + nameTransforms.put( + new QName(Constants.NSURI_SL_12_, "SignatureEnvironment"), + new QName(Constants.NSURI_MOA_12_,"VerifySignatureEnvironment")); + nameTransforms.put( + new QName(Constants.NSURI_SL_11_, "SignatureLocation"), + new QName(Constants.NSURI_MOA_12_,"VerifySignatureLocation")); + nameTransforms.put( + new QName(Constants.NSURI_SL_12_, "SignatureLocation"), + new QName(Constants.NSURI_MOA_12_,"VerifySignatureLocation")); + nameTransforms.put( + new QName(Constants.NSURI_SL_11_, "Supplement"), + new QName(Constants.NSURI_MOA_12_,"SupplementProfile")); + nameTransforms.put( + new QName(Constants.NSURI_SL_12_, "Supplement"), + new QName(Constants.NSURI_MOA_12_,"SupplementProfile")); + + Element verifyRequestElem = slVerifyXMLSignatureRequest.getDocumentElement(); + verifyRequestElem.setAttributeNS(Constants.NSURI_NAMESPACES_, + "xmlns:" + Constants.NSPRE_MOA_12_, Constants.NSURI_MOA_12_); + + // Convert SL request into MOA request + verifyRequestElem = Utils.transformDeep(verifyRequestElem, prefixMap, nsTransforms, nameTransforms); + + // Add ReturnHashInputData element + Element returnHashInputDataElem = slVerifyXMLSignatureRequest.createElementNS( + Constants.NSURI_MOA_12_, Constants.NSPRE_MOA_12_ + ":ReturnHashInputData"); + verifyRequestElem.appendChild(returnHashInputDataElem); + + // Add trust profile ID element + Element trustProfileIDElem = slVerifyXMLSignatureRequest.createElementNS( + Constants.NSURI_MOA_12_, Constants.NSPRE_MOA_12_ + ":TrustProfileID"); + trustProfileIDElem.appendChild(slVerifyXMLSignatureRequest.createTextNode(trustProfileID)); + verifyRequestElem.appendChild(trustProfileIDElem); + + return slVerifyXMLSignatureRequest; + } +} diff --git a/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/transformers/Utils.java b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/transformers/Utils.java new file mode 100644 index 000000000..d03895efe --- /dev/null +++ b/spss.slinterface/src/at/gv/egovernment/moa/spss/slinterface/transformers/Utils.java @@ -0,0 +1,129 @@ +/* + * Created on 20.11.2003 + * + * (c) Stabsstelle IKT-Strategie des Bundes + */ +package at.gv.egovernment.moa.spss.slinterface.transformers; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.apache.xerces.dom.DocumentImpl; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.traversal.DocumentTraversal; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; + +import at.gv.egovernment.moa.spss.slinterface.Constants; + +/** + * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) + */ +public class Utils +{ + /** + * + * @param elem + * @param prefixes + * @param namespaces + * @param names + * + * @pre <code>elem</code> is backed by a <code>org.apache.xerces.dom.DocumentImpl</code>. + */ + public static Element transformDeep(Element elem, Map prefixes, Map namespaces, Map names) + { + // Get node iterator for element + DocumentTraversal docTraversal = (DocumentImpl) elem.getOwnerDocument(); + NodeIterator elemsIt = docTraversal.createNodeIterator(elem, NodeFilter.SHOW_ELEMENT, null, true); + + // Make iterator immutable + List elemsList = new LinkedList(); + while (true) + { + Node currNode = elemsIt.nextNode(); + if (currNode == null) break; + elemsList.add(currNode); + } + + Iterator elemsImmIt = elemsList.iterator(); + Element returnValue = null; + while (elemsImmIt.hasNext()) + { + Element currElem = (Element) elemsImmIt.next(); + + String nsUri = currElem.getNamespaceURI(); + String localName = currElem.getLocalName(); + QName qName = new QName(nsUri, localName); + + // Check if element is in "names" + QName newQName = (QName)names.get(qName); + if (newQName != null) + { + Element transformedElem = transformElem(currElem, newQName, prefixes); + if (returnValue == null) returnValue = transformedElem; + } + else + { + String newNamespace = (String)namespaces.get(nsUri); + if (newNamespace != null) + { + newQName = new QName(newNamespace, localName); + Element transformedElem = transformElem(currElem, newQName, prefixes); + if (returnValue == null) returnValue = transformedElem; + } + } + } + return returnValue; + } + + /* ---------------------------------------------------------------------------------------------------- */ + + private static Element transformElem(Element currElem, QName newQName, Map prefixes) + { + Element newElem = currElem.getOwnerDocument().createElementNS(newQName.nsUrl_, + (String) prefixes.get(newQName.nsUrl_) + ":" + newQName.localName_); + + currElem.getParentNode().replaceChild(newElem, currElem); + + // Treat attributes of currElem + NamedNodeMap currAttrs = currElem.getAttributes(); + ArrayList currAttrsList = new ArrayList(currAttrs.getLength()); + for (int i = 0; i < currAttrs.getLength(); i++) currAttrsList.add(currAttrs.item(i)); + for (int i = 0; i < currAttrsList.size(); i++) + { + Attr currAttr = (Attr)currAttrsList.get(i); + currAttr.getOwnerElement().removeAttributeNode(currAttr); + + // Workaround for bad Xerces behaviour: default attributes in the xml namespace are created without + // the xml prefix + if (Constants.NSURI_XML_.equals(currAttr.getNamespaceURI()) && "space".equals(currAttr.getLocalName())) + { + newElem.setAttributeNS(Constants.NSURI_XML_, "xml:space", currAttr.getValue()); + } + else + { + newElem.setAttributeNode(currAttr); + } + } + + // Treat child nodes of currElem + NodeList currChildren = currElem.getChildNodes(); + ArrayList currChildrenList = new ArrayList(currChildren.getLength()); + for (int i = 0; i < currChildren.getLength(); i++) currChildrenList.add(currChildren.item(i)); + for (int i = 0; i < currChildrenList.size(); i++) + { + Node currChild = (Node)currChildrenList.get(i); + currElem.removeChild(currChild); + newElem.appendChild(currChild); + } + + return newElem; + } +} |