Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve cancel scan and logging of Veracode scanner #127

Merged
merged 7 commits into from
Jun 26, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions internal/scan-manager/scanners/common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,14 @@
<version>${org.apache.commons.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${org.apache.logging.log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${org.apache.logging.log4j.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
Expand Down Expand Up @@ -116,6 +121,7 @@
<com.jcraft.jsch.version>0.1.54</com.jcraft.jsch.version>
<org.wso2.orbit.xerces.version>2.12.0.wso2v1</org.wso2.orbit.xerces.version>
<org.apache.commons.version>1.16</org.apache.commons.version>
<org.apache.logging.log4j.version>2.11.0</org.apache.logging.log4j.version>
<org.apache.httpcomponents.httpclient.version>4.5.3</org.apache.httpcomponents.httpclient.version>
<com.google.code.gson.version>2.8.2</com.google.code.gson.version>
<scanmanager.common.internal.version>1.0-SNAPSHOT</scanmanager.common.internal.version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ public final class ScannerConstants {
public static final String POM_FILE = "pom.xml";
public static final String PDF_FILE_EXTENSION = ".pdf";
public static final String XML_FILE_EXTENSION = ".xml";
public static final String CALLBACK_RETRY_INTERVAL_SECONDS = "callback_retry_interval_seconds";
public static final String CALLBACK_RETRY_INCREASE_SECONDS = "callback_retry_interval_seconds";
public static final String CONFIGURTION_FILE_NAME = "scanner-config.yaml";
public static final String RESOURCE_FILE_PATH = "src/main/resources";
Expand All @@ -44,19 +43,12 @@ public final class ScannerConstants {

// Scan manager config.
public static final String SCAN_MANAGER_CALLBACK_URL_ENDPOINT = "scan_manager_callback_url_endpoint";
public static final String SCAN_MANAGER_CALLBACK_URL = "scan_manager_callback_url";
public static final String SCAN_MANAGER_CALLBACK_STATUS = "scan_manager_callback_status";
public static final String SCAN_MANAGER_CALLBACK_LOG = "scan_manager_callback_log";
public static final String SCAN_MANAGER_HOST = "scan.manager.host";
public static final String SCAN_MANAGER_PORT = "scan.manager.port";
public static final String SCAN_MANAGER_HOST = "SCAN_MANAGER_HOST";
public static final String SCAN_MANAGER_PORT = "SCAN_MANAGER_PORT";
public static final String HTTP_PROTOCOL = "http://";

// Log types.
public static final String INFO = "info";
public static final String WARN = "warn";
public static final String DEBUG = "debug";
public static final String ERROR = "error";

private ScannerConstants() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,21 @@

package org.wso2.security.tools.scanmanager.scanners.common;

import org.apache.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.wso2.security.tools.scanmanager.common.internal.model.ScannerScanRequest;
import org.wso2.security.tools.scanmanager.common.model.ErrorMessage;
import org.wso2.security.tools.scanmanager.common.model.LogType;
import org.wso2.security.tools.scanmanager.scanners.common.service.Scanner;
import org.wso2.security.tools.scanmanager.scanners.common.util.CallbackUtil;

import java.io.IOException;

Expand All @@ -43,8 +43,15 @@
@RequestMapping("scanner")
public class ScannerController {

private static final Logger log = Logger.getLogger(ScannerController.class);
private static final Logger log = LogManager.getLogger(ScannerController.class);
Scanner scanner;

// Scan task thread.
Thread startScanThread;

// Cancel scan task thread.
Thread cancelScanThread;

// This represents if a scan is started.
private boolean hasScanStarted = false;

Expand All @@ -57,26 +64,50 @@ public ScannerController(Scanner scanner) throws IOException {
/**
* Start a new scan.
*
* @param scanRequest Object that represent the required information for the scanner operation
* @param scannerScanRequest Object that represent the required information for the scanner operation
* @return whether the start scan request is accepted
*/
@PostMapping("scan")
@ResponseBody
public ResponseEntity startScan(@RequestBody ScannerScanRequest scanRequest) {
public ResponseEntity startScan(@RequestBody ScannerScanRequest scannerScanRequest) {
ResponseEntity responseEntity;
responseEntity = validateStartScanReq(scannerScanRequest);
if (responseEntity.getStatusCode().equals(HttpStatus.ACCEPTED)) {
if (scanner.validateStartScan(scannerScanRequest)) {
log.info("Invoking start scan API.");
startScanThread = new Thread(() -> scanner.startScan(scannerScanRequest), "StartScanThread");

if (!hasScanStarted) {
log.info("Invoking start scan API.");
responseEntity = scanner.startScan(scanRequest);
if (responseEntity.getStatusCode().equals(HttpStatus.ACCEPTED)) {
startScanThread.start();
hasScanStarted = true;
} else {
String message = "Start scan request validation is failed.";
responseEntity = new ResponseEntity<>(new ErrorMessage(HttpStatus.BAD_REQUEST.value(),
message), HttpStatus.BAD_REQUEST);
}
}
return responseEntity;
}

private ResponseEntity validateStartScanReq(ScannerScanRequest scannerScanRequest) {
ResponseEntity responseEntity;
if (!hasScanStarted) {
if (!StringUtils.isEmpty(scannerScanRequest.getAppId())) {
if (!StringUtils.isEmpty(scannerScanRequest.getJobId())) {
responseEntity = new ResponseEntity<>(HttpStatus.ACCEPTED);
} else {
String message = "Job Id is missing in the request.";
responseEntity = new ResponseEntity<>(new ErrorMessage(HttpStatus.BAD_REQUEST.value(),
message), HttpStatus.BAD_REQUEST);
}
} else {
String message = "Application Id is missing in the request.";
responseEntity = new ResponseEntity<>(new ErrorMessage(HttpStatus.BAD_REQUEST.value(),
message), HttpStatus.BAD_REQUEST);
}
} else {
String message = "Cannot start a new scan since another scan is in progress.";
NShani marked this conversation as resolved.
Show resolved Hide resolved
responseEntity = new ResponseEntity<>(new ErrorMessage(HttpStatus.BAD_REQUEST.value(),
message), HttpStatus.BAD_REQUEST);
log.error(message);
CallbackUtil.persistScanLog(scanRequest.getJobId(), message, LogType.ERROR);
}
return responseEntity;
}
Expand All @@ -96,12 +127,36 @@ public ResponseEntity cancelScan(@RequestBody ScannerScanRequest scanRequest) {
String message = "No scan running to perform cancellation.";
responseEntity = new ResponseEntity<>(new ErrorMessage(HttpStatus.NOT_ACCEPTABLE.value(),
message), HttpStatus.BAD_REQUEST);
log.error(message);
CallbackUtil.persistScanLog(scanRequest.getJobId(), message, LogType.ERROR);
} else {
log.info("Invoking cancel scan API.");
responseEntity = scanner.cancelScan(scanRequest);
if (scanner.validateCancelScan(scanRequest)) {
if (startScanThread != null) {
startScanThread.interrupt();
} else {
log.info("There is no running scan thread to cancel.");
}

cancelScanThread = new Thread(() -> {
NShani marked this conversation as resolved.
Show resolved Hide resolved
stopStartScanThread();
scanner.cancelScan(scanRequest);
}, "CancelScanThread");
cancelScanThread.start();

responseEntity = new ResponseEntity<>(HttpStatus.ACCEPTED);
} else {
String message = "Cancel scan request validation is failed.";
responseEntity = new ResponseEntity<>(new ErrorMessage(HttpStatus.BAD_REQUEST.value(),
message), HttpStatus.BAD_REQUEST);
}
}
return responseEntity;
}

private boolean stopStartScanThread() {

NShani marked this conversation as resolved.
Show resolved Hide resolved
while (startScanThread.isAlive()) {
// run until the start scan thread is dead.
NShani marked this conversation as resolved.
Show resolved Hide resolved
}
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2019, WSO2 Inc., WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.security.tools.scanmanager.scanners.common.logging;

import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.message.Message;
import org.wso2.security.tools.scanmanager.scanners.common.model.CallbackLog;
import org.wso2.security.tools.scanmanager.scanners.common.util.CallbackUtil;

/**
* Log appender to persist the logs in the scan manager.
*/
@Plugin(category = "Core", name = "CallbackLogAppender")
public class CallbackLogAppender extends AbstractAppender {

private CallbackLogAppender(String name) {
super(name, null, null);
}

@PluginFactory
public static CallbackLogAppender createAppender(@PluginAttribute("name") String name) {
return new CallbackLogAppender(name);
}

@Override
public void append(LogEvent event) {
Message message = event.getMessage();
event.getLevel();
if (message instanceof CallbackLog) {
CallbackLog callbackLog = (CallbackLog) event.getMessage();

CallbackUtil.persistScanLog(callbackLog.getJobId(), callbackLog.getMessage(), event.getLevel());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2019, WSO2 Inc., WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.security.tools.scanmanager.scanners.common.model;

import org.apache.logging.log4j.message.Message;

/**
* Model to represent the logging event message.
*/
public class CallbackLog implements Message {
private String jobId;
private String msg;
private static final Object[] NULL_OBJECT = {};
private static final long serialVersionUID = 2L;

public CallbackLog(String jobId, String msg) {
this.msg = msg;
this.jobId = jobId;
}

public String getJobId() {
return jobId;
}

public void setJobId(String jobId) {
this.jobId = jobId;
}

public String getMessage() {
return msg;
}

public void setMessage(String msg) {
this.msg = msg;
}

@Override
public String getFormattedMessage() {
return msg;
}

@Override
public String getFormat() {
return null;
}

@Override
public Object[] getParameters() {
return NULL_OBJECT;
}

@Override
public Throwable getThrowable() {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

package org.wso2.security.tools.scanmanager.scanners.common.service;

import org.springframework.http.ResponseEntity;
import org.wso2.security.tools.scanmanager.common.internal.model.ScannerScanRequest;

/**
Expand All @@ -32,16 +31,29 @@ public interface Scanner {
* Run scan.
*
* @param scanRequest Object that represent the required information for tha scanner operation
* @return details of the start scan response from the scanner service
*/
public ResponseEntity startScan(ScannerScanRequest scanRequest);
public void startScan(ScannerScanRequest scanRequest);

/**
* Validate the start scan request.
*
* @param scannerScanRequest start scan request
* @return whether start scan request is a valid one
*/
public boolean validateStartScan(ScannerScanRequest scannerScanRequest);

/**
* Stop the last scan for a given application.
*
* @param scanRequest Object that represent the required information for tha scanner operation
* @return details of the cancel scan response from the scanner service
*/
public ResponseEntity cancelScan(ScannerScanRequest scanRequest);
public void cancelScan(ScannerScanRequest scanRequest);

/**
* Validate the cancel scan request.
*
* @param scannerScanRequest cancel scan request
* @return whether cancel scan request is a valid one
*/
public boolean validateCancelScan(ScannerScanRequest scannerScanRequest);
}
Loading