/******************************************************************************* * Copyright (c) 2011 Subgraph. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Subgraph - initial API and implementation ******************************************************************************/ package com.subgraph.vega.ui.scanner.info; import java.io.IOException; import java.io.StringWriter; import java.net.URL; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpRequest; import org.apache.http.NameValuePair; import org.apache.http.RequestLine; import org.apache.http.client.utils.URLEncodedUtils; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.osgi.framework.Bundle; import org.w3c.dom.Document; import com.subgraph.vega.api.events.IEvent; import com.subgraph.vega.api.events.IEventHandler; import com.subgraph.vega.api.model.IWorkspace; import com.subgraph.vega.api.model.WorkspaceCloseEvent; import com.subgraph.vega.api.model.WorkspaceOpenEvent; import com.subgraph.vega.api.model.WorkspaceResetEvent; import com.subgraph.vega.api.model.alerts.IScanAlert; import com.subgraph.vega.api.model.requests.IRequestLog; import com.subgraph.vega.api.model.requests.IRequestLogRecord; import com.subgraph.vega.api.xml.IXmlRepository; import com.subgraph.vega.ui.scanner.Activator; import freemarker.cache.TemplateLoader; import freemarker.ext.dom.NodeModel; import freemarker.log.Logger; import freemarker.template.Configuration; import freemarker.template.DefaultObjectWrapper; import freemarker.template.Template; import freemarker.template.TemplateException; public class AlertRenderer { private final Logger logger = Logger.getLogger("alert-render"); private Configuration configuration; private final String imageURL; private final String bulletPointURL; private final String bannerPatternURL; private final String bannerLogoURL; private final String titlePatternURL; private final String redArrowURL; private final String sectionGradientURL; private final String linkArrowURL; private final Map<String, Document> alertDocumentCache = new HashMap<String, Document>(); private IRequestLog requestLog; AlertRenderer(TemplateLoader templateLoader) { imageURL = findImage("icons/vega_logo.png"); bulletPointURL = findImage("icons/doubleArrow.png"); bannerPatternURL = findImage("icons/bannerPattern.png"); bannerLogoURL = findImage("icons/bannerLogo.png"); titlePatternURL = findImage("icons/titlePattern.png"); redArrowURL = findImage("icons/redArrow.png"); sectionGradientURL = findImage("icons/sectionGradient.png"); linkArrowURL = findImage("icons/linkArrow.png"); configuration = new Configuration(); configuration.setTemplateLoader(templateLoader); configuration.setObjectWrapper(new DefaultObjectWrapper()); final IWorkspace currentWorkspace = Activator.getDefault().getModel().addWorkspaceListener(new IEventHandler() { @Override public void handleEvent(IEvent event) { if(event instanceof WorkspaceOpenEvent) handleWorkspaceOpen((WorkspaceOpenEvent) event); else if(event instanceof WorkspaceCloseEvent) handleWorkspaceClose((WorkspaceCloseEvent) event); else if(event instanceof WorkspaceResetEvent) handleWorkspaceReset((WorkspaceResetEvent) event); } }); if(currentWorkspace != null) requestLog = currentWorkspace.getRequestLog(); } private void handleWorkspaceOpen(WorkspaceOpenEvent event) { requestLog = event.getWorkspace().getRequestLog(); } private void handleWorkspaceClose(WorkspaceCloseEvent event) { requestLog = null; } private void handleWorkspaceReset(WorkspaceResetEvent event) { requestLog = event.getWorkspace().getRequestLog(); } public String render(IScanAlert alert) { final int maxAlertString = Activator.getDefault().getPreferenceStore().getInt("MaxAlertString"); Map<String, Object> root = new HashMap<String, Object>(); try { Template t = configuration.getTemplate("main.ftl"); Document xmlRoot = getAlertDocument(alert.getName()); if(xmlRoot == null) return ""; NodeModel nodeModel = NodeModel.wrap(xmlRoot); root.put("doc", nodeModel); Map<String,Object> vars = new HashMap<String,Object>(); for(String k: alert.propertyKeys()) { Object value = alert.getProperty(k); if(value instanceof String) { String s = (String) value; if(s.length() > maxAlertString) { s = s.substring(0, maxAlertString) + "..."; } vars.put(k, s); } else { vars.put(k, alert.getProperty(k)); } } String severityVar = severityToString(alert.getSeverity()); if(severityVar != null) { vars.put("severity", severityVar); } String severityCSSVar = severityToSeverityCSSClass(alert.getSeverity()); if(severityCSSVar != null) { vars.put("severityCSS", severityCSSVar); } if(imageURL != null) vars.put("imageURL", imageURL); if(bulletPointURL != null) vars.put("bulletPointURL", bulletPointURL); if(bannerPatternURL != null) vars.put("bannerPatternURL", bannerPatternURL); if(bannerLogoURL != null) vars.put("bannerLogoURL", bannerLogoURL); if(titlePatternURL != null) vars.put("titlePatternURL", titlePatternURL); if(redArrowURL != null) vars.put("redArrowURL", redArrowURL); if(redArrowURL != null) vars.put("sectionGradientURL", sectionGradientURL); if(linkArrowURL != null) vars.put("linkArrowURL", linkArrowURL); if(alert.getRequestId() >= 0 && requestLog != null) { final IRequestLogRecord record = requestLog.lookupRecord(alert.getRequestId()); if(record != null) { if(record.getRequest() instanceof HttpEntityEnclosingRequest) { vars.put("requestText", renderEntityEnclosingRequest((HttpEntityEnclosingRequest) record.getRequest())); } else { vars.put("requestText", renderBasicRequest(record.getRequest())); } vars.put("requestId", Long.toString(alert.getRequestId())); } } root.put("vars", vars); StringWriter out = new StringWriter(); t.process(root, out); out.flush(); return out.toString(); } catch (IOException e) { return "I/O error reading alert template file alerts/"+ alert.getName() + ".xml :<br><br>"+ e.getMessage(); } catch (TemplateException e) { return "Error processing alert template file alerts/"+ alert.getName() +".xml :<br><br>"+ e.getMessage(); } } private String renderEntityEnclosingRequest(HttpEntityEnclosingRequest request) { final HttpEntity entity = request.getEntity(); if(entity == null || !URLEncodedUtils.isEncoded(entity)) { return renderBasicRequest(request); } try { List<NameValuePair> args = URLEncodedUtils.parse(entity); StringBuilder sb = new StringBuilder(); sb.append(renderBasicRequest(request)); sb.append("\n["); for(NameValuePair nvp: args) { sb.append(nvp.getName()); if(nvp.getValue() != null) { sb.append("="); sb.append(nvp.getValue()); } sb.append("\n"); } sb.append("]"); return sb.toString(); } catch (IOException e) { return renderBasicRequest(request); } } private String renderBasicRequest(HttpRequest request) { final RequestLine line = request.getRequestLine(); return line.getMethod() +" "+ line.getUri(); } private Document getAlertDocument(String name) { if(alertDocumentCache.containsKey(name)) return alertDocumentCache.get(name); final IXmlRepository xmlRepository = Activator.getDefault().getXmlRepository(); if(xmlRepository == null) { logger.warn("Could not render alert because xml repository service is not available"); return null; } Document alertDocument = xmlRepository.getDocument("alerts/"+ name + ".xml"); if(alertDocument == null) alertDocument = xmlRepository.getDocument("alerts/default.xml"); if(alertDocument == null) { logger.warn("Could not load XML data for alert named '"+ name + "'"); return null; } alertDocumentCache.put(name, alertDocument); return alertDocument; } private String findImage(String imagePath) { Bundle b = Activator.getDefault().getBundle(); IPath relativePagePath = new Path(imagePath); URL fileInPlugin = FileLocator.find(b, relativePagePath, null); try { URL pageUrl = FileLocator.toFileURL(fileInPlugin); return pageUrl.toString(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } private String severityToString(IScanAlert.Severity s) { switch(s) { case HIGH: return "High"; case MEDIUM: return "Medium"; case LOW: return "Low"; case INFO: return "Info"; case UNKNOWN: return "Unknown"; } return null; } private String severityToSeverityCSSClass(IScanAlert.Severity s) { switch(s) { case HIGH: return "highrisk"; case MEDIUM: return "medrisk"; case LOW: return "lowrisk"; case INFO: return "inforisk"; case UNKNOWN: return "unknownrisk"; } return null; } }