├── .github
├── FUNDING.yml
└── workflows
│ ├── deploy.yml
│ └── deploybeta.yml
├── .gitignore
├── .mvn
└── wrapper
│ ├── MavenWrapperDownloader.java
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── Dockerfile
├── LICENSE
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
├── src
├── main
│ ├── java
│ │ └── io
│ │ │ └── mixeway
│ │ │ └── scanner
│ │ │ ├── ScannerApplication.java
│ │ │ ├── config
│ │ │ ├── SecurityConfig.java
│ │ │ ├── SessionCredentials.java
│ │ │ └── TokenAuthenticationFilter.java
│ │ │ ├── db
│ │ │ ├── entity
│ │ │ │ ├── DependencyTrackEntity.java
│ │ │ │ ├── ScanEntity.java
│ │ │ │ └── ScannerTypeEntity.java
│ │ │ └── repository
│ │ │ │ ├── DependencyTrackRepository.java
│ │ │ │ ├── ScanRepository.java
│ │ │ │ └── ScannerTypeRepository.java
│ │ │ ├── factory
│ │ │ └── ScannerFactory.java
│ │ │ ├── integrations
│ │ │ ├── ScannerIntegrationFactory.java
│ │ │ ├── model
│ │ │ │ ├── BanditResponse.java
│ │ │ │ ├── BanditResult.java
│ │ │ │ ├── BugInstance.java
│ │ │ │ ├── BugPattern.java
│ │ │ │ ├── Component.java
│ │ │ │ ├── Components.java
│ │ │ │ ├── DTrackApiKeys.java
│ │ │ │ ├── DTrackConfigProperty.java
│ │ │ │ ├── DTrackCreateProject.java
│ │ │ │ ├── DTrackCreateProjectResponse.java
│ │ │ │ ├── DTrackGetVulnsForProject.java
│ │ │ │ ├── DTrackProject.java
│ │ │ │ ├── DTrackVuln.java
│ │ │ │ ├── DependencyTrackConfiguration.java
│ │ │ │ ├── ProgPilotVuln.java
│ │ │ │ ├── SendBomRequest.java
│ │ │ │ ├── SourceLine.java
│ │ │ │ └── SpotbugReportXML.java
│ │ │ └── scanner
│ │ │ │ ├── Bandit.java
│ │ │ │ ├── DependencyTrack.java
│ │ │ │ ├── Progpilot.java
│ │ │ │ └── Spotbug.java
│ │ │ ├── rest
│ │ │ ├── controller
│ │ │ │ └── BaseController.java
│ │ │ ├── model
│ │ │ │ ├── ScanRequest.java
│ │ │ │ └── Status.java
│ │ │ └── service
│ │ │ │ └── BaseService.java
│ │ │ ├── standalone
│ │ │ └── StandAloneService.java
│ │ │ └── utils
│ │ │ ├── CodeHelper.java
│ │ │ ├── Constants.java
│ │ │ ├── GetInfoRequest.java
│ │ │ ├── GitInformations.java
│ │ │ ├── GitOperations.java
│ │ │ ├── GitResponse.java
│ │ │ ├── MixewayConnector.java
│ │ │ ├── Pom.java
│ │ │ ├── PomBuild.java
│ │ │ ├── PomConfiguration.java
│ │ │ ├── PomPlugin.java
│ │ │ ├── PomPlugins.java
│ │ │ ├── PomProject.java
│ │ │ ├── PrepareCIOperation.java
│ │ │ ├── ScannerPluginType.java
│ │ │ ├── ScannerType.java
│ │ │ ├── SourceProjectType.java
│ │ │ ├── StandaloneGitResponse.java
│ │ │ ├── Status.java
│ │ │ └── Vulnerability.java
│ └── resources
│ │ ├── application.properties
│ │ └── db
│ │ └── changelog
│ │ └── changelog.sql
└── test
│ └── java
│ └── io
│ └── mixeway
│ └── scanner
│ └── ScannerApplicationTests.java
└── startup.sh
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [siewer]
4 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: Deploy prod version
2 | on:
3 | push:
4 | branches:
5 | - 'master'
6 | jobs:
7 | publishbrod:
8 | runs-on: ubuntu-16.04
9 | steps:
10 | - uses: actions/checkout@v1
11 | - name: docker actions build & deploy
12 | uses: docker/build-push-action@v1
13 | with:
14 | username: ${{ secrets.DOCKER_USER }}
15 | password: ${{ secrets.DOCKER_TOKEN }}
16 | repository: mixeway/scanner
17 | tags: 0.9.0
--------------------------------------------------------------------------------
/.github/workflows/deploybeta.yml:
--------------------------------------------------------------------------------
1 | name: Test Build & Deploy beta
2 | on:
3 | push:
4 | branches:
5 | - '*'
6 | - '!master'
7 | pull_request:
8 | branches:
9 | - '*'
10 | - '!master'
11 | jobs:
12 | publishbeta:
13 | runs-on: ubuntu-16.04
14 | steps:
15 | - uses: actions/checkout@v1
16 | - name: docker actions build & deploy
17 | uses: docker/build-push-action@v1
18 | with:
19 | username: ${{ secrets.DOCKER_USER }}
20 | password: ${{ secrets.DOCKER_TOKEN }}
21 | repository: mixeway/scanner
22 | tags: 0.9.0-beta
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 | /mixeway_scan_sources/
35 |
--------------------------------------------------------------------------------
/.mvn/wrapper/MavenWrapperDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2007-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | import java.net.*;
18 | import java.io.*;
19 | import java.nio.channels.*;
20 | import java.util.Properties;
21 |
22 | public class MavenWrapperDownloader {
23 |
24 | private static final String WRAPPER_VERSION = "0.5.6";
25 | /**
26 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
27 | */
28 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
29 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
30 |
31 | /**
32 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
33 | * use instead of the default one.
34 | */
35 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
36 | ".mvn/wrapper/maven-wrapper.properties";
37 |
38 | /**
39 | * Path where the maven-wrapper.jar will be saved to.
40 | */
41 | private static final String MAVEN_WRAPPER_JAR_PATH =
42 | ".mvn/wrapper/maven-wrapper.jar";
43 |
44 | /**
45 | * Name of the property which should be used to override the default download url for the wrapper.
46 | */
47 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
48 |
49 | public static void main(String args[]) {
50 | System.out.println("- Downloader started");
51 | File baseDirectory = new File(args[0]);
52 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
53 |
54 | // If the maven-wrapper.properties exists, read it and check if it contains a custom
55 | // wrapperUrl parameter.
56 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
57 | String url = DEFAULT_DOWNLOAD_URL;
58 | if (mavenWrapperPropertyFile.exists()) {
59 | FileInputStream mavenWrapperPropertyFileInputStream = null;
60 | try {
61 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
62 | Properties mavenWrapperProperties = new Properties();
63 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
64 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
65 | } catch (IOException e) {
66 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
67 | } finally {
68 | try {
69 | if (mavenWrapperPropertyFileInputStream != null) {
70 | mavenWrapperPropertyFileInputStream.close();
71 | }
72 | } catch (IOException e) {
73 | // Ignore ...
74 | }
75 | }
76 | }
77 | System.out.println("- Downloading from: " + url);
78 |
79 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
80 | if (!outputFile.getParentFile().exists()) {
81 | if (!outputFile.getParentFile().mkdirs()) {
82 | System.out.println(
83 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
84 | }
85 | }
86 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
87 | try {
88 | downloadFileFromURL(url, outputFile);
89 | System.out.println("Done");
90 | System.exit(0);
91 | } catch (Throwable e) {
92 | System.out.println("- Error downloading");
93 | e.printStackTrace();
94 | System.exit(1);
95 | }
96 | }
97 |
98 | private static void downloadFileFromURL(String urlString, File destination) throws Exception {
99 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
100 | String username = System.getenv("MVNW_USERNAME");
101 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
102 | Authenticator.setDefault(new Authenticator() {
103 | @Override
104 | protected PasswordAuthentication getPasswordAuthentication() {
105 | return new PasswordAuthentication(username, password);
106 | }
107 | });
108 | }
109 | URL website = new URL(urlString);
110 | ReadableByteChannel rbc;
111 | rbc = Channels.newChannel(website.openStream());
112 | FileOutputStream fos = new FileOutputStream(destination);
113 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
114 | fos.close();
115 | rbc.close();
116 | }
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mixeway/MixewayScanner/98c0c57b48a2012db9bcbf2e5662b2394a7c674c/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM centos:8
2 | MAINTAINER siewer
3 |
4 | # Required package installation
5 | RUN yum update -y
6 | RUN yum install java-11-openjdk-devel -y
7 | RUN yum install maven -y
8 | RUN yum install git -y
9 | RUN yum install epel-release -y
10 | RUN yum install python3-pip -y
11 | RUN pip3 install bandit
12 | RUN pip3 install pipreqs
13 | RUN yum install nodejs -y
14 | RUN yum install php-cli php-zip wget unzip php-json -y
15 | RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
16 | RUN php composer-setup.php --install-dir=/usr/local/bin --filename=composer
17 | RUN php -r "copy('https://github.com/designsecurity/progpilot/releases/download/v0.8.0/progpilot_v0.8.0.phar', 'progpilot.phar');"
18 | RUN chmod +x progpilot.phar
19 | RUN mv progpilot.phar /bin/progpilot
20 |
21 | # TLS Support
22 | RUN mkdir /opt/pki
23 | RUN openssl req -new -newkey rsa:4096 -days 3650 -nodes -x509 -subj "/O=mixeway.io/CN=mixewayscanner" -keyout certificate.key -out certificate.crt
24 | RUN openssl pkcs12 -export -in certificate.crt -inkey certificate.key -out certificate.p12 -name "mixeway" -password pass:1qaz@WSX
25 | RUN mv certificate.p12 /opt/pki/certificate.p12
26 |
27 | # Download DTrack
28 | RUN mkdir /opt/dtrack && wget https://github.com/DependencyTrack/dependency-track/releases/download/3.8.0/dependency-track-embedded.war -O /opt/dtrack/dependency-track-embedded.war
29 |
30 | # Building Mixeway Scanner APP
31 | WORKDIR /app
32 | COPY ./pom.xml ./pom.xml
33 | RUN mvn dependency:go-offline -B
34 |
35 | COPY ./src ./src
36 | RUN mvn package -DskipTests && cp target/*.jar app.jar
37 |
38 | # Copy startup script
39 | COPY ./startup.sh ./startup.sh
40 |
41 | ENTRYPOINT ["/bin/bash", "/app/startup.sh"]
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Mixeway
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Mixeway Scanner Aggregator
2 |
3 |
4 | Mixeway Scanner Aggregator is Spring Boot application which aggregate and integrate the most popular OpenSurce Vulnrability scanners avaliable.
5 |
6 | ## Supported Scanners:
7 | * OWASP Dependency Track - https://dependencytrack.org
8 | * Spotbugs - https://spotbugs.github.io
9 | * Bandit - https://github.com/PyCQA/bandit
10 |
11 |
12 | ## Scope of integration
13 | MixewayScanner can be run as REST API or standalone. In REST mode it listen for scan request which contains GIT URL
14 | for repository to be scanned. Next it clone repo, create DTrack project and send SBOM. In next phase SAST scanner is executed.
15 | Detected vulnerabilities are pushed into console or to Mixeway if integration is configured.
16 |
17 | ## Requirements
18 | * Docker installed
19 | * Sonatype OSS username and key (for projects other then NPM) - https://ossindex.sonatype.org
20 | * If Maven require to download some custom libraries, link them via `-v ~/.m2:/root/.m2`
21 |
22 | ### Running options
23 | * In standalone mode, running container inside directory You want to scan
24 | ```shell script
25 | docker run -e MODE=STANDALONE \
26 | -v ${PWD}:/opt/sources \
27 | mixeway/scanner:latest
28 | ```
29 | if source to be scaned is located in current direcory. Otherwise, use `-v /opt/sources`
30 |
31 | * In REST API mode, container is running and listetning on port :8443
32 | ```shell script
33 | docker run \
34 | -e MODE=REST \
35 | mixeway/scanner:latest
36 | ```
37 | example usage:
38 | ```$xslt
39 | GET http://localhost:8443/run
40 | {"target":"https://github.com/mixeway/mixewaybackend", "branch":"master", "type":"SAST"}
41 | ```
42 | where target is URL for repo, branch is branch name to be sanned and type is SAST (only this type is supported in current version)
43 |
44 | All options and descriptions
45 |
46 | | Option | Required | Default Value | Description |
47 | |-----------------------------------|--------------------------|------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
48 | |-e OSS_USERNAME=\ | No | null | Sonatype OSS username - required to perform dependency check on projects other then NPM -to generate- https://ossindex.sonatype.org/|
49 | |-e OSS_KEY=\ | No | null | Sonatype OSS API Key - required to perform dependency check on projects other then NPM -to generate- https://ossindex.sonatype.org/ |
50 | |-e MODE=\ | No | REST | Mode of Scanner to run, in REST Mode API is started on :8443 port, in STANDALONE mode, full scan is performed in mounted directory |
51 | |-e MIXEWAY_URL=\ | No | https://hub.mixeway.io | URL to Mixeway to push results if no Mixeway data is passed results of scan will be print to console |
52 | |-e MIXEWAY_KEY=\ | No | null | CICD API Key - to generate in user profile of Mixeway |
53 | |-e MIXEWAY_PROJECT_ID=\ | No | null | ID of project in mixeway to which detected vulnerailities will be set. Required if You want enable Mixeway integration |
54 | |-e MIXEWAY_PROJECT_NAME=\ | No | null | Name of project. Required for Mixeway integration with STANDALONE scans. |
55 | |-v \:/opt/sources | Yes (STANDALONE version) | null | Passing files to scan to docker |
56 |
57 | ## Optimization
58 | * Maven projects - in scope of mvn project, task which takes the most of a time is dependency download. To skip this part just mount
59 | the `.m2` directory into docker with `-v ~/.m2:/root/.2`
60 |
61 | ## TLS support for REST API
62 | By default Mixeway Scanner use self-signed TLS certifiate generated during `docker build` action.
63 | If You want to use Your own certificate mount it as `certificate.p12` to `/opt/pki` location (e.g. `-v /etc/pki:/opt/pki`) and then
64 | during `docker run` pass `-e PKCS12_PASSWORD=` with PKCS12 password.
65 |
66 | ## Supported Languages
67 |
68 | | Scanner version | Languages |
69 | |---|---|
70 | |v0.9.0| JAVA-MAVEN |
71 | |v0.9.1| JAVA-MAVEN, Python3|
72 | |v0.9.2| JAVA-MAVEN, Python3, PHP|
--------------------------------------------------------------------------------
/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # https://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Mingw, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | fi
118 |
119 | if [ -z "$JAVA_HOME" ]; then
120 | javaExecutable="`which javac`"
121 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
122 | # readlink(1) is not available as standard on Solaris 10.
123 | readLink=`which readlink`
124 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
125 | if $darwin ; then
126 | javaHome="`dirname \"$javaExecutable\"`"
127 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
128 | else
129 | javaExecutable="`readlink -f \"$javaExecutable\"`"
130 | fi
131 | javaHome="`dirname \"$javaExecutable\"`"
132 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
133 | JAVA_HOME="$javaHome"
134 | export JAVA_HOME
135 | fi
136 | fi
137 | fi
138 |
139 | if [ -z "$JAVACMD" ] ; then
140 | if [ -n "$JAVA_HOME" ] ; then
141 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
142 | # IBM's JDK on AIX uses strange locations for the executables
143 | JAVACMD="$JAVA_HOME/jre/sh/java"
144 | else
145 | JAVACMD="$JAVA_HOME/bin/java"
146 | fi
147 | else
148 | JAVACMD="`which java`"
149 | fi
150 | fi
151 |
152 | if [ ! -x "$JAVACMD" ] ; then
153 | echo "Error: JAVA_HOME is not defined correctly." >&2
154 | echo " We cannot execute $JAVACMD" >&2
155 | exit 1
156 | fi
157 |
158 | if [ -z "$JAVA_HOME" ] ; then
159 | echo "Warning: JAVA_HOME environment variable is not set."
160 | fi
161 |
162 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
163 |
164 | # traverses directory structure from process work directory to filesystem root
165 | # first directory with .mvn subdirectory is considered project base directory
166 | find_maven_basedir() {
167 |
168 | if [ -z "$1" ]
169 | then
170 | echo "Path not specified to find_maven_basedir"
171 | return 1
172 | fi
173 |
174 | basedir="$1"
175 | wdir="$1"
176 | while [ "$wdir" != '/' ] ; do
177 | if [ -d "$wdir"/.mvn ] ; then
178 | basedir=$wdir
179 | break
180 | fi
181 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
182 | if [ -d "${wdir}" ]; then
183 | wdir=`cd "$wdir/.."; pwd`
184 | fi
185 | # end of workaround
186 | done
187 | echo "${basedir}"
188 | }
189 |
190 | # concatenates all lines of a file
191 | concat_lines() {
192 | if [ -f "$1" ]; then
193 | echo "$(tr -s '\n' ' ' < "$1")"
194 | fi
195 | }
196 |
197 | BASE_DIR=`find_maven_basedir "$(pwd)"`
198 | if [ -z "$BASE_DIR" ]; then
199 | exit 1;
200 | fi
201 |
202 | ##########################################################################################
203 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
204 | # This allows using the maven wrapper in projects that prohibit checking in binary data.
205 | ##########################################################################################
206 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
207 | if [ "$MVNW_VERBOSE" = true ]; then
208 | echo "Found .mvn/wrapper/maven-wrapper.jar"
209 | fi
210 | else
211 | if [ "$MVNW_VERBOSE" = true ]; then
212 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
213 | fi
214 | if [ -n "$MVNW_REPOURL" ]; then
215 | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
216 | else
217 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
218 | fi
219 | while IFS="=" read key value; do
220 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
221 | esac
222 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
223 | if [ "$MVNW_VERBOSE" = true ]; then
224 | echo "Downloading from: $jarUrl"
225 | fi
226 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
227 | if $cygwin; then
228 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
229 | fi
230 |
231 | if command -v wget > /dev/null; then
232 | if [ "$MVNW_VERBOSE" = true ]; then
233 | echo "Found wget ... using wget"
234 | fi
235 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
236 | wget "$jarUrl" -O "$wrapperJarPath"
237 | else
238 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
239 | fi
240 | elif command -v curl > /dev/null; then
241 | if [ "$MVNW_VERBOSE" = true ]; then
242 | echo "Found curl ... using curl"
243 | fi
244 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
245 | curl -o "$wrapperJarPath" "$jarUrl" -f
246 | else
247 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
248 | fi
249 |
250 | else
251 | if [ "$MVNW_VERBOSE" = true ]; then
252 | echo "Falling back to using Java to download"
253 | fi
254 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
255 | # For Cygwin, switch paths to Windows format before running javac
256 | if $cygwin; then
257 | javaClass=`cygpath --path --windows "$javaClass"`
258 | fi
259 | if [ -e "$javaClass" ]; then
260 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
261 | if [ "$MVNW_VERBOSE" = true ]; then
262 | echo " - Compiling MavenWrapperDownloader.java ..."
263 | fi
264 | # Compiling the Java class
265 | ("$JAVA_HOME/bin/javac" "$javaClass")
266 | fi
267 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
268 | # Running the downloader
269 | if [ "$MVNW_VERBOSE" = true ]; then
270 | echo " - Running MavenWrapperDownloader.java ..."
271 | fi
272 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
273 | fi
274 | fi
275 | fi
276 | fi
277 | ##########################################################################################
278 | # End of extension
279 | ##########################################################################################
280 |
281 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
282 | if [ "$MVNW_VERBOSE" = true ]; then
283 | echo $MAVEN_PROJECTBASEDIR
284 | fi
285 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
286 |
287 | # For Cygwin, switch paths to Windows format before running java
288 | if $cygwin; then
289 | [ -n "$M2_HOME" ] &&
290 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
291 | [ -n "$JAVA_HOME" ] &&
292 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
293 | [ -n "$CLASSPATH" ] &&
294 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
295 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
296 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
297 | fi
298 |
299 | # Provide a "standardized" way to retrieve the CLI args that will
300 | # work with both Windows and non-Windows executions.
301 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
302 | export MAVEN_CMD_LINE_ARGS
303 |
304 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
305 |
306 | exec "$JAVACMD" \
307 | $MAVEN_OPTS \
308 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
309 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
310 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
311 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM https://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM set title of command window
39 | title %0
40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
42 |
43 | @REM set %HOME% to equivalent of $HOME
44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
45 |
46 | @REM Execute a user defined script before this one
47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
51 | :skipRcPre
52 |
53 | @setlocal
54 |
55 | set ERROR_CODE=0
56 |
57 | @REM To isolate internal variables from possible post scripts, we use another setlocal
58 | @setlocal
59 |
60 | @REM ==== START VALIDATION ====
61 | if not "%JAVA_HOME%" == "" goto OkJHome
62 |
63 | echo.
64 | echo Error: JAVA_HOME not found in your environment. >&2
65 | echo Please set the JAVA_HOME variable in your environment to match the >&2
66 | echo location of your Java installation. >&2
67 | echo.
68 | goto error
69 |
70 | :OkJHome
71 | if exist "%JAVA_HOME%\bin\java.exe" goto init
72 |
73 | echo.
74 | echo Error: JAVA_HOME is set to an invalid directory. >&2
75 | echo JAVA_HOME = "%JAVA_HOME%" >&2
76 | echo Please set the JAVA_HOME variable in your environment to match the >&2
77 | echo location of your Java installation. >&2
78 | echo.
79 | goto error
80 |
81 | @REM ==== END VALIDATION ====
82 |
83 | :init
84 |
85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
86 | @REM Fallback to current working directory if not found.
87 |
88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
90 |
91 | set EXEC_DIR=%CD%
92 | set WDIR=%EXEC_DIR%
93 | :findBaseDir
94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
95 | cd ..
96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
97 | set WDIR=%CD%
98 | goto findBaseDir
99 |
100 | :baseDirFound
101 | set MAVEN_PROJECTBASEDIR=%WDIR%
102 | cd "%EXEC_DIR%"
103 | goto endDetectBaseDir
104 |
105 | :baseDirNotFound
106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
107 | cd "%EXEC_DIR%"
108 |
109 | :endDetectBaseDir
110 |
111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
112 |
113 | @setlocal EnableExtensions EnableDelayedExpansion
114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
116 |
117 | :endReadAdditionalConfig
118 |
119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
122 |
123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
124 |
125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
127 | )
128 |
129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data.
131 | if exist %WRAPPER_JAR% (
132 | if "%MVNW_VERBOSE%" == "true" (
133 | echo Found %WRAPPER_JAR%
134 | )
135 | ) else (
136 | if not "%MVNW_REPOURL%" == "" (
137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
138 | )
139 | if "%MVNW_VERBOSE%" == "true" (
140 | echo Couldn't find %WRAPPER_JAR%, downloading it ...
141 | echo Downloading from: %DOWNLOAD_URL%
142 | )
143 |
144 | powershell -Command "&{"^
145 | "$webclient = new-object System.Net.WebClient;"^
146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
148 | "}"^
149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
150 | "}"
151 | if "%MVNW_VERBOSE%" == "true" (
152 | echo Finished downloading %WRAPPER_JAR%
153 | )
154 | )
155 | @REM End of extension
156 |
157 | @REM Provide a "standardized" way to retrieve the CLI args that will
158 | @REM work with both Windows and non-Windows executions.
159 | set MAVEN_CMD_LINE_ARGS=%*
160 |
161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
162 | if ERRORLEVEL 1 goto error
163 | goto end
164 |
165 | :error
166 | set ERROR_CODE=1
167 |
168 | :end
169 | @endlocal & set ERROR_CODE=%ERROR_CODE%
170 |
171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
175 | :skipRcPost
176 |
177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
179 |
180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
181 |
182 | exit /B %ERROR_CODE%
183 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.3.3.RELEASE
9 |
10 |
11 | io.mixeway
12 | scanner
13 | 0.0.1-SNAPSHOT
14 | scanner
15 | Application which integrate number of OpenSource scanners with Mixeway via API
16 |
17 |
18 | 1.8
19 |
20 |
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-starter-jdbc
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-security
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-starter-web
33 |
34 |
35 | org.liquibase
36 | liquibase-core
37 |
38 |
39 |
40 | com.h2database
41 | h2
42 | runtime
43 |
44 |
45 | org.springframework.boot
46 | spring-boot-starter-test
47 | test
48 |
49 |
50 | org.junit.vintage
51 | junit-vintage-engine
52 |
53 |
54 |
55 |
56 | org.springframework.security
57 | spring-security-test
58 | test
59 |
60 |
61 | org.springframework.boot
62 | spring-boot-starter-data-jpa
63 |
64 |
65 | com.h2database
66 | h2
67 | runtime
68 |
69 |
70 | org.liquibase
71 | liquibase-core
72 | 3.8.0
73 |
74 |
75 | org.springframework.boot
76 | spring-boot-starter-data-jpa
77 | RELEASE
78 | compile
79 |
80 |
81 | org.hobsoft.spring
82 | spring-rest-template-logger
83 | 2.0.0
84 |
85 |
86 |
87 | org.eclipse.jgit
88 | org.eclipse.jgit
89 | 5.8.1.202007141445-r
90 |
91 |
92 | org.hibernate
93 | hibernate-validator
94 | 6.0.13.Final
95 |
96 |
97 |
98 | commons-io
99 | commons-io
100 | 2.7
101 |
102 |
103 | junit
104 | junit
105 | 4.9
106 | test
107 |
108 |
109 |
110 | org.apache.commons
111 | commons-lang3
112 | 3.11
113 |
114 |
115 | org.apache.httpcomponents
116 | httpclient
117 | 4.5.3
118 |
119 |
120 |
121 | org.projectlombok
122 | lombok
123 | 1.18.12
124 | provided
125 |
126 |
127 |
128 | com.google.code.gson
129 | gson
130 | 2.8.5
131 |
132 |
133 | com.fasterxml.jackson.dataformat
134 | jackson-dataformat-xml
135 | 2.9.8
136 |
137 |
138 | org.codehaus.woodstox
139 | woodstox-core-asl
140 | 4.4.1
141 |
142 |
143 |
144 |
145 |
146 |
147 | org.springframework.boot
148 | spring-boot-maven-plugin
149 |
150 |
151 |
152 |
153 |
154 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/ScannerApplication.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner;
2 |
3 | import com.fasterxml.jackson.core.JsonProcessingException;
4 | import io.mixeway.scanner.factory.ScannerFactory;
5 | import io.mixeway.scanner.integrations.ScannerIntegrationFactory;
6 | import io.mixeway.scanner.standalone.StandAloneService;
7 | import io.mixeway.scanner.utils.ScannerPluginType;
8 | import io.mixeway.scanner.utils.ScannerType;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.boot.SpringApplication;
11 | import org.springframework.boot.autoconfigure.SpringBootApplication;
12 | import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication;
13 | import org.springframework.boot.autoconfigure.domain.EntityScan;
14 | import org.springframework.boot.context.event.ApplicationReadyEvent;
15 | import org.springframework.context.ApplicationContext;
16 | import org.springframework.context.annotation.ComponentScan;
17 | import org.springframework.context.annotation.Profile;
18 | import org.springframework.context.event.EventListener;
19 | import org.springframework.core.env.Environment;
20 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
21 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
22 | import org.springframework.scheduling.annotation.EnableScheduling;
23 | import org.springframework.stereotype.Service;
24 |
25 | import java.io.IOException;
26 | import java.security.KeyManagementException;
27 | import java.security.KeyStoreException;
28 | import java.security.NoSuchAlgorithmException;
29 |
30 | @SpringBootApplication(scanBasePackages = "io.mixeway.scanner")
31 | @EnableScheduling
32 | @EnableJpaRepositories("io.mixeway.scanner.db.repository")
33 | @EntityScan(basePackages = "io.mixeway.scanner.db.entity")
34 | @EnableJpaAuditing
35 | public class ScannerApplication {
36 |
37 | public static void main(String[] args) {
38 |
39 | SpringApplication.run(ScannerApplication.class, args);
40 | }
41 | }
42 |
43 | @Service
44 | @ConditionalOnNotWebApplication
45 | class StandaloneMixewayApp {
46 | private final StandAloneService standAloneService;
47 |
48 | public StandaloneMixewayApp(StandAloneService standAloneService){
49 | this.standAloneService = standAloneService;
50 | }
51 | @EventListener(ApplicationReadyEvent.class)
52 | public void runStandaloneMixewayScannerApp() throws IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException, InterruptedException {
53 | standAloneService.runScan();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/config/SecurityConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @created 2020-08-18 : 21:47
3 | * @project MixewayScanner
4 | * @author siewer
5 | */
6 | package io.mixeway.scanner.config;
7 |
8 | import org.springframework.beans.factory.annotation.Value;
9 | import org.springframework.context.annotation.Bean;
10 | import org.springframework.context.annotation.Configuration;
11 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
12 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
13 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
14 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
15 | import org.springframework.security.config.http.SessionCreationPolicy;
16 | import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
17 |
18 | @Configuration
19 | @EnableWebSecurity
20 | public class SecurityConfig extends WebSecurityConfigurerAdapter {
21 |
22 | @Value("${APIKEY:changeit}")
23 | private String apiKey;
24 |
25 | //Leave whatever you had here
26 | @Override
27 | public void configure(HttpSecurity http) throws Exception {
28 | http.addFilterBefore(new TokenAuthenticationFilter(authenticationManager()), BasicAuthenticationFilter.class);
29 |
30 |
31 | http.csrf().disable()
32 | .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
33 | .and().authorizeRequests()
34 | .antMatchers("/**").authenticated();
35 | }
36 |
37 |
38 |
39 |
40 | //Add these two below.
41 | @Override
42 | public void configure(AuthenticationManagerBuilder auth) {
43 | auth.authenticationProvider(apiKeyAuthenticationProvider());
44 | }
45 |
46 | @Bean
47 | public TokenAuthenticationProvider apiKeyAuthenticationProvider() {
48 | return new TokenAuthenticationProvider(apiKey);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/config/SessionCredentials.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @created 2020-08-18 : 21:39
3 | * @project MixewayScanner
4 | * @author siewer
5 | */
6 | package io.mixeway.scanner.config;
7 |
8 | public class SessionCredentials {
9 |
10 | String apiKey;
11 | String accessToken;
12 |
13 | public SessionCredentials(String apiKey, String accessToken) {
14 | this.apiKey = apiKey;
15 | this.accessToken = accessToken;
16 | }
17 |
18 | public String getApiKey() {
19 | return apiKey;
20 | }
21 |
22 | public String getAccessToken() {
23 | return accessToken;
24 | }
25 | }
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/config/TokenAuthenticationFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @created 2020-08-18 : 21:15
3 | * @project MixewayScanner
4 | * @author siewer
5 | */
6 | package io.mixeway.scanner.config;
7 |
8 | import org.springframework.security.authentication.*;
9 | import org.springframework.security.core.Authentication;
10 | import org.springframework.security.core.AuthenticationException;
11 | import org.springframework.security.core.context.SecurityContextHolder;
12 | import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
13 | import org.springframework.util.StringUtils;
14 | import org.springframework.web.filter.GenericFilterBean;
15 |
16 | import javax.servlet.FilterChain;
17 | import javax.servlet.ServletException;
18 | import javax.servlet.ServletRequest;
19 | import javax.servlet.ServletResponse;
20 | import javax.servlet.http.HttpServletRequest;
21 | import javax.servlet.http.HttpServletResponse;
22 | import java.io.IOException;
23 |
24 |
25 | public class TokenAuthenticationFilter extends GenericFilterBean {
26 |
27 | private final AuthenticationManager authenticationManager;
28 |
29 | public TokenAuthenticationFilter(AuthenticationManager authenticationManager) {
30 | this.authenticationManager = authenticationManager;
31 | }
32 |
33 | @Override
34 | public void doFilter(ServletRequest request,
35 | ServletResponse response,
36 | FilterChain chain) throws IOException, ServletException {
37 |
38 | HttpServletRequest httpRequest = (HttpServletRequest) request;
39 | HttpServletResponse httpResponse = (HttpServletResponse) response;
40 |
41 | String apiKey = httpRequest.getHeader("apiKey");
42 |
43 | try {
44 | if (!StringUtils.isEmpty(apiKey)) {
45 | processTokenAuthentication(apiKey);
46 | }
47 | chain.doFilter(request, response);
48 | } catch (InternalAuthenticationServiceException internalAuthenticationServiceException)
49 | {
50 | SecurityContextHolder.clearContext();
51 | logger.error("Internal authentication service exception", internalAuthenticationServiceException);
52 | httpResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
53 | }
54 | catch(AuthenticationException authenticationException)
55 | {
56 | SecurityContextHolder.clearContext();
57 | httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, authenticationException.getMessage());
58 | }
59 | }
60 |
61 | private void processTokenAuthentication(String apiKey) {
62 | SessionCredentials authCredentials = new SessionCredentials(apiKey,null);
63 | Authentication requestAuthentication = new PreAuthenticatedAuthenticationToken(authCredentials, authCredentials);
64 | Authentication resultOfAuthentication = tryToAuthenticate(requestAuthentication);
65 | SecurityContextHolder.getContext().setAuthentication(resultOfAuthentication);
66 | }
67 |
68 | private Authentication tryToAuthenticate(Authentication requestAuthentication) {
69 | Authentication responseAuthentication = authenticationManager.authenticate(requestAuthentication);
70 | if (responseAuthentication == null || !responseAuthentication.isAuthenticated()) {
71 | throw new InternalAuthenticationServiceException("Unable to authenticate Domain User for provided credentials");
72 | }
73 | return responseAuthentication;
74 | }
75 | }
76 |
77 | class TokenAuthenticationProvider implements AuthenticationProvider {
78 |
79 | private final String apiKey;
80 |
81 | public TokenAuthenticationProvider(String apiKey) {
82 | this.apiKey = apiKey;
83 | }
84 |
85 | @Override
86 | public Authentication authenticate(Authentication authentication) throws AuthenticationException {
87 | SessionCredentials credentials = (SessionCredentials) authentication.getCredentials();
88 | if (credentials != null && credentials.apiKey.equals(this.apiKey)) {
89 |
90 | //Also evaluate the token here
91 |
92 | Authentication newAuthentication = new PreAuthenticatedAuthenticationToken(apiKey, credentials);
93 | newAuthentication.setAuthenticated(true);
94 | return newAuthentication;
95 | }
96 | throw new BadCredentialsException("Incorrect ApiKey");
97 | }
98 |
99 | @Override
100 | public boolean supports(Class> aClass) {
101 | return aClass.equals(PreAuthenticatedAuthenticationToken.class);
102 | }
103 | }
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/db/entity/DependencyTrackEntity.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.db.entity;
2 |
3 | import io.mixeway.scanner.integrations.scanner.DependencyTrack;
4 | import org.springframework.boot.autoconfigure.domain.EntityScan;
5 | import org.springframework.data.jpa.domain.support.AuditingEntityListener;
6 |
7 | import javax.persistence.*;
8 |
9 | @Entity
10 | @EntityScan
11 | @Table(name = "dependencytrack")
12 | @EntityListeners(AuditingEntityListener.class)
13 | public class DependencyTrackEntity {
14 | @Id
15 | @GeneratedValue(strategy = GenerationType.IDENTITY)
16 | private Long id;
17 | private boolean enabled;
18 | @Column(name = "apikey")
19 | private String apiKey;
20 |
21 | public Long getId() {
22 | return id;
23 | }
24 |
25 | public void setId(Long id) {
26 | this.id = id;
27 | }
28 |
29 | public boolean isEnabled() {
30 | return enabled;
31 | }
32 |
33 | public void setEnabled(boolean enabled) {
34 | this.enabled = enabled;
35 | }
36 |
37 | public String getApiKey() {
38 | return apiKey;
39 | }
40 |
41 | public void setApiKey(String apiKey) {
42 | this.apiKey = apiKey;
43 | }
44 | public DependencyTrackEntity() {}
45 | public DependencyTrackEntity(String apiKey){
46 | this.enabled = false;
47 | this.apiKey =apiKey;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/db/entity/ScanEntity.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.db.entity;
2 |
3 | import org.hibernate.annotations.OnDelete;
4 | import org.hibernate.annotations.OnDeleteAction;
5 | import org.springframework.boot.autoconfigure.domain.EntityScan;
6 | import org.springframework.data.jpa.domain.support.AuditingEntityListener;
7 |
8 | import javax.persistence.*;
9 | import java.util.Date;
10 |
11 | @Entity
12 | @EntityScan
13 | @Table(name = "scan")
14 | @EntityListeners(AuditingEntityListener.class)
15 | public class ScanEntity {
16 | @Id
17 | @GeneratedValue(strategy = GenerationType.IDENTITY)
18 | private Long id;
19 | private Date date;
20 | @ManyToOne(fetch = FetchType.LAZY, optional = false)
21 | @JoinColumn(name = "scannertype_id", nullable = false)
22 | @OnDelete(action = OnDeleteAction.CASCADE)
23 | private ScannerTypeEntity scannerType;
24 | private boolean running;
25 |
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/db/entity/ScannerTypeEntity.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.db.entity;
2 |
3 | import org.springframework.boot.autoconfigure.domain.EntityScan;
4 | import org.springframework.data.jpa.domain.support.AuditingEntityListener;
5 |
6 | import javax.persistence.*;
7 |
8 | @Entity
9 | @EntityScan
10 | @Table(name = "scannertype")
11 | @EntityListeners(AuditingEntityListener.class)
12 | public class ScannerTypeEntity {
13 | @Id
14 | @GeneratedValue(strategy = GenerationType.IDENTITY)
15 | private Long id;
16 | private String name;
17 |
18 | public Long getId() {
19 | return id;
20 | }
21 |
22 | public void setId(Long id) {
23 | this.id = id;
24 | }
25 |
26 | public String getName() {
27 | return name;
28 | }
29 |
30 | public void setName(String name) {
31 | this.name = name;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/db/repository/DependencyTrackRepository.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.db.repository;
2 |
3 | import io.mixeway.scanner.db.entity.DependencyTrackEntity;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 | import org.springframework.stereotype.Repository;
6 |
7 | import java.util.Optional;
8 |
9 | @Repository
10 | public interface DependencyTrackRepository extends JpaRepository {
11 | Optional findByEnabledAndApiKeyNotNull(boolean enabled);
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/db/repository/ScanRepository.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.db.repository;
2 |
3 | import io.mixeway.scanner.db.entity.ScanEntity;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 | import org.springframework.stereotype.Repository;
6 |
7 | @Repository
8 | public interface ScanRepository extends JpaRepository {
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/db/repository/ScannerTypeRepository.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.db.repository;
2 |
3 | import io.mixeway.scanner.db.entity.ScannerTypeEntity;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 | import org.springframework.stereotype.Repository;
6 |
7 | @Repository
8 | public interface ScannerTypeRepository extends JpaRepository {
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/factory/ScannerFactory.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.factory;
2 |
3 | import io.mixeway.scanner.integrations.ScannerIntegrationFactory;
4 | import io.mixeway.scanner.integrations.scanner.Bandit;
5 | import io.mixeway.scanner.integrations.scanner.DependencyTrack;
6 | import io.mixeway.scanner.integrations.scanner.Progpilot;
7 | import io.mixeway.scanner.integrations.scanner.Spotbug;
8 | import io.mixeway.scanner.rest.model.ScanRequest;
9 | import io.mixeway.scanner.utils.*;
10 | import org.apache.commons.io.FileUtils;
11 | import org.apache.commons.io.filefilter.DirectoryFileFilter;
12 | import org.apache.commons.io.filefilter.RegexFileFilter;
13 | import org.springframework.stereotype.Service;
14 |
15 | import java.io.File;
16 | import java.util.ArrayList;
17 | import java.util.List;
18 | import java.util.stream.Collectors;
19 |
20 | @Service
21 | public class ScannerFactory {
22 | private final DependencyTrack dependencyTrack;
23 | private final Spotbug spotbug;
24 | private final Bandit bandit;
25 | private final Progpilot progpilot;
26 |
27 | public ScannerFactory(DependencyTrack dependencyTrack, Spotbug spotbug,
28 | Bandit bandit, Progpilot progpilot){
29 | this.dependencyTrack = dependencyTrack;
30 | this.spotbug = spotbug;
31 | this.bandit = bandit;
32 | this.progpilot = progpilot;
33 | }
34 |
35 | /**
36 | * Method which takes proper vulnerability scanner based on a type
37 | *
38 | * @param type type of a scanner
39 | * @return returning factory of given type
40 | */
41 | public ScannerIntegrationFactory getProperScanner(ScannerPluginType type) {
42 | ScannerIntegrationFactory scanner = null;
43 | switch (type) {
44 | case DEPENDENCYTRACK:
45 | scanner = dependencyTrack;
46 | break;
47 | case SPOTBUG:
48 | scanner = spotbug;
49 | break;
50 | case BANDIT:
51 | scanner = bandit;
52 | break;
53 | case PROGPILOT:
54 | scanner = progpilot;
55 | break;
56 | }
57 | return scanner;
58 | }
59 |
60 | public List runScanForLanguage(SourceProjectType sourceProjectType) throws Exception {
61 | List vulnerabilityList = new ArrayList<>();
62 | switch (sourceProjectType) {
63 | case NPM:
64 | List packagePaths= FileUtils.listFiles(
65 | new File(CodeHelper.getProjectPath(new ScanRequest(), true)),
66 | new RegexFileFilter(Constants.PACKAGE_FILENAME),
67 | DirectoryFileFilter.DIRECTORY
68 | ).stream()
69 | .map(File::getAbsoluteFile)
70 | .map(file -> file.toString()
71 | .split(File.separatorChar + Constants.PACKAGE_FILENAME)[0])
72 | .collect(Collectors.toList());
73 | vulnerabilityList.addAll(dependencyTrack.runScanStandalone(packagePaths));
74 | break;
75 | case PHP:
76 | vulnerabilityList.addAll(dependencyTrack.runScanStandalone());
77 | vulnerabilityList.addAll(progpilot.runScanStandalone());
78 | break;
79 | case PIP:
80 | vulnerabilityList.addAll(dependencyTrack.runScanStandalone());
81 | vulnerabilityList.addAll(bandit.runScanStandalone());
82 | break;
83 | case MAVEN:
84 | List mvnPackagePaths= FileUtils.listFiles(
85 | new File(CodeHelper.getProjectPath(new ScanRequest(), true)),
86 | new RegexFileFilter(Constants.POM_FILENAME),
87 | DirectoryFileFilter.DIRECTORY
88 | ).stream()
89 | .map(File::getAbsoluteFile)
90 | .map(file -> file.toString()
91 | .split(File.separatorChar + Constants.POM_FILENAME)[0])
92 | .collect(Collectors.toList());
93 | vulnerabilityList.addAll(dependencyTrack.runScanStandalone());
94 | for (String mvnPath : mvnPackagePaths) {
95 | vulnerabilityList.addAll(spotbug.runScanStandalone(mvnPath)
96 | .stream()
97 | .filter(vulnerability -> vulnerability.getCategory().equals(Constants.SPOTBUG_CATEGORY_SECURITY) ||
98 | vulnerability.getCategory().equals(Constants.SPOTBUG_CATEGORY_MALICIOUS_CODE))
99 | .collect(Collectors.toList()));
100 | }
101 | break;
102 | case GRADLE:
103 | break;
104 | }
105 | return vulnerabilityList.stream().distinct().collect(Collectors.toList());
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/ScannerIntegrationFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @created 2020-08-18 : 22:43
3 | * @project MixewayScanner
4 | * @author siewer
5 | */
6 | package io.mixeway.scanner.integrations;
7 |
8 | import io.mixeway.scanner.rest.model.ScanRequest;
9 | import io.mixeway.scanner.utils.Vulnerability;
10 |
11 | import java.util.List;
12 |
13 | public interface ScannerIntegrationFactory {
14 | void prepare() throws Exception;
15 | List runScan(ScanRequest scanRequest) throws Exception;
16 | List runScanStandalone() throws Exception;
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/model/BanditResponse.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.integrations.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * @author gsiewruk
9 | */
10 | @JsonIgnoreProperties(ignoreUnknown = true)
11 | public class BanditResponse {
12 | List results;
13 |
14 | public List getResults() {
15 | return results;
16 | }
17 |
18 | public void setResults(List results) {
19 | this.results = results;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/model/BanditResult.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.integrations.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4 |
5 | /**
6 | * @author gsiewruk
7 | */
8 | @JsonIgnoreProperties(ignoreUnknown = true)
9 | public class BanditResult {
10 | private String line_number;
11 | private String filename;
12 | private String issue_text;
13 | private String test_name;
14 | private String more_info;
15 | private String issue_severity;
16 | private String code;
17 |
18 | public String getLine_number() {
19 | return line_number;
20 | }
21 |
22 | public void setLine_number(String line_number) {
23 | this.line_number = line_number;
24 | }
25 |
26 | public String getFilename() {
27 | return filename;
28 | }
29 |
30 | public void setFilename(String filename) {
31 | this.filename = filename;
32 | }
33 |
34 | public String getIssue_text() {
35 | return issue_text;
36 | }
37 |
38 | public void setIssue_text(String issue_text) {
39 | this.issue_text = issue_text;
40 | }
41 |
42 | public String getTest_name() {
43 | return test_name;
44 | }
45 |
46 | public void setTest_name(String test_name) {
47 | this.test_name = test_name;
48 | }
49 |
50 | public String getMore_info() {
51 | return more_info;
52 | }
53 |
54 | public void setMore_info(String more_info) {
55 | this.more_info = more_info;
56 | }
57 |
58 | public String getIssue_severity() {
59 | return issue_severity;
60 | }
61 |
62 | public void setIssue_severity(String issue_severity) {
63 | this.issue_severity = issue_severity;
64 | }
65 |
66 | public String getCode() {
67 | return code;
68 | }
69 |
70 | public void setCode(String code) {
71 | this.code = code;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/model/BugInstance.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.integrations.model;
2 |
3 | import javax.xml.bind.annotation.*;
4 |
5 | /**
6 | * @author gsiewruk
7 | */
8 | @XmlRootElement(name = "BugInstance")
9 | @XmlAccessorType(XmlAccessType.FIELD)
10 | public class BugInstance {
11 | @XmlAttribute
12 | private String cweid;
13 | @XmlAttribute
14 | private String rank;
15 | @XmlAttribute
16 | private String abbrev;
17 | @XmlAttribute
18 | private String category;
19 | @XmlAttribute
20 | private String priority;
21 | @XmlAttribute
22 | private String type;
23 | @XmlElement(name = "LongMessage")
24 | private String longMessage;
25 | @XmlElement(name = "ShortMessage")
26 | private String shortDescription;
27 | @XmlElement(name= "SourceLine")
28 | private SourceLine sourceLine;
29 | @XmlElement(name= "Details")
30 | private String details;
31 |
32 | public String getShortDescription() {
33 | return shortDescription;
34 | }
35 |
36 | public void setShortDescription(String shortDescription) {
37 | this.shortDescription = shortDescription;
38 | }
39 |
40 | public String getDetails() {
41 | return details;
42 | }
43 |
44 | public void setDetails(String details) {
45 | this.details = details;
46 | }
47 |
48 | public SourceLine getSourceLine() {
49 | return sourceLine;
50 | }
51 |
52 | public void setSourceLine(SourceLine sourceLine) {
53 | this.sourceLine = sourceLine;
54 | }
55 |
56 | public String getCweid() {
57 | return cweid;
58 | }
59 |
60 | public void setCweid(String cweid) {
61 | this.cweid = cweid;
62 | }
63 |
64 | public String getRank() {
65 | return rank;
66 | }
67 |
68 | public void setRank(String rank) {
69 | this.rank = rank;
70 | }
71 |
72 | public String getAbbrev() {
73 | return abbrev;
74 | }
75 |
76 | public void setAbbrev(String abbrev) {
77 | this.abbrev = abbrev;
78 | }
79 |
80 | public String getCategory() {
81 | return category;
82 | }
83 |
84 | public void setCategory(String category) {
85 | this.category = category;
86 | }
87 |
88 | public String getPriority() {
89 | return priority;
90 | }
91 |
92 | public void setPriority(String priority) {
93 | this.priority = priority;
94 | }
95 |
96 | public String getType() {
97 | return type;
98 | }
99 |
100 | public void setType(String type) {
101 | this.type = type;
102 | }
103 |
104 | public String getLongMessage() {
105 | return longMessage;
106 | }
107 |
108 | public void setLongMessage(String longMessage) {
109 | this.longMessage = longMessage;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/model/BugPattern.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.integrations.model;
2 |
3 | import javax.xml.bind.annotation.XmlAccessType;
4 | import javax.xml.bind.annotation.XmlAccessorType;
5 | import javax.xml.bind.annotation.XmlElement;
6 | import javax.xml.bind.annotation.XmlRootElement;
7 |
8 | /**
9 | * @author gsiewruk
10 | */
11 | @XmlRootElement(name = "BugPattern")
12 | @XmlAccessorType(XmlAccessType.FIELD)
13 | public class BugPattern {
14 | @XmlElement(name = "ShortDescription")
15 | private String shortDescriptions;
16 | @XmlElement(name = "Details")
17 | private String details;
18 |
19 |
20 | public String getShortDescriptions() {
21 | return shortDescriptions;
22 | }
23 |
24 | public void setShortDescriptions(String shortDescriptions) {
25 | this.shortDescriptions = shortDescriptions;
26 | }
27 |
28 | public String getDetails() {
29 | return details;
30 | }
31 |
32 | public void setDetails(String details) {
33 | this.details = details;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/model/Component.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.integrations.model;
2 |
3 | public class Component {
4 | private String group;
5 | private String name;
6 | private String version;
7 | private String description;
8 |
9 | public String getGroup() {
10 | return group;
11 | }
12 |
13 | public void setGroup(String group) {
14 | this.group = group;
15 | }
16 |
17 | public String getName() {
18 | return name;
19 | }
20 |
21 | public void setName(String name) {
22 | this.name = name;
23 | }
24 |
25 | public String getVersion() {
26 | return version;
27 | }
28 |
29 | public void setVersion(String version) {
30 | this.version = version;
31 | }
32 |
33 | public String getDescription() {
34 | return description;
35 | }
36 |
37 | public void setDescription(String description) {
38 | this.description = description;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/model/Components.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.integrations.model;
2 |
3 | import java.util.List;
4 |
5 | public class Components {
6 | private List components;
7 |
8 | public List getComponents() {
9 | return components;
10 | }
11 |
12 | public void setComponents(List components) {
13 | this.components = components;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/model/DTrackApiKeys.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @created 2020-08-18 : 22:18
3 | * @project MixewayScanner
4 | * @author siewer
5 | */
6 | package io.mixeway.scanner.integrations.model;
7 |
8 | public class DTrackApiKeys {
9 | String key;
10 |
11 | public String getKey() {
12 | return key;
13 | }
14 |
15 | public void setKey(String key) {
16 | this.key = key;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/model/DTrackConfigProperty.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @created 2020-08-18 : 22:43
3 | * @project MixewayScanner
4 | * @author siewer
5 | */
6 | package io.mixeway.scanner.integrations.model;
7 |
8 | public class DTrackConfigProperty {
9 | String groupName;
10 | String propertyName;
11 | Object propertyValue;
12 |
13 | public DTrackConfigProperty(String groupName, String propertyName, Object propertyValue){
14 | this.groupName = groupName;
15 | this.propertyName = propertyName;
16 | this.propertyValue = propertyValue;
17 | }
18 |
19 | public String getGroupName() {
20 | return groupName;
21 | }
22 |
23 | public void setGroupName(String groupName) {
24 | this.groupName = groupName;
25 | }
26 |
27 | public String getPropertyName() {
28 | return propertyName;
29 | }
30 |
31 | public void setPropertyName(String propertyName) {
32 | this.propertyName = propertyName;
33 | }
34 |
35 | public Object getPropertyValue() {
36 | return propertyValue;
37 | }
38 |
39 | public void setPropertyValue(Object propertyValue) {
40 | this.propertyValue = propertyValue;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/model/DTrackCreateProject.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.integrations.model;
2 |
3 | public class DTrackCreateProject {
4 | private String name;
5 |
6 | public DTrackCreateProject(String name){
7 | this.name = name;
8 | }
9 |
10 | public String getName() {
11 | return name;
12 | }
13 |
14 | public void setName(String name) {
15 | this.name = name;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/model/DTrackCreateProjectResponse.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.integrations.model;
2 |
3 | public class DTrackCreateProjectResponse {
4 | private String name;
5 | private String uuid;
6 |
7 | public String getName() {
8 | return name;
9 | }
10 |
11 | public void setName(String name) {
12 | this.name = name;
13 | }
14 |
15 | public String getUuid() {
16 | return uuid;
17 | }
18 |
19 | public void setUuid(String uuid) {
20 | this.uuid = uuid;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/model/DTrackGetVulnsForProject.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.integrations.model;
2 |
3 | import java.util.List;
4 |
5 | public class DTrackGetVulnsForProject {
6 | private List dTrackVulns;
7 |
8 | public List getdTrackVulns() {
9 | return dTrackVulns;
10 | }
11 |
12 | public void setdTrackVulns(List dTrackVulns) {
13 | this.dTrackVulns = dTrackVulns;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/model/DTrackProject.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.integrations.model;
2 |
3 | public class DTrackProject {
4 | private String name;
5 | private String uuid;
6 |
7 | public String getName() {
8 | return name;
9 | }
10 |
11 | public void setName(String name) {
12 | this.name = name;
13 | }
14 |
15 | public String getUuid() {
16 | return uuid;
17 | }
18 |
19 | public void setUuid(String uuid) {
20 | this.uuid = uuid;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/model/DTrackVuln.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.integrations.model;
2 |
3 | import java.sql.Timestamp;
4 | import java.util.List;
5 |
6 | public class DTrackVuln {
7 | private String vulnId;
8 | private String source;
9 | private String description;
10 | private Timestamp published;
11 | private String recommendation;
12 | private String references;
13 | private String Severity;
14 | private List components;
15 |
16 | public String getVulnId() {
17 | return vulnId;
18 | }
19 |
20 | public void setVulnId(String vulnId) {
21 | this.vulnId = vulnId;
22 | }
23 |
24 | public String getSource() {
25 | return source;
26 | }
27 |
28 | public void setSource(String source) {
29 | this.source = source;
30 | }
31 |
32 | public String getDescription() {
33 | return description;
34 | }
35 |
36 | public void setDescription(String description) {
37 | this.description = description;
38 | }
39 |
40 | public Timestamp getPublished() {
41 | return published;
42 | }
43 |
44 | public void setPublished(Timestamp published) {
45 | this.published = published;
46 | }
47 |
48 | public String getSeverity() {
49 | return Severity;
50 | }
51 |
52 | public void setSeverity(String severity) {
53 | Severity = severity;
54 | }
55 |
56 | public List getComponents() {
57 | return components;
58 | }
59 |
60 | public void setComponents(List components) {
61 | this.components = components;
62 | }
63 |
64 | public String getRecommendation() {
65 | return recommendation;
66 | }
67 |
68 | public void setRecommendation(String recommendation) {
69 | this.recommendation = recommendation;
70 | }
71 |
72 | public String getReferences() {
73 | return references;
74 | }
75 |
76 | public void setReferences(String references) {
77 | this.references = references;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/model/DependencyTrackConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @created 2020-08-18 : 18:19
3 | * @project MixewayScanner
4 | * @author siewer
5 | */
6 | package io.mixeway.scanner.integrations.model;
7 |
8 | import java.util.List;
9 |
10 | public class DependencyTrackConfiguration {
11 | String uuid;
12 | String name;
13 | List apiKeys;
14 |
15 | public List getApiKeys() {
16 | return apiKeys;
17 | }
18 |
19 | public void setApiKeys(List apiKeys) {
20 | this.apiKeys = apiKeys;
21 | }
22 |
23 | public String getUuid() {
24 | return uuid;
25 | }
26 |
27 | public void setUuid(String uuid) {
28 | this.uuid = uuid;
29 | }
30 |
31 | public String getName() {
32 | return name;
33 | }
34 |
35 | public void setName(String name) {
36 | this.name = name;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/model/ProgPilotVuln.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.integrations.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4 |
5 | /**
6 | * @author gsiewruk
7 | */
8 | @JsonIgnoreProperties(ignoreUnknown = true)
9 | public class ProgPilotVuln {
10 | private int[] source_line;
11 | private String[] source_file;
12 | private String vuln_name;
13 | private String vuln_cwe;
14 |
15 |
16 |
17 | public String getVuln_name() {
18 | return vuln_name;
19 | }
20 |
21 | public void setVuln_name(String vuln_name) {
22 | this.vuln_name = vuln_name;
23 | }
24 |
25 | public String getVuln_cwe() {
26 | return vuln_cwe;
27 | }
28 |
29 | public void setVuln_cwe(String vuln_cwe) {
30 | this.vuln_cwe = vuln_cwe;
31 | }
32 |
33 | public int[] getSource_line() {
34 | return source_line;
35 | }
36 |
37 | public void setSource_line(int[] source_line) {
38 | this.source_line = source_line;
39 | }
40 |
41 | public String[] getSource_file() {
42 | return source_file;
43 | }
44 |
45 | public void setSource_file(String[] source_file) {
46 | this.source_file = source_file;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/model/SendBomRequest.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.integrations.model;
2 |
3 | /**
4 | * @author gsiewruk
5 | */
6 | public class SendBomRequest {
7 |
8 | private String project;
9 | private String bom;
10 |
11 |
12 | public SendBomRequest(String project, String bom) {
13 | this.project = project;
14 | this.bom = bom;
15 | }
16 |
17 | public String getProject() {
18 | return project;
19 | }
20 |
21 | public void setProject(String project) {
22 | this.project = project;
23 | }
24 |
25 | public String getBom() {
26 | return bom;
27 | }
28 |
29 | public void setBom(String bom) {
30 | this.bom = bom;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/model/SourceLine.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.integrations.model;
2 |
3 | import javax.xml.bind.annotation.XmlAccessType;
4 | import javax.xml.bind.annotation.XmlAccessorType;
5 | import javax.xml.bind.annotation.XmlAttribute;
6 | import javax.xml.bind.annotation.XmlRootElement;
7 |
8 | /**
9 | * @author gsiewruk
10 | */
11 | @XmlRootElement(name = "SourceLine")
12 | @XmlAccessorType(XmlAccessType.FIELD)
13 | public class SourceLine {
14 | @XmlAttribute
15 | private String start;
16 | @XmlAttribute
17 | private String end;
18 | @XmlAttribute
19 | private String sourcefile;
20 | @XmlAttribute
21 | private String classname;
22 | @XmlAttribute
23 | private String sourcepath;
24 |
25 | public String getStart() {
26 | return start;
27 | }
28 |
29 | public void setStart(String start) {
30 | this.start = start;
31 | }
32 |
33 | public String getEnd() {
34 | return end;
35 | }
36 |
37 | public void setEnd(String end) {
38 | this.end = end;
39 | }
40 |
41 | public String getSourcefile() {
42 | return sourcefile;
43 | }
44 |
45 | public void setSourcefile(String sourcefile) {
46 | this.sourcefile = sourcefile;
47 | }
48 |
49 | public String getClassname() {
50 | return classname;
51 | }
52 |
53 | public void setClassname(String classname) {
54 | this.classname = classname;
55 | }
56 |
57 | public String getSourcepath() {
58 | return sourcepath;
59 | }
60 |
61 | public void setSourcepath(String sourcepath) {
62 | this.sourcepath = sourcepath;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/model/SpotbugReportXML.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.integrations.model;
2 |
3 | import javax.xml.bind.annotation.XmlAccessType;
4 | import javax.xml.bind.annotation.XmlAccessorType;
5 | import javax.xml.bind.annotation.XmlElement;
6 | import javax.xml.bind.annotation.XmlRootElement;
7 | import java.util.List;
8 |
9 | /**
10 | * @author gsiewruk
11 | */
12 | @XmlRootElement(name = "BugCollection")
13 | @XmlAccessorType(XmlAccessType.FIELD)
14 | public class SpotbugReportXML {
15 | @XmlElement(name="BugInstance")
16 | List bugInstanceList;
17 | @XmlElement(name="BugPattern")
18 | List bugPatterns;
19 |
20 | public List getBugPatterns() {
21 | return bugPatterns;
22 | }
23 |
24 | public void setBugPatterns(List bugPatterns) {
25 | this.bugPatterns = bugPatterns;
26 | }
27 |
28 | public List getBugInstanceList() {
29 | return bugInstanceList;
30 | }
31 |
32 | public void setBugInstanceList(List bugInstanceList) {
33 | this.bugInstanceList = bugInstanceList;
34 | }
35 |
36 | public SpotbugReportXML processSeverity() {
37 | if (this.bugInstanceList != null) {
38 | this.bugInstanceList.stream().filter(bi -> bi.getPriority() == null).forEach(info -> info.setPriority("Info"));
39 | this.bugInstanceList.stream().filter(bi -> bi.getPriority().equals("1")).forEach(high -> high.setPriority("High"));
40 | this.bugInstanceList.stream().filter(bi -> bi.getPriority().equals("2")).forEach(high -> high.setPriority("Medium"));
41 | this.bugInstanceList.stream().filter(bi -> bi.getPriority().equals("3")).forEach(high -> high.setPriority("Low"));
42 | this.bugInstanceList.stream().filter(bi -> bi.getPriority().equals("4")).forEach(high -> high.setPriority("Info"));
43 | }
44 | return this;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/scanner/Bandit.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.integrations.scanner;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import io.mixeway.scanner.integrations.ScannerIntegrationFactory;
5 | import io.mixeway.scanner.integrations.model.BanditResponse;
6 | import io.mixeway.scanner.integrations.model.BanditResult;
7 | import io.mixeway.scanner.rest.model.ScanRequest;
8 | import io.mixeway.scanner.utils.CodeHelper;
9 | import io.mixeway.scanner.utils.Vulnerability;
10 | import org.apache.commons.io.IOUtils;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 | import org.springframework.security.core.parameters.P;
14 | import org.springframework.stereotype.Component;
15 |
16 | import java.io.File;
17 | import java.io.IOException;
18 | import java.nio.charset.StandardCharsets;
19 | import java.util.ArrayList;
20 | import java.util.Collection;
21 | import java.util.List;
22 |
23 | /**
24 | * Bandit Python scanner integration - https://github.com/PyCQA/bandit
25 | * @author gsiewruk
26 | */
27 | @Component
28 | public class Bandit implements ScannerIntegrationFactory {
29 | private final static Logger log = LoggerFactory.getLogger(Spotbug.class);
30 | @Override
31 | public void prepare() throws Exception {
32 |
33 | }
34 |
35 | /**
36 | * Running Bandit scan with 'bandit -r . --format json' and then parse json response into object
37 | *
38 | * @param scanRequest to get directory
39 | * @throws Exception
40 | */
41 | @Override
42 | public List runScan(ScanRequest scanRequest) throws Exception {
43 | log.info("[Bandit] Starting to Scan app {}", scanRequest.getTarget());
44 | String projectDirectory = CodeHelper.getProjectPath(scanRequest, false);
45 | ProcessBuilder packageApp = new ProcessBuilder("bash", "-c", "bandit -r . --format json > bandit.vulns");
46 | packageApp.directory(new File(projectDirectory));
47 | Process packageAppProcess = packageApp.start();
48 | packageAppProcess.waitFor();
49 |
50 | BanditResponse banditResponse = processBanditReport(projectDirectory + File.separatorChar + "bandit.vulns");
51 | log.info("[Bandit] Scan completed");
52 | return convertBanditResposeIntoVulnerabilities(banditResponse);
53 | }
54 |
55 | private List convertBanditResposeIntoVulnerabilities(BanditResponse banditResponse) {
56 | List vulnerabilities = new ArrayList<>();
57 | for (BanditResult banditResult : banditResponse.getResults()){
58 | vulnerabilities.add(new Vulnerability(banditResult));
59 | }
60 | return vulnerabilities;
61 | }
62 |
63 | /**
64 | * Parsing bandit's json response into object
65 | *
66 | * @param reportPath path to bandit report
67 | */
68 | private BanditResponse processBanditReport(String reportPath) throws IOException {
69 | ObjectMapper objectMapper = new ObjectMapper();
70 | return objectMapper.readValue(new File(reportPath), BanditResponse.class);
71 | }
72 |
73 | @Override
74 | public List runScanStandalone() throws Exception {
75 | log.info("[Bandit] Starting to Scan app ");
76 | String projectDirectory = CodeHelper.getProjectPath(new ScanRequest(), true);
77 | ProcessBuilder packageApp = new ProcessBuilder("bash", "-c", "bandit -r . --format json > bandit.vulns");
78 | packageApp.directory(new File(projectDirectory));
79 | Process packageAppProcess = packageApp.start();
80 | packageAppProcess.waitFor();
81 |
82 | BanditResponse banditResponse = processBanditReport(projectDirectory + File.separatorChar + "bandit.vulns");
83 | log.info("[Bandit] Scan completed");
84 | return convertBanditResposeIntoVulnerabilities(banditResponse);
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/scanner/DependencyTrack.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @created 2020-08-18 : 22:43
3 | * @project MixewayScanner
4 | * @author siewer
5 | */
6 | package io.mixeway.scanner.integrations.scanner;
7 |
8 | import io.mixeway.scanner.db.entity.DependencyTrackEntity;
9 | import io.mixeway.scanner.db.repository.DependencyTrackRepository;
10 | import io.mixeway.scanner.integrations.ScannerIntegrationFactory;
11 | import io.mixeway.scanner.integrations.model.*;
12 | import io.mixeway.scanner.rest.model.ScanRequest;
13 | import io.mixeway.scanner.utils.Constants;
14 | import io.mixeway.scanner.utils.CodeHelper;
15 | import io.mixeway.scanner.utils.SourceProjectType;
16 | import io.mixeway.scanner.utils.Vulnerability;
17 | import org.apache.commons.io.FileUtils;
18 | import org.apache.tomcat.util.codec.binary.Base64;
19 | import org.hobsoft.spring.resttemplatelogger.LoggingCustomizer;
20 | import org.slf4j.Logger;
21 | import org.slf4j.LoggerFactory;
22 | import org.springframework.beans.factory.annotation.Autowired;
23 | import org.springframework.beans.factory.annotation.Value;
24 | import org.springframework.boot.web.client.RestTemplateBuilder;
25 | import org.springframework.core.ParameterizedTypeReference;
26 | import org.springframework.http.*;
27 | import org.springframework.stereotype.Component;
28 | import org.springframework.web.client.HttpClientErrorException;
29 | import org.springframework.web.client.HttpServerErrorException;
30 | import org.springframework.web.client.ResourceAccessException;
31 | import org.springframework.web.client.RestTemplate;
32 |
33 | import java.io.File;
34 | import java.io.IOException;
35 | import java.nio.charset.StandardCharsets;
36 | import java.util.*;
37 | import java.util.concurrent.TimeUnit;
38 |
39 | @Component
40 | public class DependencyTrack implements ScannerIntegrationFactory {
41 | private final static Logger log = LoggerFactory.getLogger(DependencyTrack.class);
42 | private DependencyTrackRepository dependencyTrackRepository;
43 | @Value("${sonatype.oss.username}")
44 | private String ossUsername;
45 | @Value("${sonatype.oss.key}")
46 | private String ossKey;
47 |
48 | @Autowired
49 | public DependencyTrack(DependencyTrackRepository dependencyTrackRepository){
50 | this.dependencyTrackRepository = dependencyTrackRepository;
51 | }
52 |
53 | public DependencyTrack(){}
54 |
55 | /**
56 | * Verify if Dependency Track is initialized - DependencyTrack has enabled=true and apiKey not null
57 | */
58 | @Override
59 | public void prepare() throws Exception {
60 | Optional dependencyTrackEntity = dependencyTrackRepository.findByEnabledAndApiKeyNotNull(true);
61 | if (!dependencyTrackEntity.isPresent()){
62 | changePassword();
63 | getApiKey();
64 | setOssIntegration();
65 | }
66 | }
67 |
68 | /**
69 | * Loading vulnerabilities from dependency-track
70 | * @param dependencyTrack to get url and api
71 | * @param uuid of project to check
72 | */
73 | private List loadVulnerabilities(DependencyTrackEntity dependencyTrack, String uuid ){
74 | RestTemplate restTemplate = new RestTemplate();
75 | HttpHeaders headers = new HttpHeaders();
76 | headers.set(Constants.DEPENDENCYTRACK_APIKEY_HEADER, dependencyTrack.getApiKey());
77 | HttpEntity entity = new HttpEntity<>(headers);
78 | ResponseEntity> response = restTemplate.exchange(Constants.DEPENDENCYTRACK_URL +
79 | Constants.DEPENDENCYTRACK_URL_VULNS + uuid, HttpMethod.GET, entity, new ParameterizedTypeReference>() {
80 | });
81 | if (response.getStatusCode() == HttpStatus.OK) {
82 | return response.getBody();
83 | } else {
84 | log.error("[Dependency Track] Unable to get Findings from Dependency Track for project {}", uuid);
85 | }
86 | return null;
87 | }
88 |
89 | /**
90 | * Setting sonatype integration
91 | *
92 | */
93 | private void setOssIntegration() throws Exception {
94 | Optional dependencyTrack = dependencyTrackRepository.findByEnabledAndApiKeyNotNull(false);
95 | if (!dependencyTrack.isPresent()) {
96 | throw new Exception("[Dependency Track] Cannot change config for not initialized scanner");
97 | }
98 | RestTemplate restTemplate = new RestTemplate();
99 | HttpHeaders headers = new HttpHeaders();
100 | headers.set(HttpHeaders.AUTHORIZATION, "Bearer " + getOAuthToken());
101 | headers.setContentType(MediaType.APPLICATION_JSON);
102 | HttpEntity entity = new HttpEntity<>(prepareOssIntegration(ossUsername,ossKey),headers);
103 | ResponseEntity response = restTemplate.exchange(Constants.DEPENDENCYTRACK_URL +
104 | Constants.DEPENDENCYTRACK_URL_OSS_CONFIG, HttpMethod.POST, entity, String.class);
105 | if (response.getStatusCode().equals(HttpStatus.OK)){
106 | dependencyTrack.get().setEnabled(true);
107 | dependencyTrackRepository.save(dependencyTrack.get());
108 | log.info("[Dependency Track] Successfully set OSS integration. DependencyTrack activated");
109 | }
110 | }
111 |
112 | /**
113 | * Preparing request body for seting sonatype oss integration
114 | *
115 | * @param ossUsername username taken from ENV variable
116 | * @param ossKey apiKey taken from ENV variable
117 | * @return array of elements
118 | */
119 | private DTrackConfigProperty[] prepareOssIntegration(String ossUsername, String ossKey) {
120 | return new DTrackConfigProperty[]{
121 | new DTrackConfigProperty("scanner","ossindex.enabled", true),
122 | new DTrackConfigProperty("scanner","ossindex.api.username", ossUsername),
123 | new DTrackConfigProperty("scanner","ossindex.api.token", ossKey)
124 | };
125 | }
126 |
127 | /**
128 | * Using obtained oAuth token to check apiKey which is set for Automation team and then save it to DB
129 | */
130 | private void getApiKey() {
131 | RestTemplate restTemplate = new RestTemplate();
132 | HttpHeaders headers = new HttpHeaders();
133 | headers.set(HttpHeaders.AUTHORIZATION, "Bearer " + getOAuthToken());
134 | HttpEntity entity = new HttpEntity<>(headers);
135 | ResponseEntity response = restTemplate.exchange(Constants.DEPENDENCYTRACK_URL +
136 | Constants.DEPENDENCYTRACK_URL_APIKEY, HttpMethod.GET, entity, DependencyTrackConfiguration[].class);
137 | if (response.getStatusCode().equals(HttpStatus.OK)){
138 | List dependencyTrackConfigurations = Arrays.asList(response.getBody());
139 | String apiKey = dependencyTrackConfigurations
140 | .stream()
141 | .filter(c -> c.getName().equals(Constants.DEPENDENCYTRACK_AUTOMATION))
142 | .findFirst()
143 | .orElse(null)
144 | .getApiKeys()
145 | .stream().findFirst().orElse(null)
146 | .getKey();
147 | String automationTeamUuid = dependencyTrackConfigurations
148 | .stream()
149 | .filter(c -> c.getName().equals(Constants.DEPENDENCYTRACK_AUTOMATION))
150 | .findFirst()
151 | .orElse(null)
152 | .getUuid();
153 | setPermissions(automationTeamUuid);
154 | dependencyTrackRepository.save(new DependencyTrackEntity(apiKey));
155 | log.info("[Dependency Track] Successfully saved apiKey");
156 | }
157 |
158 | }
159 |
160 | /**
161 | * Default API user doesn't have permission to view or create projects, those hase to be added
162 | *
163 | * @param automationTeamUuid
164 | */
165 | private void setPermissions(String automationTeamUuid) {
166 | RestTemplate restTemplate = new RestTemplateBuilder()
167 | .customizers(new LoggingCustomizer())
168 | .build();
169 | HttpHeaders headers = new HttpHeaders();
170 | headers.setBearerAuth(getOAuthToken());
171 | headers.setContentType(MediaType.APPLICATION_JSON);
172 | HttpEntity entity = new HttpEntity<>("{}",headers);
173 | String[] permissions = new String[] {"ACCESS_MANAGEMENT", "BOM_UPLOAD","PORTFOLIO_MANAGEMENT","PROJECT_CREATION_UPLOAD","SYSTEM_CONFIGURATION","VIEW_PORTFOLIO","VULNERABILITY_ANALYSIS"};
174 | for (String permision : permissions) {
175 | ResponseEntity response = restTemplate.exchange(Constants.DEPENDENCYTRACK_URL +
176 | Constants.DEPENDENCYTRACK_URL_PERMISSIONS + permision + "/team/" + automationTeamUuid, HttpMethod.POST, entity, String.class);
177 |
178 | }
179 | log.info("[Dependency Track] Permission for API enabled");
180 | }
181 |
182 |
183 | /**
184 | * whole scan logic, get UUID or create project, generate BOM, upload it to DTrack and then load vulnerabilities
185 | *
186 | * @throws Exception
187 | */
188 | @Override
189 | public List runScan(ScanRequest scanRequest) throws Exception {
190 | this.prepare();
191 | Optional dependencyTrack = dependencyTrackRepository.findByEnabledAndApiKeyNotNull(true);
192 | if(dependencyTrack.isPresent()) {
193 | String uuid = getDTrackProjectUuid(dependencyTrack.get(),scanRequest, false);
194 | SourceProjectType sourceProjectType = CodeHelper.getSourceProjectTypeFromDirectory(scanRequest, false);
195 | if (sourceProjectType == null){
196 | throw new Exception("Unknown project type. Supported: MVN, NPM, Composer, PIP");
197 | }
198 | log.info("[Dependency Track] Get UUID {} and type of project {}", uuid, sourceProjectType);
199 | String bomPath = generateBom(scanRequest, sourceProjectType, false, null);
200 | if (bomPath == null) {
201 | throw new Exception("SBOM path appears to be null");
202 | }
203 | sendBomToDTrack(dependencyTrack.get(), uuid, bomPath);
204 | //Sleep untill DTrack audit the bom
205 | TimeUnit.SECONDS.sleep(50);
206 | log.info("[Dependency Track] Scan completed");
207 | return convertDTrackResponseToVulnerabilities(loadVulnerabilities(dependencyTrack.get(),uuid));
208 | } else {
209 | log.error("[Dependency Track] Trying to run scan on not properly initialized scanner. " +
210 | "This should not happen, please collect log and issue ticket.");
211 | }
212 | return new ArrayList<>();
213 | }
214 |
215 |
216 | private List convertDTrackResponseToVulnerabilities(List loadVulnerabilities) {
217 | List vulnerabilities = new ArrayList<>();
218 | for (DTrackVuln dTrackVuln : loadVulnerabilities){
219 | vulnerabilities.add(new Vulnerability(dTrackVuln));
220 | }
221 | return vulnerabilities;
222 | }
223 |
224 | /**
225 | * Running standalone scan
226 | */
227 | @Override
228 | public List runScanStandalone() throws Exception {
229 | this.prepare();
230 | Optional dependencyTrack = dependencyTrackRepository.findByEnabledAndApiKeyNotNull(true);
231 | if(dependencyTrack.isPresent()) {
232 | String uuid = getDTrackProjectUuid(dependencyTrack.get(),new ScanRequest(), true);
233 | SourceProjectType sourceProjectType = CodeHelper.getSourceProjectTypeFromDirectory(new ScanRequest(), true);
234 | if (sourceProjectType == null){
235 | throw new Exception("Unknown project type. Supported: MVN, NPM, Composer, PIP");
236 | }
237 | log.info("[Dependency Track] Get UUID {} and type of project {}", uuid, sourceProjectType);
238 | String bomPath = generateBom(new ScanRequest(), sourceProjectType, true,null);
239 | if (bomPath == null) {
240 | throw new Exception("SBOM path appears to be null");
241 | }
242 | sendBomToDTrack(dependencyTrack.get(), uuid, bomPath);
243 | //Sleep untill DTrack audit the bom
244 | TimeUnit.SECONDS.sleep(60);
245 | log.info("[Dependency Track] Scan completed");
246 | return convertDTrackResponseToVulnerabilities(loadVulnerabilities(dependencyTrack.get(),uuid));
247 | } else {
248 | log.error("[Dependency Track] Trying to run scan on not properly initialized scanner. " +
249 | "This should not happen, please collect log and issue ticket.");
250 | }
251 | return new ArrayList<>();
252 | }
253 |
254 | /**
255 | * Method which uploads SBOM to Dependency Track
256 | *
257 | * @param dependencyTrackEntity for URL and api key
258 | * @param uuid UUID of project on DTrack to attach SBOM
259 | * @param bomPath location of file to upload
260 | */
261 | private void sendBomToDTrack(DependencyTrackEntity dependencyTrackEntity, String uuid, String bomPath) throws IOException {
262 | RestTemplate restTemplate = new RestTemplate();
263 | HttpHeaders headers = new HttpHeaders();
264 | headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
265 | headers.set(Constants.DEPENDENCYTRACK_APIKEY_HEADER, dependencyTrackEntity.getApiKey());
266 | HttpEntity entity = new HttpEntity<>(new SendBomRequest(uuid, encodeFileToBase64Binary(bomPath)), headers);
267 | ResponseEntity response = restTemplate.exchange(Constants.DEPENDENCYTRACK_URL +
268 | Constants.DEPENDENCYTRACK_URL_UPLOAD_BOM, HttpMethod.PUT, entity, String.class);
269 | if (response.getStatusCode().equals(HttpStatus.OK)){
270 | log.info("[Dependency Track] SBOM for {} uploaded successfully", uuid);
271 | }
272 | }
273 |
274 | /**
275 | * Encodes file content to base64
276 | * @param fileName file name to encode
277 | * @return return base64 string
278 | * @throws IOException
279 | */
280 | private static String encodeFileToBase64Binary(String fileName) throws IOException {
281 | File file = new File(fileName);
282 | byte[] encoded = Base64.encodeBase64(FileUtils.readFileToByteArray(file));
283 | return new String(encoded, StandardCharsets.US_ASCII);
284 | }
285 |
286 | /**
287 | * Generation of SBOM using CycloneDX plugin which depend on technology. Required for this method is language of project and path to location
288 | *
289 | * @param scanRequest needed to get location of source code
290 | * @param sourceProjectType needed to determine which type of execution to be done
291 | * @return return path to SBOM file
292 | */
293 | private String generateBom(ScanRequest scanRequest, SourceProjectType sourceProjectType, boolean standalone, String path) throws IOException, InterruptedException {
294 | String directory = path!=null ? path : CodeHelper.getProjectPath(scanRequest, standalone);
295 | ProcessBuilder install, generate;
296 | Process installProcess, generateProcess;
297 |
298 | switch (sourceProjectType) {
299 | case PIP:
300 | ProcessBuilder freeze = new ProcessBuilder("bash", "-c", "pipreqs . --force");
301 | install = new ProcessBuilder("bash", "-c", "pip3 install cyclonedx-bom");
302 | generate = new ProcessBuilder("bash", "-c", "cyclonedx-py -i requirements.txt -o bom.xml");
303 | freeze.directory(new File(directory));
304 | Process freezeProcess = freeze.start();
305 | freezeProcess.waitFor();
306 | log.info("[Dependency Track] Freezing PIP dependencies for {}", directory);
307 | install.directory(new File(directory));
308 | installProcess = install.start();
309 | installProcess.waitFor();
310 | log.info("[Dependency Track] Installed CycloneDX PIP for {}", directory);
311 | generate.directory(new File(directory));
312 | generateProcess = generate.start();
313 | generateProcess.waitFor();
314 | log.info("[Dependency Track] Generated SBOM for {}", directory);
315 | return directory + File.separatorChar + "bom.xml";
316 | case NPM:
317 | install = new ProcessBuilder("bash", "-c", "npm install -g @cyclonedx/bom");
318 | install.directory(new File(directory));
319 | installProcess = install.start();
320 | installProcess.waitFor();
321 | log.info("[Dependency Track] Installed CycloneDX NPM for {}", directory);
322 | generate = new ProcessBuilder("bash", "-c", "cyclonedx-bom -o bom.xml");
323 | generate.directory(new File(directory));
324 | generateProcess = generate.start();
325 | generateProcess.waitFor();
326 | log.info("[Dependency Track] Generated SBOM for {}", directory);
327 | return directory + File.separatorChar + "bom.xml";
328 | case MAVEN:
329 | generate = new ProcessBuilder("bash", "-c", "mvn -DskipTests -DSPDXParser.OnlyUseLocalLicenses=true org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom").inheritIO();
330 | generate.directory(new File(directory));
331 | generateProcess = generate.start();
332 | generateProcess.waitFor();
333 | log.info("[Dependency Track] Generated SBOM for {}", directory);
334 | return directory + File.separatorChar + "target" + File.separatorChar + "bom.xml";
335 | case GRADLE:
336 | log.error("[Dependency Track] GRADLE not yet supported");
337 | break;
338 | case PHP:
339 | install = new ProcessBuilder("bash", "-c", "composer require --dev cyclonedx/cyclonedx-php-composer");
340 | install.directory(new File(directory));
341 | installProcess = install.start();
342 | installProcess.waitFor();
343 | log.info("[Dependency Track] Installed CycloneDX COMPOSER for {}", directory);
344 | generate = new ProcessBuilder("bash", "-c", "composer make-bom");
345 | generate.directory(new File(directory));
346 | generateProcess = generate.start();
347 | generateProcess.waitFor();
348 | log.info("[Dependency Track] Generated SBOM for {}", directory);
349 | return directory + File.separatorChar + "bom.xml";
350 | default:
351 | return null;
352 | }
353 | return null;
354 | }
355 |
356 | /**
357 | * Getting oAuth token for Dependency track using default username and password
358 | *
359 | * @return oAuth token
360 | */
361 | private String getOAuthToken(){
362 | RestTemplate restTemplate = new RestTemplate();
363 | HttpHeaders headers = new HttpHeaders();
364 | headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
365 | HttpEntity entity = new HttpEntity<>(Constants.DEPENDENCYTRACK_LOGIN_STRING, headers);
366 | ResponseEntity response = restTemplate.exchange(Constants.DEPENDENCYTRACK_URL +
367 | Constants.DEPENDENCYTRACK_URL_LOGIN, HttpMethod.POST, entity, String.class);
368 | if (response.getStatusCode().equals(HttpStatus.OK)){
369 | return response.getBody();
370 | }
371 | return null;
372 | }
373 |
374 | /**
375 | * Loading projects from DependencyTrack to check if project is already created on platform
376 | *
377 | * @return list of projects
378 | */
379 | private List getProjects(DependencyTrackEntity dependencyTrackEntity) {
380 | RestTemplate restTemplate = new RestTemplate();
381 | HttpHeaders headers = new HttpHeaders();
382 | headers.set(Constants.DEPENDENCYTRACK_APIKEY_HEADER, dependencyTrackEntity.getApiKey());
383 | HttpEntity entity = new HttpEntity<>(headers);
384 | try {
385 | ResponseEntity> response = restTemplate.exchange(Constants.DEPENDENCYTRACK_URL +
386 | Constants.DEPENDENCYTRACK_GET_PROJECTS, HttpMethod.GET, entity, new ParameterizedTypeReference>() {});
387 | if (response.getStatusCode() == HttpStatus.OK) {
388 | return response.getBody();
389 | } else {
390 | log.error("[Dependency Track] Unable to load Dependency Track projects");
391 | }
392 | } catch (HttpClientErrorException | HttpServerErrorException | ResourceAccessException e){
393 | log.error("[Dependency Track] Error during getting Dependency Track project list {}", e.getLocalizedMessage());
394 | }
395 | return null;
396 | }
397 |
398 | /**
399 | * Saving project to DependencyTrack
400 | *
401 | * @param dependencyTrackEntity needed for ApiKey
402 | * @param name name of project to be created
403 | * @return uuid of project
404 | */
405 | private String createProject(DependencyTrackEntity dependencyTrackEntity, String name, String branch, boolean standalone) {
406 | RestTemplate restTemplate = new RestTemplate();
407 | HttpHeaders headers = new HttpHeaders();
408 | headers.set(Constants.DEPENDENCYTRACK_APIKEY_HEADER, dependencyTrackEntity.getApiKey());
409 | headers.setContentType(MediaType.APPLICATION_JSON);
410 | HttpEntity entity = new HttpEntity<>(new DTrackCreateProject(standalone? UUID.randomUUID().toString() : name + "_" + branch),headers);
411 | try {
412 | ResponseEntity response = restTemplate.exchange(Constants.DEPENDENCYTRACK_URL +
413 | Constants.DEPENDENCYTRACK_GET_PROJECTS, HttpMethod.PUT, entity, DTrackCreateProjectResponse.class);
414 | if (response.getStatusCode() == HttpStatus.CREATED) {
415 | log.info("[Dependency Track] Successfully created Dependency Track project for {} with UUID {}", name ,response.getBody().getUuid());
416 | return response.getBody().getUuid();
417 | } else {
418 | log.error("[Dependency Track] Unable to to create project Dependency Track for project {}", name);
419 | }
420 | } catch (HttpClientErrorException | HttpServerErrorException e){
421 | log.error("[Dependency Track] Error during Creation of project for {} with code {}", name, e.getStatusCode());
422 | }
423 | return null;
424 | }
425 |
426 | /**
427 | * Change default admin password - DTrack require admin after first login to force password change
428 | *
429 | */
430 | private void changePassword() {
431 | RestTemplate restTemplate = new RestTemplate();
432 | HttpHeaders headers = new HttpHeaders();
433 | headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
434 | HttpEntity entity = new HttpEntity<>(Constants.DEPENDENCYTRACK_CHANGE_PASSWORD_STRING, headers);
435 | ResponseEntity response = restTemplate.exchange(Constants.DEPENDENCYTRACK_URL +
436 | Constants.DEPENDENCYTRACK_URL_CHANGE_PASSWORD, HttpMethod.POST, entity, String.class);
437 | if (response.getStatusCode().equals(HttpStatus.OK)){
438 | log.info("[Dependency Track] Default admin password changed");
439 | }
440 | }
441 |
442 | /**
443 | * Method which return UUID for project on DependencyTrack by ScanRequest.class.
444 | * If project is present it simply return its UUID, if project is not present it is being created
445 | *
446 | * @param dependencyTrackEntity entity for apiKey usage
447 | * @param scanRequest request with name and url repo
448 | * @return UUID on dependency track
449 | */
450 | private String getDTrackProjectUuid(DependencyTrackEntity dependencyTrackEntity, ScanRequest scanRequest, boolean standalone){
451 | List dTrackProjects = getProjects(dependencyTrackEntity);
452 | String projectName;
453 | if (standalone){
454 | projectName = UUID.randomUUID().toString();
455 | } else {
456 | projectName = CodeHelper.getNameFromRepoUrlforSAST(scanRequest.getTarget(), standalone) + "_" + scanRequest.getBranch();
457 | }
458 | if (dTrackProjects!= null && dTrackProjects.size() > 0) {
459 | Optional dTrackProject = dTrackProjects
460 | .stream()
461 | .filter(p -> p.getName().equals(projectName))
462 | .findFirst();
463 | if (dTrackProject.isPresent()){
464 | return dTrackProject.get().getUuid();
465 | } else {
466 | return createProject(dependencyTrackEntity, CodeHelper.getNameFromRepoUrlforSAST(scanRequest.getTarget(), standalone), scanRequest.getBranch(), standalone);
467 | }
468 | } else {
469 | return createProject(dependencyTrackEntity, CodeHelper.getNameFromRepoUrlforSAST(scanRequest.getTarget(), standalone), scanRequest.getBranch(), standalone);
470 | }
471 | }
472 |
473 | /**
474 | * Running DTrack scan for given path, NPM only supported
475 | * @param packagePath path where package.json is located
476 | * @return
477 | */
478 | public List runScanStandalone(List packagePath) throws Exception {
479 | this.prepare();
480 | List vulns = new ArrayList<>();
481 | List uuids = new ArrayList<>();
482 | Optional dependencyTrack = dependencyTrackRepository.findByEnabledAndApiKeyNotNull(true);
483 | if(dependencyTrack.isPresent()) {
484 | for (String path : packagePath) {
485 | String uuid = getDTrackProjectUuid(dependencyTrack.get(), new ScanRequest(), true);
486 | //Only NPM supported ATM
487 | //SourceProjectType sourceProjectType = CodeHelper.getSourceProjectTypeFromDirectory(new ScanRequest(), true);
488 |
489 | log.info("[Dependency Track] Get UUID {} and type of project {}", uuid, SourceProjectType.NPM);
490 | String bomPath = generateBom(new ScanRequest(), SourceProjectType.NPM, true, path);
491 | if (bomPath == null) {
492 | throw new Exception("SBOM path appears to be null");
493 | }
494 | sendBomToDTrack(dependencyTrack.get(), uuid, bomPath);
495 | uuids.add(uuid);
496 | log.info("[Dependency Track] Scan completed for {}", path);
497 | }
498 | //Sleep untill DTrack audit the bom
499 | TimeUnit.SECONDS.sleep(60);
500 | for (String uuid : uuids){
501 | vulns.addAll(convertDTrackResponseToVulnerabilities(loadVulnerabilities(dependencyTrack.get(), uuid)));
502 | }
503 | return vulns;
504 |
505 | } else {
506 | log.error("[Dependency Track] Trying to run scan on not properly initialized scanner. " +
507 | "This should not happen, please collect log and issue ticket.");
508 | }
509 | return new ArrayList<>();
510 | }
511 | }
512 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/scanner/Progpilot.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.integrations.scanner;
2 |
3 | import com.fasterxml.jackson.core.type.TypeReference;
4 | import com.fasterxml.jackson.databind.ObjectMapper;
5 | import io.mixeway.scanner.integrations.ScannerIntegrationFactory;
6 | import io.mixeway.scanner.integrations.model.BanditResponse;
7 | import io.mixeway.scanner.integrations.model.ProgPilotVuln;
8 | import io.mixeway.scanner.rest.model.ScanRequest;
9 | import io.mixeway.scanner.utils.CodeHelper;
10 | import io.mixeway.scanner.utils.Vulnerability;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 | import org.springframework.security.core.parameters.P;
14 | import org.springframework.stereotype.Component;
15 |
16 | import java.io.File;
17 | import java.io.IOException;
18 | import java.util.ArrayList;
19 | import java.util.List;
20 |
21 | /**
22 | * Progpilot PHP scanner integration - https://github.com/designsecurity/progpilot
23 | * @author gsiewruk
24 | */
25 | @Component
26 | public class Progpilot implements ScannerIntegrationFactory {
27 | private final static Logger log = LoggerFactory.getLogger(Progpilot.class);
28 | @Override
29 | public void prepare() throws Exception {
30 |
31 | }
32 |
33 | @Override
34 | public List runScan(ScanRequest scanRequest) throws Exception {
35 | log.info("[Progpilot] Starting to package app {}", scanRequest.getTarget());
36 | String projectDirectory = CodeHelper.getProjectPath(scanRequest, false);
37 | ProcessBuilder packageApp = new ProcessBuilder("bash", "-c", "progpilot . > progpilot.vulns");
38 | packageApp.directory(new File(projectDirectory));
39 | Process packageAppProcess = packageApp.start();
40 | packageAppProcess.waitFor();
41 | log.info("[Progpilot] Scan completed");
42 | List progPilotVulns = processProgPilotReport(projectDirectory + File.separatorChar + "progpilot.vulns");
43 | return convertProgpilotReportToVulns(progPilotVulns);
44 | }
45 |
46 | private List convertProgpilotReportToVulns(List progPilotVulns) {
47 | List vulnerabilities = new ArrayList<>();
48 | for (ProgPilotVuln progPilotVuln : progPilotVulns) {
49 | vulnerabilities.add(new Vulnerability(progPilotVuln));
50 | }
51 | return vulnerabilities;
52 | }
53 |
54 | @Override
55 | public List runScanStandalone() throws Exception {
56 | log.info("[Progpilot] Starting to package app ");
57 | String projectDirectory = CodeHelper.getProjectPath(new ScanRequest(), true);
58 | ProcessBuilder packageApp = new ProcessBuilder("bash", "-c", "progpilot . > progpilot.vulns");
59 | packageApp.directory(new File(projectDirectory));
60 | Process packageAppProcess = packageApp.start();
61 | packageAppProcess.waitFor();
62 | log.info("[Progpilot] Scan completed");
63 | List progPilotVulns = processProgPilotReport(projectDirectory + File.separatorChar + "progpilot.vulns");
64 | return convertProgpilotReportToVulns(progPilotVulns);
65 | }
66 | /**
67 | * Parsing bandit's json response into object
68 | *
69 | * @param reportPath path to bandit report
70 | */
71 | private List processProgPilotReport(String reportPath) throws IOException {
72 | ObjectMapper objectMapper = new ObjectMapper();
73 | return objectMapper.readValue(new File(reportPath), new TypeReference>(){});
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/integrations/scanner/Spotbug.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @created 2020-08-18 : 22:43
3 | * @project MixewayScanner
4 | * @author siewer
5 | */
6 | package io.mixeway.scanner.integrations.scanner;
7 |
8 |
9 | import com.fasterxml.jackson.annotation.JsonInclude;
10 | import com.fasterxml.jackson.core.JsonProcessingException;
11 | import com.fasterxml.jackson.databind.DeserializationFeature;
12 | import com.fasterxml.jackson.dataformat.xml.XmlMapper;
13 | import io.mixeway.scanner.integrations.ScannerIntegrationFactory;
14 | import io.mixeway.scanner.integrations.model.BugInstance;
15 | import io.mixeway.scanner.integrations.model.SpotbugReportXML;
16 | import io.mixeway.scanner.rest.model.ScanRequest;
17 | import io.mixeway.scanner.rest.service.BaseService;
18 | import io.mixeway.scanner.utils.*;
19 | import org.slf4j.Logger;
20 | import org.slf4j.LoggerFactory;
21 | import org.springframework.stereotype.Component;
22 | import org.w3c.dom.Document;
23 | import org.w3c.dom.Element;
24 | import org.w3c.dom.Node;
25 | import org.w3c.dom.NodeList;
26 | import org.xml.sax.InputSource;
27 | import org.xml.sax.SAXException;
28 |
29 | import javax.xml.bind.JAXBContext;
30 | import javax.xml.bind.JAXBException;
31 | import javax.xml.bind.Unmarshaller;
32 | import javax.xml.parsers.DocumentBuilder;
33 | import javax.xml.parsers.DocumentBuilderFactory;
34 | import javax.xml.parsers.ParserConfigurationException;
35 | import javax.xml.transform.Transformer;
36 | import javax.xml.transform.TransformerConfigurationException;
37 | import javax.xml.transform.TransformerException;
38 | import javax.xml.transform.TransformerFactory;
39 | import javax.xml.transform.dom.DOMSource;
40 | import javax.xml.transform.stream.StreamResult;
41 | import java.io.*;
42 | import java.nio.charset.StandardCharsets;
43 | import java.nio.file.Files;
44 | import java.nio.file.Path;
45 | import java.nio.file.Paths;
46 | import java.util.ArrayList;
47 | import java.util.List;
48 | import java.util.concurrent.TimeUnit;
49 | import java.util.stream.Collectors;
50 | import java.util.stream.Stream;
51 |
52 | @Component
53 | public class Spotbug implements ScannerIntegrationFactory {
54 | private final static Logger log = LoggerFactory.getLogger(Spotbug.class);
55 | @Override
56 | public void prepare() {
57 |
58 | }
59 |
60 | /**
61 | * Running proper command
62 | * @param scanRequest
63 | */
64 | @Override
65 | public List runScan(ScanRequest scanRequest) throws IOException, InterruptedException {
66 | log.info("[Spotbug] Starting to package app {}", scanRequest.getTarget());
67 | List spotbugReportXMLS = new ArrayList<>();
68 | List reportPaths = new ArrayList<>();
69 | String projectDirectory = CodeHelper.getProjectPath(scanRequest, false);
70 | log.info("[Spotbug] Starting to generate Spotbug report for {}", scanRequest.getTarget());
71 | ProcessBuilder spotbug = new ProcessBuilder("bash",
72 | "-c",
73 | "mvn compile -DskipTests com.github.spotbugs:spotbugs-maven-plugin:spotbugs").inheritIO();
74 | spotbug.directory(new File(projectDirectory));
75 | Process spotbugProcess = spotbug.inheritIO().start();
76 | spotbugProcess.waitFor();
77 | log.info("[Spotbug] Report ready to process {}", scanRequest.getTarget());
78 | SpotbugReportXML spotbugReportXML = processXmlReport(projectDirectory + File.separatorChar + "target" + File.separatorChar + "spotbugsXml.xml");
79 | log.info("[Spotbug] Scan completed");
80 | searchForReports(spotbugReportXMLS, projectDirectory);
81 | return convertSpotbugReportIntoVulnList(spotbugReportXMLS);
82 | }
83 |
84 | private void searchForReports(List spotbugReportXMLS, String projectDirectory) throws IOException {
85 | List reportPaths;
86 | try (Stream paths = Files.walk(Paths.get(projectDirectory))) {
87 | reportPaths = paths
88 | .filter(Files::isRegularFile)
89 | .filter(f -> f.getFileName().toString().equals("spotbugsXml.xml"))
90 | .collect(Collectors.toList());
91 | }
92 | for (Path path : reportPaths){
93 | spotbugReportXMLS.add(processXmlReport(path.toString()));
94 | }
95 | }
96 |
97 | /**
98 | * Converts spotbug XML report into Vulnerabilities
99 | * @param spotbugReportXMLs report to parse
100 | * @return list of shared items
101 | */
102 | private List convertSpotbugReportIntoVulnList(List spotbugReportXMLs) {
103 | List vulnerabilities = new ArrayList<>();
104 | for (SpotbugReportXML reportXML : spotbugReportXMLs) {
105 | if (reportXML.getBugInstanceList() !=null) {
106 | for (BugInstance bugInstance : reportXML.getBugInstanceList()) {
107 | vulnerabilities.add(new Vulnerability(bugInstance,
108 | reportXML
109 | .getBugPatterns()
110 | .stream()
111 | .filter(bugPattern -> bugPattern.getShortDescriptions().equals(bugInstance.getShortDescription()))
112 | .findFirst()
113 | .orElse(null)));
114 | }
115 | }
116 | }
117 | return vulnerabilities;
118 | }
119 |
120 | @Override
121 | public List runScanStandalone() throws IOException, InterruptedException {
122 | try {
123 | List spotbugReportXMLS = new ArrayList<>();
124 | List reportPaths = new ArrayList<>();
125 | String projectDirectory = CodeHelper.getProjectPath(new ScanRequest(), true);
126 | log.info("[Spotbug] Preparing POM, create backup and generate new");
127 | preparePomforSpotbugAnalysis(projectDirectory);
128 | log.info("[Spotbug] Starting to generate Spotbug report for {}", projectDirectory);
129 | ProcessBuilder spotbug = new ProcessBuilder("bash",
130 | "-c",
131 | "mvn compile -DskipTests spotbugs:spotbugs").inheritIO();
132 | spotbug.directory(new File(projectDirectory));
133 | Process spotbugProcess = spotbug.start();
134 | spotbugProcess.waitFor(5, TimeUnit.MINUTES);
135 | spotbugProcess.destroy();
136 | spotbugProcess.waitFor();
137 | log.info("[Spotbug] Report ready to process {}", projectDirectory);
138 | searchForReports(spotbugReportXMLS, projectDirectory);
139 | clearAfterPomManipulation(projectDirectory);
140 | log.info("[Spotbug] Scan completed, artifact cleared");
141 | return convertSpotbugReportIntoVulnList(spotbugReportXMLS);
142 | } catch (Exception e) {
143 | e.printStackTrace();
144 | log.error("[Spotbug] Error occuredd during scanning reason {} on line {}", e.getLocalizedMessage(), e.getStackTrace()[0].getLineNumber());
145 | return new ArrayList<>();
146 | }
147 | }
148 | public List runScanStandalone(String directory) throws IOException, InterruptedException {
149 | try {
150 | List spotbugReportXMLS = new ArrayList<>();
151 | List reportPaths = new ArrayList<>();
152 | String projectDirectory = directory!=null ? directory : CodeHelper.getProjectPath(new ScanRequest(), true);
153 | log.info("[Spotbug] Preparing POM, create backup and generate new");
154 | preparePomforSpotbugAnalysis(projectDirectory);
155 | log.info("[Spotbug] Starting to generate Spotbug report for {}", projectDirectory);
156 | ProcessBuilder spotbug = new ProcessBuilder("bash",
157 | "-c",
158 | "mvn compile -DskipTests spotbugs:spotbugs").inheritIO();
159 | spotbug.directory(new File(projectDirectory));
160 | Process spotbugProcess = spotbug.start();
161 | spotbugProcess.waitFor(5, TimeUnit.MINUTES);
162 | spotbugProcess.destroy();
163 | spotbugProcess.waitFor();
164 | log.info("[Spotbug] Report ready to process {}", projectDirectory);
165 | searchForReports(spotbugReportXMLS, projectDirectory);
166 | clearAfterPomManipulation(projectDirectory);
167 | log.info("[Spotbug] Scan completed, artifact cleared");
168 | return convertSpotbugReportIntoVulnList(spotbugReportXMLS);
169 | } catch (Exception e) {
170 | e.printStackTrace();
171 | log.error("[Spotbug] Error occuredd during scanning reason {} on line {}", e.getLocalizedMessage(), e.getStackTrace()[0].getLineNumber());
172 | return new ArrayList<>();
173 | }
174 | }
175 |
176 | /**
177 | * Method which takes directory for spotbugXml.xml report file and convert it into readable object
178 | *
179 | * @param directory to spotbugXml.xml file
180 | * @return object with defects
181 | */
182 | private SpotbugReportXML processXmlReport(String directory){
183 | File xmlFile = new File(directory);
184 | JAXBContext jaxbContext;
185 | try
186 | {
187 | jaxbContext = JAXBContext.newInstance(SpotbugReportXML.class);
188 | Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
189 | return ((SpotbugReportXML) jaxbUnmarshaller.unmarshal(xmlFile)).processSeverity();
190 | }
191 | catch (JAXBException e)
192 | {
193 | e.printStackTrace();
194 | }
195 | return null;
196 | }
197 |
198 | /**
199 | * First builds spotbugs build with plugins completed
200 | * Second replace build tag in pom with new one
201 | * third create backup of old pom.xml
202 | * end create new pom
203 | * @param directory to look for pom
204 | */
205 | private void preparePomforSpotbugAnalysis(String directory) throws IOException, ParserConfigurationException, SAXException, TransformerException, InterruptedException {
206 | File file = new File(directory + File.separatorChar + "pom.xml");
207 | XmlMapper xmlMapper = new XmlMapper();
208 | xmlMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
209 | xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
210 |
211 | List plugins = new ArrayList<>();
212 | plugins.add(buildSpotbugPlugin());
213 |
214 | String replaceWith = "" + xmlMapper.
215 | writer()
216 | .withRootName("plugins")
217 | .writeValueAsString(plugins).replaceAll("item","plugin") + "";
218 |
219 | DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
220 | DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
221 | Document doc = dBuilder.parse(file);
222 | NodeList buildNode = doc.getElementsByTagName("project");
223 | Element element = dbFactory.newDocumentBuilder().parse(new InputSource(new StringReader(
224 | replaceWith))).getDocumentElement();
225 | Node firstDocImportedNode = doc.importNode(element, true);
226 |
227 | boolean spotbugsAdded = false;
228 | for(int i=0; i");
286 | }
287 | //Create spotbugs-security-exclude.xml
288 | try (Writer writer = new BufferedWriter(new OutputStreamWriter(
289 | new FileOutputStream(s + File.separatorChar + "spotbugs-security-exclude.xml"), StandardCharsets.UTF_8))) {
290 | writer.write("");
291 | }
292 | }
293 |
294 |
295 | /**
296 | * Create Spotbug element which will be appended into Pom.xml
297 | * @return configured spotbugs with find-sec-bugs
298 | */
299 | public PomPlugin buildSpotbugPlugin(){
300 | List findSecBugList = new ArrayList<>();
301 | PomPlugin findSecBugs = PomPlugin.builder()
302 | .groupId("com.h3xstream.findsecbugs")
303 | .artifactId("findsecbugs-plugin")
304 | .version("1.10.1")
305 | .build();
306 | findSecBugList.add(findSecBugs);
307 | PomConfiguration configuration = PomConfiguration.builder()
308 | .effort("Max")
309 | .threshold("Low")
310 | .failOnError("true")
311 | .plugins(findSecBugList)
312 | .build();
313 | return PomPlugin.builder()
314 | .groupId("com.github.spotbugs")
315 | .artifactId("spotbugs-maven-plugin")
316 | .version("4.0.4")
317 | .configuration(configuration)
318 | .build();
319 | }
320 | }
321 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/rest/controller/BaseController.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @created 2020-08-18 : 16:43
3 | * @project MixewayScanner
4 | * @author siewer
5 | */
6 | package io.mixeway.scanner.rest.controller;
7 |
8 | import io.mixeway.scanner.rest.model.ScanRequest;
9 | import io.mixeway.scanner.rest.model.Status;
10 | import io.mixeway.scanner.rest.service.BaseService;
11 | import io.mixeway.scanner.utils.Vulnerability;
12 | import org.springframework.http.ResponseEntity;
13 | import org.springframework.web.bind.annotation.PostMapping;
14 | import org.springframework.web.bind.annotation.RequestBody;
15 | import org.springframework.web.bind.annotation.RestController;
16 |
17 | import javax.validation.Valid;
18 | import java.util.List;
19 |
20 | @RestController
21 | public class BaseController {
22 | BaseService baseService;
23 |
24 | public BaseController(BaseService baseService){
25 | this.baseService = baseService;
26 | }
27 | @PostMapping("/run")
28 | public ResponseEntity> runScan(@Valid @RequestBody ScanRequest scanRequest) throws Exception {
29 | return baseService.runScan(scanRequest);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/rest/model/ScanRequest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @created 2020-08-18 : 16:44
3 | * @project MixewayScanner
4 | * @author siewer
5 | */
6 | package io.mixeway.scanner.rest.model;
7 |
8 | import io.mixeway.scanner.utils.ScannerPluginType;
9 | import io.mixeway.scanner.utils.ScannerType;
10 |
11 | import javax.validation.constraints.NotNull;
12 |
13 | public class ScanRequest {
14 | @NotNull(message = "Scanner Type cannot be null possible options 'SAST' or 'DAST'")
15 | public ScannerType type;
16 | @NotNull(message = "Target cannot be null. In scope of SAST scan target is GIT repo, in scope of DAST scan target is URL to scan")
17 | public String target;
18 | public String username;
19 | public String password;
20 | public String exclusions;
21 | public String branch;
22 | public String projectName;
23 |
24 | public String getProjectName() {
25 | return projectName;
26 | }
27 |
28 | public void setProjectName(String projectName) {
29 | this.projectName = projectName;
30 | }
31 |
32 | public String getBranch() {
33 | return branch;
34 | }
35 |
36 | public void setBranch(String branch) {
37 | this.branch = branch;
38 | }
39 |
40 | public ScannerType getType() {
41 | return type;
42 | }
43 |
44 | public void setType(ScannerType type) {
45 | this.type = type;
46 | }
47 |
48 | public String getTarget() {
49 | return target;
50 | }
51 |
52 | public void setTarget(String target) {
53 | this.target = target;
54 | }
55 |
56 | public String getUsername() {
57 | return username;
58 | }
59 |
60 | public void setUsername(String username) {
61 | this.username = username;
62 | }
63 |
64 | public String getPassword() {
65 | return password;
66 | }
67 |
68 | public void setPassword(String password) {
69 | this.password = password;
70 | }
71 |
72 | public String getExclusions() {
73 | return exclusions;
74 | }
75 |
76 | public void setExclusions(String exclusions) {
77 | this.exclusions = exclusions;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/rest/model/Status.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @created 2020-08-18 : 23:35
3 | * @project MixewayScanner
4 | * @author siewer
5 | */
6 | package io.mixeway.scanner.rest.model;
7 |
8 | public class Status {
9 | String result;
10 |
11 | public Status(String result) {
12 | this.result = result;
13 | }
14 |
15 | public String getResult() {
16 | return result;
17 | }
18 |
19 | public void setResult(String result) {
20 | this.result = result;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/rest/service/BaseService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @created 2020-08-18 : 23:34
3 | * @project MixewayScanner
4 | * @author siewer
5 | */
6 | package io.mixeway.scanner.rest.service;
7 |
8 | import io.mixeway.scanner.factory.ScannerFactory;
9 | import io.mixeway.scanner.integrations.ScannerIntegrationFactory;
10 | import io.mixeway.scanner.rest.model.ScanRequest;
11 | import io.mixeway.scanner.utils.*;
12 | import org.aspectj.apache.bcel.classfile.Code;
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 | import org.springframework.http.HttpStatus;
16 | import org.springframework.http.ResponseEntity;
17 | import org.springframework.stereotype.Service;
18 |
19 | import java.util.ArrayList;
20 | import java.util.List;
21 |
22 | @Service
23 | public class BaseService {
24 | private final static Logger log = LoggerFactory.getLogger(BaseService.class);
25 | ScannerFactory scannerFactory;
26 | GitOperations gitOperations;
27 | MixewayConnector mixewayConnector;
28 |
29 |
30 | public BaseService(ScannerFactory scannerFactory, GitOperations gitOperations, MixewayConnector mixewayConnector){
31 | this.scannerFactory = scannerFactory;
32 | this.gitOperations = gitOperations;
33 | this.mixewayConnector = mixewayConnector;
34 | }
35 |
36 | /**
37 | * Running scan for given request
38 | *
39 | * @param scanRequest sent by client
40 | * @return status
41 | */
42 | public ResponseEntity> runScan(ScanRequest scanRequest) {
43 | List vulnerabilities = new ArrayList<>();
44 | try {
45 | GitResponse gitResponse = null;
46 | String projectName = null;
47 | if (scanRequest.getType().equals(ScannerType.SAST)) {
48 | if (gitOperations.isProjectPresent(scanRequest)) {
49 | gitResponse = gitOperations.pull(scanRequest);
50 | } else {
51 | gitResponse = gitOperations.clone(scanRequest);
52 | }
53 | projectName = CodeHelper.getNameFromRepoUrlforSAST(scanRequest.getTarget(),false);
54 | SourceProjectType sourceProjectType = CodeHelper.getSourceProjectTypeFromDirectory(scanRequest, false);
55 | if (sourceProjectType == null) {
56 | log.error("Repository doesnt contain any of the known types of projects. Current version support only JAVA-Maven projects.");
57 | return new ResponseEntity<>(HttpStatus.PRECONDITION_FAILED);
58 | }
59 |
60 |
61 | ScannerIntegrationFactory openSourceScan = scannerFactory.getProperScanner(ScannerPluginType.DEPENDENCYTRACK);
62 | vulnerabilities.addAll(openSourceScan.runScan(scanRequest));
63 |
64 | switch (sourceProjectType) {
65 | case MAVEN:
66 | ScannerIntegrationFactory spotbug = scannerFactory.getProperScanner(ScannerPluginType.SPOTBUG);
67 | vulnerabilities.addAll(spotbug.runScan(scanRequest));
68 | break;
69 | case PIP:
70 | ScannerIntegrationFactory bandit = scannerFactory.getProperScanner(ScannerPluginType.BANDIT);
71 | vulnerabilities.addAll(bandit.runScan(scanRequest));
72 | break;
73 | case PHP:
74 | ScannerIntegrationFactory progpilot = scannerFactory.getProperScanner(ScannerPluginType.PROGPILOT);
75 | vulnerabilities.addAll(progpilot.runScan(scanRequest));
76 | break;
77 | default:
78 | log.error("Source Code Language not supported");
79 | return new ResponseEntity<>(HttpStatus.PRECONDITION_FAILED);
80 | }
81 | // TODO get SAST SCAN
82 | } else if (scanRequest.getType().equals(ScannerType.DAST)) {
83 | // TODO run DAST SCAN
84 | } else {
85 | log.error("[REST] Got request with unknown scan type {}", scanRequest.getType().toString());
86 | }
87 | mixewayConnector.sendRequestToMixeway(vulnerabilities, projectName, scanRequest.branch, gitResponse.getCommitId());
88 | } catch (Exception e){
89 | e.printStackTrace();
90 | log.error(e.getLocalizedMessage());
91 | }
92 |
93 | return new ResponseEntity<>(vulnerabilities,HttpStatus.OK);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/standalone/StandAloneService.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.standalone;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import com.fasterxml.jackson.core.JsonProcessingException;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 | import com.fasterxml.jackson.databind.SerializationFeature;
7 | import com.google.gson.Gson;
8 | import io.mixeway.scanner.factory.ScannerFactory;
9 | import io.mixeway.scanner.integrations.ScannerIntegrationFactory;
10 | import io.mixeway.scanner.rest.model.ScanRequest;
11 | import io.mixeway.scanner.utils.*;
12 | import org.apache.commons.lang3.StringUtils;
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 | import org.springframework.beans.factory.annotation.Value;
16 | import org.springframework.stereotype.Service;
17 |
18 | import java.io.File;
19 | import java.io.FileWriter;
20 | import java.io.IOException;
21 | import java.io.Writer;
22 | import java.nio.file.Files;
23 | import java.nio.file.Paths;
24 | import java.security.KeyManagementException;
25 | import java.security.KeyStoreException;
26 | import java.security.NoSuchAlgorithmException;
27 | import java.util.ArrayList;
28 | import java.util.List;
29 |
30 | /**
31 | * Class which run Standalone test. Gets current location as mounted application, check for language used and then
32 | * run full SAST scan
33 | *
34 | * @author gsiewruk
35 | */
36 | @Service
37 | public class StandAloneService {
38 |
39 | @Value("${BRANCH:}")
40 | String branch;
41 | @Value("${COMMIT_ID:}")
42 | String commitId;
43 | @Value("${MIXEWAY_PROJECT_NAME:}")
44 | String mixewayProjectName;
45 | private final static Logger log = LoggerFactory.getLogger(StandAloneService.class);
46 | ScannerFactory scannerFactory;
47 | MixewayConnector mixewayConnector;
48 | GitOperations gitOperations;
49 | public StandAloneService(ScannerFactory scannerFactory,
50 | MixewayConnector mixewayConnector,
51 | GitOperations gitOperations){
52 | this.scannerFactory = scannerFactory;
53 | this.mixewayConnector = mixewayConnector;
54 | this.gitOperations = gitOperations;
55 | }
56 |
57 | /**
58 | * Running scan in hardcoded location, first it check if location exists (is mounted during docker run),
59 | * and if yes it go full SAST scan, if not log info and exit.
60 | */
61 | public void runScan() throws IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException, InterruptedException {
62 | List vulnerabilityList = new ArrayList<>();
63 | String directory = CodeHelper.getProjectPath(new ScanRequest(), true);
64 |
65 | try {
66 | checkMountPoint();
67 | for (SourceProjectType projectType : SourceProjectType.values()){
68 | if (CodeHelper.isProjectInLanguage(directory, projectType)){
69 | vulnerabilityList.addAll(scannerFactory.runScanForLanguage(projectType));
70 | }
71 | }
72 | } catch (Exception e ){
73 | e.printStackTrace();
74 | log.error("[Standalone Mixeway App] Fatal error: {}", e.getLocalizedMessage());
75 | }
76 | printResults(vulnerabilityList);
77 | writeResultsToFile(vulnerabilityList, CodeHelper.getProjectPath(new ScanRequest(), true));
78 | processMixeway(vulnerabilityList);
79 | }
80 |
81 | /**
82 | * Send vulnerabilities to Mixeway and waits for results if result is success exit with success, if failure exit with code 1
83 | *
84 | */
85 | private void processMixeway(List vulnerabilityList) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException, InterruptedException {
86 | GitInformations gitInformations = GitOperations.getGitInformations();
87 | Status status;
88 | if (gitInformations != null){
89 | PrepareCIOperation prepareCiOperations = mixewayConnector.getCIInfo(new GetInfoRequest(gitInformations));
90 | status = mixewayConnector.sendRequestToMixewayWithGitInfo(gitInformations, prepareCiOperations, vulnerabilityList);
91 | } else if (StringUtils.isNotBlank(mixewayProjectName) && StringUtils.isNotBlank(commitId) && StringUtils.isNotBlank(branch)){
92 | status = mixewayConnector.sendRequestToMixewayStandalone(vulnerabilityList, mixewayProjectName, branch, commitId);
93 | } else {
94 | status = mixewayConnector.sendAnonymousRequestToMixeway(vulnerabilityList);
95 | }
96 |
97 | if (status != null && status.getStatus().equals(Constants.GATEWAY_SUCCESS)){
98 | System.exit(0);
99 | } else if (status == null) {
100 | System.exit(0);
101 | } else {
102 | System.exit(1);
103 | }
104 | }
105 |
106 | /**
107 | * Save results to file mixeway_sast_report.json
108 | * @param vulnerabilityList
109 | * @param directory
110 | */
111 | private void writeResultsToFile(List vulnerabilityList, String directory) {
112 | try {
113 | Gson gson = new Gson();
114 | Writer writer = null;
115 | try {
116 | writer = new FileWriter(directory + File.separator + "mixeway_sast_report.json");
117 | gson.toJson(vulnerabilityList, writer);
118 |
119 | } catch (IOException e) {
120 | e.printStackTrace();
121 | } finally {
122 | try {
123 | if (writer != null) {
124 | writer.close();
125 | } else {
126 | log.error("Buffer has not been initialized!");
127 | }
128 | } catch (IOException e) {
129 | e.printStackTrace();
130 | }
131 | }
132 | } catch (Exception e) {
133 | log.error("Cannot write to {} check permission or use vulnerabilities from console", directory);
134 | }
135 | }
136 |
137 | /**
138 | * Printing results
139 | *
140 | * @param vulnerabilityList
141 | */
142 | private void printResults(List vulnerabilityList) throws JsonProcessingException {
143 | ObjectMapper mapper = new ObjectMapper();
144 | mapper.enable(SerializationFeature.INDENT_OUTPUT);
145 | mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
146 | String json = mapper.writeValueAsString(vulnerabilityList);
147 | System.out.println(json);
148 | }
149 |
150 | /**
151 | * Checking if source directory is mounted properly:
152 | * -v ${PWD}:/opt/sources
153 | */
154 | public void checkMountPoint(){
155 | log.info("Running Standalone Mixeway Scanner App");
156 | if (Files.isDirectory(Paths.get(Constants.STANDALONE_DEFAULT_SOURCE_PATH))) {
157 | log.info("Directory is properly mounted proceeding...");
158 | } else {
159 | log.error("No location mounted exiting. Please make sure You have used '-v ${PWD}:/opt/sources'");
160 | System.exit(1);
161 | }
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/CodeHelper.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.utils;
2 |
3 | import io.mixeway.scanner.rest.model.ScanRequest;
4 | import org.apache.commons.io.FileUtils;
5 | import org.apache.commons.io.filefilter.DirectoryFileFilter;
6 | import org.apache.commons.io.filefilter.RegexFileFilter;
7 | import org.springframework.beans.factory.annotation.Value;
8 | import org.springframework.stereotype.Component;
9 |
10 | import java.io.File;
11 | import java.nio.file.Path;
12 | import java.util.Collection;
13 | import java.util.List;
14 | import java.util.stream.Collectors;
15 |
16 | /**
17 | * @author gsiewruk
18 | */
19 | @Component
20 | public class CodeHelper {
21 | public static String sourceLocation;
22 |
23 | @Value( "${sources.location}" )
24 | public void setSourceLocation(String sourcesPath) {
25 | sourceLocation = sourcesPath;
26 | }
27 |
28 | /**
29 | * Gettig repo name from URL
30 | * e.g: https://github.com/mixeway/mixewayhub.git should return mixewayhub
31 | *
32 | * @param repoUrl URL for repository
33 | * @return name of repository
34 | */
35 | public static String getNameFromRepoUrlforSAST(String repoUrl, boolean standalone){
36 | if (standalone) {
37 | return "standaloneApp";
38 | } else {
39 | String[] partsOfUrl = repoUrl.split("/");
40 | String repoName = partsOfUrl[partsOfUrl.length - 1];
41 | return repoName.split("\\.")[0];
42 | }
43 | }
44 | /**
45 | * Determine type of source code in given location - JAVA-MVN, JAVA-Gradle, NPM, PIP or PHP-COMPOSER
46 | *
47 | */
48 | public static SourceProjectType getSourceProjectTypeFromDirectory(ScanRequest scanRequest, boolean standalone){
49 | String projectLocation;
50 | if (standalone){
51 | projectLocation = Constants.STANDALONE_DEFAULT_SOURCE_PATH;
52 | } else {
53 | projectLocation = sourceLocation + File.separatorChar + getNameFromRepoUrlforSAST(scanRequest.getTarget(), standalone);
54 | }
55 | File pom = new File(projectLocation + File.separatorChar + "pom.xml");
56 | if(pom.exists()){
57 | return SourceProjectType.MAVEN;
58 | }
59 | File gradle = new File(projectLocation + File.separatorChar + "build.xml");
60 | File gradle2 = new File(projectLocation + File.separatorChar + "build.gradle");
61 | if (gradle.exists() || gradle2.exists()) {
62 | prepareGradle(gradle);
63 | return SourceProjectType.GRADLE;
64 | }
65 | File npm = new File(projectLocation + File.separatorChar + "package.json");
66 | if(npm.exists()){
67 | return SourceProjectType.NPM;
68 | }
69 | File composer = new File(projectLocation + File.separatorChar + "composer.json");
70 | if(composer.exists() || directoryContainsPhp(projectLocation)){
71 | return SourceProjectType.PHP;
72 | }
73 | Collection pip = FileUtils.listFiles(
74 | new File(projectLocation),
75 | new RegexFileFilter(".*\\.py"),
76 | DirectoryFileFilter.DIRECTORY
77 | ).stream().map(File::getName).collect(Collectors.toList());
78 | if (pip.size() > 3) {
79 | return SourceProjectType.PIP;
80 | }
81 | return null;
82 | }
83 | /**
84 | * Check if project is is particular language
85 | */
86 | public static boolean isProjectInLanguage(String directory, SourceProjectType sourceProjectType){
87 | switch (sourceProjectType) {
88 | case PIP:
89 | Collection pip = FileUtils.listFiles(
90 | new File(directory),
91 | new RegexFileFilter(".*\\.py"),
92 | DirectoryFileFilter.DIRECTORY
93 | ).stream().map(File::getName).collect(Collectors.toList());
94 | return pip.size() > 3;
95 | case GRADLE:
96 | File gradle = new File(directory + File.separatorChar + "build.xml");
97 | File gradle2 = new File(directory + File.separatorChar + "build.gradle");
98 | if (gradle.exists() || gradle2.exists()) {
99 | prepareGradle(gradle);
100 | return true;
101 | } else {
102 | return false;
103 | }
104 | case PHP:
105 | File composer = new File(directory + File.separatorChar + "composer.json");
106 | return composer.exists() || directoryContainsPhp(directory);
107 | case NPM:
108 | List packagePaths= FileUtils.listFiles(
109 | new File(directory),
110 | new RegexFileFilter(Constants.PACKAGE_FILENAME),
111 | DirectoryFileFilter.DIRECTORY
112 | ).stream()
113 | .map(File::getAbsoluteFile)
114 | .map(file -> file.toString()
115 | .split(File.separatorChar + Constants.PACKAGE_FILENAME)[0])
116 | .collect(Collectors.toList());
117 | return packagePaths.size()>0;
118 | case MAVEN:
119 | File pom = new File(directory + File.separatorChar + "pom.xml");
120 | return pom.exists();
121 | }
122 | return false;
123 | }
124 |
125 |
126 |
127 | /**
128 | * Check if directory contains php files
129 | * @param projectLocation
130 | * @return
131 | */
132 | private static boolean directoryContainsPhp(String projectLocation) {
133 | Collection php = FileUtils.listFiles(
134 | new File(projectLocation),
135 | new RegexFileFilter(".*\\.php"),
136 | DirectoryFileFilter.DIRECTORY
137 | ).stream().map(File::getName).collect(Collectors.toList());
138 | return php.size() > 5;
139 | }
140 |
141 | /**
142 | * Method which preare build.xml file to use CycloneDX plugin to generate SBOM
143 | *
144 | * @param gradle path to gradle file
145 | */
146 | private static void prepareGradle(File gradle) {
147 | //TODO edit of build.xml
148 | }
149 |
150 | /**
151 | * Method which return path to project git downloaded
152 | *
153 | * @param scanRequest to process
154 | * @return path to code
155 | */
156 | public static String getProjectPath(ScanRequest scanRequest, boolean standalone){
157 | if (standalone){
158 | return Constants.STANDALONE_DEFAULT_SOURCE_PATH;
159 | } else {
160 | return sourceLocation + File.separatorChar + getNameFromRepoUrlforSAST(scanRequest.getTarget(), standalone);
161 | }
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/Constants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @created 2020-08-18 : 16:55
3 | * @project MixewayScanner
4 | * @author siewer
5 | */
6 | package io.mixeway.scanner.utils;
7 |
8 | import java.net.URI;
9 |
10 | public final class Constants {
11 | public static final String DEPENDENCYTRACK_USERNAME = "admin";
12 | public static final String DEPENDENCYTRACK_PASSWORD = "admin";
13 | public static final String DEPENDENCYTRACK_URL = "http://localhost:8080";
14 | public static final String DEPENDENCYTRACK_URL_LOGIN = "/api/v1/user/login";
15 | public static final String DEPENDENCYTRACK_URL_APIKEY = "/api/v1/team?searchText=&sortOrder=asc";
16 | public static final String DEPENDENCYTRACK_LOGIN_STRING = "username=admin&password=admin1";
17 | public static final String DEPENDENCYTRACK_CHANGE_PASSWORD_STRING = "username=admin&password=admin&newPassword=admin1&confirmPassword=admin1";
18 | public static final String DEPENDENCYTRACK_AUTOMATION = "Automation";
19 | public static final String DEPENDENCYTRACK_URL_OSS_CONFIG = "/api/v1/configProperty/aggregate";
20 | public static final String DEPENDENCYTRACK_APIKEY_HEADER = "X-Api-Key";
21 | public static final String DEPENDENCYTRACK_GET_PROJECTS = "/api/v1/project";
22 | public static final String DEPENDENCYTRACK_URL_PERMISSIONS = "/api/v1/permission/";
23 | public static final String GIT_BRANCH_MASTER = "master";
24 | public static final String DEPENDENCYTRACK_URL_CHANGE_PASSWORD = "/api/v1/user/forceChangePassword";
25 | public static final String DEPENDENCYTRACK_URL_UPLOAD_BOM = "/api/v1/bom";
26 |
27 | public static final String DEPENDENCYTRACK_URL_VULNS = "/api/v1/vulnerability/project/";
28 | public static final String STANDALONE_DEFAULT_SOURCE_PATH = "/opt/sources";
29 | public static final String MIXEWAY_URL_SAAS = "https://hub.mixeway.io";
30 | public static final String MIXEWAY_API_KEY = "apikey";
31 | public static final String MIXEWAY_PUSH_VULN_URL = "/v2/api/cicd/loadvulnerabilities";
32 |
33 | public static final String GATEWAY_SUCCESS = "Ok";
34 | public static final String PACKAGE_FILENAME = "package.json";
35 | public static final String POM_FILENAME = "pom.xml";
36 | public static final String SPOTBUG_CATEGORY_SECURITY = "SECURITY";
37 | public static final String SPOTBUG_CATEGORY_MALICIOUS_CODE = "MALICIOUS_CODE";
38 | public static final String MIXEWAY_GET_SCANNER_INFO_URL = "/v2/api/cicd/getscannerinfo";
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/GetInfoRequest.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.utils;
2 |
3 | /**
4 | * @author gsiewruk
5 | */
6 | public class GetInfoRequest {
7 | String repoUrl;
8 | String branch;
9 | String scope;
10 | String repoName;
11 |
12 | public GetInfoRequest(GitInformations gitInformations) {
13 | this.repoUrl = gitInformations.getRepoUrl();
14 | this.branch = gitInformations.getBranchName();
15 | this.scope = "opensource";
16 | this.repoName=gitInformations.getProjectName();
17 | }
18 |
19 | public String getRepoName() {
20 | return repoName;
21 | }
22 |
23 | public void setRepoName(String repoName) {
24 | this.repoName = repoName;
25 | }
26 |
27 | public String getBranch() {
28 | return branch;
29 | }
30 |
31 | public void setBranch(String branch) {
32 | this.branch = branch;
33 | }
34 |
35 | public String getRepoUrl() {
36 | return repoUrl;
37 | }
38 |
39 | public void setRepoUrl(String repoUrl) {
40 | this.repoUrl = repoUrl;
41 | }
42 |
43 | public String getScope() {
44 | return scope;
45 | }
46 |
47 | public void setScope(String scope) {
48 | this.scope = scope;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/GitInformations.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.utils;
2 |
3 | import lombok.Builder;
4 | import lombok.Getter;
5 |
6 | /**
7 | * @author gsiewruk
8 | */
9 | @Builder
10 | @Getter
11 | public class GitInformations {
12 | private String projectName;
13 | private String commitId;
14 | private String branchName;
15 | private String repoUrl;
16 |
17 | public GitInformations(){}
18 | public GitInformations(String projectName, String commitId, String branchName, String repoUrl) {
19 | this.projectName = projectName;
20 | this.commitId = commitId;
21 | this.branchName = branchName;
22 | this.repoUrl = repoUrl;
23 | }
24 |
25 | public String getRepoUrl() {
26 | return repoUrl;
27 | }
28 |
29 | public void setRepoUrl(String repoUrl) {
30 | this.repoUrl = repoUrl;
31 | }
32 |
33 | public String getProjectName() {
34 | return projectName;
35 | }
36 |
37 | public void setProjectName(String projectName) {
38 | this.projectName = projectName;
39 | }
40 |
41 | public String getCommitId() {
42 | return commitId;
43 | }
44 |
45 | public void setCommitId(String commitId) {
46 | this.commitId = commitId;
47 | }
48 |
49 | public String getBranchName() {
50 | return branchName;
51 | }
52 |
53 | public void setBranchName(String branchName) {
54 | this.branchName = branchName;
55 | }
56 | }
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/GitOperations.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @created 2020-08-19 : 18:30
3 | * @project MixewayScanner
4 | * @author siewer
5 | */
6 | package io.mixeway.scanner.utils;
7 |
8 | import io.mixeway.scanner.rest.model.ScanRequest;
9 | import org.eclipse.jgit.api.ListBranchCommand;
10 | import org.eclipse.jgit.revwalk.RevCommit;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 | import org.springframework.beans.factory.annotation.Value;
14 | import org.springframework.stereotype.Component;
15 | import org.eclipse.jgit.api.Git;
16 | import org.eclipse.jgit.api.ResetCommand;
17 | import org.eclipse.jgit.api.errors.GitAPIException;
18 | import org.eclipse.jgit.lib.Ref;
19 | import org.eclipse.jgit.lib.Repository;
20 | import org.eclipse.jgit.merge.MergeStrategy;
21 | import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
22 | import org.eclipse.jgit.transport.CredentialsProvider;
23 | import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
24 |
25 | import java.io.File;
26 | import java.io.IOException;
27 | import java.nio.file.Files;
28 | import java.nio.file.Path;
29 | import java.nio.file.Paths;
30 | import java.util.List;
31 | import java.util.stream.Stream;
32 |
33 | /**
34 | * Class which enable integration with GIT Repositories
35 | */
36 | @Component
37 | public class GitOperations {
38 | @Value( "${sources.location}" )
39 | private String sourceLocation;
40 | private static String LOCATION_STATIC;
41 | @Value("${sources.location}")
42 | public void setSourceLocationStatic(String name){
43 | GitOperations.LOCATION_STATIC = name;
44 | }
45 | private final Logger log = LoggerFactory.getLogger(GitOperations.class);
46 |
47 | /**
48 | * Get default directory of /opt/sources and try to load active branch, last commitID and repo name from it
49 | *
50 | * @return git info object containing above data
51 | */
52 | public static GitInformations getGitInformations() {
53 | final Logger log = LoggerFactory.getLogger(GitOperations.class);
54 | try {
55 | FileRepositoryBuilder builder = new FileRepositoryBuilder();
56 | Repository repository = builder.setGitDir(Paths.get(LOCATION_STATIC + File.separatorChar + ".git").toFile())
57 | .readEnvironment()
58 | .findGitDir()
59 | .build();
60 | RevCommit latestCommit = new Git(repository).log().setMaxCount(1).call().iterator().next();
61 | String latestCommitHash = latestCommit.getName();
62 |
63 | GitInformations gitInformations = GitInformations
64 | .builder()
65 | .branchName(Stream.of(repository.getFullBranch().split("/")).reduce((first, last) -> last).get())
66 | .commitId(latestCommitHash)
67 | .projectName(Stream.of(repository.getConfig().getString("remote", "origin", "url").split("/")).reduce((first, last) -> last).get())
68 | .repoUrl(repository.getConfig().getString("remote", "origin", "url"))
69 | .build();
70 | log.info("[GIT] Processing scan for {} with active branch {} and latest commit {}", gitInformations.getProjectName(), gitInformations.getBranchName(), gitInformations.getCommitId());
71 | return gitInformations;
72 | } catch (IOException | GitAPIException e){
73 | log.error("[GIT] Unable to load GIT informations reason - {}", e.getLocalizedMessage());
74 | }
75 | return null;
76 | }
77 |
78 |
79 | /**
80 | * Method which is pulling git repo based on scanRequest
81 | *
82 | * @param scanRequest with repo url and auth credentials
83 | * @return object with commit id for given branch
84 | */
85 | public GitResponse pull(ScanRequest scanRequest) throws Exception {
86 | try {
87 | verifyLocation();
88 | } catch (Exception e){
89 | throw new Exception (e.getLocalizedMessage());
90 | }
91 | try {
92 | FileRepositoryBuilder builder = new FileRepositoryBuilder();
93 | CredentialsProvider credentialsProvider = prepareCredentails(scanRequest);
94 |
95 | Repository repository = builder.setGitDir(Paths.get(sourceLocation + File.separatorChar + CodeHelper.getNameFromRepoUrlforSAST(scanRequest.getTarget(), false) + File.separatorChar + ".git").toFile())
96 | .readEnvironment()
97 | .findGitDir()
98 | .build();
99 | Git git = new Git(repository);
100 | git.reset().setMode(ResetCommand.ResetType.HARD).call();
101 | git.pull()
102 | .setRemote("origin")
103 | .setStrategy(MergeStrategy.THEIRS)
104 | .setCredentialsProvider(credentialsProvider)
105 | .setRemoteBranchName(scanRequest.getBranch() != null ? scanRequest.getBranch() : Constants.GIT_BRANCH_MASTER)
106 | .call();
107 | Ref call = git.checkout().setName("origin/" + (scanRequest.getBranch() != null ? scanRequest.getBranch() : Constants.GIT_BRANCH_MASTER)).call();
108 | String commitId = git.log().setMaxCount(1).call().iterator().next().getName();
109 | log.info("[GIT] Successfully fetched repo for {} commitId id is {} branch {}", scanRequest.getTarget(), commitId, scanRequest.getBranch());
110 | return new GitResponse(true,commitId);
111 | } catch (GitAPIException | IOException e){
112 | log.error("[GIT] Error during fetching repo {}", e.getLocalizedMessage());
113 | }
114 | return new GitResponse(false,"");
115 | }
116 |
117 | /**
118 | * Method which clone repository based on scanRequest
119 | * @param scanRequest given scanRequest with repo url and auth credentials
120 | * @return commitid of given branch
121 | */
122 | public GitResponse clone(ScanRequest scanRequest) throws Exception {
123 | try {
124 | verifyLocation();
125 | } catch (Exception e){
126 | throw new Exception (e.getLocalizedMessage());
127 | }
128 | try {
129 | Git git = Git.cloneRepository()
130 | .setCredentialsProvider(prepareCredentails(scanRequest))
131 | .setURI(scanRequest.getTarget() + ".git")
132 | .setDirectory(Paths.get(sourceLocation + File.separatorChar + CodeHelper.getNameFromRepoUrlforSAST(scanRequest.getTarget(), false)).toFile())
133 | .call();
134 | Ref call = git.checkout().setName("origin/" + (scanRequest.getBranch() != null ? scanRequest.getBranch() : Constants.GIT_BRANCH_MASTER)).call();
135 | String commitId = git.log().setMaxCount(1).call().iterator().next().getName();
136 | log.info("[GIT] Successfully cloned repo for {} commitId is {} branch {}", scanRequest.getTarget(), commitId, scanRequest.getBranch());
137 | return new GitResponse(true, commitId);
138 | } catch (GitAPIException e){
139 | log.error("[GIT] Error cloning repo {}", e.getLocalizedMessage());
140 | }
141 | return new GitResponse(false, "");
142 | }
143 |
144 | /**
145 | * Preparing CredentialsProvider for given auth info:
146 | * - No auth if no pass and user given
147 | * - Token auth if only pass provided
148 | * - basic auth if both pass and user provided
149 | * @param scanRequest scan request to prepare credentials for
150 | * @return credentials provided object
151 | */
152 | private CredentialsProvider prepareCredentails(ScanRequest scanRequest) {
153 | if (scanRequest.getUsername() ==null && scanRequest.getPassword()!=null) {
154 | return new UsernamePasswordCredentialsProvider("PRIVATE-TOKEN", scanRequest.getPassword());
155 | } else if (scanRequest.getUsername() !=null && scanRequest.getPassword()!=null ) {
156 | return new UsernamePasswordCredentialsProvider(scanRequest.getUsername(), scanRequest.getPassword());
157 | } else {
158 | return null;
159 | }
160 | }
161 |
162 | /**
163 | * Method which verify if location and configuration for given request is already configured
164 | *
165 | * @param scanRequest scan request with target to verify
166 | * @return boolean if location exists or not
167 | */
168 | public boolean isProjectPresent(ScanRequest scanRequest){
169 | Path path = Paths.get(sourceLocation + File.separatorChar + CodeHelper.getNameFromRepoUrlforSAST(scanRequest.getTarget(), false));
170 | return Files.exists(path);
171 | }
172 |
173 | /**
174 | * Method which verify if sourcesLocation exist on FileSystem. Directory is created if needed.
175 | * Permissions to write on given location is required.
176 | */
177 | private void verifyLocation() throws Exception {
178 | Path path = Paths.get(sourceLocation);
179 | if (!Files.exists(path)) {
180 | File file = new File(sourceLocation);
181 | if (!file.exists()) {
182 | if (file.mkdir()) {
183 | log.info("[GIT] Directory is created! {}", sourceLocation);
184 | } else {
185 | log.warn("[GIT] Failed to create directory {}", sourceLocation);
186 | throw new Exception("Cannot create directory");
187 | }
188 | }
189 | }
190 | }
191 |
192 | }
193 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/GitResponse.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.utils;
2 |
3 | public class GitResponse {
4 | private Boolean status;
5 | private String commitId;
6 |
7 | public GitResponse(Boolean status, String commitId){
8 | this.commitId = commitId;
9 | this.status = status;
10 | }
11 | public Boolean getStatus() {
12 | return status;
13 | }
14 |
15 | public void setStatus(Boolean status) {
16 | this.status = status;
17 | }
18 |
19 | public String getCommitId() {
20 | return commitId;
21 | }
22 |
23 | public void setCommitId(String commitId) {
24 | this.commitId = commitId;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/MixewayConnector.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @created 2020-08-27 : 16:53
3 | * @project MixewayScanner
4 | * @author siewer
5 | */
6 | package io.mixeway.scanner.utils;
7 |
8 | import org.apache.commons.lang3.StringUtils;
9 | import org.apache.http.conn.ssl.NoopHostnameVerifier;
10 | import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
11 | import org.apache.http.impl.client.CloseableHttpClient;
12 | import org.apache.http.impl.client.HttpClients;
13 | import org.apache.http.ssl.TrustStrategy;
14 | import org.slf4j.Logger;
15 | import org.slf4j.LoggerFactory;
16 | import org.springframework.beans.factory.annotation.Value;
17 | import org.springframework.http.*;
18 | import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
19 | import org.springframework.stereotype.Service;
20 | import org.springframework.web.client.HttpClientErrorException;
21 | import org.springframework.web.client.HttpServerErrorException;
22 | import org.springframework.web.client.RestTemplate;
23 |
24 | import javax.net.ssl.SSLContext;
25 | import java.security.KeyManagementException;
26 | import java.security.KeyStoreException;
27 | import java.security.NoSuchAlgorithmException;
28 | import java.util.List;
29 |
30 | @Service
31 | public class MixewayConnector {
32 | private final static Logger log = LoggerFactory.getLogger(MixewayConnector.class);
33 | @Value("${mixeway.url}")
34 | String mixewayUrl;
35 | @Value("${mixeway.key}")
36 | String mixewayKey;
37 | @Value("${mixeway.project}")
38 | int mixewayProject;
39 | @Value("${mixeway.project.name}")
40 | String mixewayProjectName;
41 | int tries = 0;
42 | public Status sendRequestToMixeway(List vulnerabilities, String projectName, String branch, String commit) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
43 | if (StringUtils.isNoneBlank(mixewayKey) && mixewayProject > 0){
44 | log.info("[Mixeway Connector] Mixeway integraiton is enabled. Starting to push the results to {}", mixewayUrl);
45 | RestTemplate restTemplate = getRestTemplate();
46 | HttpHeaders headers = new HttpHeaders();
47 | headers.set(Constants.MIXEWAY_API_KEY, mixewayKey);
48 | headers.setContentType(MediaType.APPLICATION_JSON);
49 | HttpEntity> entity = new HttpEntity<>(vulnerabilities,headers);
50 | try {
51 | ResponseEntity response = restTemplate.exchange(mixewayUrl +
52 | Constants.MIXEWAY_PUSH_VULN_URL
53 | + "/" + mixewayProject + "/" + projectName + "/" + branch + "/" + commit,
54 | HttpMethod.POST, entity, Status.class);
55 | if (response.getStatusCode() == HttpStatus.OK) {
56 | log.info("[Mixeway Connector] Results pushed and already visible at {}", mixewayUrl);
57 | return response.getBody();
58 | } else {
59 | log.error("[Mixeway Connector] Push results to Mixeway - {}", response.getStatusCodeValue());
60 | }
61 | } catch (HttpServerErrorException | HttpClientErrorException e) {
62 | log.error("[Mixeway Connector] Problem with contaictint with Mixeway - {}",e.getLocalizedMessage());
63 | }
64 | } else {
65 | log.info("[Mixeway Connector] Mixeway integration is not enabled, if You want to push results into mixeway please set MIXEWAY_URL and MIXEWAY_KEY. Read more at docs.");
66 | }
67 | return null;
68 | }
69 | public Status sendRequestToMixewayStandalone(List vulnerabilities, String projectName, String branch, String commit) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
70 | if (StringUtils.isNoneBlank(mixewayKey) ){
71 | log.info("[Mixeway Connector] Mixeway integraiton is enabled. Starting to push the results to {}", mixewayUrl);
72 | RestTemplate restTemplate = getRestTemplate();
73 | HttpHeaders headers = new HttpHeaders();
74 | headers.set(Constants.MIXEWAY_API_KEY, mixewayKey);
75 | headers.setContentType(MediaType.APPLICATION_JSON);
76 | HttpEntity> entity = new HttpEntity<>(vulnerabilities,headers);
77 | try {
78 | ResponseEntity response = restTemplate.exchange(mixewayUrl +
79 | Constants.MIXEWAY_PUSH_VULN_URL
80 | + (mixewayProject > 0 ? "/"+mixewayProject:"")
81 | + "/" + projectName + "/" + branch + "/" + commit,
82 | HttpMethod.POST, entity, Status.class);
83 | if (response.getStatusCode() == HttpStatus.OK) {
84 | log.info("[Mixeway Connector] Results pushed and already visible at {}", mixewayUrl);
85 | return response.getBody();
86 | } else {
87 | log.error("[Mixeway Connector] Push results to Mixeway - {}", response.getStatusCodeValue());
88 | }
89 | } catch (HttpServerErrorException | HttpClientErrorException e) {
90 | log.error("[Mixeway Connector] Problem with contaictint with Mixeway - {}",e.getLocalizedMessage());
91 | }
92 | } else {
93 | log.info("[Mixeway Connector] Mixeway integration is not enabled, if You want to push results into mixeway please set MIXEWAY_URL and MIXEWAY_KEY. Read more at docs.");
94 | }
95 | return null;
96 | }
97 |
98 | public Status sendAnonymousRequestToMixeway(List vulnerabilities) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
99 | if (StringUtils.isNoneBlank(mixewayProjectName) && StringUtils.isNoneBlank(mixewayKey)){
100 | log.info("[Mixeway Connector] Mixeway integraiton is enabled. Starting to push the results to {}", mixewayUrl);
101 | RestTemplate restTemplate = getRestTemplate();
102 | HttpHeaders headers = new HttpHeaders();
103 | headers.set(Constants.MIXEWAY_API_KEY, mixewayKey);
104 | headers.setContentType(MediaType.APPLICATION_JSON);
105 | try{
106 | HttpEntity> entity = new HttpEntity<>(vulnerabilities, headers);
107 | ResponseEntity response = restTemplate.exchange(mixewayUrl +
108 | Constants.MIXEWAY_PUSH_VULN_URL + "/" + mixewayProjectName,
109 | HttpMethod.POST, entity, Status.class);
110 | if (response.getStatusCode() == HttpStatus.OK) {
111 | log.info("[Mixeway Connector] Results pushed and already visible at {}", mixewayUrl);
112 | return response.getBody();
113 | } else {
114 | log.error("[Mixeway Connector] Push results to Mixeway - {}", response.getStatusCodeValue());
115 | }
116 | } catch (HttpServerErrorException | HttpClientErrorException e) {
117 | log.error("[Mixeway Connector] Problem with contaictint with Mixeway - {}",e.getLocalizedMessage());
118 | }
119 | } else {
120 | log.info("[Mixeway Connector] Mixeway integration is not enabled, if You want to push results into mixeway please set MIXEWAY_URL, MIXEWAY_KEY and MIXEWAY_PROJECT_NAME. Read more at docs.");
121 | }
122 | return null;
123 | }
124 |
125 | /**
126 | * Geting information about OpenSource scan infos
127 | */
128 | public PrepareCIOperation getCIInfo(GetInfoRequest getInfoRequest) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException, InterruptedException {
129 |
130 | RestTemplate restTemplate = getRestTemplate();
131 | HttpHeaders headers = new HttpHeaders();
132 | headers.set(Constants.MIXEWAY_API_KEY, mixewayKey);
133 | headers.setContentType(MediaType.APPLICATION_JSON);
134 | HttpEntity entity = new HttpEntity<>(getInfoRequest,headers);
135 | try {
136 | ResponseEntity response = restTemplate.exchange(mixewayUrl +
137 | Constants.MIXEWAY_GET_SCANNER_INFO_URL,
138 | HttpMethod.POST, entity, PrepareCIOperation.class);
139 | return response.getBody();
140 | } catch (HttpClientErrorException | HttpServerErrorException e){
141 | tries++;
142 | log.error("[Mixeway] Cannot get info for Mixeway configuration... try {} ... reason - {}",tries, e.getLocalizedMessage());
143 | if (tries < 4){
144 | Thread.sleep(3000);
145 | return getCIInfo(getInfoRequest);
146 | }
147 | }
148 | return null;
149 | }
150 |
151 | public RestTemplate getRestTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
152 | TrustStrategy acceptingTrustStrategy = (x509Certificates, s) -> true;
153 | SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
154 | SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
155 | CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();
156 | HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
157 | requestFactory.setHttpClient(httpClient);
158 | return new RestTemplate(requestFactory);
159 | }
160 |
161 | public Status sendRequestToMixewayWithGitInfo(GitInformations gitInformations, PrepareCIOperation prepareCiOperations, List vulnerabilityList) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
162 | if (StringUtils.isNoneBlank(mixewayKey) ){
163 | log.info("[Mixeway Connector] Mixeway integraiton is enabled. Starting to push the results to {}", mixewayUrl);
164 | RestTemplate restTemplate = getRestTemplate();
165 | HttpHeaders headers = new HttpHeaders();
166 | headers.set(Constants.MIXEWAY_API_KEY, mixewayKey);
167 | headers.setContentType(MediaType.APPLICATION_JSON);
168 | HttpEntity> entity = new HttpEntity<>(vulnerabilityList,headers);
169 | try {
170 | ResponseEntity response = restTemplate.exchange(mixewayUrl +
171 | Constants.MIXEWAY_PUSH_VULN_URL
172 | + "/" + gitInformations.getProjectName() + "/" + gitInformations.getBranchName() + "/" + gitInformations.getCommitId(),
173 | HttpMethod.POST, entity, Status.class);
174 | if (response.getStatusCode() == HttpStatus.OK) {
175 | log.info("[Mixeway Connector] Results pushed and already visible at {}", mixewayUrl);
176 | return response.getBody();
177 | } else {
178 | log.error("[Mixeway Connector] Push results to Mixeway - {}", response.getStatusCodeValue());
179 | }
180 | } catch (HttpServerErrorException | HttpClientErrorException e) {
181 | log.error("[Mixeway Connector] Problem with contaictint with Mixeway - {}",e.getLocalizedMessage());
182 | }
183 | } else {
184 | log.info("[Mixeway Connector] Mixeway integration is not enabled, if You want to push results into mixeway please set MIXEWAY_URL and MIXEWAY_KEY. Read more at docs.");
185 | }
186 | return null;
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/Pom.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.utils;
2 |
3 | import javax.xml.bind.annotation.XmlElement;
4 |
5 | /**
6 | * @author gsiewruk
7 | */
8 | public class Pom {
9 | @XmlElement
10 | PomBuild build;
11 |
12 | public PomBuild getBuild() {
13 | return build;
14 | }
15 |
16 | public void setBuild(PomBuild build) {
17 | this.build = build;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/PomBuild.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.utils;
2 |
3 | import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
4 | import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
5 | import com.sun.xml.txw2.annotation.XmlElement;
6 | import lombok.AllArgsConstructor;
7 | import lombok.Builder;
8 |
9 | import javax.xml.bind.annotation.XmlRootElement;
10 | import java.util.List;
11 |
12 | /**
13 | * @author gsiewruk
14 | */
15 | @Builder
16 | @AllArgsConstructor
17 | @XmlRootElement(name = "build")
18 | @XmlElement("build")
19 | public class PomBuild {
20 | List plugins;
21 |
22 | public PomBuild(){}
23 |
24 | public List getPlugins() {
25 | return plugins;
26 | }
27 |
28 | public void setPlugins(List plugins) {
29 | this.plugins = plugins;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/PomConfiguration.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.utils;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Builder;
6 |
7 | import javax.xml.bind.annotation.XmlRootElement;
8 | import java.util.List;
9 |
10 | /**
11 | * @author gsiewruk
12 | */
13 | @Builder
14 | @AllArgsConstructor
15 | @JsonInclude(JsonInclude.Include.NON_EMPTY)
16 | @XmlRootElement(name = "configuration")
17 | public class PomConfiguration {
18 | String effort;
19 | String threshold;
20 | String failOnError;
21 | List plugins;
22 |
23 | public PomConfiguration(){}
24 |
25 |
26 | public String getThreshold() {
27 | return threshold;
28 | }
29 |
30 | public void setThreshold(String threshold) {
31 | this.threshold = threshold;
32 | }
33 |
34 | public String getEffort() {
35 | return effort;
36 | }
37 |
38 | public void setEffort(String effort) {
39 | this.effort = effort;
40 | }
41 |
42 | public String getFailOnError() {
43 | return failOnError;
44 | }
45 |
46 | public void setFailOnError(String failOnError) {
47 | this.failOnError = failOnError;
48 | }
49 |
50 | public List getPlugins() {
51 | return plugins;
52 | }
53 |
54 | public void setPlugins(List plugins) {
55 | this.plugins = plugins;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/PomPlugin.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.utils;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import com.sun.xml.txw2.annotation.XmlElement;
5 | import lombok.AllArgsConstructor;
6 | import lombok.Builder;
7 | import lombok.Getter;
8 |
9 | import javax.xml.bind.annotation.XmlRootElement;
10 |
11 | /**
12 | * @author gsiewruk
13 | */
14 | @Builder
15 | @AllArgsConstructor
16 | @JsonInclude(JsonInclude.Include.NON_EMPTY)
17 | @XmlRootElement(name = "plugin")
18 | @XmlElement("build")
19 | public class PomPlugin {
20 | String groupId;
21 | String artifactId;
22 | String version;
23 | PomConfiguration configuration;
24 |
25 | public PomPlugin(){}
26 |
27 | public String getGroupId() {
28 | return groupId;
29 | }
30 |
31 | public void setGroupId(String groupId) {
32 | this.groupId = groupId;
33 | }
34 |
35 | public String getArtifactId() {
36 | return artifactId;
37 | }
38 |
39 | public void setArtifactId(String artifactId) {
40 | this.artifactId = artifactId;
41 | }
42 |
43 | public String getVersion() {
44 | return version;
45 | }
46 |
47 | public void setVersion(String version) {
48 | this.version = version;
49 | }
50 |
51 | public PomConfiguration getConfiguration() {
52 | return configuration;
53 | }
54 |
55 | public void setConfiguration(PomConfiguration configuration) {
56 | this.configuration = configuration;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/PomPlugins.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.utils;
2 |
3 | import javax.xml.bind.annotation.XmlRootElement;
4 | import java.util.List;
5 |
6 | /**
7 | * @author gsiewruk
8 | */
9 | @XmlRootElement(name = "plugins")
10 | public class PomPlugins {
11 | List plugins;
12 |
13 | public List getPlugins() {
14 | return plugins;
15 | }
16 |
17 | public void setPlugins(List plugins) {
18 | this.plugins = plugins;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/PomProject.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.utils;
2 |
3 | import javax.xml.bind.annotation.XmlRootElement;
4 |
5 | /**
6 | * @author gsiewruk
7 | */
8 | @XmlRootElement(name = "project")
9 | public class PomProject {
10 | PomBuild build;
11 |
12 | public PomBuild getBuild() {
13 | return build;
14 | }
15 |
16 | public void setBuild(PomBuild build) {
17 | this.build = build;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/PrepareCIOperation.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.utils;
2 |
3 | /**
4 | * @author gsiewruk
5 | */
6 | public class PrepareCIOperation {
7 | Long projectId;
8 | Long codeProjectId;
9 | String openSourceScannerProjectId;
10 | String openSourceScannerCredentials;
11 | String openSourceScannerApiUrl;
12 | boolean openSourceScannerIntegration;
13 | String scannerType;
14 |
15 | public Long getCodeProjectId() {
16 | return codeProjectId;
17 | }
18 |
19 | public void setCodeProjectId(Long codeProjectId) {
20 | this.codeProjectId = codeProjectId;
21 | }
22 |
23 | public String getScannerType() {
24 | return scannerType;
25 | }
26 |
27 | public void setScannerType(String scannerType) {
28 | this.scannerType = scannerType;
29 | }
30 |
31 | public boolean isOpenSourceScannerIntegration() {
32 | return openSourceScannerIntegration;
33 | }
34 |
35 | public void setOpenSourceScannerIntegration(boolean openSourceScannerIntegration) {
36 | this.openSourceScannerIntegration = openSourceScannerIntegration;
37 | }
38 |
39 | public Long getProjectId() {
40 | return projectId;
41 | }
42 |
43 | public void setProjectId(Long projectId) {
44 | this.projectId = projectId;
45 | }
46 |
47 | public String getOpenSourceScannerProjectId() {
48 | return openSourceScannerProjectId;
49 | }
50 |
51 | public void setOpenSourceScannerProjectId(String openSourceScannerProjectId) {
52 | this.openSourceScannerProjectId = openSourceScannerProjectId;
53 | }
54 |
55 | public String getOpenSourceScannerCredentials() {
56 | return openSourceScannerCredentials;
57 | }
58 |
59 | public void setOpenSourceScannerCredentials(String openSourceScannerCredentials) {
60 | this.openSourceScannerCredentials = openSourceScannerCredentials;
61 | }
62 |
63 | public String getOpenSourceScannerApiUrl() {
64 | return openSourceScannerApiUrl;
65 | }
66 |
67 | public void setOpenSourceScannerApiUrl(String openSourceScannerApiUrl) {
68 | this.openSourceScannerApiUrl = openSourceScannerApiUrl;
69 | }
70 |
71 | }
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/ScannerPluginType.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.utils;
2 |
3 | public enum ScannerPluginType {
4 | DEPENDENCYTRACK,
5 | SPOTBUG,
6 | BANDIT,
7 | PROGPILOT;
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/ScannerType.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.utils;
2 |
3 | public enum ScannerType {
4 | OPENSOURCE,
5 | SAST,
6 | DAST,
7 | PROGPILOT
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/SourceProjectType.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.utils;
2 |
3 | /**
4 | * @author gsiewruk
5 | */
6 | public enum SourceProjectType {
7 | MAVEN,
8 | GRADLE,
9 | NPM,
10 | PIP,
11 | PHP
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/StandaloneGitResponse.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.utils;
2 |
3 | import lombok.Builder;
4 | import lombok.Getter;
5 |
6 | /**
7 | * @author gsiewruk
8 | */
9 | @Builder
10 | @Getter
11 | public class StandaloneGitResponse {
12 | private String branch;
13 | private String commitId;
14 | private String projectName;
15 |
16 | public StandaloneGitResponse(String branch, String commitId, String projectName) {
17 | this.branch = branch;
18 | this.commitId = commitId;
19 | this.projectName = projectName;
20 | }
21 |
22 | public StandaloneGitResponse() {
23 |
24 | }
25 |
26 | @Override
27 | public String toString() {
28 | return "StandaloneGitResponse{" +
29 | "branch='" + branch + '\'' +
30 | ", commitId='" + commitId + '\'' +
31 | ", projectName='" + projectName + '\'' +
32 | '}';
33 | }
34 |
35 | public String getBranch() {
36 | return branch;
37 | }
38 |
39 | public void setBranch(String branch) {
40 | this.branch = branch;
41 | }
42 |
43 | public String getCommitId() {
44 | return commitId;
45 | }
46 |
47 | public void setCommitId(String commitId) {
48 | this.commitId = commitId;
49 | }
50 |
51 | public String getProjectName() {
52 | return projectName;
53 | }
54 |
55 | public void setProjectName(String projectName) {
56 | this.projectName = projectName;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/Status.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.utils;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | public class Status {
7 | private final static Logger log = LoggerFactory.getLogger(Status.class);
8 | private String status;
9 | private String requestId;
10 |
11 | public String getRequestId() {
12 | return requestId;
13 | }
14 |
15 | public void setRequestId(String requestId) {
16 | this.requestId = requestId;
17 | }
18 |
19 | public String getStatus() {
20 | return status;
21 | }
22 |
23 | public void setStatus(String status) {
24 | this.status = status;
25 | }
26 |
27 | public Status(){}
28 |
29 | public Status(String status) {
30 | this.status = status;
31 | }
32 |
33 | public Status(String status, String requestId) {
34 | this.status = status;
35 | this.requestId = requestId;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/io/mixeway/scanner/utils/Vulnerability.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner.utils;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import io.mixeway.scanner.integrations.model.*;
5 | import org.apache.commons.lang3.StringUtils;
6 |
7 | /**
8 | * @author gsiewruk
9 | */
10 | @JsonInclude(JsonInclude.Include.NON_NULL)
11 | public class Vulnerability {
12 | private String name;
13 | private ScannerType scannerType;
14 | private String description;
15 | private String filename;
16 | private String line;
17 | private String severity;
18 | private String packageName;
19 | private String packageVersion;
20 | private String recomendations;
21 | private String references;
22 | private String category;
23 |
24 | /**
25 | * for Bandit integration
26 | * @param banditResult bandit report
27 | */
28 | public Vulnerability(BanditResult banditResult) {
29 | this.name = banditResult.getTest_name();
30 | this.description = banditResult.getIssue_text();
31 | this.filename = banditResult.getFilename();
32 | this.severity = StringUtils.capitalize(banditResult.getIssue_severity());
33 | this.line = banditResult.getLine_number();
34 | this.references = banditResult.getMore_info();
35 | this.scannerType = ScannerType.SAST;
36 | }
37 |
38 | /**
39 | * For Dependency Track Integraiton
40 | * @param dTrackVuln dTrack report
41 | */
42 | public Vulnerability(DTrackVuln dTrackVuln) {
43 | this.name = dTrackVuln.getVulnId();
44 | this.scannerType = ScannerType.OPENSOURCE;
45 | this.packageName = dTrackVuln.getComponents().stream().findFirst().orElse(null).getName();
46 | this.packageVersion = dTrackVuln.getComponents().stream().findFirst().orElse(null).getVersion();
47 | this.severity = dTrackVuln.getSeverity();
48 | this.description = dTrackVuln.getDescription();
49 | this.references = dTrackVuln.getReferences();
50 | this.recomendations = dTrackVuln.getRecommendation();
51 | }
52 |
53 | /**
54 | * For spotbug integration
55 | * @param bugInstance spotbug report
56 | */
57 | public Vulnerability(BugInstance bugInstance, BugPattern bugPattern) {
58 | this.name = bugPattern != null? bugPattern.getShortDescriptions() : bugInstance.getShortDescription();
59 | this.severity = getSeverityFromBugInstanceRank(bugInstance.getRank());
60 | this.filename = bugInstance.getSourceLine().getSourcepath();
61 | this.line = bugInstance.getSourceLine().getStart();
62 | this.description = bugPattern != null? bugPattern.getDetails() : bugInstance.getLongMessage();
63 | this.scannerType = ScannerType.SAST;
64 | this.category = bugInstance.getCategory();
65 | }
66 |
67 | public String getCategory() {
68 | return category;
69 | }
70 |
71 | public void setCategory(String category) {
72 | this.category = category;
73 | }
74 |
75 | private String getSeverityFromBugInstanceRank(String rank) {
76 | int rankValue = Integer.parseInt(rank);
77 | String severity = "Info";
78 | if (rankValue < 5){
79 | severity = "Critical";
80 | } else if (rankValue >=5 && rankValue < 10){
81 | severity = "High";
82 | } else if ( rankValue >= 10 && rankValue < 15){
83 | severity = "Medium";
84 | } else {
85 | severity = "Low";
86 | }
87 | return severity;
88 | }
89 |
90 | /**
91 | * For Progpilot integration
92 | * @param progPilotVuln
93 | */
94 | public Vulnerability(ProgPilotVuln progPilotVuln) {
95 | this.name = progPilotVuln.getVuln_name();
96 | this.scannerType = ScannerType.SAST;
97 | this.line = String.valueOf(progPilotVuln.getSource_line()[0]);
98 | this.filename =progPilotVuln.getSource_file()[0];
99 | }
100 |
101 | public String getRecomendations() {
102 | return recomendations;
103 | }
104 |
105 | public void setRecomendations(String recomendations) {
106 | this.recomendations = recomendations;
107 | }
108 |
109 | public String getName() {
110 | return name;
111 | }
112 |
113 | public void setName(String name) {
114 | this.name = name;
115 | }
116 |
117 | public ScannerType getScannerType() {
118 | return scannerType;
119 | }
120 |
121 | public void setScannerType(ScannerType scannerType) {
122 | this.scannerType = scannerType;
123 | }
124 |
125 | public String getDescription() {
126 | return description;
127 | }
128 |
129 | public void setDescription(String description) {
130 | this.description = description;
131 | }
132 |
133 | public String getFilename() {
134 | return filename;
135 | }
136 |
137 | public void setFilename(String filename) {
138 | this.filename = filename;
139 | }
140 |
141 | public String getLine() {
142 | return line;
143 | }
144 |
145 | public void setLine(String line) {
146 | this.line = line;
147 | }
148 |
149 | public String getSeverity() {
150 | return severity;
151 | }
152 |
153 | public void setSeverity(String severity) {
154 | this.severity = severity;
155 | }
156 |
157 | public String getPackageName() {
158 | return packageName;
159 | }
160 |
161 | public void setPackageName(String packageName) {
162 | this.packageName = packageName;
163 | }
164 |
165 | public String getPackageVersion() {
166 | return packageVersion;
167 | }
168 |
169 | public void setPackageVersion(String packageVersion) {
170 | this.packageVersion = packageVersion;
171 | }
172 |
173 | public String getReferences() {
174 | return references;
175 | }
176 |
177 | public void setReferences(String references) {
178 | this.references = references;
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | spring.application.name=mixeway
2 | server.port: 8443
3 | # SSL Configuration
4 | server.ssl.key-store:${PKCS12:/opt/pki/certificate.p12}
5 | server.ssl.key-store-password: ${PKCS12_PASSWORD:1qaz@WSX}
6 | server.ssl.keyStoreType: PKCS12
7 | spring.datasource.driverClassName=org.h2.Driver
8 | spring.datasource.username=sa
9 | spring.datasource.password=password
10 | spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
11 | spring.datasource.url=jdbc:h2:file:~/data/scannerdb
12 | spring.liquibase.change-log=classpath:db/changelog/changelog.sql
13 | sources.location=${SOURCES_LOCATION:mixeway_scan_sources}
14 | sonatype.oss.username=${OSS_USERNAME:blank}
15 | sonatype.oss.key=${OSS_KEY:blank}
16 | source.branch=${BRANCH:master}
17 | mixeway.url=${MIXEWAY_URL:https://hub.mixeway.io}
18 | mixeway.key=${MIXEWAY_KEY:}
19 | mixeway.project=${MIXEWAY_PROJECT_ID:0}
20 | mixeway.project.name=${MIXEWAY_PROJECT_NAME:}
--------------------------------------------------------------------------------
/src/main/resources/db/changelog/changelog.sql:
--------------------------------------------------------------------------------
1 | --liquibase formatted sql
2 |
3 | --changeset gsiewruk:prerelease
4 | create table dependencytrack
5 | (
6 | id serial primary key,
7 | enabled boolean,
8 | apikey text
9 | );
10 | create table scannertype(
11 | id serial primary key,
12 | name text
13 | );
14 | insert into scannertype (name) values ('DependencyTrack'), ('Spotbug');
15 | create table scan (
16 | id serial primary key,
17 | scannertype_id int references scannertype(id),
18 | inserted date,
19 | running boolean
20 | );
--------------------------------------------------------------------------------
/src/test/java/io/mixeway/scanner/ScannerApplicationTests.java:
--------------------------------------------------------------------------------
1 | package io.mixeway.scanner;
2 |
3 |
4 | import com.fasterxml.jackson.annotation.JsonInclude;
5 | import com.fasterxml.jackson.databind.DeserializationFeature;
6 | import com.fasterxml.jackson.dataformat.xml.XmlMapper;
7 | import io.mixeway.scanner.utils.Pom;
8 | import io.mixeway.scanner.utils.PomBuild;
9 | import io.mixeway.scanner.utils.PomConfiguration;
10 | import io.mixeway.scanner.utils.PomPlugin;
11 | import org.apache.commons.io.FileUtils;
12 | import org.apache.commons.io.filefilter.DirectoryFileFilter;
13 | import org.apache.commons.io.filefilter.RegexFileFilter;
14 | import org.dom4j.DocumentException;
15 | import org.dom4j.io.SAXReader;
16 | import org.junit.jupiter.api.Test;
17 | import org.junit.runner.RunWith;
18 | import org.springframework.test.context.junit4.SpringRunner;
19 | import org.w3c.dom.Document;
20 | import org.w3c.dom.Element;
21 | import org.w3c.dom.Node;
22 | import org.w3c.dom.NodeList;
23 | import org.xml.sax.InputSource;
24 | import org.xml.sax.SAXException;
25 |
26 |
27 | import javax.xml.parsers.DocumentBuilder;
28 | import javax.xml.parsers.DocumentBuilderFactory;
29 | import javax.xml.parsers.ParserConfigurationException;
30 | import javax.xml.transform.Transformer;
31 | import javax.xml.transform.TransformerConfigurationException;
32 | import javax.xml.transform.TransformerException;
33 | import javax.xml.transform.TransformerFactory;
34 | import javax.xml.transform.dom.DOMSource;
35 | import javax.xml.transform.stream.StreamResult;
36 | import java.io.*;
37 | import java.util.ArrayList;
38 | import java.util.Collection;
39 | import java.util.List;
40 | import java.util.Optional;
41 | import java.util.function.Predicate;
42 | import java.util.stream.Collectors;
43 |
44 | @RunWith(SpringRunner.class)
45 | class ScannerApplicationTests {
46 |
47 | @Test
48 | void contextLoads() throws IOException, InterruptedException, ParserConfigurationException, SAXException, DocumentException, TransformerException {
49 | List packagePaths= FileUtils.listFiles(
50 | new File("/tmp/testjs"),
51 | new RegexFileFilter("package.json"),
52 | DirectoryFileFilter.DIRECTORY
53 | ).stream().map(File::getAbsoluteFile).map(file -> file.toString().split("/package.json")[0]).collect(Collectors.toList());
54 | packagePaths.forEach(s -> System.out.println(s));
55 |
56 |
57 | }
58 |
59 |
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/startup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | PROFILES=("REST" "STANDALONE")
3 | # Run DTrack
4 |
5 | echo "Starting Dependency-Track"
6 | cd /opt/dtrack/ && nohup java -Xmx4G -XX:ActiveProcessorCount=2 -jar dependency-track-embedded.war > /opt/dtrack/dtrack.log 2>&1 &
7 | echo "Waiting for NVD to load"
8 | sleep 25
9 | echo "Starting Mixeway Scanner APP"
10 |
11 | if [ -n "$MODE" ]; then
12 | if [[ "$MODE" = "REST" ]] ; then
13 | echo "Selected mode: REST"
14 | cd /app && java -jar /app/app.jar
15 | elif [[ "$MODE" = "STANDALONE" ]] ; then
16 | echo "Selected mode: STANDALONE"
17 | cd /app && java -jar -Dspring.main.web-application-type=NONE /app/app.jar
18 | else
19 | echo "Unknown MODE - $MODE, quitting.."
20 | exit 1
21 | fi
22 | else
23 | echo "MODE variable is not set, running REST which is default mode"
24 | cd /app && java -jar /app/app.jar
25 | fi
26 |
27 |
--------------------------------------------------------------------------------