Java tutorial
/* * Zed Attack Proxy (ZAP) and its related class files. * * ZAP is an HTTP/HTTPS proxy for assessing web application security. * * Copyright 2012 The ZAP Development Team * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.zaproxy.zap.model; import java.awt.EventQueue; import java.util.ArrayList; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import java.util.regex.Pattern; import org.apache.commons.httpclient.URI; import org.apache.log4j.Logger; import org.parosproxy.paros.core.scanner.Alert; import org.parosproxy.paros.model.HistoryReference; import org.parosproxy.paros.model.Session; import org.parosproxy.paros.model.SiteNode; import org.parosproxy.paros.network.HttpMessage; import org.zaproxy.zap.authentication.AuthenticationMethod; import org.zaproxy.zap.authentication.ManualAuthenticationMethodType.ManualAuthenticationMethod; import org.zaproxy.zap.extension.authorization.AuthorizationDetectionMethod; import org.zaproxy.zap.extension.authorization.BasicAuthorizationDetectionMethod; import org.zaproxy.zap.extension.authorization.BasicAuthorizationDetectionMethod.LogicalOperator; import org.zaproxy.zap.session.CookieBasedSessionManagementMethodType.CookieBasedSessionManagementMethod; import org.zaproxy.zap.session.SessionManagementMethod; public class Context { public static final String CONTEXT_CONFIG = "context"; public static final String CONTEXT_CONFIG_NAME = CONTEXT_CONFIG + ".name"; public static final String CONTEXT_CONFIG_DESC = CONTEXT_CONFIG + ".desc"; public static final String CONTEXT_CONFIG_INSCOPE = CONTEXT_CONFIG + ".inscope"; public static final String CONTEXT_CONFIG_INC_REGEXES = CONTEXT_CONFIG + ".incregexes"; public static final String CONTEXT_CONFIG_EXC_REGEXES = CONTEXT_CONFIG + ".excregexes"; public static final String CONTEXT_CONFIG_TECH = CONTEXT_CONFIG + ".tech"; public static final String CONTEXT_CONFIG_TECH_INCLUDE = CONTEXT_CONFIG_TECH + ".include"; public static final String CONTEXT_CONFIG_TECH_EXCLUDE = CONTEXT_CONFIG_TECH + ".exclude"; public static final String CONTEXT_CONFIG_URLPARSER = CONTEXT_CONFIG + ".urlparser"; public static final String CONTEXT_CONFIG_URLPARSER_CLASS = CONTEXT_CONFIG_URLPARSER + ".class"; public static final String CONTEXT_CONFIG_URLPARSER_CONFIG = CONTEXT_CONFIG_URLPARSER + ".config"; public static final String CONTEXT_CONFIG_POSTPARSER = CONTEXT_CONFIG + ".postparser"; public static final String CONTEXT_CONFIG_POSTPARSER_CLASS = CONTEXT_CONFIG_POSTPARSER + ".class"; public static final String CONTEXT_CONFIG_POSTPARSER_CONFIG = CONTEXT_CONFIG_POSTPARSER + ".config"; private static Logger log = Logger.getLogger(Context.class); private Session session; private int index; private String name; private String description = ""; private List<String> includeInRegexs = new ArrayList<>(); private List<String> excludeFromRegexs = new ArrayList<>(); private List<Pattern> includeInPatterns = new ArrayList<>(); private List<Pattern> excludeFromPatterns = new ArrayList<>(); /** The authentication method. */ private AuthenticationMethod authenticationMethod = null; /** The session management method. */ private SessionManagementMethod sessionManagementMethod; /** The authorization detection method used for this context. */ private AuthorizationDetectionMethod authorizationDetectionMethod; private TechSet techSet = new TechSet(Tech.builtInTech); private boolean inScope = true; private ParameterParser urlParamParser = new StandardParameterParser(); private ParameterParser postParamParser = new StandardParameterParser(); public Context(Session session, int index) { this.session = session; this.index = index; this.name = String.valueOf(index); this.sessionManagementMethod = new CookieBasedSessionManagementMethod(index); this.authenticationMethod = new ManualAuthenticationMethod(index); this.authorizationDetectionMethod = new BasicAuthorizationDetectionMethod(null, null, null, LogicalOperator.AND); } public boolean isIncludedInScope(SiteNode sn) { if (!this.inScope) { return false; } return this.isIncluded(sn); } public boolean isIncluded(SiteNode sn) { if (sn == null) { return false; } return isIncluded(sn.getHierarchicNodeName()); } /* * Not needed right now, but may be needed in the future? public boolean * isExplicitlyIncluded(SiteNode sn) { if (sn == null) { return false; } return * isExplicitlyIncluded(sn.getHierarchicNodeName()); } * * public boolean isExplicitlyIncluded(String url) { if (url == null) { return false; } try { * return this.includeInPatterns.contains(this.getPatternUrl(url, false)) || * this.includeInPatterns.contains(this.getPatternUrl(url, false)); } catch (Exception e) { * return false; } } */ public boolean isIncluded(String url) { if (url == null) { return false; } if (url.indexOf("?") > 0) { // Strip off any parameters url = url.substring(0, url.indexOf("?")); } for (Pattern p : this.includeInPatterns) { if (p.matcher(url).matches()) { return true; } } return false; } public boolean isExcludedFromScope(SiteNode sn) { if (!this.inScope) { return false; } return this.isExcluded(sn); } public boolean isExcluded(SiteNode sn) { if (sn == null) { return false; } return isExcluded(sn.getHierarchicNodeName()); } public boolean isExcluded(String url) { if (url == null) { return false; } if (url.indexOf("?") > 0) { // Strip off any parameters url = url.substring(0, url.indexOf("?")); } for (Pattern p : this.excludeFromPatterns) { if (p.matcher(url).matches()) { return true; } } return false; } public boolean isInContext(HistoryReference href) { if (href == null) { return false; } if (href.getSiteNode() != null) { return this.isInContext(href.getSiteNode()); } try { return this.isInContext(href.getURI().toString()); } catch (Exception e) { log.error(e.getMessage(), e); } return false; } public boolean isInContext(SiteNode sn) { if (sn == null) { return false; } return isInContext(sn.getHierarchicNodeName()); } public boolean isInContext(String url) { if (url.indexOf("?") > 0) { // String off any parameters url = url.substring(0, url.indexOf("?")); } if (!this.isIncluded(url)) { // Not explicitly included return false; } // Check to see if its explicitly excluded return !this.isExcluded(url); } /** * Gets the nodes from the site tree which are "In Scope". Searches recursively starting from * the root node. Should be used with care, as it is time-consuming, querying the database for * every node in the Site Tree. * * @return the nodes in scope from site tree */ public List<SiteNode> getNodesInContextFromSiteTree() { List<SiteNode> nodes = new LinkedList<>(); SiteNode rootNode = (SiteNode) session.getSiteTree().getRoot(); fillNodesInContext(rootNode, nodes); return nodes; } /** * Gets the nodes from the site tree which are "In Scope". Searches recursively starting from * the root node. Should be used with care, as it is time-consuming, querying the database for * every node in the Site Tree. * * @return the nodes in scope from site tree */ public List<SiteNode> getTopNodesInContextFromSiteTree() { List<SiteNode> nodes = new LinkedList<>(); SiteNode rootNode = (SiteNode) session.getSiteTree().getRoot(); @SuppressWarnings("unchecked") Enumeration<SiteNode> en = rootNode.children(); while (en.hasMoreElements()) { SiteNode sn = en.nextElement(); if (isContainsNodesInContext(sn)) { nodes.add(sn); } } return nodes; } /** * Fills a given list with nodes in scope, searching recursively. * * @param rootNode the root node * @param nodesList the nodes list */ private void fillNodesInContext(SiteNode rootNode, List<SiteNode> nodesList) { @SuppressWarnings("unchecked") Enumeration<SiteNode> en = rootNode.children(); while (en.hasMoreElements()) { SiteNode sn = en.nextElement(); if (isInContext(sn)) { nodesList.add(sn); } fillNodesInContext(sn, nodesList); } } /** * Fills a given list with nodes in scope, searching recursively. * * @param rootNode the root node * @param nodesList the nodes list */ private boolean isContainsNodesInContext(SiteNode node) { if (isInContext(node)) { return true; } @SuppressWarnings("unchecked") Enumeration<SiteNode> en = node.children(); while (en.hasMoreElements()) { SiteNode sn = en.nextElement(); if (isContainsNodesInContext(sn)) { return true; } } return false; } public List<String> getIncludeInContextRegexs() { return includeInRegexs; } private void checkRegexs(List<String> regexs) throws Exception { for (String url : regexs) { url = url.trim(); if (url.length() > 0) { Pattern.compile(url, Pattern.CASE_INSENSITIVE); } } } public void setIncludeInContextRegexs(List<String> includeRegexs) throws Exception { // Check they are all valid regexes first checkRegexs(includeRegexs); // Check if theyve been changed if (includeInRegexs.size() == includeRegexs.size()) { boolean changed = false; for (int i = 0; i < includeInRegexs.size(); i++) { if (!includeInRegexs.get(i).equals(includeRegexs.get(i))) { changed = true; break; } } if (!changed) { // No point reapplying the same regexs return; } } includeInRegexs.clear(); includeInPatterns.clear(); for (String url : includeRegexs) { url = url.trim(); if (url.length() > 0) { Pattern p = Pattern.compile(url, Pattern.CASE_INSENSITIVE); includeInRegexs.add(url); includeInPatterns.add(p); } } } private String getPatternFromNode(SiteNode sn, boolean recurse) throws Exception { return this.getPatternUrl(new URI(sn.getHierarchicNodeName(), false).toString(), recurse); } private String getPatternUrl(String url, boolean recurse) throws Exception { if (url.indexOf("?") > 0) { // Strip off any parameters url = url.substring(0, url.indexOf("?")); } if (recurse) { url = Pattern.quote(url) + ".*"; } else { url = Pattern.quote(url); } return url; } public void excludeFromContext(SiteNode sn, boolean recurse) throws Exception { addExcludeFromContextRegex(this.getPatternFromNode(sn, recurse)); } public void addIncludeInContextRegex(String includeRegex) { Pattern p = Pattern.compile(includeRegex, Pattern.CASE_INSENSITIVE); includeInPatterns.add(p); includeInRegexs.add(includeRegex); } public List<String> getExcludeFromContextRegexs() { return excludeFromRegexs; } public void setExcludeFromContextRegexs(List<String> excludeRegexs) throws Exception { // Check they are all valid regexes first checkRegexs(excludeRegexs); // Check if theyve been changed if (excludeFromRegexs.size() == excludeRegexs.size()) { boolean changed = false; for (int i = 0; i < excludeFromRegexs.size(); i++) { if (!excludeFromRegexs.get(i).equals(excludeRegexs.get(i))) { changed = true; break; } } if (!changed) { // No point reapplying the same regexs return; } } excludeFromRegexs.clear(); excludeFromPatterns.clear(); for (String url : excludeRegexs) { url = url.trim(); if (url.length() > 0) { Pattern p = Pattern.compile(url, Pattern.CASE_INSENSITIVE); excludeFromPatterns.add(p); excludeFromRegexs.add(url); } } } public void addExcludeFromContextRegex(String excludeRegex) { Pattern p = Pattern.compile(excludeRegex, Pattern.CASE_INSENSITIVE); excludeFromPatterns.add(p); excludeFromRegexs.add(excludeRegex); } public void save() { this.session.saveContext(this); } public TechSet getTechSet() { return techSet; } public void setTechSet(TechSet techSet) { this.techSet = techSet; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public int getIndex() { return this.index; } public boolean isInScope() { return inScope; } public void setInScope(boolean inScope) { this.inScope = inScope; } /** * Gets the authentication method corresponding to this context. * * @return the authentication method */ public AuthenticationMethod getAuthenticationMethod() { return authenticationMethod; } /** * Sets the authentication method corresponding to this context. * * @param authenticationMethod the new authentication method */ public void setAuthenticationMethod(AuthenticationMethod authenticationMethod) { this.authenticationMethod = authenticationMethod; } /** * Gets the session management method corresponding to this context. * * @return the session management method */ public SessionManagementMethod getSessionManagementMethod() { return sessionManagementMethod; } /** * Sets the session management method corresponding to this context. * * @param sessionManagementMethod the new session management method */ public void setSessionManagementMethod(SessionManagementMethod sessionManagementMethod) { this.sessionManagementMethod = sessionManagementMethod; } /** * Gets the authorization detection method corresponding to this context. * * @return the authorization detection method */ public AuthorizationDetectionMethod getAuthorizationDetectionMethod() { return authorizationDetectionMethod; } /** * Sets the authorization detection method corresponding to this context. * * @param authorizationDetectionMethod the new authorization detectionmethod */ public void setAuthorizationDetectionMethod(AuthorizationDetectionMethod authorizationDetectionMethod) { this.authorizationDetectionMethod = authorizationDetectionMethod; } public ParameterParser getUrlParamParser() { return urlParamParser; } public void setUrlParamParser(ParameterParser paramParser) { this.urlParamParser = paramParser; restructureSiteTree(); } public ParameterParser getPostParamParser() { return postParamParser; } public void setPostParamParser(ParameterParser postParamParser) { this.postParamParser = postParamParser; } public void restructureSiteTree() { if (EventQueue.isDispatchThread()) { restructureSiteTreeEventHandler(); } else { try { EventQueue.invokeLater(new Runnable() { @Override public void run() { restructureSiteTreeEventHandler(); } }); } catch (Exception e) { log.error(e.getMessage(), e); } } } private void restructureSiteTreeEventHandler() { log.debug("Restructure site tree for context: " + this.getName()); HttpMessage msg; SiteNode sn2; for (SiteNode sn : this.getNodesInContextFromSiteTree()) { log.debug("Restructure site tree, node: " + sn.getNodeName()); try { msg = sn.getHistoryReference().getHttpMessage(); if (msg != null) { sn2 = session.getSiteTree().findNode(msg, sn.getChildCount() > 0); if (sn2 == null) { sn2 = session.getSiteTree().addPath(sn.getHistoryReference(), msg); } if (!sn2.equals(sn)) { // TODO: Might be better in a 'merge'? Do we need to copy other things, list custom icons? for (Alert alert : sn.getAlerts()) { sn2.addAlert(alert); } for (Alert alert : sn.getAlerts()) { sn.deleteAlert(alert); } session.getSiteTree().removeNodeFromParent(sn); } } } catch (Exception e) { log.error(e.getMessage(), e); } } } /** * Creates a copy of the Context. The copy is deep, with the exception of the TechSet. * * @return the context */ public Context duplicate() { Context newContext = new Context(session, getIndex()); newContext.description = this.description; newContext.name = this.name; newContext.includeInRegexs = new ArrayList<>(this.includeInRegexs); newContext.includeInPatterns = new ArrayList<>(this.includeInPatterns); newContext.excludeFromRegexs = new ArrayList<>(this.excludeFromRegexs); newContext.excludeFromPatterns = new ArrayList<>(this.excludeFromPatterns); newContext.inScope = this.inScope; newContext.techSet = new TechSet(this.techSet); newContext.authenticationMethod = this.authenticationMethod.clone(); newContext.sessionManagementMethod = this.sessionManagementMethod.clone(); newContext.urlParamParser = this.urlParamParser.clone(); newContext.postParamParser = this.postParamParser.clone(); newContext.authorizationDetectionMethod = this.authorizationDetectionMethod.clone(); return newContext; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + index; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Context other = (Context) obj; if (index != other.index) return false; return true; } }