BDD-Security

1. Gradle Basics

bdd-security uses the Gradle build system. Below we would have a brief introduction on gradle with the build.gradle in the bdd-security project.

1.1 import

import net.masterthought.cucumber.ReportBuilder

It imports a class at the very beginning.

1.2 buildscript

buildscript{
            repositories {
                maven {
                    url "http://repo.bodar.com"
                }
                mavenCentral()
            }

            dependencies {
                classpath "org.codehaus.gpars:gpars:1.2.1",
                        "net.masterthought:cucumber-reporting:1.4.0"
            }
        }
    ...
    repositories {
        maven {
            url "http://repo.bodar.com"
        }
        mavenCentral()
    }
    

1.2.1 buildscript

The buildScript block determines which plugins, task classes, and other classes are available for use in the rest of the build script. Without a buildScript block, you can use everything that ships with Gradle out-of-the-box. If you additionally want to use third-party plugins, task classes, or other classes (in the build script!), you have to specify the corresponding dependencies in the buildScript block.

1.2.2 repositories inside buildscript{} vs repositories in the build.gradle

  • The repositories in the buildScript block are used to fetch the dependencies of your buildScript dependencies. These are the dependencies that are put on the classpath of your build and that you can refer to from your build file. For instance extra plugins that exist on the internet.
  • The repositories on the root level are used to fetch the dependencies that your project depends on. So all the dependencies you need to compile your project.

1.3 Working with Gradle behind a proxy

Unfortunately, after hours of works, I still couldnt find out a way to work with Gradle behind an enterprise proxy.

1.3.1 Official Document

It mentioned setting up the proxy details in a properties file.

  • from gradle.properties in project build dir.
  • from gradle.properties in gradle user home.
  • from system properties, e.g. when -Dsome.property is set on the command line.
systemProp.http.proxyHost=www.somehost.org
systemProp.http.proxyPort=8080
systemProp.http.proxyUser=userid
systemProp.http.proxyPassword=password
systemProp.http.nonProxyHosts=*.nonproxyrepos.com|localhost
systemProp.https.proxyHost=www.somehost.org
systemProp.https.proxyPort=8080
systemProp.https.proxyUser=userid
systemProp.https.proxyPassword=password
systemProp.http.nonProxyHosts=*.nonproxyrepos.com|localhost

With it, I could download the gradle wrapper defined in /bdd-security/gradle/wrapper/gradle-wrapper.properties. But for maven dependencies, it is not working. Not sure why.

1.3.2 Java Networking and Proxies

$ JAVA_OPTS="-Dhttp.proxyHost=my.corp.proxy -Dhttp.proxyPort=8080 -Dhttps.proxyHost=my.corp.proxy -Dhttps.proxyPort=8080 -Dhttp.proxyUser=''xxxx/xxxxxxxx'' -Dhttp.proxyPassword=''<my_pw>'' -Dhttps.proxyUser=''xxxx/xxxxxxxx'' -Dhttps.proxyPassword=''<my_pw>''" gradle clean

Still failed. No idea.

1.3.3 Use Local repo

It is frustrating, but that is the only way I found which is working.

First download the dependencies with maven, then modify build.gradle

buildscript {
            repositories {
                mavenLocal()
            }

            dependencies {
                classpath "org.codehaus.gpars:gpars:1.2.1",
                        "net.masterthought:cucumber-reporting:1.4.0"
            }
        }
        ...
        repositories {
            mavenLocal()
        }
    

1.4 gpars

"org.codehaus.gpars:gpars:1.2.1". It is a library for groovy building.

1.5 cucumber reporting

I am not quite sure. Little document could be found.
But here are examples(1, 2).

configurations {
    cucumberRuntime {
        extendsFrom testRuntime
    }
}

task cleanReports() {
    File reportOutputDirectory = new File("build/reports/cucumber")
    reportOutputDirectory.deleteDir()
}

task cucumber() {
    dependsOn clean, cleanReports, assemble, compileTestJava
    doLast {
        javaexec {
            main = "cucumber.api.cli.Main"
            classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
            args = [''--plugin'', ''pretty'', ''--glue'', ''net.continuumsecurity.steps'', ''src/test/resources/features'']
        }
        generateReport()
    }
}

task generateReportTask() {
    doLast {
        generateReport()
    }
}

def generateReport() { ... }

test {
    systemProperties = System.properties
    dependsOn assemble, compileTestJava, cleanReports
    finalizedBy(generateReportTask)
}

//Ensure the cucumber tests are executed as part of the build. Makes for a very pretty output.
build.dependsOn cucumber

1.5.1 Task

