All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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 exceptionList = new ArrayList();

		for(int i=0;i