org.owasp.esapi.waf.configuration.ConfigurationParser Maven / Gradle / Ivy
/**
* OWASP Enterprise Security API (ESAPI)
*
* This file is part of the Open Web Application Security Project (OWASP)
* Enterprise Security API (ESAPI) project. For details, please see
* http://www.owasp.org/index.php/ESAPI.
*
* Copyright (c) 2009 - The OWASP Foundation
*
* The ESAPI is published by OWASP under the BSD license. You should read and accept the
* LICENSE before you use, modify, and/or redistribute this software.
*
* @author Arshan Dabirsiaghi Aspect Security
* @created 2009
*/
package org.owasp.esapi.waf.configuration;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.Elements;
import nu.xom.ParsingException;
import nu.xom.ValidityException;
import org.apache.log4j.Level;
import org.owasp.esapi.ESAPI;
import org.owasp.esapi.waf.ConfigurationException;
import org.owasp.esapi.waf.rules.AddHTTPOnlyFlagRule;
import org.owasp.esapi.waf.rules.AddHeaderRule;
import org.owasp.esapi.waf.rules.AddSecureFlagRule;
import org.owasp.esapi.waf.rules.AuthenticatedRule;
import org.owasp.esapi.waf.rules.BeanShellRule;
import org.owasp.esapi.waf.rules.DetectOutboundContentRule;
import org.owasp.esapi.waf.rules.EnforceHTTPSRule;
import org.owasp.esapi.waf.rules.HTTPMethodRule;
import org.owasp.esapi.waf.rules.IPRule;
import org.owasp.esapi.waf.rules.MustMatchRule;
import org.owasp.esapi.waf.rules.PathExtensionRule;
import org.owasp.esapi.waf.rules.ReplaceContentRule;
import org.owasp.esapi.waf.rules.RestrictContentTypeRule;
import org.owasp.esapi.waf.rules.RestrictUserAgentRule;
import org.owasp.esapi.waf.rules.SimpleVirtualPatchRule;
import bsh.EvalError;
/**
*
* The class used to turn a policy file's contents into an object model.
*
* @author Arshan Dabirsiaghi
* @see org.owasp.esapi.waf.configuration.AppGuardianConfiguration
*/
public class ConfigurationParser {
private static final String REGEX = "regex";
private static final String DEFAULT_PATH_APPLY_ALL = ".*";
private static final int DEFAULT_RESPONSE_CODE = 403;
private static final String DEFAULT_SESSION_COOKIE;
static {
String sessionIdName = null;
try {
sessionIdName = ESAPI.securityConfiguration().getHttpSessionIdName();
} catch (Throwable t) {
sessionIdName = "JSESSIONID"; // If all else fails...
}
DEFAULT_SESSION_COOKIE = sessionIdName;
}
private static final String[] STAGES = {
"before-request-body",
"after-request-body",
"before-response"
};
public static AppGuardianConfiguration readConfigurationFile(InputStream stream, String webRootDir) throws ConfigurationException {
AppGuardianConfiguration config = new AppGuardianConfiguration();
Builder parser = new Builder();
Document doc;
Element root;
try {
doc = parser.build(stream);
root = doc.getRootElement();
Element settingsRoot = root.getFirstChildElement("settings");
Element authNRoot = root.getFirstChildElement("authentication-rules");
Element authZRoot = root.getFirstChildElement("authorization-rules");
Element urlRoot = root.getFirstChildElement("url-rules");
Element headerRoot = root.getFirstChildElement("header-rules");
Element customRulesRoot = root.getFirstChildElement("custom-rules");;
Element virtualPatchesRoot = root.getFirstChildElement("virtual-patches");
Element outboundRoot = root.getFirstChildElement("outbound-rules");
Element beanShellRoot = root.getFirstChildElement("bean-shell-rules");
/**
* Parse the 'settings' section.
*/
if ( settingsRoot == null ) {
throw new ConfigurationException("", "The section is required");
} else if ( settingsRoot != null ) {
try {
String sessionCookieName = settingsRoot.getFirstChildElement("session-cookie-name").getValue();
if ( ! "".equals(sessionCookieName) ) {
config.setSessionCookieName(sessionCookieName);
}
} catch (NullPointerException npe) {
config.setSessionCookieName(DEFAULT_SESSION_COOKIE);
}
String mode = settingsRoot.getFirstChildElement("mode").getValue();
if ( "block".equals(mode.toLowerCase() ) ) {
AppGuardianConfiguration.DEFAULT_FAIL_ACTION = AppGuardianConfiguration.BLOCK;
} else if ( "redirect".equals(mode.toLowerCase() ) ){
AppGuardianConfiguration.DEFAULT_FAIL_ACTION = AppGuardianConfiguration.REDIRECT;
} else {
AppGuardianConfiguration.DEFAULT_FAIL_ACTION = AppGuardianConfiguration.LOG;
}
Element errorHandlingRoot = settingsRoot.getFirstChildElement("error-handling");
config.setDefaultErrorPage( errorHandlingRoot.getFirstChildElement("default-redirect-page").getValue() );
try {
config.setDefaultResponseCode( Integer.parseInt(errorHandlingRoot.getFirstChildElement("block-status").getValue()) );
} catch (Exception e) {
config.setDefaultResponseCode( DEFAULT_RESPONSE_CODE );
}
}
/*
* The WAF separate logging is going to be merged in the 2.0
* release, so this is deprecated.
*/
Element loggingRoot = settingsRoot.getFirstChildElement("logging");
if ( loggingRoot != null ) {
config.setLogDirectory(loggingRoot.getFirstChildElement("log-directory").getValue());
config.setLogLevel(Level.toLevel(loggingRoot.getFirstChildElement("log-level").getValue()));
}
/**
* Parse the 'authentication-rules' section if they have one.
*/
if ( authNRoot != null ) {
String key = authNRoot.getAttributeValue("key");
String path = authNRoot.getAttributeValue("path");
String id = authNRoot.getAttributeValue("id");
if ( path != null && key != null ) {
config.addBeforeBodyRule(new AuthenticatedRule(id,key,Pattern.compile(path),getExceptionsFromElement(authNRoot)));
} else if ( key != null ) {
config.addBeforeBodyRule(new AuthenticatedRule(id,key,null,getExceptionsFromElement(authNRoot)));
} else {
throw new ConfigurationException("","The rule requires a 'key' attribute");
}
}
/**
* Parse 'authorization-rules' section if they have one.
*/
if ( authZRoot != null ) {
Elements restrictNodes = authZRoot.getChildElements("restrict-source-ip");
for(int i=0;i exceptions = getExceptionsFromElement(e);
config.addBeforeBodyRule( new EnforceHTTPSRule(id, Pattern.compile(path), exceptions, action) );
}
}
if ( headerRoot != null ) {
Elements restrictContentTypes = headerRoot.getChildElements("restrict-content-type");
Elements restrictUserAgents = headerRoot.getChildElements("restrict-user-agent");
for(int i=0;i rules. This could be used to add:
* - X-I-DONT-WANT-TO-BE-FRAMED
* - Caching prevention headers
* - Custom application headers
*/
Elements addHeaderNodes = outboundRoot.getChildElements("add-header");
for(int i=0;i rules that allow
* us to add the HTTPOnly flag to cookies, both
* custom and app server.
*/
Elements addHTTPOnlyFlagNodes = outboundRoot.getChildElements("add-http-only-flag");
for(int i=0;i patterns = new ArrayList();
for(int j=0;j rules that allow
* us to add the secure flag to cookies, both
* custom and app server.
*/
Elements addSecureFlagNodes = outboundRoot.getChildElements("add-secure-flag");
for(int i=0;i patterns = new ArrayList();
for(int j=0;j rules must contain a 'pattern' attribute");
} else if ( contentType == null ) {
throw new ConfigurationException("", " rules must contain a 'content-type' attribute");
}
DetectOutboundContentRule docr = new DetectOutboundContentRule(
id,
Pattern.compile(contentType),
Pattern.compile(token,Pattern.DOTALL),
path != null ? Pattern.compile(path) : null);
config.addBeforeResponseRule(docr);
}
}
/**
* Parse the 'bean-shell-rules' section.
*/
if ( beanShellRoot != null ) {
Elements beanShellRules = beanShellRoot.getChildElements("bean-shell-script");
for (int i=0;i getExceptionsFromElement(Element root) {
Elements exceptions = root.getChildElements("path-exception");
ArrayList