dependsOn clean, cleanReports, assemble, compileTestJava means before running tasks - cucumber, tasks - clean, cleanReports, assemble, compileTestJava should be run first.

You could run gradle -q tasks --all to see the meaning of each task.
Ref: JAVA Plugin

  $ gradle -q tasks --all
  ...
  Build tasks
  ...
  clean - Deletes the build directory (build)
Task name Depends on Type Description
assemble All archive tasks in the project, including jar. Some plugins add additional archive tasks to the project. Task Assembles all the archives in the project.
compileTestJava compile, plus all tasks which produce the test compile classpath. JavaCompile Compiles test Java source files using javac.
clean - Delete Deletes the project build directory.

1.5.2 Cucumber options

Defines steps & features.

args = [''--plugin'', ''pretty'', ''--glue'', ''net.continuumsecurity.steps'', ''src/test/resources/features'']

1.6 dependencies

  dependencies {
    // you could also write as
    // compile ''net.masterthought:cucumber-reporting:1.4.0''
    compile group: ''net.masterthought'', name: ''cucumber-reporting'', version: "1.4.0"
    testCompile ''junit:junit:4.11''
    testCompile "info.cukes:cucumber-junit:$cucumberVersion"
    testCompile "info.cukes:cucumber-java:$cucumberVersion"
    testCompile "info.cukes:cucumber-picocontainer:$cucumberVersion"

    testCompile ''org.glassfish.jersey.core:jersey-client:2.15''
    testCompile ''com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.4.1''
    testCompile ''org.glassfish.jersey.media:jersey-media-moxy:2.15''
    testCompile ''org.apache.cxf:cxf-rt-rs-client:3.1.1''  //Jersey client
    testCompile ''junit:junit-dep:4.11''
    testCompile ''org.hamcrest:hamcrest-all:1.3''
    testCompile (''org.seleniumhq.selenium:selenium-java:2.53.1'') { exclude group: ''junit'' }
    testCompile ''org.seleniumhq.selenium:selenium-api:2.53.1''
    testCompile ''log4j:log4j:1.2.17''
    testCompile ''args4j:args4j:2.0.16''
    testCompile ''commons-configuration:commons-configuration:1.8''
    testCompile ''uk.com.robust-it:cloning:1.9.0''
    testCompile ''jline:jline:2.6''
    testCompile ''com.googlecode.java-diff-utils:diffutils:1.2.1''
    //testCompile ''org.apache.httpcomponents:httpcore:4.2.5''
    testCompile ''org.codehaus.jackson:jackson-mapper-asl:1.9.12''
    testCompile ''commons-jxpath:commons-jxpath:1.3''
    testCompile ''org.glassfish.jersey.core:jersey-client:2.6''
    testCompile ''org.glassfish.jersey.connectors:jersey-apache-connector:2.6''
    testCompile ''net.htmlparser.jericho:jericho-html:3.3''
    testCompile ''edu.umass.cs.benchlab:harlib:1.1.2''
    testCompile ''org.zaproxy:zap-clientapi:1.0.0''
    testCompile files ("lib/zap-client-1.0.0.jar", "lib/nessus-java-client-0.1-SNAPSHOT.jar","lib/jssylze-0.2-SNAPSHOT.jar")
  }

compile:
The dependencies required to compile the production source of the project.

runtime:
The dependencies required by the production classes at runtime. By default, also includes the compile time dependencies.

testCompile:
The dependencies required to compile the test source of the project. By default, also includes the compiled production classes and the compile time dependencies.

testRuntime:
The dependencies required to run the tests. By default, also includes the compile, runtime and test compile dependencies.

Ref

2. Cucumber

2.1 Gitbook

Building a Test Framework Using Cucumber-JVM · GitBook

2.2 YouTube Training

Cucumber Java Framework for begginers

2.3 Wiki:

2.4 Cucumber Options

dryRun will check if RegEx matches, doesnt actually run the test for you. Skip execution of glue code.
strict will fail the build if anything not working properly.

Glue Code is the code that interacts directly with your application. There are two kinds of Glue code – Step Definitions and Hooks.

2.5 Generating Glue Code

================
to-do

3. bdd-security

3.1 BDD-Security History

Recently, bdd-security has been migrated from JBehave + ant to Cucumber + Gradle. The documentation is not synced between Github Wiki and Offical Site.

Please be noted when pulling master branch from github, it is using cucumber + gradle.

3.1.1 Cucumber-JVM

3.1.1.1 JBehave

Pros:
GivenStories and data tables defined as external text files.

Cons:
The data table is not visible in the story itself (although it is visible in the report).

