From 664daa097cca512a80d5ad1931191b5beda4ef2e Mon Sep 17 00:00:00 2001 From: JordanGS Date: Mon, 10 Jul 2017 17:50:44 -0400 Subject: [PATCH 1/4] Updated README.md -updated the README document to reflect 1.1.0 release. --- README.md | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 31b3930..422d8fe 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,8 @@ You can also: * Jenkins version * ZAP version * ZAP Jenkins Plugin version - * Firefox version + * Firefox version (if running AJAX Spider or a Selenium build) + * Selenium (if applicable) * Upload copies of the zap.log files and a copy of the console output of the jenkins log to [pastebin](https://pastebin.mozilla.org/). * Jenkins is always running on a master, is ZAP running on the master as well or on a separate slave machine? * Relevant Jenkins Job Configurations sanitized screenshots. @@ -45,6 +46,10 @@ You can also: ### Issue Tracking * Issues can be created on the Jenkins JIRA for the component [zap-plugin](https://issues.jenkins-ci.org/issues/?jql=project%20%3D%20JENKINS%20AND%20component%20%3D%20zap-plugin). + * [All](https://issues.jenkins-ci.org/issues/?jql=project%20%3D%20JENKINS%20AND%20component%20%3D%20zap-plugin) Issues + * Want to see what we need help with? See [Open, Reopened and Verified](https://issues.jenkins-ci.org/browse/JENKINS-43384?jql=project%20%3D%20JENKINS%20AND%20status%20in%20%28Open%2C%20Reopened%2C%20Verified%29%20AND%20component%20%3D%20zap-plugin) Issues + * Want to see what contributors are currently working on? See [In Progress and In Review](https://issues.jenkins-ci.org/browse/JENKINS-43483?jql=project%20%3D%20JENKINS%20AND%20status%20in%20%28%22In%20Progress%22%2C%20%22In%20Review%22%29%20AND%20component%20%3D%20zap-plugin) Issues + * Want to see what we've done so far? See [Closed and Resolved](https://issues.jenkins-ci.org/browse/JENKINS-41069?jql=project%20%3D%20JENKINS%20AND%20status%20in%20%28Resolved%2C%20Closed%29%20AND%20component%20%3D%20zap-plugin) Issues * Before creating an Issue please read the [JIRA guidelines](https://wiki.jenkins-ci.org/display/JENKINS/How+to+report+an+issue). * Notice: GitHub Issues have been disabled. @@ -56,11 +61,34 @@ You can also: ### Version History
-
Latest Release - Version 1.0.8 (Mar 19, 2017)
-
warning Changed the default authentication script directory for the plugin to match the directory for ZAP (GUI) and updated resource files accordingly. See updated documentation for Script-Based Auth.
+
Latest Release - Version 1.1.0 (July 10, 2017)
+
add [ JENKINS-39985 ] Added support for context Alert Filters.
+
add [ JENKINS-43554 ] Added support for the internationalization of: +
    +
  1. UI Elements
  2. +
  3. Associated Help Doc's
  4. +
+
+
warning [ JENKINS-43483 ] Added support to the authentication module to be able to utilize Logged Out Indicators.
+
remove [ JENKINS-43384 ] Removed support from the ZAP Settings Variable for System Environment Variables, Build Variables as well as Environment Inject Plugin Variables since the Job Configuration page is ONLY run on the master and has no access to the slave.
+
bugfix Bug-fixes: +
    +
  1. Fixed Broken links in Help Files
  2. +
  3. Fixed misused variables (evaluatedSessionFilename instead of evaluatedZapSettingsDir) of ZAPDriver.java
  4. +
  5. Correct improper use of JIRA Extension parameters.
  6. +
+
+
info Usability Improvements: +
    +
  • Updated all affected help files
  • +
  • Created the webapp folder
  • +
  • Established clearer distinction between the ZAP Installation Directory and ZAP Home Directory
  • +
+
+
info Updated LICENSE and README information.
-See [Full Version History](https://wiki.jenkins-ci.org/display/JENKINS/zap-plugin+History) +See [Full Version History](https://wiki.jenkins.io/display/JENKINS/Version+History) ### License From 73d5c4e9c727e77a3cfd6cefe5eaefe8e3291dc6 Mon Sep 17 00:00:00 2001 From: JordanGS Date: Mon, 10 Jul 2017 22:09:39 -0400 Subject: [PATCH 2/4] Add commit message later --- .../java/org/jenkinsci/plugins/zap/ZAP.java | 318 ++++++++++ .../org/jenkinsci/plugins/zap/ZAPBuilder.java | 11 + .../org/jenkinsci/plugins/zap/ZAPDriver.java | 25 +- .../plugins/zap/ZAPInterfaceAction.java | 121 ++++ .../jenkinsci/plugins/zap/ZAPManagement.java | 574 ++++++++++++++++++ .../plugins/zap/ZAPManagementBuilder.java | 210 +++++++ .../jenkinsci/plugins/zap/Messages.properties | 3 +- .../plugins/zap/ZAPManagement/config.jelly | 68 +++ .../zap/ZAPManagementBuilder/config.jelly | 30 + .../help-buildThresholds.html | 6 + 10 files changed, 1362 insertions(+), 4 deletions(-) create mode 100644 src/main/java/org/jenkinsci/plugins/zap/ZAP.java create mode 100644 src/main/java/org/jenkinsci/plugins/zap/ZAPInterfaceAction.java create mode 100644 src/main/java/org/jenkinsci/plugins/zap/ZAPManagement.java create mode 100644 src/main/java/org/jenkinsci/plugins/zap/ZAPManagementBuilder.java create mode 100644 src/main/resources/org/jenkinsci/plugins/zap/ZAPManagement/config.jelly create mode 100644 src/main/resources/org/jenkinsci/plugins/zap/ZAPManagementBuilder/config.jelly create mode 100644 src/main/resources/org/jenkinsci/plugins/zap/ZAPManagementBuilder/help-buildThresholds.html diff --git a/src/main/java/org/jenkinsci/plugins/zap/ZAP.java b/src/main/java/org/jenkinsci/plugins/zap/ZAP.java new file mode 100644 index 0000000..268de5b --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/zap/ZAP.java @@ -0,0 +1,318 @@ +package org.jenkinsci.plugins.zap; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import hudson.model.*; +import hudson.remoting.VirtualChannel; +import hudson.slaves.NodeSpecific; +import hudson.slaves.SlaveComputer; +import hudson.tools.ToolDescriptor; +import hudson.tools.ToolInstallation; +import jenkins.model.Jenkins; + +import org.kohsuke.stapler.DataBoundConstructor; +import org.zaproxy.clientapi.core.ApiResponseList; +import org.zaproxy.clientapi.core.ApiResponseSet; +import org.zaproxy.clientapi.core.ClientApi; +import org.zaproxy.clientapi.core.ClientApiException; +import org.apache.commons.lang.exception.ExceptionUtils; +import org.apache.tools.ant.BuildException; +import org.jenkinsci.remoting.RoleChecker; + +import hudson.EnvVars; +import hudson.Extension; +import hudson.FilePath; +import hudson.Launcher; +import hudson.Proc; +import hudson.FilePath.FileCallable; + +public class ZAP extends AbstractDescribableImpl implements Serializable { + + private static final long serialVersionUID = 1L; + private static final String API_KEY = "ZAPROXY-PLUGIN"; + + /* Command Line Options - Not exposed through the API */ + private static final String CMD_LINE_DIR = "-dir"; + private static final String CMD_LINE_HOST = "-host"; + private static final String CMD_LINE_PORT = "-port"; + private static final String CMD_LINE_DAEMON = "-daemon"; + private static final String CMD_LINE_CONFIG = "-config"; + private static final String CMD_LINE_API_KEY = "api.key"; + + private int timeout; + private String installationEnvVar; + private String homeDir; + private AbstractBuild build; + private BuildListener listener; + private Launcher launcher; + private String host; + private int port; + private List command = new ArrayList(); + private ArrayList commandLineArgs; + private EnvVars envVars; + + /* ZAP executable files */ + private static final String ZAP_PROG_NAME_BAT = "zap.bat"; + private static final String ZAP_PROG_NAME_SH = "zap.sh"; + + public ZAP(AbstractBuild build, BuildListener listener, Launcher launcher, + int timeout, String installationEnvVar, String homeDir, + String host, int port, ArrayList commandLineArgs) throws IOException, InterruptedException { + this.build = build; + this.listener = listener; + this.launcher = launcher; + this.timeout = timeout; + this.installationEnvVar = installationEnvVar; + this.homeDir = homeDir; + this.host = host; + this.port = port; + this.commandLineArgs = commandLineArgs; + this.envVars = build.getEnvironment(listener);; + System.out.println(this.toString()); + } + + private void init () { + + } + + @Override + public String toString() { + String s = ""; + s += "Something"; + s += "\n"; + return s; + } + + public String getInstallationDir() throws IOException, InterruptedException { + return this.build.getEnvironment(this.listener).get(this.installationEnvVar); + } + + public String getAppName() throws IOException, InterruptedException { + Node node = build.getBuiltOn(); + String appName = ""; + + /* Append zap program following Master/Slave and Windows/Unix */ + if ("".equals(node.getNodeName())) { // Master + if (File.pathSeparatorChar == ':') + appName = "/" + ZAP_PROG_NAME_SH; + else + appName = "\\" + ZAP_PROG_NAME_BAT; + } else if ("Unix".equals(((SlaveComputer) node.toComputer()).getOSDescription())) + appName = "/" + ZAP_PROG_NAME_SH; + else + appName = "\\" + ZAP_PROG_NAME_BAT; + return appName; + } + + public FilePath getWorkspace(){ + FilePath workspace = build.getWorkspace(); + if (workspace == null) { + Node node = build.getBuiltOn(); + if (node == null) + throw new NullPointerException("No such build node: " + build.getBuiltOnStr()); + throw new NullPointerException("No workspace from node " + node + " which is computer " + node.toComputer() + " and has channel " + node.getChannel()); + } + return workspace; + } + + public FilePath getAppPath() throws IOException, InterruptedException { + FilePath fp = new FilePath(getWorkspace().getChannel(), getInstallationDir() + getAppName()); + Utils.loggerMessage(listener, 0, "[{0}] CONFIGURE RUN COMMANDS for [ {1} ]", Utils.ZAP, fp.getRemote()); + return fp; + } + + public void checkParams(String installationDir) throws IllegalArgumentException, IOException, InterruptedException { + Utils.loggerMessage(listener, 0, "[{0}] PLUGIN VALIDATION (PLG), VARIABLE VALIDATION AND ENVIRONMENT INJECTOR EXPANSION (EXP)", Utils.ZAP); + + if (installationDir == null || installationDir.isEmpty()) + throw new IllegalArgumentException("ZAP INSTALLATION DIRECTORY IS MISSING, PROVIDED [ " + installationDir + " ]"); + else + Utils.loggerMessage(listener, 1, "ZAP INSTALLATION DIRECTORY = [ {0} ]", installationDir); + } + + public List getCommand() { + return this.command; + } + + public void setCommand() throws IOException, InterruptedException { + this.command.add(getAppPath().getRemote()); + this.command.add(CMD_LINE_DAEMON); + this.command.add(CMD_LINE_HOST); + this.command.add(host); + this.command.add(CMD_LINE_PORT); + this.command.add(Integer.toString(port)); + this.command.add(CMD_LINE_CONFIG); + this.command.add(CMD_LINE_API_KEY + "=" + API_KEY); + this.command.add(CMD_LINE_DIR); + this.command.add(homeDir); + + System.out.println("this.command: " + this.command.size()); + System.out.println("this.commandLineArgs: " + this.commandLineArgs.size()); + /* Adds command line arguments if it's provided */ + if (!this.commandLineArgs.isEmpty()) addZapCmdLine(this.command, this.commandLineArgs); + } + + /** + * Add list of command line to the list in param + * + * @param list + * of type List: the list to attach ZAP command line to. + * @param cmdList + * of type ArrayList: the list of ZAP command line options and their values. + */ + private void addZapCmdLine(List list, ArrayList cmdList) { + System.out.println("extra: " + cmdList.size()); + System.out.println("original: " + list.size()); + for (ZAPCmdLine zapCmd : cmdList) { + if (zapCmd.getCmdLineOption() != null && !zapCmd.getCmdLineOption().isEmpty()) list.add(zapCmd.getCmdLineOption()); + if (zapCmd.getCmdLineValue() != null && !zapCmd.getCmdLineValue().isEmpty()) list.add(zapCmd.getCmdLineValue()); + } + } + + // If the JDK was changed through the job's configurations, then update the Build's Environment Variables, can now remove the Java field to save space. Important, check if the 1.6 LTS is working with this or not. + public void setBuildJDK() throws IOException, InterruptedException { + EnvVars envVars = getEnvVars(); + + System.out.println("setBuildJDK INSIDE: " + build.getBuildVariables().entrySet().size()); + + for (Map.Entry e : build.getBuildVariables().entrySet()) { + envVars.put(e.getKey(), e.getValue()); + System.out.println("KEY: " + e.getKey() + "VALUE: " + e.getValue()); + } + + System.out.println("INSIDE THE SETTER"); + AbstractProject project = build.getProject(); + //JDK 8u131 test + System.out.println("project.getJDK()"); + JDK jdk = project.getJDK(); + System.out.println("JDK: " + (jdk == null)); + + System.out.println("Jenkins.getInstance().getJDK(\"JDK 8u131 test\")"); + jdk = Jenkins.getInstance().getJDK("JDK 8u131 test"); + System.out.println("JDK: " + (jdk == null)); + + if (jdk != null) { + // System.out.println("JDK: " + jdkToUse.getHome()); + // System.out.println("JDK: " + jdkToUse.getName()); + Computer computer = Computer.currentComputer(); + /* just in case we are not in a build */ + if (computer != null) + jdk = jdk.forNode(computer.getNode(), listener); + jdk.buildEnvVars(envVars); + } + } + + private EnvVars getEnvVars () throws IOException, InterruptedException { + return this.envVars; + } + + public Proc launch () throws IOException, InterruptedException { + FilePath workDir = new FilePath(getWorkspace().getChannel(), getInstallationDir()); + + System.out.println(); + printMap(getEnvVars()); + System.out.println(); + + Utils.loggerMessage(listener, 0, "[{0}] EXECUTE LAUNCH COMMAND", Utils.ZAP); + Proc proc = launcher.launch().cmds(getCommand()).envs(envVars).stdout(listener).pwd(workDir).start(); + + /* Call waitForSuccessfulConnectionToZap(int, BuildListener) remotely */ + Utils.lineBreak(listener); + Utils.loggerMessage(listener, 0, "[{0}] INITIALIZATION [ START ]", Utils.ZAP); + build.getWorkspace().act(new WaitZAPInitCallable(listener, this)); + Utils.lineBreak(listener); + Utils.loggerMessage(listener, 0, "[{0}] INITIALIZATION [ SUCCESSFUL ]", Utils.ZAP); + Utils.lineBreak(listener); + return proc; + + } + + private void printMap(Map mp) { + Iterator it = mp.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry) it.next(); + System.out.println(pair.getKey() + " = " + pair.getValue()); + it.remove(); // avoids a ConcurrentModificationException + } + } + + private void waitForSuccessfulConnectionToZap(BuildListener listener) { + Utils.loggerMessage(listener, 0, "[{0}] timeout is [ SUCCESSFUL ]", Integer.toString(timeout)); + int timeoutInMs = (int) TimeUnit.SECONDS.toMillis(timeout); + int connectionTimeoutInMs = timeoutInMs; + int pollingIntervalInMs = (int) TimeUnit.SECONDS.toMillis(1); + boolean connectionSuccessful = false; + long startTime = System.currentTimeMillis(); + Socket socket = null; + do + try { + socket = new Socket(); + socket.connect(new InetSocketAddress(host, port), connectionTimeoutInMs); + connectionSuccessful = true; + } + catch (SocketTimeoutException ignore) { + listener.error(ExceptionUtils.getStackTrace(ignore)); + throw new BuildException("Unable to connect to ZAP's proxy after " + timeout + " seconds."); + + } + catch (IOException ignore) { + /* Try again but wait some time first */ + try { + Thread.sleep(pollingIntervalInMs); + } + catch (InterruptedException e) { + listener.error(ExceptionUtils.getStackTrace(ignore)); + throw new BuildException("The task was interrupted while sleeping between connection polling.", e); + } + + long ellapsedTime = System.currentTimeMillis() - startTime; + if (ellapsedTime >= timeoutInMs) { + listener.error(ExceptionUtils.getStackTrace(ignore)); + throw new BuildException("Unable to connect to ZAP's proxy after " + timeout + " seconds."); + } + connectionTimeoutInMs = (int) (timeoutInMs - ellapsedTime); + } + finally { + if (socket != null) try { + socket.close(); + } + catch (IOException e) { + listener.error(ExceptionUtils.getStackTrace(e)); + } + } + while (!connectionSuccessful); + } + + private static class WaitZAPInitCallable implements FileCallable { + + private static final long serialVersionUID = 1L; + + private BuildListener listener; + private ZAP zaproxy; + + public WaitZAPInitCallable(BuildListener listener, ZAP zaproxy) { + this.listener = listener; + this.zaproxy = zaproxy; + } + + @Override + public Void invoke(File f, VirtualChannel channel) { + zaproxy.waitForSuccessfulConnectionToZap(listener); + return null; + } + + @Override + public void checkRoles(RoleChecker checker) throws SecurityException { + /* N/A */ } + } +} diff --git a/src/main/java/org/jenkinsci/plugins/zap/ZAPBuilder.java b/src/main/java/org/jenkinsci/plugins/zap/ZAPBuilder.java index 62b26e7..d5390b7 100644 --- a/src/main/java/org/jenkinsci/plugins/zap/ZAPBuilder.java +++ b/src/main/java/org/jenkinsci/plugins/zap/ZAPBuilder.java @@ -270,6 +270,7 @@ public boolean prebuild(AbstractBuild build, BuildListener listener) { /** Method called when the build is launching */ @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) { + listener.getLogger().println("zaproxy: " + zaproxy); if (!startZAPFirst) try { Utils.lineBreak(listener); Utils.loggerMessage(listener, 0, "[{0}] START BUILD STEP", Utils.ZAP); @@ -334,6 +335,16 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen listener.error(ExceptionUtils.getStackTrace(e)); return false; } + + build.addAction(new ZAPInterfaceAction()); + ZAPInterfaceAction zapInterface = build.getAction(ZAPInterfaceAction.class); + zapInterface.setBuildStatus(true); + zapInterface.setInstallationEnvVar(zaproxy.getZapHome()); + zapInterface.setHomeDir(zaproxy.getZapSettingsDir()); + zapInterface.setTimeout(zaproxy.getTimeout()); + zapInterface.setHost(zaproxy.getEvaluatedZapHost()); + zapInterface.setPort(zaproxy.getEvaluatedZapPort()); + zapInterface.setCommandLineArgs(zaproxy.getEvaluatedCmdLinesZap()); return res; } diff --git a/src/main/java/org/jenkinsci/plugins/zap/ZAPDriver.java b/src/main/java/org/jenkinsci/plugins/zap/ZAPDriver.java index ff214a5..e71b0cc 100644 --- a/src/main/java/org/jenkinsci/plugins/zap/ZAPDriver.java +++ b/src/main/java/org/jenkinsci/plugins/zap/ZAPDriver.java @@ -86,6 +86,7 @@ import hudson.model.EnvironmentSpecific; import hudson.model.JDK; import hudson.model.Node; +import hudson.model.Result; import hudson.remoting.VirtualChannel; import hudson.slaves.NodeSpecific; import hudson.slaves.SlaveComputer; @@ -632,7 +633,8 @@ public Proc startZAP(AbstractBuild build, BuildListener listener, Launcher cmd.add(CMD_LINE_API_KEY + "=" + API_KEY); /* Set the default directory used by ZAP if it's defined and if a scan is provided */ - if (this.activeScanURL && this.zapSettingsDir != null && !this.zapSettingsDir.isEmpty()) { + //if (this.activeScanURL && this.zapSettingsDir != null && !this.zapSettingsDir.isEmpty()) { + if (this.zapSettingsDir != null && !this.zapSettingsDir.isEmpty()) { cmd.add(CMD_LINE_DIR); cmd.add(this.zapSettingsDir); } @@ -1250,6 +1252,23 @@ else if (this.selectedReportMethod.equals(EXPORT_REPORT)) { return buildSuccess; } + public Result executeZAPPostBuild(BuildListener listener, FilePath workspace) { + Result buildStatus = Result.SUCCESS; + ClientApi clientApi = new ClientApi(this.evaluatedZapHost, this.evaluatedZapPort, API_KEY); + Utils.lineBreak(listener); +// Utils.loggerMessage(listener, 0, "[{0}] MANAGE POST-BUILD THRESHOLD(S) ENABLED [ {1} ]", Utils.ZAP, String.valueOf(this.buildThresholds).toUpperCase()); +// if(this.buildThresholds) try { +// buildStatus = ManageThreshold(listener, clientApi, this.hThresholdValue, this.hSoftValue, this.mThresholdValue, this.mSoftValue, this.lThresholdValue, this.lSoftValue, this.iThresholdValue, this.iSoftValue, this.cumulValue); +// } catch (ClientApiException e) { +// e.printStackTrace(); +// } catch (IOException e) { +// e.printStackTrace(); +// } + + return buildStatus; + + } + /** * Method used to return the checked state inside CREATE JIRA ISSUES. **/ @@ -2786,11 +2805,11 @@ private void getAvailableFormats(ZAPDriverDescriptorImpl zapDriver) { private final ArrayList cmdLinesZAP; /* List of all ZAP command lines specified by the user ArrayList because it needs to be Serializable (whereas List is not Serializable). */ - public List getCmdLinesZAP() { return cmdLinesZAP; } + public ArrayList getCmdLinesZAP() { return cmdLinesZAP; } private ArrayList evaluatedCmdLinesZap; /* Todo */ - public List getEvaluatedCmdLinesZap() { return evaluatedCmdLinesZap; } + public ArrayList getEvaluatedCmdLinesZap() { return evaluatedCmdLinesZap; } public void setEvaluatedCmdLinesZap(ArrayList evaluatedCmdLinesZap) { this.evaluatedCmdLinesZap = evaluatedCmdLinesZap; } diff --git a/src/main/java/org/jenkinsci/plugins/zap/ZAPInterfaceAction.java b/src/main/java/org/jenkinsci/plugins/zap/ZAPInterfaceAction.java new file mode 100644 index 0000000..e6997e6 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/zap/ZAPInterfaceAction.java @@ -0,0 +1,121 @@ +package org.jenkinsci.plugins.zap; + +import java.util.ArrayList; + +import org.zaproxy.clientapi.core.ClientApi; + +import hudson.model.Action; + +public class ZAPInterfaceAction implements Action { + + private boolean buildStatus; + private int timeout; + private String installationEnvVar; + private String homeDir; + private String host; + private int port; + ArrayList commandLineArgs; + + public ZAPInterfaceAction() { + this.buildStatus = false; + + this.timeout = -1; + this.homeDir = ""; + this.installationEnvVar = ""; + this.host = ""; + this.port = 0; + this.commandLineArgs = null; + System.out.println(); + System.out.println("timeout: " + timeout); + System.out.println("homeDir: " + homeDir); + System.out.println("installationEnv: " + installationEnvVar); + } + + public ZAPInterfaceAction(boolean buildStatus, String hello, int low, ClientApi i, int timeout, String installationEnvVar, String homeDir, String host, int port, ArrayList commandLineArgs) { + this.buildStatus = buildStatus; + this.timeout = timeout; + this.installationEnvVar = installationEnvVar; + this.homeDir = homeDir; + this.host = host; + this.port = port; + this.commandLineArgs = commandLineArgs; + System.out.println(); + System.out.println("timeout: " + timeout); + System.out.println("homeDir: " + homeDir); + System.out.println("commandLineArgs: " + commandLineArgs.size()); + + } + public boolean getBuildStatus() { + return this.buildStatus; + } + + public void setBuildStatus(boolean buildStatus) { + this.buildStatus = buildStatus; + } + + public int getTimeout() { + return this.timeout; + } + + public void setTimeout(int timeout) { + this.timeout = timeout; + } + + public String getInstallationEnvVar() { + return this.installationEnvVar; + } + + public void setInstallationEnvVar(String installationEnvVar) { + this.installationEnvVar = installationEnvVar; + } + + public String getHomeDir() { + return this.homeDir; + } + + public void setHomeDir(String homeDir) { + this.homeDir = homeDir; + } + + public String getHost() { + return this.host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return this.port; + } + + public void setPort(int port) { + this.port = port; + } + + public ArrayList getCommandLineArgs(){ + return commandLineArgs; + } + + public void setCommandLineArgs(ArrayList commandLineArgs){ + this.commandLineArgs = commandLineArgs; + } + + @Override + public String getDisplayName() { + return "My Action"; + } + + @Override + public String getIconFileName() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getUrlName() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/main/java/org/jenkinsci/plugins/zap/ZAPManagement.java b/src/main/java/org/jenkinsci/plugins/zap/ZAPManagement.java new file mode 100644 index 0000000..f2d4e62 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/zap/ZAPManagement.java @@ -0,0 +1,574 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016 Goran Sarenkapa (JordanGS), and a number of other of contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.jenkinsci.plugins.zap; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import hudson.model.*; +import hudson.remoting.VirtualChannel; +import hudson.slaves.SlaveComputer; +import jenkins.model.Jenkins; + +import org.kohsuke.stapler.DataBoundConstructor; +import org.zaproxy.clientapi.core.ApiResponseList; +import org.zaproxy.clientapi.core.ApiResponseSet; +import org.zaproxy.clientapi.core.ClientApi; +import org.zaproxy.clientapi.core.ClientApiException; +import org.apache.commons.lang.exception.ExceptionUtils; +import org.apache.tools.ant.BuildException; +import org.jenkinsci.remoting.RoleChecker; + +import hudson.EnvVars; +import hudson.Extension; +import hudson.FilePath; +import hudson.Launcher; +import hudson.Proc; +import hudson.FilePath.FileCallable; + +/** + * Contains methods to start and execute ZAPZAPManagement. Members variables are + * bound to the config.jelly placed to + * {@link "com/github/jenkinsci/zaproxyplugin/ZAPZAPManagement/config.jelly"} + * + * @author Goran Sarenkapa + * @author Mostafa AbdelMoez + * @author Tanguy de Lignières + * @author Abdellah Azougarh + * @author Thilina Madhusanka + * @author Johann Ollivier-Lapeyre + * @author Ludovic Roucoux + * + * @see + * [JAVA] Client API The pom should show the artifact being from maven + * central. + */ +public class ZAPManagement extends AbstractDescribableImpl implements Serializable { + + private static final long serialVersionUID = 1L; + private static final String API_KEY = "ZAPROXY-PLUGIN"; + + /* ZAP executable files */ + private static final String ZAP_PROG_NAME_BAT = "zap.bat"; + private static final String ZAP_PROG_NAME_SH = "zap.sh"; + + @DataBoundConstructor + public ZAPManagement(boolean buildThresholds, int hThresholdValue, int hSoftValue, int mThresholdValue, + int mSoftValue, int lThresholdValue, int lSoftValue, int iThresholdValue, int iSoftValue, int cumulValue) { + /* Post Build Step */ + this.buildThresholds = buildThresholds; + this.hThresholdValue = hThresholdValue; + this.hSoftValue = hSoftValue; + this.mThresholdValue = mThresholdValue; + this.mSoftValue = mSoftValue; + this.lThresholdValue = lThresholdValue; + this.lSoftValue = lSoftValue; + this.iThresholdValue = iThresholdValue; + this.iSoftValue = iSoftValue; + this.cumulValue = cumulValue; + System.out.println(this.toString()); + } + + /** + * Evaluated values will return null, this is printed to console on save + * + * @return + */ + @Override + public String toString() { + String s = "\n\npost build to string\n\n"; + return s; + } + + public Proc startZAP(AbstractBuild build, BuildListener listener, Launcher launcher) throws IllegalArgumentException, IOException, InterruptedException { + System.out.println(""); + System.out.println("INITIATING POST BUILD"); + System.out.println(""); + System.out.println(""); + + if (this.buildStatus == false){ + Utils.loggerMessage(listener, 0, "[{0}] WE GOT FALSE SO WE BREAK", Utils.ZAP); + System.out.println("WE GOT FALSE SO WE BREAK"); + return null; + } + System.out.println("WE GOT TRUE SO WE INIT"); + ZAP zap = new ZAP(build, listener, launcher, this.getTimeout(), this.getInstallationEnvVar(), this.getHomeDir(), this.getHost(), this.getPort(), this.getCommandLineArgs()); + + this.zapInstallationDir = zap.getInstallationDir(); + zap.checkParams(this.zapInstallationDir); + + System.out.println("startZAP list -------------"); + for(int i = 0; i < this.getCommandLineArgs().size(); i++) { + System.out.println(this.getCommandLineArgs().get(i)); + } + + /* Command to start ZAProxy with parameters */ + zap.setCommand(); + + System.out.println("new list -------------"); + for(int i = 0; i < zap.getCommand().size(); i++) { + //System.out.println(zap.getCommand().get(i)); + } + + EnvVars envVars = build.getEnvironment(listener); + + System.out.println(""); + System.out.println(""); + System.out.println("BEFORE SETTING JDK"); + zap.setBuildJDK(); + + /* + * Launch ZAP process on remote machine (on master if no remote machine) + */ +// Utils.loggerMessage(listener, 0, "[{0}] EXECUTE LAUNCH COMMAND", Utils.ZAP); +// Proc proc = launcher.launch().cmds(zap.getCommand()).envs(envVars).stdout(listener).pwd(workDir).start(); +// +// /* Call waitForSuccessfulConnectionToZap(int, BuildListener) remotely */ +// Utils.lineBreak(listener); +// Utils.loggerMessage(listener, 0, "[{0}] INITIALIZATION [ START ]", Utils.ZAP); +// build.getWorkspace().act(new WaitZAPManagementInitCallable(listener, this)); +// Utils.lineBreak(listener); +// Utils.loggerMessage(listener, 0, "[{0}] INITIALIZATION [ SUCCESSFUL ]", Utils.ZAP); +// Utils.lineBreak(listener); +// return proc; + return zap.launch(); + } + + /** + * Wait for ZAP's initialization such that it is ready to use at the end of + * the method, otherwise catch the exception. If there is a remote machine, + * then this method will be launched there. + * + * @param listener + * of type BuildListener: the display log listener during the + * Jenkins job execution. + * @param timeout + * of type int: the time in seconds to try to connect to ZAP. + * @see + * [JAVA] Avoid sleep to wait ZAProxy initialization + */ + + + /** + * Execute ZAPDriver method following build's setup and stop ZAP at the end. + * Note: No param's to executeZAP method since they would also need to be + * accessible in Builder, somewhat redundant. + * + * @param listener + * of type BuildListener: the display log listener during the + * Jenkins job execution. + * @param workspace + * of type FilePath: a {@link FilePath} representing the build's + * workspace. + * @return of type: boolean DESC: true if no exception is caught, false + * otherwise. + */ + public boolean executeZAP(BuildListener listener, FilePath workspace) { + listener.getLogger().println("executeZAP"); + boolean buildSuccess = true; + + /* + * Check to make sure that plugin's are installed with ZAP if they are + * selected in the UI. + */ + listener.getLogger().println("host: " + host); + listener.getLogger().println("port: " + port); + ClientApi clientApi = new ClientApi(host, port, API_KEY); + + try { + if (buildSuccess) { + } + } catch (Exception e) { + listener.error(ExceptionUtils.getStackTrace(e)); + buildSuccess = false; + } finally { + try { + stopZAP(listener, clientApi); + } catch (ClientApiException e) { + listener.error(ExceptionUtils.getStackTrace(e)); + buildSuccess = false; + } + } + Utils.lineBreak(listener); + return buildSuccess; + } + + /** + * ManageThreshold define build value failed, pass , unstable. + * + * @param listener + * of type BuildListener: the display log listener during the + * Jenkins job execution. + * @param clientApi + * of type ClientApi: the ZAP client API to call method. + * @param hThresholdValue + * of type int: the Weight of the alert severity high. + * @param hSoftValue + * of type int: the threshold of the alert severity high. + * @param mThresholdValue + * of type int: the Weight of the alert severity meduim. + * @param mSoftValue + * of type int: the threshold of the alert severity meduim. + * @param lThresholdValue + * of type int: the Weight of the alert severity low. + * @param lSoftValue + * of type int: the threshold of the alert severity low. + * @param iThresholdValue + * of type int: the Weight of the alert severity informational. + * @param iSoftValue + * of type int: the threshold of the alert severity + * informational. + * @param cumulValue + * of type int: the cumulative threshold of the alerts. + * + */ + + private Result ManageThreshold(BuildListener listener, ClientApi clientApi, int hThresholdValue, int hSoftValue, + int mThresholdValue, int mSoftValue, int lThresholdValue, int lSoftValue, int iThresholdValue, + int iSoftValue, int cumulValue) throws ClientApiException, IOException { + + Utils.lineBreak(listener); + Utils.loggerMessage(listener, 0, "START : COMPUTE THRESHOLD", Utils.ZAP); + Result buildStatus = Result.SUCCESS; + + Utils.lineBreak(listener); + int nbAlertHigh = countAlertbySeverity(clientApi, "High"); + Utils.loggerMessage(listener, 1, "ALERTS High COUNT [ {1} ]", Utils.ZAP, Integer.toString(nbAlertHigh)); + + int nbAlertMedium = countAlertbySeverity(clientApi, "Medium"); + Utils.loggerMessage(listener, 1, "ALERTS Medium COUNT [ {1} ]", Utils.ZAP, Integer.toString(nbAlertMedium)); + + int nbAlertLow = countAlertbySeverity(clientApi, "Low"); + // setLowAlert(nbAlertLow); + Utils.loggerMessage(listener, 1, "ALERTS Low COUNT [ {1} ]", Utils.ZAP, Integer.toString(nbAlertLow)); + + int nbAlertInfo = countAlertbySeverity(clientApi, "Informational"); + Utils.loggerMessage(listener, 1, "ALERTS Informational COUNT [ {1} ]", Utils.ZAP, + Integer.toString(nbAlertInfo)); + int count = 0; + + int hScale = computeProduct(hThresholdValue, nbAlertHigh); + int mScale = computeProduct(mThresholdValue, nbAlertMedium); + int lScale = computeProduct(lThresholdValue, nbAlertLow); + int iScale = computeProduct(iThresholdValue, nbAlertInfo); + + if ((hScale > hSoftValue) || (mScale > mSoftValue) || (lScale > lSoftValue) || (iScale > iSoftValue)) { + count++; + } + if ((hScale + mScale + lScale + iScale) > cumulValue) { + count++; + } + + if (count == 1) { + buildStatus = Result.UNSTABLE; + } + if (count == 2) { + buildStatus = Result.FAILURE; + } + + Utils.loggerMessage(listener, 0, "END : COMPUTING THRESHOLD", Utils.ZAP); + + return buildStatus; + + } + + /** + * computeProduct do the product of two Integer. + * + * @param a + * of type Integer. + * @param b + * of type Integer. + */ + public int computeProduct(int a, int b) { + int res; + res = a * b; + return res; + } + + /** + * countAlertbySeverity count the number of alert by severity. + * + * @param clientApi + * of type ClientApi: the ZAP client API to call method. + * @param risk + * of type string : it's the alert severity. + */ + public int countAlertbySeverity(ClientApi clientApi, String risk) throws ClientApiException { + int nbAlert = 0; + List tempid = new ArrayList(); + tempid.add("begin"); + + List allAlerts1 = ((ApiResponseList) clientApi.core.alerts("", "", "")).getItems(); + for (int i = 0; i < allAlerts1.size(); i++) { + ApiResponseSet temp = ((ApiResponseSet) allAlerts1.get(i)); + if (!tempid.contains(temp.getValue("alert").toString())) { + if (risk.equals(temp.getValue("risk").toString())) { + nbAlert++; + } + } + tempid.add(temp.getValue("alert").toString()); + } + + return nbAlert; + } + + /** + * Stop ZAP if it has been previously started. + * + * @param listener + * of type BuildListener: the display log listener during the + * Jenkins job execution. + * @param clientApi + * of type ClientApi: the ZAP client API to call method. + * @throws ClientApiException + */ + private void stopZAP(BuildListener listener, ClientApi clientApi) throws ClientApiException { + if (clientApi != null) { + Utils.lineBreak(listener); + Utils.loggerMessage(listener, 0, "[{0}] SHUTDOWN [ START ]", Utils.ZAP); + Utils.lineBreak(listener); + /** + * @class ApiResponse org.zaproxy.clientapi.gen.Core + * + * @method shutdown + * + * @param String + * apikey + * + * @throws ClientApiException + */ + clientApi.core.shutdown(); + } else + Utils.loggerMessage(listener, 0, "[{0}] SHUTDOWN [ ERROR ]", Utils.ZAP); + } + + @Extension + public static class ZAPManagementDescriptorImpl extends Descriptor implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * To persist global configuration information, simply store it in a + * field and call save(). + * + *

+ * If you don't want fields to be persisted, use transient. + */ + + /** Represents the build's workspace */ + private FilePath workspace; + + public void setWorkspace(FilePath ws) { + this.workspace = ws; + } + + @Override + public String getDisplayName() { + return null; + } + + /** + * In order to load the persisted global configuration, you have to call + * load() in the constructor. + */ + public ZAPManagementDescriptorImpl() { + load(); + } + } + + /* + * Variable Declaration Getters allows to load members variables into UI. + * Setters + */ + @Override + public ZAPManagementDescriptorImpl getDescriptor() { + return (ZAPManagementDescriptorImpl) super.getDescriptor(); + } + + /* + * Overridden for better type safety. If your plugin doesn't really define + * any property on Descriptor, you don't have to do this. + */ + + private String contextId; /* ID of the created context. */ + + private String userId; /* ID of the created user. */ + + /* Post Build Step >> Manage Threshold */ + + private int nbAlertLow; + + private void setLowAlert(int a) { + nbAlertLow = a; + } + + public int getLowAlert() { + return nbAlertLow; + } + + // private final String jdk; /* The IDK to use to start ZAP. */ + // + // public String getJdk() { return jdk; } + // + // /* Gets the JDK that this Sonar builder is configured with, or null. */ + // public JDK getJDK() { return Jenkins.getInstance().getJDK(jdk); } + + // private String zapProgram; /* Path to the ZAP security tool. */ + + private String zapInstallationDir; + + private final boolean buildThresholds; + + public boolean isbuildThresholds() { + return buildThresholds; + } + + private final int hThresholdValue; + + public int gethThresholdValue() { + return hThresholdValue; + } + + private final int hSoftValue; + + public int gethSoftValue() { + return hSoftValue; + } + + private final int mThresholdValue; + + public int getmThresholdValue() { + return mThresholdValue; + } + + private final int mSoftValue; + + public int getmSoftValue() { + return mSoftValue; + } + + private final int lThresholdValue; + + public int getlThresholdValue() { + return lThresholdValue; + } + + private final int lSoftValue; + + public int getlSoftValue() { + return lSoftValue; + } + + private final int iThresholdValue; + + public int getiThresholdValue() { + return iThresholdValue; + } + + private final int iSoftValue; + + public int getiSoftValue() { + return iSoftValue; + } + + private final int cumulValue; + + public Boolean execute; + + public int getcumulValue() { + return cumulValue; + } + + /*****************************/ + + private boolean buildStatus; + private int timeout; + private String installationEnvVar; + private String homeDir; + private String host; + private int port; + + public void setBuildStatus(boolean buildStatus) { + this.buildStatus = buildStatus; + } + + private int getTimeout() { + return this.timeout; + } + + public void setTimeout(int timeout) { + this.timeout = timeout; + } + + private String getInstallationEnvVar() { + return this.installationEnvVar; + } + + public void setInstallationEnvVar(String installationEnvVar) { + this.installationEnvVar = installationEnvVar; + } + + private String getHomeDir() { + return this.homeDir; + } + + public void setHomeDir(String homeDir) { + this.homeDir = homeDir; + } + + public String getHost() { + return this.host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return this.port; + } + + public void setPort(int port) { + this.port = port; + } + + private ArrayList commandLineArgs; /* List of all ZAP command lines specified by the user ArrayList because it needs to be Serializable (whereas List is not Serializable). */ + + public ArrayList getCommandLineArgs() { return commandLineArgs; } + + public void setCommandLineArgs(ArrayList commandLineArgs) { this.commandLineArgs = commandLineArgs; } +} diff --git a/src/main/java/org/jenkinsci/plugins/zap/ZAPManagementBuilder.java b/src/main/java/org/jenkinsci/plugins/zap/ZAPManagementBuilder.java new file mode 100644 index 0000000..a7e17f0 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/zap/ZAPManagementBuilder.java @@ -0,0 +1,210 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016 Goran Sarenkapa (JordanGS), and a number of other of contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.jenkinsci.plugins.zap; + +import java.io.File; +import java.io.IOException; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang.exception.ExceptionUtils; +import org.jenkinsci.remoting.RoleChecker; +import org.kohsuke.stapler.DataBoundConstructor; + +import hudson.EnvVars; +import hudson.Extension; +import hudson.FilePath; +import hudson.FilePath.FileCallable; +import hudson.Launcher; +import hudson.Proc; +import hudson.model.AbstractBuild; +import hudson.model.AbstractProject; +import hudson.model.BuildListener; +import hudson.model.Result; +import hudson.remoting.VirtualChannel; +import hudson.tasks.BuildStepDescriptor; +import hudson.tasks.BuildStepMonitor; +import hudson.tasks.Publisher; +import hudson.tasks.Recorder; + +/** + * + * @author Goran Sarenkapa + * + */ +public class ZAPManagementBuilder extends Recorder { + + + @DataBoundConstructor + public ZAPManagementBuilder(ZAPManagement management) { + this.management = management; + + /* Call the set methods of ZAPDriver to set the values */ + // this.zaproxy.setJiraUsername(ZAPBuilder.DESCRIPTOR.getJiraUsername()); + // this.zaproxy.setJiraPassword(ZAPBuilder.DESCRIPTOR.getJiraPassword()); + // ZAPInterfaceAction zapInterface = + // build.getAction(ZAPInterfaceAction.class); + // + // System.out.println("my action timeout: " + + // zapInterface.getTimeout()); + // System.out.println("my action install dir: " + + // zapInterface.getInstallationDir()); + // System.out.println("my action home dir: " + + // zapInterface.getHomeDir()); + } + + private ZAPManagement management; + + public ZAPManagement getManagement() { return management; } + + private Proc proc = null; + + @Override + public BuildStepMonitor getRequiredMonitorService() { + return BuildStepMonitor.NONE; + } + + @Override /* @Override for better type safety, not needed if plugin doesn't define any property on Descriptor */ + public ZAPManagementBuilderDescriptorImpl getDescriptor() { return (ZAPManagementBuilderDescriptorImpl) super.getDescriptor(); } + + /** Method called when the build is launching + * @throws InterruptedException + * @throws IOException */ + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { + listener.getLogger().println("[ZAP Jenkins Plugin] POST-BUILD MANAGEMENT"); + ZAPInterfaceAction zapInterface = build.getAction(ZAPInterfaceAction.class); + if (zapInterface != null) { + if (zapInterface.getBuildStatus()) { + System.out.println("----- ----- ----- ----- ----- ----- ----- ----- ----- ----- "); + System.out.println("my action timeout: " + zapInterface.getTimeout()); + System.out.println("my action install dir: " + zapInterface.getInstallationEnvVar()); + System.out.println("my action home dir: " + zapInterface.getHomeDir()); + System.out.println("my action host: " + zapInterface.getHost()); + System.out.println("my action port: " + zapInterface.getPort()); + System.out.println("my action command line args extra: " + zapInterface.getCommandLineArgs().size()); + System.out.println("----- ----- ----- ----- ----- ----- ----- ----- ----- ----- "); + for (int i = 0; i < zapInterface.getCommandLineArgs().size(); i++) { + System.out.println(zapInterface.getCommandLineArgs().get(i)); + } + this.management.setBuildStatus(zapInterface.getBuildStatus()); + this.management.setTimeout(zapInterface.getTimeout()); + this.management.setInstallationEnvVar(zapInterface.getInstallationEnvVar()); + this.management.setHomeDir(zapInterface.getHomeDir()); + this.management.setHost(zapInterface.getHost()); + this.management.setPort(zapInterface.getPort()); + this.management.setCommandLineArgs(zapInterface.getCommandLineArgs()); + } + } + else { + /* THE DEFAULT CONSTRUCTOR IS NEVER TRIGGER, DERP DERP */ + Utils.lineBreak(listener); + Utils.loggerMessage(listener, 0, "[{0}] THERE IS NO BUILD STEP, MARKED AS FAILURE", Utils.ZAP); + Utils.lineBreak(listener); + return false; + } + try { + Utils.lineBreak(listener); + Utils.loggerMessage(listener, 0, "[{0}] START BUILD STEP", Utils.ZAP); + Utils.lineBreak(listener); + listener.getLogger().println("management: " + management); + listener.getLogger().println("build: " + build); + listener.getLogger().println("listener: " + listener); + listener.getLogger().println("launcher: " + launcher); + + proc = management.startZAP(build, listener, launcher); + listener.getLogger().println("after proc assignment"); + } + catch (Exception e) { + listener.getLogger().println("we failed"); + e.printStackTrace(); + listener.error(ExceptionUtils.getStackTrace(e)); + return false; + } + + boolean res; + try { + res = build.getWorkspace().act(new ZAPManagementCallable(listener, this.management)); + proc.joinWithTimeout(60L, TimeUnit.MINUTES, listener); + Utils.lineBreak(listener); + Utils.lineBreak(listener); + Utils.loggerMessage(listener, 0, "[{0}] SHUTDOWN [ SUCCESSFUL ]", Utils.ZAP); + Utils.lineBreak(listener); + } + catch (Exception e) { + e.printStackTrace(); + listener.error(ExceptionUtils.getStackTrace(e)); + return false; + } + // EnvVars abc = build.getEnvironment(listener); + // printMap(abc); + return res; + } + private void printMap(Map mp) { + Iterator it = mp.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry) it.next(); + System.out.println(pair.getKey() + " = " + pair.getValue()); + it.remove(); // avoids a ConcurrentModificationException + } + } + @Extension + public static final class ZAPManagementBuilderDescriptorImpl extends BuildStepDescriptor { + + /* In order to load the persisted global configuration, you have to call load() in the constructor. */ + public ZAPManagementBuilderDescriptorImpl() { load(); } + + /* Indicates that this builder can be used with all kinds of project types */ + @SuppressWarnings("rawtypes") + @Override + public boolean isApplicable(Class aClass) { return true; } + + /* This human readable name is used in the configuration screen. */ + @Override + public String getDisplayName() { return Messages.jenkins_jobconfig_addpostbuild_zap(); } + } + + /** + * Used to execute ZAP remotely. + */ + private static class ZAPManagementCallable implements FileCallable { + + private static final long serialVersionUID = 1L; + private BuildListener listener; + private ZAPManagement management; + + public ZAPManagementCallable(BuildListener listener, ZAPManagement management) { + this.listener = listener; + this.management = management; + } + + @Override + public Boolean invoke(File f, VirtualChannel channel) { return management.executeZAP(listener, new FilePath(f)); } + + @Override + public void checkRoles(RoleChecker checker) throws SecurityException { /* N/A */ } + } +} diff --git a/src/main/resources/org/jenkinsci/plugins/zap/Messages.properties b/src/main/resources/org/jenkinsci/plugins/zap/Messages.properties index 582bd46..fb18af9 100644 --- a/src/main/resources/org/jenkinsci/plugins/zap/Messages.properties +++ b/src/main/resources/org/jenkinsci/plugins/zap/Messages.properties @@ -1 +1,2 @@ -jenkins.jobconfig.addbuildstep.zap=Execute ZAP \ No newline at end of file +jenkins.jobconfig.addbuildstep.zap=ZAP Executor +jenkins.jobconfig.addpostbuild.zap=ZAP Management diff --git a/src/main/resources/org/jenkinsci/plugins/zap/ZAPManagement/config.jelly b/src/main/resources/org/jenkinsci/plugins/zap/ZAPManagement/config.jelly new file mode 100644 index 0000000..8f48371 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/zap/ZAPManagement/config.jelly @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
${%Threshold Value}${%Soft Threshold }
High
Medium
Low
Info
+ + + + + +
Cumulative Threshold
+
+
+
+
+
diff --git a/src/main/resources/org/jenkinsci/plugins/zap/ZAPManagementBuilder/config.jelly b/src/main/resources/org/jenkinsci/plugins/zap/ZAPManagementBuilder/config.jelly new file mode 100644 index 0000000..dd7fdac --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/zap/ZAPManagementBuilder/config.jelly @@ -0,0 +1,30 @@ + + + + + + + + diff --git a/src/main/resources/org/jenkinsci/plugins/zap/ZAPManagementBuilder/help-buildThresholds.html b/src/main/resources/org/jenkinsci/plugins/zap/ZAPManagementBuilder/help-buildThresholds.html new file mode 100644 index 0000000..b86ad1c --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/zap/ZAPManagementBuilder/help-buildThresholds.html @@ -0,0 +1,6 @@ +Post Build Management Threshold, allows zap to define if a build is flagged as passed, failed or unstable.

+Threshold value stand for the weight of each alert severity

+Soft value is threshold of each alert severity

+Cumulative value is the threshold of the all build

+The build goes unstable when we are under the soft or cumulative value

+The build goes failed when we are under the soft and cumulative value



From 565dd50a2835c859072eb707a61d53650c14a77d Mon Sep 17 00:00:00 2001 From: tfl421 Date: Mon, 14 Aug 2017 21:57:25 +0200 Subject: [PATCH 3/4] Delete README.md --- README.md | 106 ------------------------------------------------------ 1 file changed, 106 deletions(-) delete mode 100644 README.md diff --git a/README.md b/README.md deleted file mode 100644 index dd6225e..0000000 --- a/README.md +++ /dev/null @@ -1,106 +0,0 @@ -[![Release](https://img.shields.io/github/release/jenkinsci/zap-plugin.svg)](https://github.com/jenkinsci/zap-plugin/releases) -[![Jenkins](https://ci.jenkins.io/job/Plugins/job/zap-plugin/job/master/badge/icon)](https://ci.jenkins.io/job/Plugins/job/zap-plugin/job/master/) -[![Coverity](https://scan.coverity.com/projects/10817/badge.svg)](https://scan.coverity.com/projects/jenkinsci-zap-plugin) -[![Best Practices](https://bestpractices.coreinfrastructure.org/projects/490/badge)](https://bestpractices.coreinfrastructure.org/projects/490) -[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jenkinsci/zap-plugin/blob/master/LICENSE) - -
- - - -
- -[Official OWASP Zed Attack Proxy Jenkins Plugin](https://wiki.jenkins-ci.org/display/JENKINS/zap+plugin) -============================================== - -
- -The OWASP Zed Attack Proxy ([ZAP](https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project)) is one of the world’s most popular free security tools and is actively maintained by hundreds of international volunteers. It can help you automatically find security vulnerabilities in your web applications while you are developing and testing your applications. Its also a great tool for experienced pentesters to use for manual security testing. - -The [Official OWASP ZAP Jenkins Plugin](https://wiki.jenkins-ci.org/display/JENKINS/zap+plugin) extends the functionality of the [ZAP](https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project) security tool into a CI Environment. - - - Manage Sessions (Load or Persist) - - Define Context (Name, Include URLs and Exclude URLs) - - Attack Contexts (Spider Scan, AJAX Spider, Active Scan) - -You can also: - - Setup Authentication (Form Based or Script Based) - - Run as Pre-Build as part of a [Selenium](http://docs.seleniumhq.org/) Build - - Generate Reports (**.xhtml** [![XHTML](https://wiki.jenkins-ci.org/download/attachments/102662470/html.png)](http://www.w3schools.com/html/html_xhtml.asp), **.xml** [![XML](https://wiki.jenkins-ci.org/download/attachments/102662470/xml.png)](http://www.w3schools.com/xml/default.asp), **.json** [![JSON](https://wiki.jenkins-ci.org/download/attachments/102662470/json.png)](http://www.w3schools.com/js/js_json_intro.asp)) - -### Questions/Troubleshooting - -* Please use the [Google Group](https://groups.google.com/forum/#!forum/zaproxy-jenkins) for any questions about using the plugin. -* Notice: - * Include the following: - * Java version - * Jenkins version - * ZAP version - * ZAP Jenkins Plugin version - * Firefox version (if running AJAX Spider or a Selenium build) - * Selenium (if applicable) - * Upload copies of the zap.log files and a copy of the console output of the jenkins log to [pastebin](https://pastebin.mozilla.org/). - * Jenkins is always running on a master, is ZAP running on the master as well or on a separate slave machine? - * Relevant Jenkins Job Configurations sanitized screenshots. - -### Issue Tracking - -* Issues can be created on the Jenkins JIRA for the component [zap-plugin](https://issues.jenkins-ci.org/issues/?jql=project%20%3D%20JENKINS%20AND%20component%20%3D%20zap-plugin). - * [All](https://issues.jenkins-ci.org/issues/?jql=project%20%3D%20JENKINS%20AND%20component%20%3D%20zap-plugin) Issues - * Want to see what we need help with? See [Open, Reopened and Verified](https://issues.jenkins-ci.org/browse/JENKINS-43384?jql=project%20%3D%20JENKINS%20AND%20status%20in%20%28Open%2C%20Reopened%2C%20Verified%29%20AND%20component%20%3D%20zap-plugin) Issues - * Want to see what contributors are currently working on? See [In Progress and In Review](https://issues.jenkins-ci.org/browse/JENKINS-43483?jql=project%20%3D%20JENKINS%20AND%20status%20in%20%28%22In%20Progress%22%2C%20%22In%20Review%22%29%20AND%20component%20%3D%20zap-plugin) Issues - * Want to see what we've done so far? See [Closed and Resolved](https://issues.jenkins-ci.org/browse/JENKINS-41069?jql=project%20%3D%20JENKINS%20AND%20status%20in%20%28Resolved%2C%20Closed%29%20AND%20component%20%3D%20zap-plugin) Issues -* Before creating an Issue please read the [JIRA guidelines](https://wiki.jenkins-ci.org/display/JENKINS/How+to+report+an+issue). -* Notice: GitHub Issues have been disabled. - -### Security Vulnerabilities - -* If you find any security vulnerabilities or exploits caused by the plugin, please send a private email to one of the [maintainer(s)](https://wiki.jenkins-ci.org/display/JENKINS/zap+plugin#zapplugin-PluginInformation). -* Notice: These should be kept private until a fix is issued. - -### Latest Release - Version 1.1.0 (July 10, 2017) - -* add [ JENKINS-39985 ] Added support for context Alert Filters. -* add [ JENKINS-43554 ] Added support for the internationalization of: - 1. UI Elements - 1. Associated Help Doc's -* warning [ JENKINS-43483 ] Added support to the authentication module to be able to utilize Logged Out Indicators. -* remove [ JENKINS-43384 ] Removed support from the ZAP Settings Variable for System Environment Variables, Build Variables as well as Environment Inject Plugin Variables since the Job Configuration page is ONLY run on the master and has no access to the slave. -* bugfix Bug-fixes: - 1. Fixed Broken links in Help Files - 1. Fixed misused variables (evaluatedSessionFilename instead of evaluatedZapSettingsDir) of ZAPDriver.java - 1. Correct improper use of JIRA Extension parameters -* info Usability Improvements: - * Updated all affected help files - * Created the webapp folder - * Established clearer distinction between the ZAP Installation Directory and ZAP Home Directory -* info Updated LICENSE and README information. - -See [Full Version History](https://wiki.jenkins.io/display/JENKINS/Version+History) - -### License - - The MIT License (MIT) - - Copyright (c) 2016 Goran Sarenkapa (JordanGS), and a number of other of contributors - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - -See [License](LICENSE) \ No newline at end of file From 8a859de2518e07bf4f90b50e4783ab700bc100a8 Mon Sep 17 00:00:00 2001 From: tfl421 Date: Thu, 17 Aug 2017 11:21:44 +0200 Subject: [PATCH 4/4] New Feature ZAP Controller and Thresholding --- .../java/org/jenkinsci/plugins/zap/ZAP.java | 192 ++++--- .../org/jenkinsci/plugins/zap/ZAPBuilder.java | 19 +- .../org/jenkinsci/plugins/zap/ZAPDriver.java | 106 +--- .../plugins/zap/ZAPInterfaceAction.java | 62 ++- .../jenkinsci/plugins/zap/ZAPManagement.java | 486 +++++++++--------- .../plugins/zap/ZAPManagementBuilder.java | 17 +- 6 files changed, 425 insertions(+), 457 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/zap/ZAP.java b/src/main/java/org/jenkinsci/plugins/zap/ZAP.java index 268de5b..bb26bc0 100644 --- a/src/main/java/org/jenkinsci/plugins/zap/ZAP.java +++ b/src/main/java/org/jenkinsci/plugins/zap/ZAP.java @@ -60,20 +60,24 @@ public class ZAP extends AbstractDescribableImpl implements Serializable { private List command = new ArrayList(); private ArrayList commandLineArgs; private EnvVars envVars; - + private Boolean autoInstall; + private String toolUsed; /* The ZAP tool to use. */ + /* ZAP executable files */ private static final String ZAP_PROG_NAME_BAT = "zap.bat"; private static final String ZAP_PROG_NAME_SH = "zap.sh"; public ZAP(AbstractBuild build, BuildListener listener, Launcher launcher, - int timeout, String installationEnvVar, String homeDir, - String host, int port, ArrayList commandLineArgs) throws IOException, InterruptedException { + int timeout, String installationEnvVar, String homeDir, String toolUsed, Boolean autoInstall, + String host, int port, ArrayList commandLineArgs) throws IOException, InterruptedException { this.build = build; this.listener = listener; this.launcher = launcher; this.timeout = timeout; this.installationEnvVar = installationEnvVar; this.homeDir = homeDir; + this.toolUsed = toolUsed; + this.autoInstall = autoInstall; this.host = host; this.port = port; this.commandLineArgs = commandLineArgs; @@ -82,7 +86,7 @@ public ZAP(AbstractBuild build, BuildListener listener, Launcher launcher, } private void init () { - + } @Override @@ -94,9 +98,23 @@ public String toString() { } public String getInstallationDir() throws IOException, InterruptedException { - return this.build.getEnvironment(this.listener).get(this.installationEnvVar); + String installPath = null; + if (autoInstall) { + Node node = build.getBuiltOn(); + for (ToolDescriptor desc : ToolInstallation.all()) + for (ToolInstallation tool : desc.getInstallations()) + if (tool.getName().equals(this.toolUsed)) { + if (tool instanceof NodeSpecific) tool = (ToolInstallation) ((NodeSpecific) tool).forNode(node, listener); + if (tool instanceof EnvironmentSpecific) tool = (ToolInstallation) ((EnvironmentSpecific) tool).forEnvironment(this.envVars); + installPath = tool.getHome(); + return installPath; + } + } + else installPath = this.build.getEnvironment(this.listener).get(this.installationEnvVar); + return installPath; } + public String getAppName() throws IOException, InterruptedException { Node node = build.getBuiltOn(); String appName = ""; @@ -137,7 +155,35 @@ public void checkParams(String installationDir) throws IllegalArgumentException, if (installationDir == null || installationDir.isEmpty()) throw new IllegalArgumentException("ZAP INSTALLATION DIRECTORY IS MISSING, PROVIDED [ " + installationDir + " ]"); else - Utils.loggerMessage(listener, 1, "ZAP INSTALLATION DIRECTORY = [ {0} ]", installationDir); + Utils.loggerMessage(listener, 1, "[{0}] ZAP INSTALLATION DIRECTORY = [ {1} ]", Utils.ZAP, installationDir); + } + + /** + * Stop ZAP if it has been previously started. + * + * @param listener + * of type BuildListener: the display log listener during the Jenkins job execution. + * @param clientApi + * of type ClientApi: the ZAP client API to call method. + * @throws ClientApiException + */ + static void stopZAP(BuildListener listener, ClientApi clientApi) throws ClientApiException { + if (clientApi != null) { + Utils.lineBreak(listener); + Utils.loggerMessage(listener, 0, "[{0}] SHUTDOWN [ START ]", Utils.ZAP); + Utils.lineBreak(listener); + /** + * @class ApiResponse org.zaproxy.clientapi.gen.Core + * + * @method shutdown + * + * @param String apikey + * + * @throws ClientApiException + */ + clientApi.core.shutdown(); + } + else Utils.loggerMessage(listener, 0, "[{0}] SHUTDOWN [ ERROR ]", Utils.ZAP); } public List getCommand() { @@ -153,9 +199,14 @@ public void setCommand() throws IOException, InterruptedException { this.command.add(Integer.toString(port)); this.command.add(CMD_LINE_CONFIG); this.command.add(CMD_LINE_API_KEY + "=" + API_KEY); - this.command.add(CMD_LINE_DIR); - this.command.add(homeDir); - + + /* Set the default directory used by ZAP if it's defined and if a scan is provided */ + //if (this.activeScanURL && this.zapSettingsDir != null && !this.zapSettingsDir.isEmpty()) { + if (this.homeDir != null && !this.homeDir.isEmpty()) { + this.command.add(CMD_LINE_DIR); + this.command.add(this.homeDir); + } + System.out.println("this.command: " + this.command.size()); System.out.println("this.commandLineArgs: " + this.commandLineArgs.size()); /* Adds command line arguments if it's provided */ @@ -185,6 +236,7 @@ public void setBuildJDK() throws IOException, InterruptedException { System.out.println("setBuildJDK INSIDE: " + build.getBuildVariables().entrySet().size()); + /* on Windows environment variables are converted to all upper case, but no such conversions are done on Unix, so to make this cross-platform, convert variables to all upper cases. */ for (Map.Entry e : build.getBuildVariables().entrySet()) { envVars.put(e.getKey(), e.getValue()); System.out.println("KEY: " + e.getKey() + "VALUE: " + e.getValue()); @@ -216,38 +268,9 @@ private EnvVars getEnvVars () throws IOException, InterruptedException { return this.envVars; } - public Proc launch () throws IOException, InterruptedException { - FilePath workDir = new FilePath(getWorkspace().getChannel(), getInstallationDir()); - - System.out.println(); - printMap(getEnvVars()); - System.out.println(); - - Utils.loggerMessage(listener, 0, "[{0}] EXECUTE LAUNCH COMMAND", Utils.ZAP); - Proc proc = launcher.launch().cmds(getCommand()).envs(envVars).stdout(listener).pwd(workDir).start(); - - /* Call waitForSuccessfulConnectionToZap(int, BuildListener) remotely */ - Utils.lineBreak(listener); - Utils.loggerMessage(listener, 0, "[{0}] INITIALIZATION [ START ]", Utils.ZAP); - build.getWorkspace().act(new WaitZAPInitCallable(listener, this)); - Utils.lineBreak(listener); - Utils.loggerMessage(listener, 0, "[{0}] INITIALIZATION [ SUCCESSFUL ]", Utils.ZAP); - Utils.lineBreak(listener); - return proc; - - } - - private void printMap(Map mp) { - Iterator it = mp.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry pair = (Map.Entry) it.next(); - System.out.println(pair.getKey() + " = " + pair.getValue()); - it.remove(); // avoids a ConcurrentModificationException - } - } - private void waitForSuccessfulConnectionToZap(BuildListener listener) { - Utils.loggerMessage(listener, 0, "[{0}] timeout is [ SUCCESSFUL ]", Integer.toString(timeout)); + static void waitForSuccessfulConnectionToZap(BuildListener listener, int timeout, String evaluatedZapHost, int evaluatedZapPort) { + Utils.loggerMessage(listener, 0, "[{0}] Waiting for connection", Utils.ZAP); int timeoutInMs = (int) TimeUnit.SECONDS.toMillis(timeout); int connectionTimeoutInMs = timeoutInMs; int pollingIntervalInMs = (int) TimeUnit.SECONDS.toMillis(1); @@ -257,62 +280,65 @@ private void waitForSuccessfulConnectionToZap(BuildListener listener) { do try { socket = new Socket(); - socket.connect(new InetSocketAddress(host, port), connectionTimeoutInMs); + socket.connect(new InetSocketAddress(evaluatedZapHost, evaluatedZapPort), connectionTimeoutInMs); connectionSuccessful = true; } - catch (SocketTimeoutException ignore) { - listener.error(ExceptionUtils.getStackTrace(ignore)); - throw new BuildException("Unable to connect to ZAP's proxy after " + timeout + " seconds."); - - } - catch (IOException ignore) { - /* Try again but wait some time first */ - try { - Thread.sleep(pollingIntervalInMs); - } - catch (InterruptedException e) { - listener.error(ExceptionUtils.getStackTrace(ignore)); - throw new BuildException("The task was interrupted while sleeping between connection polling.", e); - } - - long ellapsedTime = System.currentTimeMillis() - startTime; - if (ellapsedTime >= timeoutInMs) { + catch (SocketTimeoutException ignore) { listener.error(ExceptionUtils.getStackTrace(ignore)); throw new BuildException("Unable to connect to ZAP's proxy after " + timeout + " seconds."); + } - connectionTimeoutInMs = (int) (timeoutInMs - ellapsedTime); - } - finally { - if (socket != null) try { - socket.close(); + catch (IOException ignore) { + /* Try again but wait some time first */ + try { + Thread.sleep(pollingIntervalInMs); + } + catch (InterruptedException e) { + listener.error(ExceptionUtils.getStackTrace(ignore)); + throw new BuildException("The task was interrupted while sleeping between connection polling.", e); + } + + long ellapsedTime = System.currentTimeMillis() - startTime; + if (ellapsedTime >= timeoutInMs) { + listener.error(ExceptionUtils.getStackTrace(ignore)); + throw new BuildException("Unable to connect to ZAP's proxy after " + timeout + " seconds."); + } + connectionTimeoutInMs = (int) (timeoutInMs - ellapsedTime); } - catch (IOException e) { - listener.error(ExceptionUtils.getStackTrace(e)); + finally { + if (socket != null) try { + socket.close(); + } + catch (IOException e) { + listener.error(ExceptionUtils.getStackTrace(e)); + } } - } while (!connectionSuccessful); + Utils.loggerMessage(listener, 0, "[{0}] Connection established", Utils.ZAP); } - private static class WaitZAPInitCallable implements FileCallable { + public Proc launch () throws IOException, InterruptedException { - private static final long serialVersionUID = 1L; + System.out.println(); + printMap(getEnvVars()); + System.out.println(); - private BuildListener listener; - private ZAP zaproxy; + setCommand(); - public WaitZAPInitCallable(BuildListener listener, ZAP zaproxy) { - this.listener = listener; - this.zaproxy = zaproxy; - } + FilePath workDir = new FilePath(getWorkspace().getChannel(), getInstallationDir()); - @Override - public Void invoke(File f, VirtualChannel channel) { - zaproxy.waitForSuccessfulConnectionToZap(listener); - return null; - } + Utils.loggerMessage(listener, 0, "[{0}] EXECUTE LAUNCH COMMAND", Utils.ZAP); + + return launcher.launch().cmds(getCommand()).envs(envVars).stdout(listener).pwd(workDir).start(); + + } - @Override - public void checkRoles(RoleChecker checker) throws SecurityException { - /* N/A */ } + private void printMap(Map mp) { + Iterator it = mp.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry) it.next(); + System.out.println(pair.getKey() + " = " + pair.getValue()); + it.remove(); // avoids a ConcurrentModificationException + } } -} +} \ No newline at end of file diff --git a/src/main/java/org/jenkinsci/plugins/zap/ZAPBuilder.java b/src/main/java/org/jenkinsci/plugins/zap/ZAPBuilder.java index d5390b7..30264f9 100644 --- a/src/main/java/org/jenkinsci/plugins/zap/ZAPBuilder.java +++ b/src/main/java/org/jenkinsci/plugins/zap/ZAPBuilder.java @@ -61,7 +61,8 @@ /** * The main class of the plugin. This class adds a build step in a Jenkins job that allows you to launch the ZAP security tool and generate reports based on the alerts. - * + * + * @author Lenaic Tchokogoue * @author Goran Sarenkapa * @author Mostafa AbdelMoez * @author Tanguy de Lignières @@ -69,13 +70,13 @@ * @author Thilina Madhusanka * @author Johann Ollivier-Lapeyre * @author Ludovic Roucoux - * + * */ -public class ZAPBuilder extends Builder { +public class ZAPBuilder extends Builder { /** * The @DataBoundConstructor is a constructor and it's parameter names must match the fields in associated config file {@link "com/github/jenkinsci/zaproxyplugin/ZAPBuilder/config.jelly"} and additional can set the parameter values for the global configurations {@link "com/github/jenkinsci/zaproxyplugin/ZAPBuilder/global.jelly"}. - * + * * @param startZAPFirst * of type boolean: start zap as a pre-build step or not. * @param zapHost @@ -344,7 +345,11 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen zapInterface.setTimeout(zaproxy.getTimeout()); zapInterface.setHost(zaproxy.getEvaluatedZapHost()); zapInterface.setPort(zaproxy.getEvaluatedZapPort()); + zapInterface.setAutoInstall(zaproxy.getAutoInstall()); + zapInterface.setToolUsed(zaproxy.getToolUsed()); zapInterface.setCommandLineArgs(zaproxy.getEvaluatedCmdLinesZap()); + zapInterface.setSessionFilePath(zaproxy.getSessionFilePath()); + return res; } @@ -373,13 +378,13 @@ public static String applyMacro(AbstractBuild build, BuildListener listene /** * @Extension indicates to Jenkins this is an implementation of an extension point. - * + * * Descriptor for {@link ZAPBuilder}. Used as a singleton. The class is marked as public so that it can be accessed from views. * *

* See src/main/resources/com/github/jenkinsci/zaproxyplugin/ZAPBuilder/*.jelly for the actual HTML fragment for the configuration screen. */ - @Extension + @Extension public static final ZAPBuilderDescriptorImpl DESCRIPTOR = new ZAPBuilderDescriptorImpl(); public static final class ZAPBuilderDescriptorImpl extends BuildStepDescriptor { @@ -508,7 +513,7 @@ private static class CopyFileCallable implements FileCallable { private File sourceFile; private String destination; private String stringForLogger; - + public CopyFileCallable(File sourceFile, String destination, String stringForLogger) { this.sourceFile = sourceFile; this.destination = destination; diff --git a/src/main/java/org/jenkinsci/plugins/zap/ZAPDriver.java b/src/main/java/org/jenkinsci/plugins/zap/ZAPDriver.java index e71b0cc..5d24797 100644 --- a/src/main/java/org/jenkinsci/plugins/zap/ZAPDriver.java +++ b/src/main/java/org/jenkinsci/plugins/zap/ZAPDriver.java @@ -736,49 +736,7 @@ private void addZAPAuthScriptParam(ArrayList authScriptParam * @see [JAVA] Avoid sleep to wait ZAProxy initialization */ private void waitForSuccessfulConnectionToZap(BuildListener listener, int timeout) { - int timeoutInMs = (int) TimeUnit.SECONDS.toMillis(timeout); - int connectionTimeoutInMs = timeoutInMs; - int pollingIntervalInMs = (int) TimeUnit.SECONDS.toMillis(1); - boolean connectionSuccessful = false; - long startTime = System.currentTimeMillis(); - Socket socket = null; - do - try { - socket = new Socket(); - socket.connect(new InetSocketAddress(evaluatedZapHost, evaluatedZapPort), connectionTimeoutInMs); - connectionSuccessful = true; - } - catch (SocketTimeoutException ignore) { - listener.error(ExceptionUtils.getStackTrace(ignore)); - throw new BuildException("Unable to connect to ZAP's proxy after " + timeout + " seconds."); - - } - catch (IOException ignore) { - /* Try again but wait some time first */ - try { - Thread.sleep(pollingIntervalInMs); - } - catch (InterruptedException e) { - listener.error(ExceptionUtils.getStackTrace(ignore)); - throw new BuildException("The task was interrupted while sleeping between connection polling.", e); - } - - long ellapsedTime = System.currentTimeMillis() - startTime; - if (ellapsedTime >= timeoutInMs) { - listener.error(ExceptionUtils.getStackTrace(ignore)); - throw new BuildException("Unable to connect to ZAP's proxy after " + timeout + " seconds."); - } - connectionTimeoutInMs = (int) (timeoutInMs - ellapsedTime); - } - finally { - if (socket != null) try { - socket.close(); - } - catch (IOException e) { - listener.error(ExceptionUtils.getStackTrace(e)); - } - } - while (!connectionSuccessful); + ZAP.waitForSuccessfulConnectionToZap(listener, timeout, evaluatedZapHost, evaluatedZapPort); } /** @@ -1241,7 +1199,7 @@ else if (this.selectedReportMethod.equals(EXPORT_REPORT)) { } finally { try { - stopZAP(listener, clientApi); + ZAP.stopZAP(listener, clientApi); } catch (ClientApiException e) { listener.error(ExceptionUtils.getStackTrace(e)); @@ -1252,22 +1210,6 @@ else if (this.selectedReportMethod.equals(EXPORT_REPORT)) { return buildSuccess; } - public Result executeZAPPostBuild(BuildListener listener, FilePath workspace) { - Result buildStatus = Result.SUCCESS; - ClientApi clientApi = new ClientApi(this.evaluatedZapHost, this.evaluatedZapPort, API_KEY); - Utils.lineBreak(listener); -// Utils.loggerMessage(listener, 0, "[{0}] MANAGE POST-BUILD THRESHOLD(S) ENABLED [ {1} ]", Utils.ZAP, String.valueOf(this.buildThresholds).toUpperCase()); -// if(this.buildThresholds) try { -// buildStatus = ManageThreshold(listener, clientApi, this.hThresholdValue, this.hSoftValue, this.mThresholdValue, this.mSoftValue, this.lThresholdValue, this.lSoftValue, this.iThresholdValue, this.iSoftValue, this.cumulValue); -// } catch (ClientApiException e) { -// e.printStackTrace(); -// } catch (IOException e) { -// e.printStackTrace(); -// } - - return buildStatus; - - } /** * Method used to return the checked state inside CREATE JIRA ISSUES. @@ -2124,34 +2066,6 @@ else if (authMode) { else Utils.loggerMessage(listener, 1, "SKIP ACTIVE SCAN FOR THE SITE [ {0} ]", targetURL); } - /** - * Stop ZAP if it has been previously started. - * - * @param listener - * of type BuildListener: the display log listener during the Jenkins job execution. - * @param clientApi - * of type ClientApi: the ZAP client API to call method. - * @throws ClientApiException - */ - private void stopZAP(BuildListener listener, ClientApi clientApi) throws ClientApiException { - if (clientApi != null) { - Utils.lineBreak(listener); - Utils.loggerMessage(listener, 0, "[{0}] SHUTDOWN [ START ]", Utils.ZAP); - Utils.lineBreak(listener); - /** - * @class ApiResponse org.zaproxy.clientapi.gen.Core - * - * @method shutdown - * - * @param String apikey - * - * @throws ClientApiException - */ - clientApi.core.shutdown(); - } - else Utils.loggerMessage(listener, 0, "[{0}] SHUTDOWN [ ERROR ]", Utils.ZAP); - } - /** * Descriptor for {@link ZAPDriver}. Used as a singleton. The class is marked as public so that it can be accessed from views. * @@ -2875,6 +2789,22 @@ private void getAvailableFormats(ZAPDriverDescriptorImpl zapDriver) { public void setEvaluatedInternalSites(String evaluatedInternalSites) { this.evaluatedInternalSites = evaluatedInternalSites; } + private String sessionFilePath ; + + public void setSessionFilePath(String sessionFilePath ){ this.sessionFilePath = sessionFilePath; } + + public String getSessionFilePath(){ + sessionFilePath = null ; + if (this.autoLoadSession) { /* LOAD SESSION */ + File sessionFile = new File(this.loadSession); + sessionFilePath = sessionFile.getAbsolutePath() ; + } + else { /* PERSIST SESSION */ + File sessionFile = new File(this.zapHome, this.evaluatedSessionFilename); + sessionFilePath = sessionFile.getAbsolutePath() ; + } + return sessionFilePath; + } /* Session Properties */ private final String contextName; /* Context name to use for the session. */ diff --git a/src/main/java/org/jenkinsci/plugins/zap/ZAPInterfaceAction.java b/src/main/java/org/jenkinsci/plugins/zap/ZAPInterfaceAction.java index e6997e6..a51b29e 100644 --- a/src/main/java/org/jenkinsci/plugins/zap/ZAPInterfaceAction.java +++ b/src/main/java/org/jenkinsci/plugins/zap/ZAPInterfaceAction.java @@ -1,11 +1,14 @@ package org.jenkinsci.plugins.zap; import java.util.ArrayList; - -import org.zaproxy.clientapi.core.ClientApi; - import hudson.model.Action; +/** + * @author Lenaic Tchokogoue + * @author Goran Sarenkapa + * + */ + public class ZAPInterfaceAction implements Action { private boolean buildStatus; @@ -14,8 +17,11 @@ public class ZAPInterfaceAction implements Action { private String homeDir; private String host; private int port; + private boolean autoInstall; + private String toolUsed; + public String sessionFilePath; ArrayList commandLineArgs; - + public ZAPInterfaceAction() { this.buildStatus = false; @@ -25,13 +31,12 @@ public ZAPInterfaceAction() { this.host = ""; this.port = 0; this.commandLineArgs = null; - System.out.println(); - System.out.println("timeout: " + timeout); - System.out.println("homeDir: " + homeDir); - System.out.println("installationEnv: " + installationEnvVar); + this.autoInstall = false; + this.toolUsed= null; + this.sessionFilePath=null; } - public ZAPInterfaceAction(boolean buildStatus, String hello, int low, ClientApi i, int timeout, String installationEnvVar, String homeDir, String host, int port, ArrayList commandLineArgs) { + public ZAPInterfaceAction(boolean buildStatus, String toolUsed, boolean autoInstall, String sessionFilePath, int timeout, String installationEnvVar, String homeDir, String host, int port, ArrayList commandLineArgs) { this.buildStatus = buildStatus; this.timeout = timeout; this.installationEnvVar = installationEnvVar; @@ -39,11 +44,10 @@ public ZAPInterfaceAction(boolean buildStatus, String hello, int low, ClientApi this.host = host; this.port = port; this.commandLineArgs = commandLineArgs; - System.out.println(); - System.out.println("timeout: " + timeout); - System.out.println("homeDir: " + homeDir); - System.out.println("commandLineArgs: " + commandLineArgs.size()); - + this.autoInstall = autoInstall; + this.toolUsed= toolUsed; + this.sessionFilePath = sessionFilePath; + } public boolean getBuildStatus() { return this.buildStatus; @@ -53,6 +57,22 @@ public void setBuildStatus(boolean buildStatus) { this.buildStatus = buildStatus; } + public boolean getAutoInstall() { + return this.autoInstall; + } + + public void setAutoInstall(boolean autoInstall) { + this.autoInstall = autoInstall; + } + + public String getToolUsed() { + return this.toolUsed; + } + + public void setToolUsed(String toolUsed) { + this.toolUsed = toolUsed; + } + public int getTimeout() { return this.timeout; } @@ -76,11 +96,11 @@ public String getHomeDir() { public void setHomeDir(String homeDir) { this.homeDir = homeDir; } - + public String getHost() { return this.host; } - + public void setHost(String host) { this.host = host; } @@ -88,19 +108,23 @@ public void setHost(String host) { public int getPort() { return this.port; } - + public void setPort(int port) { this.port = port; } - + public ArrayList getCommandLineArgs(){ return commandLineArgs; } - + public void setCommandLineArgs(ArrayList commandLineArgs){ this.commandLineArgs = commandLineArgs; } + public String getSessionFilePath(){return this.sessionFilePath;} + + public void setSessionFilePath(String sessionFilePath){this.sessionFilePath = sessionFilePath;} + @Override public String getDisplayName() { return "My Action"; diff --git a/src/main/java/org/jenkinsci/plugins/zap/ZAPManagement.java b/src/main/java/org/jenkinsci/plugins/zap/ZAPManagement.java index f2d4e62..7592181 100644 --- a/src/main/java/org/jenkinsci/plugins/zap/ZAPManagement.java +++ b/src/main/java/org/jenkinsci/plugins/zap/ZAPManagement.java @@ -31,14 +31,16 @@ import java.net.Socket; import java.net.SocketTimeoutException; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import hudson.model.*; import hudson.remoting.VirtualChannel; +import hudson.slaves.NodeSpecific; import hudson.slaves.SlaveComputer; +import hudson.tools.ToolDescriptor; +import hudson.tools.ToolInstallation; import jenkins.model.Jenkins; import org.kohsuke.stapler.DataBoundConstructor; @@ -58,10 +60,9 @@ import hudson.FilePath.FileCallable; /** - * Contains methods to start and execute ZAPZAPManagement. Members variables are - * bound to the config.jelly placed to - * {@link "com/github/jenkinsci/zaproxyplugin/ZAPZAPManagement/config.jelly"} + * Contains methods to start and execute ZAPManagement. Members variables are bound to the config.jelly placed to {@link "com/github/jenkinsci/zaproxyplugin/ZAPManagement/config.jelly"} * + * @author Lenaic Tchokogoue * @author Goran Sarenkapa * @author Mostafa AbdelMoez * @author Tanguy de Lignières @@ -70,26 +71,33 @@ * @author Johann Ollivier-Lapeyre * @author Ludovic Roucoux * - * @see - * [JAVA] Client API The pom should show the artifact being from maven - * central. + * @see [JAVA] Client API The pom should show the artifact being from maven central. */ public class ZAPManagement extends AbstractDescribableImpl implements Serializable { private static final long serialVersionUID = 1L; private static final String API_KEY = "ZAPROXY-PLUGIN"; + /* Command Line Options - Not exposed through the API */ + private static final String CMD_LINE_DIR = "-dir"; + private static final String CMD_LINE_HOST = "-host"; + private static final String CMD_LINE_PORT = "-port"; + private static final String CMD_LINE_DAEMON = "-daemon"; + private static final String CMD_LINE_CONFIG = "-config"; + private static final String CMD_LINE_API_KEY = "api.key"; + + // private static final int timeout = 60; /* Time total to wait for ZAP initialization. After this time, the program is stopped. */ + /* ZAP executable files */ private static final String ZAP_PROG_NAME_BAT = "zap.bat"; private static final String ZAP_PROG_NAME_SH = "zap.sh"; @DataBoundConstructor - public ZAPManagement(boolean buildThresholds, int hThresholdValue, int hSoftValue, int mThresholdValue, - int mSoftValue, int lThresholdValue, int lSoftValue, int iThresholdValue, int iSoftValue, int cumulValue) { - /* Post Build Step */ - this.buildThresholds = buildThresholds; - this.hThresholdValue = hThresholdValue; + public ZAPManagement(boolean buildThresholds, int hThresholdValue, int hSoftValue, int mThresholdValue, int mSoftValue, int lThresholdValue, int lSoftValue, int iThresholdValue, int iSoftValue, int cumulValue) { + + /* Post Build Step*/ + this.buildThresholds=buildThresholds; + this.hThresholdValue= hThresholdValue; this.hSoftValue = hSoftValue; this.mThresholdValue = mThresholdValue; this.mSoftValue = mSoftValue; @@ -106,9 +114,25 @@ public ZAPManagement(boolean buildThresholds, int hThresholdValue, int hSoftValu * * @return */ + @Override public String toString() { - String s = "\n\npost build to string\n\n"; + String s = ""; + s += "\n"; + s += "\n"; + s += "Post Build action\n"; + s += "\n"; + s += "Manage Threshold\n"; + s += "-------------------------------------------------------\n"; + s += "high ThresholdValue [" + hThresholdValue + "]\n"; + s += "high SoftValue [" + hSoftValue + "]\n"; + s += "medium ThresholdValue [" + mThresholdValue + "]\n"; + s += "medium SoftValue [" + mSoftValue + "]\n"; + s += "low ThresholdValue [" + lThresholdValue + "]\n"; + s += "low SoftValue [" + lSoftValue + "]\n"; + s += "info ThresholdValue [" + iThresholdValue + "]\n"; + s += "low SoftValue [" + iSoftValue + "]\n"; + s += "cumulative Value [" + cumulValue + "]\n"; return s; } @@ -118,33 +142,22 @@ public Proc startZAP(AbstractBuild build, BuildListener listener, Launcher System.out.println(""); System.out.println(""); - if (this.buildStatus == false){ + if (!this.buildStatus){ Utils.loggerMessage(listener, 0, "[{0}] WE GOT FALSE SO WE BREAK", Utils.ZAP); System.out.println("WE GOT FALSE SO WE BREAK"); return null; } System.out.println("WE GOT TRUE SO WE INIT"); - ZAP zap = new ZAP(build, listener, launcher, this.getTimeout(), this.getInstallationEnvVar(), this.getHomeDir(), this.getHost(), this.getPort(), this.getCommandLineArgs()); + ZAP zap = new ZAP(build, listener, launcher, this.getTimeout(), this.getInstallationEnvVar(), this.getHomeDir(), this.getToolUsed(),this.getAutoInstall(), this.getHost(), this.getPort(), this.getCommandLineArgs()); - this.zapInstallationDir = zap.getInstallationDir(); - zap.checkParams(this.zapInstallationDir); + this.zapProgram = zap.getInstallationDir(); + zap.checkParams(this.zapProgram); System.out.println("startZAP list -------------"); for(int i = 0; i < this.getCommandLineArgs().size(); i++) { System.out.println(this.getCommandLineArgs().get(i)); } - - /* Command to start ZAProxy with parameters */ - zap.setCommand(); - System.out.println("new list -------------"); - for(int i = 0; i < zap.getCommand().size(); i++) { - //System.out.println(zap.getCommand().get(i)); - } - - EnvVars envVars = build.getEnvironment(listener); - - System.out.println(""); System.out.println(""); System.out.println("BEFORE SETTING JDK"); zap.setBuildJDK(); @@ -152,86 +165,97 @@ public Proc startZAP(AbstractBuild build, BuildListener listener, Launcher /* * Launch ZAP process on remote machine (on master if no remote machine) */ -// Utils.loggerMessage(listener, 0, "[{0}] EXECUTE LAUNCH COMMAND", Utils.ZAP); -// Proc proc = launcher.launch().cmds(zap.getCommand()).envs(envVars).stdout(listener).pwd(workDir).start(); -// -// /* Call waitForSuccessfulConnectionToZap(int, BuildListener) remotely */ -// Utils.lineBreak(listener); -// Utils.loggerMessage(listener, 0, "[{0}] INITIALIZATION [ START ]", Utils.ZAP); -// build.getWorkspace().act(new WaitZAPManagementInitCallable(listener, this)); -// Utils.lineBreak(listener); -// Utils.loggerMessage(listener, 0, "[{0}] INITIALIZATION [ SUCCESSFUL ]", Utils.ZAP); -// Utils.lineBreak(listener); -// return proc; - return zap.launch(); + Proc proc = zap.launch(); + + + /* Call waitForSuccessfulConnectionToZap(int, BuildListener) remotely */ + Utils.lineBreak(listener); + Utils.loggerMessage(listener, 0, "[{0}] INITIALIZATION [ START ]", Utils.ZAP); + build.getWorkspace().act(new WaitZAPManagementInitCallable(listener, this)); + Utils.lineBreak(listener); + Utils.loggerMessage(listener, 0, "[{0}] INITIALIZATION [ SUCCESSFUL ]", Utils.ZAP); + Utils.lineBreak(listener); + + return proc; } - + /** - * Wait for ZAP's initialization such that it is ready to use at the end of - * the method, otherwise catch the exception. If there is a remote machine, - * then this method will be launched there. + * Wait for ZAP's initialization such that it is ready to use at the end of the method, otherwise catch the exception. If there is a remote machine, then this method will be launched there. * * @param listener - * of type BuildListener: the display log listener during the - * Jenkins job execution. - * @param timeout - * of type int: the time in seconds to try to connect to ZAP. - * @see - * [JAVA] Avoid sleep to wait ZAProxy initialization + * of type BuildListener: the display log listener during the Jenkins job execution. + * @see [JAVA] Avoid sleep to wait ZAProxy initialization */ - + private void waitForSuccessfulConnectionToZap(BuildListener listener) { + ZAP.waitForSuccessfulConnectionToZap(listener, timeout, getHost(), getPort()); + } /** - * Execute ZAPDriver method following build's setup and stop ZAP at the end. - * Note: No param's to executeZAP method since they would also need to be - * accessible in Builder, somewhat redundant. + * Execute ZAPDriver method following build's setup and stop ZAP at the end. Note: No param's to executeZAP method since they would also need to be accessible in Builder, somewhat redundant. * * @param listener - * of type BuildListener: the display log listener during the - * Jenkins job execution. + * of type BuildListener: the display log listener during the Jenkins job execution. * @param workspace - * of type FilePath: a {@link FilePath} representing the build's - * workspace. - * @return of type: boolean DESC: true if no exception is caught, false - * otherwise. + * of type FilePath: a {@link FilePath} representing the build's workspace. + * @return of type: boolean DESC: true if no exception is caught, false otherwise. */ - public boolean executeZAP(BuildListener listener, FilePath workspace) { + public Result executeZAP(BuildListener listener, FilePath workspace) { listener.getLogger().println("executeZAP"); + Result buildResult = Result.SUCCESS; boolean buildSuccess = true; - /* - * Check to make sure that plugin's are installed with ZAP if they are - * selected in the UI. - */ - listener.getLogger().println("host: " + host); - listener.getLogger().println("port: " + port); - ClientApi clientApi = new ClientApi(host, port, API_KEY); + + /* Check to make sure that plugin's are installed with ZAP if they are selected in the UI. */ + + ClientApi clientApi = new ClientApi(getHost(), getPort(), API_KEY); + try { if (buildSuccess) { + /* LOAD SESSION */ + /* + * @class org.zaproxy.clientapi.gen.Core + * + * @method loadSession + * + * @param String apikey + * @param String name + * + * @throws ClientApiException + */ + Utils.loggerMessage(listener, 0, "[{0}] Loading session : {1}", Utils.ZAP, this.getSessionFilePath()); + clientApi.core.loadSession(this.getSessionFilePath()); + + /* SETUP THRESHOLDING */ + Utils.lineBreak(listener); + buildResult = manageThreshold( listener, clientApi, this.hThresholdValue, this.hSoftValue, this.mThresholdValue, this.mSoftValue, this.lThresholdValue, this.lSoftValue, this.iThresholdValue, this.iSoftValue, this.cumulValue); + } - } catch (Exception e) { + } + catch (Exception e) { listener.error(ExceptionUtils.getStackTrace(e)); buildSuccess = false; - } finally { + buildResult=Result.ABORTED; + } + finally { try { - stopZAP(listener, clientApi); - } catch (ClientApiException e) { + ZAP.stopZAP(listener, clientApi); + } + catch (ClientApiException e) { listener.error(ExceptionUtils.getStackTrace(e)); buildSuccess = false; + buildResult=Result.ABORTED; } } Utils.lineBreak(listener); - return buildSuccess; + return buildResult; } /** - * ManageThreshold define build value failed, pass , unstable. + * manageThreshold define build value failed, pass , unstable. * * @param listener - * of type BuildListener: the display log listener during the - * Jenkins job execution. + * of type BuildListener: the display log listener during the Jenkins job execution. * @param clientApi * of type ClientApi: the ZAP client API to call method. * @param hThresholdValue @@ -247,61 +271,71 @@ public boolean executeZAP(BuildListener listener, FilePath workspace) { * @param lSoftValue * of type int: the threshold of the alert severity low. * @param iThresholdValue - * of type int: the Weight of the alert severity informational. + * of type int: the Weight of the alert severity informational. * @param iSoftValue - * of type int: the threshold of the alert severity - * informational. + * of type int: the threshold of the alert severity informational. * @param cumulValue * of type int: the cumulative threshold of the alerts. * */ - private Result ManageThreshold(BuildListener listener, ClientApi clientApi, int hThresholdValue, int hSoftValue, - int mThresholdValue, int mSoftValue, int lThresholdValue, int lSoftValue, int iThresholdValue, - int iSoftValue, int cumulValue) throws ClientApiException, IOException { + private Result manageThreshold(BuildListener listener,ClientApi clientApi, int hThresholdValue, int hSoftValue, int mThresholdValue, int mSoftValue, int lThresholdValue, int lSoftValue, int iThresholdValue, int iSoftValue, int cumulValue) throws ClientApiException, IOException { Utils.lineBreak(listener); - Utils.loggerMessage(listener, 0, "START : COMPUTE THRESHOLD", Utils.ZAP); - Result buildStatus = Result.SUCCESS; + Utils.loggerMessage(listener, 0, "[{0}] -------------------------------------------------------", Utils.ZAP); + Utils.loggerMessage(listener, 0, "[{0}] START : COMPUTE THRESHOLD", Utils.ZAP); + Result buildResult = Result.SUCCESS; Utils.lineBreak(listener); int nbAlertHigh = countAlertbySeverity(clientApi, "High"); - Utils.loggerMessage(listener, 1, "ALERTS High COUNT [ {1} ]", Utils.ZAP, Integer.toString(nbAlertHigh)); + Utils.loggerMessage(listener, 1, "[{0}] ALERTS High COUNT [ {1} ]", Utils.ZAP, Integer.toString(nbAlertHigh)); int nbAlertMedium = countAlertbySeverity(clientApi, "Medium"); - Utils.loggerMessage(listener, 1, "ALERTS Medium COUNT [ {1} ]", Utils.ZAP, Integer.toString(nbAlertMedium)); + Utils.loggerMessage(listener, 1, "[{0}] ALERTS Medium COUNT [ {1} ]", Utils.ZAP, Integer.toString(nbAlertMedium)); int nbAlertLow = countAlertbySeverity(clientApi, "Low"); - // setLowAlert(nbAlertLow); - Utils.loggerMessage(listener, 1, "ALERTS Low COUNT [ {1} ]", Utils.ZAP, Integer.toString(nbAlertLow)); + //setLowAlert(nbAlertLow); + Utils.loggerMessage(listener, 1, "[{0}] ALERTS Low COUNT [ {1} ]", Utils.ZAP, Integer.toString(nbAlertLow)); - int nbAlertInfo = countAlertbySeverity(clientApi, "Informational"); - Utils.loggerMessage(listener, 1, "ALERTS Informational COUNT [ {1} ]", Utils.ZAP, - Integer.toString(nbAlertInfo)); - int count = 0; + int nbAlertInfo =countAlertbySeverity(clientApi, "Informational"); + Utils.loggerMessage(listener, 1, "[{0}] ALERTS Informational COUNT [ {1} ]", Utils.ZAP, Integer.toString(nbAlertInfo)); - int hScale = computeProduct(hThresholdValue, nbAlertHigh); - int mScale = computeProduct(mThresholdValue, nbAlertMedium); - int lScale = computeProduct(lThresholdValue, nbAlertLow); - int iScale = computeProduct(iThresholdValue, nbAlertInfo); + int hScale = computeProduct(hThresholdValue,nbAlertHigh); + int mScale = computeProduct(mThresholdValue,nbAlertMedium); + int lScale = computeProduct(lThresholdValue,nbAlertLow); + int iScale = computeProduct(iThresholdValue,nbAlertInfo); - if ((hScale > hSoftValue) || (mScale > mSoftValue) || (lScale > lSoftValue) || (iScale > iSoftValue)) { - count++; - } - if ((hScale + mScale + lScale + iScale) > cumulValue) { - count++; - } + Utils.lineBreak(listener); + Utils.loggerMessage(listener, 1, "[{0}] ----- COMPUTED / SOFT THRESHOLD -----", Utils.ZAP); + Utils.loggerMessage(listener, 1, "[{0}] High [ {1} / {2} ]", Utils.ZAP, Integer.toString(hScale), Integer.toString(hSoftValue)); + Utils.loggerMessage(listener, 1, "[{0}] Medium [ {1} / {2} ]", Utils.ZAP, Integer.toString(mScale), Integer.toString(mSoftValue)); + Utils.loggerMessage(listener, 1, "[{0}] Low [ {1} / {2} ]", Utils.ZAP, Integer.toString(lScale), Integer.toString(lSoftValue)); + Utils.loggerMessage(listener, 1, "[{0}] Informational [ {1} / {2} ]", Utils.ZAP, Integer.toString(iScale), Integer.toString(iSoftValue)); + Utils.loggerMessage(listener, 1, "[{0}] Cumulative [ {1} / {2} ]", Utils.ZAP, Integer.toString(hScale+mScale+lScale+iScale), Integer.toString(cumulValue)); + Utils.lineBreak(listener); - if (count == 1) { - buildStatus = Result.UNSTABLE; - } - if (count == 2) { - buildStatus = Result.FAILURE; + + if((hScale > hSoftValue) || ((hScale+mScale+lScale+iScale)> cumulValue)) { + Utils.loggerMessage(listener, 1, "[{0}] ##################################################", Utils.ZAP); + Utils.loggerMessage(listener, 1, "[{0}] # HIGH OR CUMULATIVE SOFT THRESHOLD HAS BEEN HIT #", Utils.ZAP); + Utils.loggerMessage(listener, 1, "[{0}] # BUILD IS MARKED AS FAILED #", Utils.ZAP); + Utils.loggerMessage(listener, 1, "[{0}] ##################################################", Utils.ZAP); + Utils.lineBreak(listener); + buildResult = Result.FAILURE; + } else if((mScale > mSoftValue) || (lScale > lSoftValue ) || (iScale > iSoftValue)) { + Utils.loggerMessage(listener, 1, "[{0}] ###########################################", Utils.ZAP); + Utils.loggerMessage(listener, 1, "[{0}] # ONE OR MORE SOFT THRESHOLD HAS BEEN HIT #", Utils.ZAP); + Utils.loggerMessage(listener, 1, "[{0}] # BUILD IS MARKED AS UNSTABLE #", Utils.ZAP); + Utils.loggerMessage(listener, 1, "[{0}] ###########################################", Utils.ZAP); + Utils.lineBreak(listener); + buildResult = Result.UNSTABLE; } - Utils.loggerMessage(listener, 0, "END : COMPUTING THRESHOLD", Utils.ZAP); - return buildStatus; + Utils.loggerMessage(listener, 0, "[{0}] END : COMPUTING THRESHOLD", Utils.ZAP); + Utils.loggerMessage(listener, 0, "[{0}] -------------------------------------------------------", Utils.ZAP); + + return buildResult; } @@ -313,10 +347,8 @@ private Result ManageThreshold(BuildListener listener, ClientApi clientApi, int * @param b * of type Integer. */ - public int computeProduct(int a, int b) { - int res; - res = a * b; - return res; + public int computeProduct(int a, int b){ + return a * b; } /** @@ -327,18 +359,16 @@ public int computeProduct(int a, int b) { * @param risk * of type string : it's the alert severity. */ - public int countAlertbySeverity(ClientApi clientApi, String risk) throws ClientApiException { + public int countAlertbySeverity(ClientApi clientApi,String risk)throws ClientApiException{ int nbAlert = 0; List tempid = new ArrayList(); tempid.add("begin"); - List allAlerts1 = ((ApiResponseList) clientApi.core.alerts("", "", "")).getItems(); - for (int i = 0; i < allAlerts1.size(); i++) { + List allAlerts1 = ((ApiResponseList) clientApi.core.alerts("","","")).getItems(); + for(int i=0;i { + + private static final long serialVersionUID = 1L; + + private BuildListener listener; + private ZAPManagement zapManagement; + + public WaitZAPManagementInitCallable(BuildListener listener, ZAPManagement zapManagement) { + this.listener = listener; + this.zapManagement = zapManagement; + } + + @Override + public Void invoke(File f, VirtualChannel channel) { + zapManagement.waitForSuccessfulConnectionToZap(listener); + return null; + } + + @Override + public void checkRoles(RoleChecker checker) throws SecurityException { /* N/A */ } } @Extension @@ -382,8 +407,7 @@ public static class ZAPManagementDescriptorImpl extends Descriptor * If you don't want fields to be persisted, use transient. @@ -392,18 +416,13 @@ public static class ZAPManagementDescriptorImpl extends Descriptor> Manage Threshold */ private int nbAlertLow; - - private void setLowAlert(int a) { + private void setLowAlert (int a){ nbAlertLow = a; } - - public int getLowAlert() { + public int getLowAlert(){ return nbAlertLow; } - // private final String jdk; /* The IDK to use to start ZAP. */ - // - // public String getJdk() { return jdk; } - // - // /* Gets the JDK that this Sonar builder is configured with, or null. */ - // public JDK getJDK() { return Jenkins.getInstance().getJDK(jdk); } - - // private String zapProgram; /* Path to the ZAP security tool. */ + // private final String jdk; /* The IDK to use to start ZAP. */ +// +// public String getJdk() { return jdk; } +// +// /* Gets the JDK that this Sonar builder is configured with, or null. */ +// public JDK getJDK() { return Jenkins.getInstance().getJDK(jdk); } +//*********** + private static String zapHost; + private static int zapPort; - private String zapInstallationDir; + //*************/ + private String zapProgram; /* Path to the ZAP security tool. */ private final boolean buildThresholds; - - public boolean isbuildThresholds() { - return buildThresholds; - } + public boolean isbuildThresholds() {return buildThresholds;} private final int hThresholdValue; - - public int gethThresholdValue() { - return hThresholdValue; - } + public int gethThresholdValue() {return hThresholdValue;} private final int hSoftValue; - - public int gethSoftValue() { - return hSoftValue; - } + public int gethSoftValue() {return hSoftValue;} private final int mThresholdValue; - - public int getmThresholdValue() { - return mThresholdValue; - } + public int getmThresholdValue() {return mThresholdValue;} private final int mSoftValue; - - public int getmSoftValue() { - return mSoftValue; - } + public int getmSoftValue() {return mSoftValue;} private final int lThresholdValue; - - public int getlThresholdValue() { - return lThresholdValue; - } + public int getlThresholdValue() {return lThresholdValue;} private final int lSoftValue; - - public int getlSoftValue() { - return lSoftValue; - } + public int getlSoftValue() {return lSoftValue;} private final int iThresholdValue; - - public int getiThresholdValue() { - return iThresholdValue; - } + public int getiThresholdValue() {return iThresholdValue;} private final int iSoftValue; - - public int getiSoftValue() { - return iSoftValue; - } + public int getiSoftValue() {return iSoftValue;} private final int cumulValue; public Boolean execute; - - public int getcumulValue() { - return cumulValue; - } + public int getcumulValue() {return cumulValue;} /*****************************/ private boolean buildStatus; + private boolean autoInstall; private int timeout; private String installationEnvVar; private String homeDir; private String host; private int port; + private String toolUsed; + public String sessionFilePath; - public void setBuildStatus(boolean buildStatus) { - this.buildStatus = buildStatus; - } + public void setBuildStatus(boolean buildStatus) {this.buildStatus = buildStatus;} - private int getTimeout() { - return this.timeout; - } + public boolean getAutoInstall(){return this.autoInstall;} - public void setTimeout(int timeout) { - this.timeout = timeout; - } + public void setAutoInstall(boolean autoInstall) {this.autoInstall = autoInstall;} - private String getInstallationEnvVar() { - return this.installationEnvVar; - } + private String getToolUsed(){return this.toolUsed;} - public void setInstallationEnvVar(String installationEnvVar) { - this.installationEnvVar = installationEnvVar; - } + public void setToolUsed(String toolUsed) {this.toolUsed = toolUsed;} - private String getHomeDir() { - return this.homeDir; - } + private int getTimeout() {return this.timeout;} - public void setHomeDir(String homeDir) { - this.homeDir = homeDir; - } + public void setTimeout(int timeout) {this.timeout = timeout;} - public String getHost() { - return this.host; - } - - public void setHost(String host) { - this.host = host; - } + private String getInstallationEnvVar() {return this.installationEnvVar;} - public int getPort() { - return this.port; - } - - public void setPort(int port) { - this.port = port; - } + public void setInstallationEnvVar(String installationEnvVar) {this.installationEnvVar = installationEnvVar;} + + private String getHomeDir() {return this.homeDir;} + + public void setHomeDir(String homeDir) {this.homeDir = homeDir;} + + public String getHost() {return this.host;} + + public void setHost(String host) {this.host = host;} + + public int getPort() {return this.port;} + + public void setPort(int port) {this.port = port;} + + public String getSessionFilePath(){return this.sessionFilePath;} + + public void setSessionFilePath(String sessionFilePath){this.sessionFilePath = sessionFilePath;} private ArrayList commandLineArgs; /* List of all ZAP command lines specified by the user ArrayList because it needs to be Serializable (whereas List is not Serializable). */ diff --git a/src/main/java/org/jenkinsci/plugins/zap/ZAPManagementBuilder.java b/src/main/java/org/jenkinsci/plugins/zap/ZAPManagementBuilder.java index a7e17f0..beee3b2 100644 --- a/src/main/java/org/jenkinsci/plugins/zap/ZAPManagementBuilder.java +++ b/src/main/java/org/jenkinsci/plugins/zap/ZAPManagementBuilder.java @@ -51,7 +51,7 @@ import hudson.tasks.Recorder; /** - * + * @author Lenaic Tchokogoue * @author Goran Sarenkapa * */ @@ -106,6 +106,9 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen System.out.println("my action host: " + zapInterface.getHost()); System.out.println("my action port: " + zapInterface.getPort()); System.out.println("my action command line args extra: " + zapInterface.getCommandLineArgs().size()); + System.out.println("my action autoinstall: " + zapInterface.getAutoInstall()); + System.out.println("my action tool used: " + zapInterface.getToolUsed()); + System.out.println("my action session path: " + zapInterface.getSessionFilePath()); System.out.println("----- ----- ----- ----- ----- ----- ----- ----- ----- ----- "); for (int i = 0; i < zapInterface.getCommandLineArgs().size(); i++) { System.out.println(zapInterface.getCommandLineArgs().get(i)); @@ -117,6 +120,9 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen this.management.setHost(zapInterface.getHost()); this.management.setPort(zapInterface.getPort()); this.management.setCommandLineArgs(zapInterface.getCommandLineArgs()); + this.management.setAutoInstall(zapInterface.getAutoInstall()); + this.management.setToolUsed(zapInterface.getToolUsed()); + this.management.setSessionFilePath(zapInterface.getSessionFilePath()); } } else { @@ -145,9 +151,10 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen return false; } - boolean res; + Result res; try { res = build.getWorkspace().act(new ZAPManagementCallable(listener, this.management)); + build.setResult(res); proc.joinWithTimeout(60L, TimeUnit.MINUTES, listener); Utils.lineBreak(listener); Utils.lineBreak(listener); @@ -161,7 +168,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen } // EnvVars abc = build.getEnvironment(listener); // printMap(abc); - return res; + return res.completeBuild; } private void printMap(Map mp) { Iterator it = mp.entrySet().iterator(); @@ -190,7 +197,7 @@ public static final class ZAPManagementBuilderDescriptorImpl extends BuildStepDe /** * Used to execute ZAP remotely. */ - private static class ZAPManagementCallable implements FileCallable { + private static class ZAPManagementCallable implements FileCallable { private static final long serialVersionUID = 1L; private BuildListener listener; @@ -202,7 +209,7 @@ public ZAPManagementCallable(BuildListener listener, ZAPManagement management) { } @Override - public Boolean invoke(File f, VirtualChannel channel) { return management.executeZAP(listener, new FilePath(f)); } + public Result invoke(File f, VirtualChannel channel) { return management.executeZAP(listener, new FilePath(f)); } @Override public void checkRoles(RoleChecker checker) throws SecurityException { /* N/A */ }