/* * 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); } } }