3.1.1.2 Cucumber

Pros:
- Support more JVM languages for the step files including JRuby, Jython, Groovy.
- Better integration with 3rd party tools.

Cons:
- Only supports inline tables, cant be auto-generated.

3.2 Gradle

3.2.1 Ant + Ivy

Need manually run a "resolve" task on the first installation to pull down the necessary libraries.

3.2.2 Gradle

Well supported and extremely flexible with all the lovely automatic dependency resolution of maven without the XML hell.

3.3 Features & Steps

  • Features are specified in below location.
    • bdd-security/src/test/resources/features/*
  • Steps are specified in below location.
    • bdd-security/src/test/java/net/continuumsecurity/steps/*

Please be noted you wont find a 1vs1 step corresponding to a feature.

3.4 Using bdd-security

3.4.1 Starting your target App

Example: http://localhost:8080

3.4.2 Config

For more details, visit offical wiki - Configuration.

Configuration file - /path/to/bdd-security/config.xml

<?xml version="1.0" encoding="ISO-8859-1" ?>
<web-app>

    <!-- Base URL of the application to test -->
    <baseUrl>http://localhost:8080/</baseUrl>

    <!-- A Java class to hold the Selenium steps to test the application in depth. Optionally required for in-depth authn/z and session management testing. -->
    <class>net.continuumsecurity.examples.ropeytasks.RopeyTasksApplication</class>

    <!-- Optional names of the session ID cookies for session management testing. -->
    <sessionIds>
        <name>JSESSIONID</name>
    </sessionIds>

    <!-- the default user to use when logging in to the app -->
    <defaultUsername>bob</defaultUsername>
    <defaultPassword>password</defaultPassword>

    <scanner>
        <ignoreUrl>.*logout.*</ignoreUrl>
        <spiderUrl>baseUrl</spiderUrl>
    </scanner>

    <incorrectPassword>SDFsdfwjx1</incorrectPassword>
    <incorrectUsername>bobbles</incorrectUsername>

    <zapPath>zap/zap.sh</zapPath>

  </web-app>

In the config.xml, you should define:

  1. <baseUrl> - Your target application
  2. <class> - The Java class which defines the Selenium steps
  3. <sessionIds> - Cookie name
  4. And more

3.4.3 Features

The features file define the security requirements and should be written by Security team?

Add / Modify *.features files under ./src/test/resources/features/*

3.4.4 Selenium

A Java class which defines Selenium steps. Please define it in config.xml.

Author of bdd-security has provided an example. /bdd-security/src/test/java/net/continuumsecurity/examples/ropeytasks/RopeyTasksApplication.java defines the Selenium steps. In case you need to test another app, write another class.

Override methods:

  • openLoginPage
  • login
  • isLoggedIn
  • logout

==================
To-DO

3.4.5 Select a browser

By default, bdd-security uses HtmlUnit. It seems for Scanning related features, we cant use HtmlUnit, but chrome / firefox. Depending on your firefox version, it may not work if you use the embedded firefox in Selenium. For more details, visit Marionette - WebDriver and GitHub - Marionette proxy

<!-- File: config.xml -->
<!-- The web driver to use, can be either Firefox, Chrome or HtmlUnit.  Optionally specify path to the driver (required for linux)
         Some drivers require a path to the platform specific driver binary, for example chrome needs chromedriver.  If these values are not specified, we''ll use HtmlUnit
    <defaultDriver>firefox</defaultDriver>
    <defaultDriver path="src/test/resources/drivers/chromedriver-mac">Chrome</defaultDriver> -->

3.4.6 ZAP Scan

3.4.6.1 ZAP Config

It looks like for security reason, calling a ZAP daemon to scan a site requires an API key. Please DO NOT change the key defined in ZapManager.java.

public class ZapManager {
        private final static Logger log = Logger.getLogger(ZapManager.class.getName());
        private static ZapManager instance = null;
        private int port;
        String HOST = "127.0.0.1";
        int CONNECTION_TIMEOUT = 15000; //milliseconds
        public static final String API_KEY = "zapapisecret";
        Process process;
    

3.4.6.2 Scanning

./gradlew -Dcucumber.options="--tags @app_scan --tags ~@skip" test

Alternatives

  1. Automated Security Testing Using OWASP ZAP - Software Test Academy - Ruby Capybara
  2. Using OWASP ZAP, Selenium, and Jenkins to automate your security tests - Blog - Securify B.V.
  3. GitHub - continuumsecurity/zap-webdriver: Example security tests using Selenium WebDriver and OWASP ZAP - Maven

参考

Show Comments