/* * 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.InputStream; 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.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; 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.moainvoker.MOAInvoker; 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_; private SLRequest slRequest_; /* ---------------------------------------------------------------------------------------------------- */ /** * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) */ public void init(FilterConfig config) throws ServletException { // Store filter configuration config_ = config; slRequest_ = new SLRequest(); // Initialize stylesheet transform SL2MOA // ServletContext context = config_.getServletContext(); // Transformer sl2MoaTransformer = (Transformer) context.getAttribute(Constants.WSCP_SL2MOA_TRANSFORMER_); // if (sl2MoaTransformer == null) // { // initTransformer(context, Constants.IP_SL2MOA_STYLESHEET_); // } // Initialize stylesheet transform MOA2SL // Transformer moa2SlTransformer = (Transformer) context.getAttribute(Constants.WSCP_MOA2SL_TRANSFORMER_); // if (moa2SlTransformer == null) // { // initTransformer(context, Constants.IP_MOA2SL_STYLESHEET_); // } } /* ---------------------------------------------------------------------------------------------------- */ /* * @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 { // Check if request is HTTP-POST checkHttpPost((HttpServletRequest) request); // Get SL request from content of request parseRequest((HttpServletRequest) request); // Schema validate SL request CharArrayReader slXmlRequestCAR = new CharArrayReader(slRequest_.xmlRequest_.toCharArray()); Document slXMLRequestDoc = parseSlXmlRequest(slXmlRequestCAR); // Transform SL request into a MOA SPSS request // Transformer sl2MoaTransformer = // (Transformer) config_.getServletContext().getAttribute(Constants.WSCP_SL2MOA_TRANSFORMER_); // DOMSource slXMLRequestDS = new DOMSource(slXMLRequestDoc); // ByteArrayOutputStream moaRequestBOS = new ByteArrayOutputStream(); // StreamResult moaRequestResult = new StreamResult(moaRequestBOS); // try // { // sl2MoaTransformer.transform(slXMLRequestDS, moaRequestResult); // } // catch (TransformerException e) // { // String message = "Transforming SL XML request into MOA XML request failed."; // logger_.error(message, e); // throw new ServletException(message, e); // } // logger_.debug("MOA XML Request:\n" + moaRequestBOS.toString()); // ByteArrayInputStream moaRequestIS = new ByteArrayInputStream(moaRequestBOS.toByteArray()); 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()); // Invoke MOA SPSS RequestWrapper requestWrapper = new RequestWrapper((HttpServletRequest) request, moaRequestIS); ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) response); chain.doFilter(requestWrapper, responseWrapper); // Prepare response to client response.setContentType("text/xml"); // Transform MOA response into a SL response and send SL response back to client // Transformer moa2SlTransformer = // (Transformer) config_.getServletContext().getAttribute(Constants.WSCP_MOA2SL_TRANSFORMER_); // ServletOutputStream moaResponseSOS = (ServletOutputStream) responseWrapper.getOutputStream(); // ByteArrayInputStream moaResponseBIS = new ByteArrayInputStream(moaResponseSOS.toByteArray()); // StreamSource moaResponseSource = new StreamSource(moaResponseBIS); // StreamResult slResponseResult = new StreamResult(response.getOutputStream()); // try // { // moa2SlTransformer.transform(moaResponseSource, slResponseResult); // } // catch (TransformerException e) // { // String message = "Transforming MOA XML response into SL XML response failed."; // logger_.error(message, e); // throw new ServletException(message, e); // } 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); try { xmlParser.parse(responseSource); Document moaResponseDoc = xmlParser.getDocument(); Document slResponseDoc = MOA2SL.toSlVerifyXMLSignatureResponse(moaResponseDoc); MOAInvoker.serializeDocument(slResponseDoc, response.getOutputStream()); } catch (SAXException e) { String message = "Transforming MOA XML response into SL XML response failed."; logger_.error(message, e); throw new ServletException(message, e); } } /* ---------------------------------------------------------------------------------------------------- */ /** * @see javax.servlet.Filter#destroy() */ public void destroy() { // Nothing to do here at the moment. } /* ---------------------------------------------------------------------------------------------------- */ 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 void parseRequest(HttpServletRequest request) throws IOException { // 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 combindation of XMLRequest and StylesheetURL allowed at the moment String message = "Currently only (XMLRequest + DataURL) is supported."; logger_.error(message); throw new IOException(message); } } /* ---------------------------------------------------------------------------------------------------- */ 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); } } /* ---------------------------------------------------------------------------------------------------- */ /** * Helper class, representing the fields of a Security-Layer request. * * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) */ class SLRequest { public String xmlRequest_; public String dataUrl_; public String stylesheetUrl_; public String redirectUrl_; } }