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

[ASA 9675] DAST rescan #176

Merged
merged 15 commits into from
Dec 16, 2024
8 changes: 5 additions & 3 deletions src/main/java/com/hcl/appscan/sdk/CoreConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public interface CoreConstants {
String API_PRESENCES_ID = API_ENV_LATEST + "/Presences/%s"; //$NON-NLS-1$
String API_PRESENCES_NEW_KEY = API_ENV_LATEST + "/Presences/%s/NewKey"; //$NON-NLS-1$
String API_BASIC_DETAILS = API_ENV_LATEST + "/Scans"; //$NON-NLS-1$
String API_SCANNER_DETAILS = API_ENV + "/Scans/&s/&s"; //$NON-NLS-1$
String API_SCANNER_DETAILS = API_ENV_LATEST + "/Scans/%s/%s"; //$NON-NLS-1$
String API_FILE_UPLOAD = API_ENV_LATEST + "/FileUpload"; //$NON-NLS-1$
String API_SCAN = API_ENV + "/%s"; //$NON-NLS-1$
String API_SCANNER = API_ENV_LATEST + "/Scans/%s"; //$NON-NLS-1$
Expand All @@ -91,6 +91,8 @@ public interface CoreConstants {
String API_IS_VALID_URL = API_ENV_LATEST + "/Scans/IsValidUrl"; //$NON-NLS-1$
String API_AUTHENTICATION = API_ENV_LATEST + "/Account/IsAuthenticated"; //$NON-NLS-1$
String API_TENANT_INFO = API_ENV_LATEST + "/Account/TenantInfo"; //$NON-NLS-1$
String API_SAST_DETAILS = API_ENV_LATEST + "/Sast/%s"; //$NON-NLS-1$
String API_EXECUTION_DETAILS = API_ENV_LATEST + "/Scans/%s/Executions"; //$NON-NLS-1$

String DEFAULT_RESULT_NAME = "asoc_results"; //$NON-NLS-1$
String SACLIENT_INSTALL_DIR = "SAClientInstall"; //$NON-NLS-1$
Expand Down Expand Up @@ -146,8 +148,8 @@ public interface CoreConstants {
String ERROR_GETTING_INFO = "error.getting.info"; //$NON-NLS-1$
String ERROR_URL_VALIDATION = "error.url.validation"; //$NON-NLS-1$
String FORMAT_PARAMS = "FormatParams"; //$NON-NLS-1$
String ERROR_GETTING_SCANLOG = "error.getting.scanlog"; //$NON-NLS-1$
String ERROR_GETTING_SCANLOG = "error.getting.scanlog"; //$NON-NLS-1$
String ERROR_CANCEL_RESCAN = "error.cancel.rescan"; //$NON-NLS-1$
// ASE Status Messages
String CREATING_JOB = "message.creating.job"; //$NON-NLS-1$
String CREATE_JOB_SUCCESS = "message.created.job"; //$NON-NLS-1$
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/hcl/appscan/sdk/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ error.getting.info=An error occurred getting information for {0} with id {1}.
error.getting.scanlog=An error occurred retrieving the scan log.
error.url.validation = An error occurred while validating the Starting URL: {0}.
message.update.job = Updated the scan job parameters.
error.cancel.rescan = The rescan may have been cancelled due to an issue. Please check the scan status on the AppScan server.

#Presence
error.getting.presence.details=An error occurred retrieving details for Presence with id {0}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,16 @@ protected void loadResults() {
return;
}

if (m_executionId != null && !m_executionId.isEmpty()) {
String executionId = obj.getString(ID);
if (executionId.equals(m_executionId)) {
m_status = obj.getString(STATUS);
} else {
m_progress.setStatus(new Message(Message.INFO, Messages.getMessage(ERROR_CANCEL_RESCAN)));
m_status = FAILED;
}
}

m_status = obj.getString(STATUS);
if (FAILED.equalsIgnoreCase(m_status) && obj.has(USER_MESSAGE)) {
m_progress.setStatus(new Message(Message.ERROR, obj.getString(USER_MESSAGE)));
m_message = obj.getString(USER_MESSAGE);
Expand Down
14 changes: 10 additions & 4 deletions src/main/java/com/hcl/appscan/sdk/scanners/dynamic/DASTScan.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,19 @@ public void run() throws ScannerException, InvalidTargetException {

try {
JSONObject propertiesJSON = createJSONForProperties(params);
setScanId(getServiceProvider().createAndExecuteScan(type, propertiesJSON));
if (getRescan()) {
setScanId(params.get(CoreConstants.SCAN_ID));
setExecutionId(getServiceProvider().rescan(getScanId(), propertiesJSON));
if(getExecutionId() == null)
throw new ScannerException(Messages.getMessage(ERROR_CREATING_SCAN));
} else {
setScanId(getServiceProvider().createAndExecuteScan(type, propertiesJSON));
if(getScanId() == null)
throw new ScannerException(Messages.getMessage(ERROR_CREATING_SCAN));
}
} catch (JSONException e) {
throw new ScannerException(Messages.getMessage(ERROR_RUNNING_SCAN, e.getLocalizedMessage()));
}

if(getScanId() == null)
throw new ScannerException(Messages.getMessage(ERROR_CREATING_SCAN));
}

private JSONObject createJSONForProperties(Map<String, String> params) throws JSONException {
Expand Down
6 changes: 4 additions & 2 deletions src/main/java/com/hcl/appscan/sdk/scanners/sast/SASTScan.java
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,14 @@ protected void analyzeIR() throws IOException, ScannerException {
setScanId(params.get(CoreConstants.SCAN_ID));
params.put(CoreConstants.FILE_ID, fileId);
submitRescan();
if(getExecutionId() == null)
throw new ScannerException(Messages.getMessage(ERROR_CREATING_SCAN));
} else {
params.put(FILE_ID, fileId);
submitScan();
if(getScanId() == null)
throw new ScannerException(Messages.getMessage(ERROR_CREATING_SCAN));
}
if(getScanId() == null)
throw new ScannerException(Messages.getMessage(ERROR_SUBMITTING_IRX));
}

protected void submitScan() {
Expand Down
3 changes: 0 additions & 3 deletions src/main/java/com/hcl/appscan/sdk/utils/ArchiveUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,6 @@ public static void zipFileOrFolder(File fileToZip, File zipFile) throws IOExcept
}

private static void zipFile(File fileToZip, String fileName, ZipOutputStream zipOut) throws IOException {
if (fileToZip.getName().startsWith(".")) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was the reason for the removal of this check?

Copy link
Author

@vishalhcl-5960 vishalhcl-5960 Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is being made to include the ".git" folder when creating a zip archive of the parent folder from a Git repository.
Task detail: https://jira02.hclpnp.com/browse/ASA-9830

return;
}
if (fileToZip.isDirectory()) {
File[] children = fileToZip.listFiles();
for (File childFile : children) {
Expand Down
146 changes: 110 additions & 36 deletions src/main/java/com/hcl/appscan/sdk/utils/ServiceUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -223,77 +223,151 @@ private static boolean hasEntitlement(String scanType, IAuthenticationProvider p
return false;
}

public static String updatedScanType(String type) {
switch (type) {
case "Static Analyzer":
return STATIC_TECH;
case "Dynamic Analyzer":
return DYNAMIC_TECH;
case CoreConstants.SOFTWARE_COMPOSITION_ANALYZER:
return SCA_TECH;
}
return type;
}

/**
* Checks if the given scanId is valid for scanning.
* Update the scan data.
*
* @param scanId The scanId to test.
* @param applicationId The applicationId to verify.
* @param type The scanType to verify.
* @param scanId The scanId of the scan whose configuration has to update.
* @param params The map of properties which has to update .
* @param provider The IAuthenticationProvider for authentication.
* @return True if the scanId is valid. False is returned if the scanId is not valid, the request fails, or an exception occurs.
* @param progress The IProgress for setting the status messages.
*/
public static boolean isScanId(String scanId, String applicationId, String type, IAuthenticationProvider provider) {
public static void updateScanData(Map<String, String> params, String scanId, IAuthenticationProvider provider, IProgress progress) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the other comments, it's not clear why this is being added as a utility method, as opposed to the IScanServiceProvider that performs related functions.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I will move it to the cloudScanServiceProvider class.

if (provider.isTokenExpired()) {
return true;
return;
}

String request_url = provider.getServer() + API_BASIC_DETAILS;
request_url += "?$filter=Id%20eq%20" + scanId + "&%24select=AppId%2C%20Technology";
String request_url = provider.getServer() + String.format(API_SCANNER,scanId);
Map<String, String> request_headers = provider.getAuthorizationHeader(true);
request_headers.put("accept", "application/json");
request_headers.put("Content-Type", "application/json");

HttpClient client = new HttpClient(provider.getProxy(), provider.getacceptInvalidCerts());
try {
HttpResponse response = client.get(request_url, request_headers, null);

if (response.isSuccess()) {
JSONObject obj = (JSONObject) response.getResponseBodyAsJSON();
JSONArray array = (JSONArray) obj.get(ITEMS);
if (array.isEmpty()) {
return false;
} else {
JSONObject body = (JSONObject) array.getJSONObject(0);
String appId = body.getString(CoreConstants.APP_ID);
String technologyName = body.getString("Technology");
return appId.equals(applicationId) && technologyName.equals(updatedScanType(type));
}
HttpResponse response = client.put(request_url, request_headers, params);
if (response.getResponseCode() == HttpsURLConnection.HTTP_NO_CONTENT) {
progress.setStatus(new Message(Message.INFO, Messages.getMessage(UPDATE_JOB)));
}
} catch (IOException | JSONException e) {
// Ignore and return false.
progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_UPDATE_JOB, e.getLocalizedMessage())));
}

return false;
}

public static String updatedScanType(String type) {
public static String scanTypeShortForm(String type) {
switch (type) {
case "Static Analyzer":
return STATIC_TECH;
return "Sast";
case "Dynamic Analyzer":
return DYNAMIC_TECH;
return "Dast";
case CoreConstants.SOFTWARE_COMPOSITION_ANALYZER:
return SCA_TECH;
return "Sca";
}
return type;
}

public static void updateScanData(Map<String, String> params, String scanId, IAuthenticationProvider provider, IProgress progress) {
/**
* Fetch the detailed description of a scan.
*
* @param type The selected scan type
* @param scanId The scanId to test
* @param provider The IAuthenticationProvider for authentication.
* @return JSONObject.
*/
public static JSONObject scanSpecificDetails(String type, String scanId, IAuthenticationProvider provider) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name of this method should be an action, like "getScanDetails()".

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, renaming the method to "getScanDetails()".

if (provider.isTokenExpired()) {
return;
return null;
}

String request_url = provider.getServer() + String.format(API_SCANNER,scanId);
String request_url = provider.getServer() + String.format(API_SCANNER_DETAILS, scanTypeShortForm(type), scanId);
Map<String, String> request_headers = provider.getAuthorizationHeader(true);
request_headers.put("accept", "application/json");
request_headers.put("Content-Type", "application/json");

HttpClient client = new HttpClient(provider.getProxy(), provider.getacceptInvalidCerts());
try {
HttpResponse response = client.put(request_url, request_headers, params);
if (response.getResponseCode() == HttpsURLConnection.HTTP_NO_CONTENT) {
progress.setStatus(new Message(Message.INFO, Messages.getMessage(UPDATE_JOB)));
HttpResponse response = client.get(request_url, request_headers, null);

if (response.isSuccess()) {
return (JSONObject) response.getResponseBodyAsJSON();
}
} catch (IOException | JSONException e) {
progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_UPDATE_JOB, e.getLocalizedMessage())));
// Ignore and return false.
}

return null;
}

/**
* Fetch the details of all the executions of a scan.
*
* @param scanId The scanId to test
* @param provider The IAuthenticationProvider for authentication.
* @return JSONArray.
*/
public static JSONArray getExecutionDetails(String scanId, IAuthenticationProvider provider) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are there DAST specific checks here? The "IsValidForIncremental" property would only be true for DAST scans, but what if someone called this method for a SAST or SCA scan? This seems like a very specific method that is being added as a general utility method.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is used to fetch the "executionIds" which helps to fill the base scan dropdown field of incremental scan. I am renaming this method to "getBaseScanDetails" for better understanding.

if (provider.isTokenExpired()) {
return null;
}

String request_url = provider.getServer() + String.format(API_EXECUTION_DETAILS, scanId);
request_url += "?$filter=IsValidForIncremental%20eq%20true&%24select=Id%2C%20CreatedAt%2C%20IsValidForIncremental&%24orderby=CreatedAt%20desc";
Map<String, String> request_headers = provider.getAuthorizationHeader(true);
request_headers.put("accept", "application/json");
request_headers.put("Content-Type", "application/json");

HttpClient client = new HttpClient(provider.getProxy(), provider.getacceptInvalidCerts());
try {
HttpResponse response = client.get(request_url, request_headers, null);

if (response.isSuccess()) {
return (JSONArray) response.getResponseBodyAsJSON();
}
} catch (IOException | JSONException e) {
// Ignore and return false.
}

return null;
}

/**
* Fetch the details of all the executions of a scan.
*
* @param provider The IAuthenticationProvider for authentication.
* @return String.
*/
public static String getA360Version(IAuthenticationProvider provider) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a number of problems with this method:

  1. The javadoc comment is not accurate.
  2. The method name should just be getServiceVersion, not getA360Version.
  3. We shouldn't need a valid token to check the service version.
  4. We shouldn't need the authentication header.
  5. You should use "body.getString()" as opposed to casting.
  6. The comment in the catch block doesn't make sense.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, Made the suggested changes.

if (provider.isTokenExpired()) {
return null;
}

String request_url = provider.getServer() + "/assets/versions.json";
Map<String, String> request_headers = provider.getAuthorizationHeader(true);
request_headers.put("accept", "application/json");
request_headers.put("Content-Type", "application/json");

HttpClient client = new HttpClient(provider.getProxy(), provider.getacceptInvalidCerts());
try {
HttpResponse response = client.get(request_url, request_headers, null);

if (response.isSuccess()) {
JSONObject body = (JSONObject) response.getResponseBodyAsJSON();
return (String) body.get("MainVersion");
}
} catch (IOException | JSONException e) {
// Ignore and return false.
}

return null;
}
}