diff --git a/.gitignore b/.gitignore index cefd1dcd..f01626ba 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,4 @@ bin/ .settings/ .env .DS_Store -*.iml \ No newline at end of file +*.iml diff --git a/Dockerfile b/Dockerfile index d64fbc7a..b7c3f2da 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:11.0.10-jdk-slim +FROM openjdk:11.0-jdk-slim RUN mkdir /javavulny /app COPY . /javavulny/ diff --git a/README.md b/README.md index c4f9e3d1..45366c83 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,29 @@ docker-compose up -d ./gradlew --no-daemon bootRun ``` +## Building and Running on Windows +```shell script +./gradlew.bat bootRun --args='--spring.profiles.active=windows' +``` + +### Build + +In PowerShell, with administrative privileges: + +1. [Install gradle](https://docs.gradle.org/current/userguide/installation.html#microsoft_windows_users) + 1. unpack zip file + 2. add the new gradle directory to `$env:PATH` +2. Run the gradle build: + 1. `.\gradlew.bat --no-daemon build` +3. Update the `spring.datasource.url` in your local [application.properties](https://github.com/kaakaww/javaspringvulny/blob/main/src/main/resources/application.properties) file from `spring.datasource.url=jdbc:h2:file:${PWD}/db/vulny;DB_CLOSE_ON_EXIT=FALSE;AUTO_RECONNECT=TRUE` to an absolute path. + 1. For instance: `spring.datasource.url=jdbc:h2:file:C:/Users/Dan/projects/javaspringvulny/db/vulny;DB_CLOSE_ON_EXIT=FALSE;AUTO_RECONNECT=TRUE`. + +### Run + +```shell script +.\gradlew.bat --no-daemon bootRun +``` + ## Using the Application ### Reaching the App @@ -152,9 +175,15 @@ docker run --tty --rm --network host --volume $(pwd):/hawk \ stackhawk/hawkscan stackhawk.d/stackhawk.yml stackhawk.d/stackhawk-auth-basic.yml ``` +## Examples + +Here are examples of how to use HawkScan with differently configured applications and CICD pipelines. + ### Example Specs -By default HawkScan will run with the `stackhawk.yml` file if it's defined and present, but can instead use named specs such as `hawk scan stackhawk.yml` +By default running `hawk scan` will run with the `stackhawk.yml` file in the same directory if it's defined and present, but can instead use named specs such as `hawk scan stackhawk-openapi.yml`. HawkScan also supports layering of multiple specs, such as `hawk scan stackhawk-base.yml stackhawk-windows-custom.yml` for a combined configuration. + +Look for these in the [stackhawk.d](https://github.com/kaakaww/javaspringvulny/tree/main/stackhawk.d) directory: `stackhawk-openapi.yml` - scan with OpenAPI configuration `stackhawk-custom-spider-curl.yml` scan with custom discovery using curl @@ -162,4 +191,11 @@ By default HawkScan will run with the `stackhawk.yml` file if it's defined and p `stackhawk-auth-script-form-multi.yml` scripted authentication `stackhawk-jsv-form-cookie.yml` scan with form authentication and cookie authorization `stackhawk-jsv-json-token` scan with JSON authentication and token authorization -`stackhawk-ajax.yml` - scan with the ajax spider \ No newline at end of file +`stackhawk-ajax.yml` - scan with the ajax spider + +### Example Pipelines + +These are example CICD pipelines to refer to: + +[github actions](https://github.com/kaakaww/javaspringvulny/blob/main/.github/workflows/hawkscan.yml) +[azure-pipelines](https://github.com/kaakaww/javaspringvulny/blob/main/azure-pipelines.yml) diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 00000000..b9702309 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,85 @@ +# HawkScan Scanning in Azure Pipelines +# This is a demonstration of running JavaSpringVulny (a web applications) in azure-pipelines (a cicd pipeline) with the StackHawk extension (DAST testing) +# https://marketplace.visualstudio.com/items?itemName=StackHawk.stackhawk-extensions +# https://github.com/kaakaww/javaspringvulny +# https://aka.ms/yaml + +# matrix builds for different build systems +# use `condition: eq(variables['imageName'], 'ubuntu-latest')` property to filter tasks for specific operating systems +strategy: + matrix: + windows-msi: + imageName: "windows-latest" + installerType: "msi" + windows-zip: + imageName: "windows-latest" + installerType: "zip" + linux-zip: + imageName: "ubuntu-latest" + installerType: "zip" + windows-auto: + imageName: "windows-latest" + installerType: "auto" + linux-auto: + imageName: "ubuntu-latest" + installerType: "auto" + +pool: + vmImage: $(imageName) + +trigger: + - main + +steps: + - checkout: self + + - script: echo Azure Pipelines build for $(imageName)! + displayName: "🦅 $(imageName)" + + # install the latest version of hawkscan + - task: HawkScanInstall@1 + inputs: + version: "latest" + installerType: "$(installerType)" + + # docker-compose starts the postgres database on linux os's, not on windows + - task: DockerCompose@0 + displayName: Start JavaSpringVulny on linux with docker-compose + condition: eq(variables['imageName'], 'ubuntu-latest') + inputs: + containerregistrytype: "Azure Container Registry" + dockerComposeFile: docker-compose.yml + action: Run services + + # specific path replacement for in-memory database on windows in azure-pipelines + - powershell: | + $file = 'src/main/resources/application.properties' + $find = 'spring.datasource.url=jdbc:h2:file:${PWD}/db/vulny;' + $replace = "spring.datasource.url=jdbc:h2:file:D:\\a\\1\\db\\vulny;" + (Get-Content $file).replace($find, $replace) | Set-Content $file + condition: eq(variables['imageName'], 'windows-latest') + displayName: Configure JavaSpringVulny for windows + + # azure pipelines default jdk is 8, so we upgrade to 11 to run JavaSpringVulny + # the hawkscan msi bundles java with it, so this step isn't necesarry for running HawkScan + - task: JavaToolInstaller@0 + inputs: + versionSpec: "11" + jdkArchitectureOption: "x64" + jdkSourceOption: "PreInstalled" + + # start javaspringVulny in the background + - powershell: | + start-process ./gradlew.bat bootRun + displayName: Start JavaSpringVulny on windows with gradle in the background + condition: eq(variables['imageName'], 'windows-latest') + + # run hawkscan with the StackHawk Azure Extension + - task: RunHawkScan@1 + inputs: + configFile: "stackhawk.yml" + version: "latest" + env: + HAWK_API_KEY: $(HAWK_API_KEY) # use variables in the azure devops ui to configure secrets and env vars + APP_ENV: $(imageName) + APP_ID: $(APP_ID) diff --git a/scripts/multi-cookie-auth.sh b/scripts/multi-cookie-auth.sh new file mode 100755 index 00000000..de3fc628 --- /dev/null +++ b/scripts/multi-cookie-auth.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +# Request login (XLOGINID) and session (JSESSIONID) cookies from server +curl -k -c cookie-jar.txt https://localhost:9000/login-code +# Set local JSESSIONID variable to the JSESSIONID cookie +JSESSIONID=$(awk 'match($0, /JSESSIONID.*/){print substr($0, RSTART + 11, RLENGTH)}' cookie-jar.txt ) +# Set local XLOGINID variable to the XLOGINID cookie +XLOGINID=$(awk 'match($0, /XLOGINID.*/){print substr($0, RSTART + 9, RLENGTH)}' cookie-jar.txt) +# Request page with XLOGINID and JSESSIONID cookies and extract the _csrf token +CSRF=$(curl -k -b cookie-jar.txt \ + https://localhost:9000/login-form-multi | awk 'match($0,/_csrf".*/) { print substr($0, RSTART+14, RLENGTH -17)}') +# Log into the mutli cooke endpoint using XLOGINID and JSESSIONID cookies and username/password +curl -v -k \ + -d "_csrf=${CSRF}&loginCode=${XLOGINID}&username=user&password=password&remember=on" \ + -b cookie-jar.txt \ + -H "Content-Type: application/x-www-form-urlencoded" \ + "https://localhost:9000/login-form-multi" + +# Run HawkScan injecting local variables as environment variables +hawk scan -e JSESSIONID=${JSESSIONID} -e XLOGINID=${XLOGINID} ./stackhawk.d/stackhawk-multi-cookie-auth.yml + diff --git a/src/main/java/hawk/Application.java b/src/main/java/hawk/Application.java index be2c1048..160e0ae5 100644 --- a/src/main/java/hawk/Application.java +++ b/src/main/java/hawk/Application.java @@ -66,8 +66,12 @@ public CommandLineRunner commandLineRunner(ApplicationContext ctx, ItemRepo repo System.out.println(String.format("Adding user%d", i)); userRepo.save(new User(String.format("user%d", i), String.format("we have the best users, users%d", i), "1234567")); }); + + // This should be removed once we confirm that all instances of "user" have been removed userRepo.save(new User("user", "The auth user", "1234567")); + userRepo.save(new User("janesmith", "The auth user", "1234567")); + TenantContext.setCurrentTenant("12345678"); Stream.of(4, 5, 6).forEach(i -> { System.out.println(String.format("Adding item%d", i)); diff --git a/src/main/java/hawk/MultiHttpSecurityConfig.java b/src/main/java/hawk/MultiHttpSecurityConfig.java index f3cca7a9..197ae901 100644 --- a/src/main/java/hawk/MultiHttpSecurityConfig.java +++ b/src/main/java/hawk/MultiHttpSecurityConfig.java @@ -161,7 +161,14 @@ public UserDetailsService userDetailsService() { .roles("USER") .build(); - return new InMemoryUserDetailsManager(user); + UserDetails user2 = + User.withDefaultPasswordEncoder() + .username("janesmith") + .password("password") + .roles("USER") + .build(); + + return new InMemoryUserDetailsManager(user, user2); } // "/api/okta/**" diff --git a/src/main/java/hawk/controller/LoginController.java b/src/main/java/hawk/controller/LoginController.java index f6f329c4..5a5a345e 100644 --- a/src/main/java/hawk/controller/LoginController.java +++ b/src/main/java/hawk/controller/LoginController.java @@ -105,4 +105,14 @@ public String loginFormMulti(HttpServletRequest req, } } + @GetMapping("/login-multi-check") + public String loginCheck(HttpServletRequest req, HttpServletResponse resp, Model model, @CookieValue("XLOGINID") String xLoginId) { + String sessId = req.getSession().getId(); + String loginCode = loginCodes.get("cookie-" + sessId); + if (loginCode == null || !loginCode.equals(xLoginId)) + return "redirect:/login-form-multi"; + model.addAttribute("title", "StackHawk Java Vulny Application"); + return "index"; + } + } \ No newline at end of file diff --git a/src/main/resources/application-windows.properties b/src/main/resources/application-windows.properties new file mode 100644 index 00000000..8800762a --- /dev/null +++ b/src/main/resources/application-windows.properties @@ -0,0 +1,2 @@ + +spring.datasource.url=jdbc:h2:file:D:\\a\\1\\db\\vulny;DB_CLOSE_ON_EXIT=FALSE;AUTO_RECONNECT=TRUE diff --git a/stackhawk.d/stackhawk-auth-form-cookie.yml b/stackhawk.d/stackhawk-auth-form-cookie.yml index 0f695362..3bff7986 100644 --- a/stackhawk.d/stackhawk-auth-form-cookie.yml +++ b/stackhawk.d/stackhawk-auth-form-cookie.yml @@ -10,7 +10,7 @@ app: loginPagePath: /login usernameField: username passwordField: password - scanUsername: "user" + scanUsername: "janesmith" scanPassword: "password" cookieAuthorization: cookieNames: diff --git a/stackhawk.d/stackhawk-multi-cookie-auth.yml b/stackhawk.d/stackhawk-multi-cookie-auth.yml new file mode 100644 index 00000000..56f2021f --- /dev/null +++ b/stackhawk.d/stackhawk-multi-cookie-auth.yml @@ -0,0 +1,26 @@ +app: + applicationId: ${APP_ID:test-app} + env: ${APP_ENV:Multi Cookie Auth} + openApiConf: + path: /openapi + host: ${HOST:https://localhost:9000} + excludePaths: + - "/logout" + - "/login-form-multi" + - "/login-code" + authentication: + external: + values: + - type: COOKIE + value: + name: "XLOGINID" + val: ${XLOGINID} + - type: COOKIE + value: + name: "JSESSIONID" + val: ${JSESSIONID} + testPath: + path: /login-multi-check + success: ".*200.*" + loggedInIndicator: "\\QSign Out\\E" + loggedOutIndicator: ".*Location:.*/login.*" diff --git a/stackhawk.yml b/stackhawk.yml index 5ae9e330..a2f87327 100644 --- a/stackhawk.yml +++ b/stackhawk.yml @@ -2,6 +2,10 @@ app: applicationId: ${APP_ID:dacc7d3e-babc-47d2-b040-ab117ab04526} env: ${APP_ENV:Development} host: ${APP_HOST:https://localhost:9000} + waitForAppTarget: + path: / + waitTimeoutMillis: 200000 + pollDelay: 6000 excludePaths: - "/logout" - "/login-form-multi"