diff --git a/Notices.txt b/Notices.txt
new file mode 100644
index 00000000..2793e869
--- /dev/null
+++ b/Notices.txt
@@ -0,0 +1,278 @@
+-----------------------
+Notices and Information
+-----------------------
+-----------------------
+HCL AppScan SDK v1.1.11
+-----------------------
+
+======
+DETAIL
+======
+Note: generic licenses are marked with (*)
+Note: missing copyright references are marked with (*)
+***************************************************************
+1. Library: appscan-sdk-appscan.sdk-1.1.10 Product: AppScan-SDK
+***************************************************************
+--------
+PROJECTS
+--------
+1.1.11
+
+
+========
+LICENSES
+========
+Licensed under Apache 2.0
+License terms can be found at: https://github.com/HCL-TECH-SOFTWARE/appscan-sdk/blob/appscan.sdk-1.1.10/LICENSE
+
+License Text Under Appendix
+
+
+
+==========
+COPYRIGHTS
+==========
+(*) The copyright for this library is unknown
+
+****************************************************
+2. Library: wink-json4j-1.4.jar Product: AppScan-SDK
+****************************************************
+--------
+PROJECTS
+--------
+1.1.11
+
+
+========
+LICENSES
+========
+Licensed under Apache 2.0
+License terms can be found at: https://repo.maven.apache.org/maven2/org/apache/wink/wink-json4j/1.4/wink-json4j-1.4.pom
+
+License Text Under Appendix
+
+
+
+==========
+COPYRIGHTS
+==========
+Copyrighted under Copyright The Apache Software Foundation
+Copyright terms can be found at: null(*) Cannot be established
+
+
+
+
+=========================
+APPENDIX: License Details
+=========================
+
+**********
+Apache 2.0
+**********
+License Text:
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
+
+
+
+
diff --git a/README.md b/README.md
index 9046f8c2..88a3c584 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# appscan-sdk
-SDK for interacting with HCL AppScan on Cloud and HCL AppScan Enterprise ADAC Jobs
+SDK for interacting with HCL AppScan on Cloud, HCL AppScan 360° and HCL AppScan Enterprise ADAC Jobs.
# JavaDoc
https://www.javadoc.io/doc/com.hcl/appscan.sdk/latest/index.html
diff --git a/pom.xml b/pom.xml
index c57af4ef..56e65d62 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
com.hcl
appscan.sdk
- 1.1.3-SNAPSHOT
+ 1.1.12-SNAPSHOT
HCL AppScan on Cloud SDK
SDK for interacting with HCL AppScan on Cloud
@@ -22,6 +22,10 @@
+
+ UTF-8
+
+
@@ -45,10 +49,19 @@
maven-compiler-plugin
3.5.1
- 1.7
- 1.7
+ 1.8
+ 1.8
+
+ org.sonatype.central
+ central-publishing-maven-plugin
+ 0.8.0
+ true
+
+ central
+
+
@@ -58,6 +71,16 @@
wink-json4j
1.4
+
+ org.apache.commons
+ commons-compress
+ 1.26.0
+
+
+ commons-io
+ commons-io
+ 2.17.0
+
@@ -123,12 +146,12 @@
- ossrh
- https://oss.sonatype.org/content/repositories/snapshots
+ central
+ https://central.sonatype.com/repository/maven-snapshots
- ossrh
- https://oss.sonatype.org/service/local/staging/deploy/maven2/
+ central
+ https://central.sonatype.com
diff --git a/src/main/java/com/hcl/appscan/sdk/CoreConstants.java b/src/main/java/com/hcl/appscan/sdk/CoreConstants.java
index c5722594..5235c22f 100644
--- a/src/main/java/com/hcl/appscan/sdk/CoreConstants.java
+++ b/src/main/java/com/hcl/appscan/sdk/CoreConstants.java
@@ -1,6 +1,6 @@
/**
* © Copyright IBM Corporation 2016.
- * © Copyright HCL Technologies Ltd. 2017, 2024.
+ * © Copyright HCL Technologies Ltd. 2017, 2026.
* LICENSE: Apache License, Version 2.0 https://www.apache.org/licenses/LICENSE-2.0
*/
@@ -10,13 +10,19 @@ public interface CoreConstants {
String DEFAULT_SERVER = "https://cloud.appscan.com"; //$NON-NLS-1$
+ //Technologies
+ String DYNAMIC_TECH = "DynamicAnalyzer"; //$NON-NLS-1$
+ String SCA_TECH = "ScaAnalyzer"; //$NON-NLS-1$
+ String STATIC_TECH = "StaticAnalyzer"; //$NON-NLS-1$
+
String APP_ID = "AppId"; //$NON-NLS-1$
String EMAIL_NOTIFICATION = "EnableMailNotification"; //$NON-NLS-1$
- String PERSONAL_SCAN = "Personal"; //$NON-NLS-1$
+ String PERSONAL_SCAN = "Personal"; //$NON-NLS-1$
String FILE_ID = "FileId"; //$NON-NLS-1$
String FILE_TO_UPLOAD = "fileToUpload"; //$NON-NLS-1$
String UPLOADED_FILE = "uploadedFile"; //$NON-NLS-1$
String ID = "Id"; //$NON-NLS-1$
+ String SCAN_ID = "ScanId"; //$NON-NLS-1$
String KEY = "Key"; //$NON-NLS-1$
String LATEST_EXECUTION = "LatestExecution"; //$NON-NLS-1$
String LOCALE = "Locale"; //$NON-NLS-1$
@@ -27,18 +33,18 @@ public interface CoreConstants {
String SCANNER_TYPE = "type"; //$NON-NLS-1$
String STATUS = "Status"; //$NON-NLS-1$
String TARGET = "target"; //$NON-NLS-1$
- String OPEN_SOURCE_ONLY = "openSourceOnly"; //$NON-NLS-1$
- String INCLUDE_SCA = "includeSCA"; //$NON-NLS-1$
+ String OPEN_SOURCE_ONLY = "openSourceOnly"; //$NON-NLS-1$
+ String INCLUDE_SCA = "includeSCA"; //$NON-NLS-1$
String VERSION_NUMBER = "VersionNumber"; //$NON-NLS-1$
String USER_MESSAGE = "UserMessage"; //$NON-NLS-1$
String IS_VALID = "IsValid"; //$NON-NLS-1$
- String SOURCE_CODE_ONLY = "sourceCodeOnly"; //$NON-NLS-1$
- String SOFTWARE_COMPOSITION_ANALYZER = "Software Composition Analyzer"; //$NON-NLS-1$
- String SCA = "Sca"; //$NON-NLS-1$
+ String SOURCE_CODE_ONLY = "sourceCodeOnly"; //$NON-NLS-1$
+ String SOFTWARE_COMPOSITION_ANALYZER= "Software Composition Analyzer"; //$NON-NLS-1$
+ String SCA = "Sca"; //$NON-NLS-1$
- String CREATE_IRX = "createIRX"; //$NON-NLS-1$
- String UPLOAD_DIRECT = "uploadDirect"; //$NON-NLS-1$
- String BINDING_ID = "Bindingid"; //$NON-NLS-1$
+ String CREATE_IRX = "createIRX"; //$NON-NLS-1$
+ String UPLOAD_DIRECT = "uploadDirect"; //$NON-NLS-1$
+ String BINDING_ID = "Bindingid"; //$NON-NLS-1$
String APPSCAN_OPTS = "APPSCAN_OPTS"; //$NON-NLS-1$
String BLUEMIX_SERVER = "BLUEMIX_SERVER"; //$NON-NLS-1$
String KEY_ID = "KeyId"; //$NON-NLS-1$
@@ -56,34 +62,37 @@ public interface CoreConstants {
String CLIENT_TYPE = "ClientType"; //$NON-NLS-1$
String API_ENV = "/api/v2"; //$NON-NLS-1$
- String API_ENV_LATEST = "/api/v4"; //$NON-NLS-1$
+ String API_ENV_LATEST = "/api/v4"; //$NON-NLS-1$
String API_BLUEMIX = "Bluemix"; //$NON-NLS-1$
String API_BLUEMIX_LOGIN = API_ENV + "/Account/BluemixLogin"; //$NON-NLS-1$
- String API_KEY_LOGIN = API_ENV_LATEST + "/Account/ApiKeyLogin"; //$NON-NLS-1$
+ String API_KEY_LOGIN = API_ENV_LATEST + "/Account/ApiKeyLogin"; //$NON-NLS-1$
String API_LOGOUT = API_ENV + "/Account/Logout"; //$NON-NLS-1$
String API_APPS = API_ENV_LATEST + "/Apps"; //$NON-NLS-1$
- String API_PRESENCES = API_ENV_LATEST + "/Presences"; //$NON-NLS-1$
- 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_FILE_UPLOAD = API_ENV_LATEST + "/FileUpload"; //$NON-NLS-1$
+ String API_PRESENCES = API_ENV_LATEST + "/Presences"; //$NON-NLS-1$
+ 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_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$
+ String API_SCANNER = API_ENV_LATEST + "/Scans/%s"; //$NON-NLS-1$
+ String API_RESCAN = API_ENV_LATEST + "/Scans/%s/Executions"; //$NON-NLS-1$
String API_SCANS = API_ENV + "/Scans"; //$NON-NLS-1$
String API_NONCOMPLIANT_ISSUES = API_ENV + "/Scans/%s/NonCompliantIssues"; //$NON-NLS-1$
- String API_SCANS_REPORT = API_ENV_LATEST + "/Scans/%s/Report/%s"; //$NON-NLS-1$
- String API_REPORT_SELECTED_ISSUES = API_ENV_LATEST + "/Reports/Security/%s/%s"; //$NON-NLS-1$
- String API_DOWNLOAD_REPORT = API_ENV_LATEST + "/Reports/%s/Download"; //$NON-NLS-1$
- String API_SACLIENT_DOWNLOAD = API_ENV_LATEST + "/Tools/SAClientUtil?os=%s"; //$NON-NLS-1$
- String API_SACLIENT_VERSION = API_ENV_LATEST + "/Tools/SAClientUtil?os=%s&meta=%s"; //$NON-NLS-1$
+ String API_SCANS_REPORT = API_ENV_LATEST + "/Scans/%s/Report/%s"; //$NON-NLS-1$
+ String API_REPORT_SELECTED_ISSUES = API_ENV_LATEST + "/Reports/Security/%s/%s"; //$NON-NLS-1$
+ String API_DOWNLOAD_REPORT = API_ENV_LATEST + "/Reports/%s/Download"; //$NON-NLS-1$
+ String API_SACLIENT_DOWNLOAD = API_ENV_LATEST + "/Tools/SAClientUtilByType?toolType=%s"; //$NON-NLS-1$
+ String API_SACLIENT_VERSION = API_ENV_LATEST + "/Tools/SAClientUtilByType?toolType=%s&meta=%s"; //$NON-NLS-1$
String API_KEY_PATH = "/api/ideclientuilogin"; //$NON-NLS-1$
- String API_REPORT_STATUS = API_ENV_LATEST + "/Reports"; //$NON-NLS-1$
- String API_ISSUES_COUNT = API_ENV_LATEST + "/Issues/%s/%s"; //$NON-NLS-1$
- String API_REGIONS = API_ENV_LATEST + "/Utils/Regions"; //$NON-NLS-1$
- 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_REPORT_STATUS = API_ENV_LATEST + "/Reports"; //$NON-NLS-1$
+ String API_ISSUES_COUNT = API_ENV_LATEST + "/Issues/%s/%s"; //$NON-NLS-1$
+ String API_REGIONS = API_ENV_LATEST + "/Utils/Regions"; //$NON-NLS-1$
+ String API_IS_VALID_URL = API_ENV_LATEST + "/Scans/IsValidUrl"; //$NON-NLS-1$
+ String API_IS_VALID_DOMAIN = API_ENV_LATEST + "/Domains/Verify"; //$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_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$
@@ -98,20 +107,27 @@ public interface CoreConstants {
String PAUSING = "Pausing"; //$NON-NLS-1$
String PAUSED = "Paused"; //$NON-NLS-1$
String SUSPENDED = "Suspended"; //$NON-NLS-1$
- String UNKNOWN = "Unknown"; //$NON-NLS-1$
- String SERVER_URL = "serverURL"; //$NON-NLS-1$
- String ACCEPT_INVALID_CERTS = "acceptInvalidCerts"; //$NON-NLS-1$
-
- String TOTAL_ISSUES = "NIssuesFound"; //$NON-NLS-1$
- String CRITICAL_ISSUES = "NCriticalIssues"; //$NON-NLS-1$
+ String CANCELING = "Canceling"; //$NON-NLS-1$
+ String UNKNOWN = "Unknown"; //$NON-NLS-1$
+ String PARTIAL_SUCCESS = "PartialSuccess"; //$NON-NLS-1$
+ String SERVER_URL = "serverURL"; //$NON-NLS-1$
+ String ACCEPT_INVALID_CERTS = "acceptInvalidCerts"; //$NON-NLS-1$
+ String FULL_SCAN = "Full Scan"; //$NON-NLS-1$
+ String TEST_ONLY = "Test Only"; //$NON-NLS-1$
+ String POSTMAN_COLLECTION = "Postman Collection"; //$NON-NLS-1$
+
+ String TOTAL_ISSUES = "NIssuesFound"; //$NON-NLS-1$
+ String CRITICAL_ISSUES = "NCriticalIssues"; //$NON-NLS-1$
String HIGH_ISSUES = "NHighIssues"; //$NON-NLS-1$
String MEDIUM_ISSUES = "NMediumIssues"; //$NON-NLS-1$
String LOW_ISSUES = "NLowIssues"; //$NON-NLS-1$
String INFO_ISSUES = "NInfoIssues"; //$NON-NLS-1$
- String ITEMS = "Items"; //$NON-NLS-1$
+ String ITEMS = "Items"; //$NON-NLS-1$
String CREATE_SCAN_SUCCESS = "message.created.scan"; //$NON-NLS-1$
String SCAN_OVERVIEW = "message.scan.overview"; //$NON-NLS-1$
+ String RESCAN_SUCCESS = "message.rescan"; //$NON-NLS-1$
+ String RESCAN_OVERVIEW = "message.rescan.overview"; //$NON-NLS-1$
String DOWNLOADING_CLIENT = "message.downloading.client"; //$NON-NLS-1$
String EXECUTING_SCAN = "message.running.scan"; //$NON-NLS-1$
String UPLOADING_FILE = "message.uploading.file"; //$NON-NLS-1$
@@ -120,11 +136,12 @@ public interface CoreConstants {
String REGIONS = "Regions"; //$NON-NLS-1$
String DEFAULT_REGION = "DefaultRegion"; //$NON-NLS-1$
String URL = "Url"; //$NON-NLS-1$
-
+ String STP = "STP"; //$NON-NLS-1$
+
String ERROR_AUTHENTICATING = "error.authenticating"; //$NON-NLS-1$
String ERROR_DOWNLOADING_CLIENT = "error.download.client"; //$NON-NLS-1$
String ERROR_GETTING_DETAILS = "error.getting.details"; //$NON-NLS-1$
- String ERROR_GETTING_DETAILS_SCAN_ID = "error.getting.details.scan.id"; //$NON-NLS-1$
+ String ERROR_GETTING_DETAILS_SCAN_ID= "error.getting.details.scan.id"; //$NON-NLS-1$
String ERROR_GETTING_RESULT = "error.getting.result"; //$NON-NLS-1$
String ERROR_GENERATING_REPORT = "error.generating.report"; //$NON-NLS-1$
String ERROR_INVALID_APP = "error.invalid.app"; //$NON-NLS-1$
@@ -135,49 +152,52 @@ public interface CoreConstants {
String ERROR_SUBMITTING_SCAN = "error.submit.scan"; //$NON-NLS-1$
String ERROR_UPLOADING_FILE = "error.upload.file"; //$NON-NLS-1$
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_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_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$
String ERROR_CREATE_JOB = "error.create.job"; //$NON-NLS-1$
+ String UPDATE_JOB = "message.update.job"; //$NON-NLS-1$
String ERROR_UPDATE_JOB = "error.update.job"; //$NON-NLS-1$
String EXECUTING_JOB = "message.running.job"; //$NON-NLS-1$
String EXECUTE_JOB_SUCCESS = "message.executed.job"; //$NON-NLS-1$
String ERROR_EXECUTE_JOB = "error.execute.job"; //$NON-NLS-1$
String RESULTS_UNAVAILABLE = "message.results.unavailable"; //$NON-NLS-1$
String ERROR_INVALID_DETAILS = "error.invalid.details"; //$NON-NLS-1$
+ String UPDATE_POSTMAN_COLLECTION_SUCCESS = "update.postman.collection.success"; //$NON-NLS-1$
+ String ERROR_FILE_NOT_FOUND = "error.file.not.found"; //$NON-NLS-1$
// ASE APIs
- String ASE_API = "/api"; //$NON-NLS-1$
- String ASE_APPS = ASE_API + "/applications"; //$NON-NLS-1$
- String ASE_FOLDERS = ASE_API + "/folders"; //$NON-NLS-1$
- String ASE_TEST_POLICIES = ASE_API + "/testPolicies"; //$NON-NLS-1$
- String ASE_AGENT_SERVER = ASE_API + "/agentServer"; //$NON-NLS-1$
- String ASE_UPDSCANT = ASE_API + "/jobs/%s/dastconfig/updatescant"; //$NON-NLS-1$
- String ASE_UPDTRAFFIC = ASE_API + "/jobs/%s/dastconfig/updatetraffic/%s"; //$NON-NLS-1$
- String ASE_UPDTAGENT = ASE_API + "/jobs/%s/designateAgentServer/%s"; //$NON-NLS-1$
- String ASE_SCAN_TYPE = ASE_API + "/jobs/scantype"; //$NON-NLS-1$
- String ASE_LOGIN_API = ASE_API + "/keylogin/apikeylogin"; //$NON-NLS-1$
- String ASE_KEY_ID = "keyId"; //$NON-NLS-1$
- String ASE_KEY_SECRET = "keySecret"; //$NON-NLS-1$
- String ASE_NAME_ATTRIBUTE = "name"; //$NON-NLS-1$
- String ASE_ID_ATTRIBUTE = "id"; //$NON-NLS-1$
- String ASE_CREATEJOB_TEMPLATE_ID = ASE_API + "/jobs/%s/dastconfig/createjob"; //$NON-NLS-1$
- String ASE_GET_JOB = ASE_API + "/jobs/%s"; //$NON-NLS-1$
- String ASE_RUN_JOB_ACTION = ASE_API +"/jobs/%s/actions"; //$NON-NLS-1$
- String ASE_REPORTPACK = ASE_API + "/folderitems/%s/reportPack"; //$NON-NLS-1$
- String ASE_REPORTS = ASE_API + "/folderitems/%s/reports"; //$NON-NLS-1$
- String ASE_GET_FOLDERITEMS = ASE_API + "/folderitems/%s"; //$NON-NLS-1$
- String ASE_UPLOADED_FILE = "uploadedfile"; //$NON-NLS-1$
- String ASE_CURRENTUSER_V2 = ASE_API + "/currentuser_v2"; //$NON-NLS-1$
- String ASE_GET_FOLDER_ITEMS_STATISTICS = ASE_API + "/folderitems/%s/statistics"; //$NON-NLS-1$
-
- String UNAUTHORIZED_ACTION = "UNAUTHORIZED_ACTION"; //$NON-NLS-1$
-
- String API_SCANS_SCANLOGS = API_ENV_LATEST + "/Scans/ScanLogs/%s";
+ String ASE_API = "/api"; //$NON-NLS-1$
+ String ASE_APPS = ASE_API + "/applications"; //$NON-NLS-1$
+ String ASE_FOLDERS = ASE_API + "/folders"; //$NON-NLS-1$
+ String ASE_TEST_POLICIES = ASE_API + "/testPolicies"; //$NON-NLS-1$
+ String ASE_AGENT_SERVER = ASE_API + "/agentServer"; //$NON-NLS-1$
+ String ASE_UPDSCANT = ASE_API + "/jobs/%s/dastconfig/updatescant"; //$NON-NLS-1$
+ String ASE_UPDTRAFFIC = ASE_API + "/jobs/%s/dastconfig/updatetraffic/%s"; //$NON-NLS-1$
+ String ASE_UPDTAGENT = ASE_API + "/jobs/%s/designateAgentServer/%s"; //$NON-NLS-1$
+ String ASE_SCAN_TYPE = ASE_API + "/jobs/scantype"; //$NON-NLS-1$
+ String ASE_LOGIN_API = ASE_API + "/keylogin/apikeylogin"; //$NON-NLS-1$
+ String ASE_KEY_ID = "keyId"; //$NON-NLS-1$
+ String ASE_KEY_SECRET = "keySecret"; //$NON-NLS-1$
+ String ASE_NAME_ATTRIBUTE = "name"; //$NON-NLS-1$
+ String ASE_ID_ATTRIBUTE = "id"; //$NON-NLS-1$
+ String ASE_CREATEJOB_TEMPLATE_ID = ASE_API + "/jobs/%s/dastconfig/createjob"; //$NON-NLS-1$
+ String ASE_GET_JOB = ASE_API + "/jobs/%s"; //$NON-NLS-1$
+ String ASE_RUN_JOB_ACTION = ASE_API +"/jobs/%s/actions"; //$NON-NLS-1$
+ String ASE_REPORTPACK = ASE_API + "/folderitems/%s/reportPack"; //$NON-NLS-1$
+ String ASE_REPORTS = ASE_API + "/folderitems/%s/reports"; //$NON-NLS-1$
+ String ASE_GET_FOLDERITEMS = ASE_API + "/folderitems/%s"; //$NON-NLS-1$
+ String ASE_UPLOADED_FILE = "uploadedfile"; //$NON-NLS-1$
+ String ASE_CURRENTUSER_V2 = ASE_API + "/currentuser_v2"; //$NON-NLS-1$
+ String ASE_GET_FOLDER_ITEMS_STATISTICS = ASE_API + "/folderitems/%s/statistics"; //$NON-NLS-1$
+ String ASE_POSTMAN_COLLECTION = ASE_API + "/jobs/%s/dastconfig/postman/create"; //$NON-NLS-1$
+
+ String UNAUTHORIZED_ACTION = "UNAUTHORIZED_ACTION"; //$NON-NLS-1$
+
+ String API_SCANS_SCANLOGS = API_ENV_LATEST + "/Scans/ScanLogs/%s"; //$NON-NLS-1$
}
diff --git a/src/main/java/com/hcl/appscan/sdk/http/HttpClient.java b/src/main/java/com/hcl/appscan/sdk/http/HttpClient.java
index 2caf1399..7352a17c 100644
--- a/src/main/java/com/hcl/appscan/sdk/http/HttpClient.java
+++ b/src/main/java/com/hcl/appscan/sdk/http/HttpClient.java
@@ -18,7 +18,6 @@
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -158,6 +157,35 @@ public HttpResponse put(String url,
return makeRequest(Method.PUT, url, headerProperties, body);
}
+ /**
+ * Submit a put request.
+ *
+ * @param url The URL string.
+ * @param headerProperties An optional Map of header properties.
+ * @param parameters An optional Map of properties.
+ * @return The response as a byte array.
+ * @throws IOException If an error occurs.
+ */
+ public HttpResponse put(String url, Map headerProperties, Map parameters)
+ throws IOException, JSONException {
+ JSONObject objectMap = new JSONObject();
+ for (String key : parameters.keySet()) {
+ if (parameters.get(key) != null){
+ String value = parameters.get(key);
+ if (value.equalsIgnoreCase("true")) {
+ objectMap.put(key, true);
+ } else if (value.equalsIgnoreCase("false")) {
+ objectMap.put(key, false);
+ } else {
+ // If the string is not "true" or "false," keep it as is
+ objectMap.put(key, value);
+ }
+ }
+ }
+ String body = objectMap.toString();
+ return put(url, headerProperties, body);
+ }
+
/**
* Submit a delete request.
*
diff --git a/src/main/java/com/hcl/appscan/sdk/messages.properties b/src/main/java/com/hcl/appscan/sdk/messages.properties
index 4564dc39..b8d59c64 100644
--- a/src/main/java/com/hcl/appscan/sdk/messages.properties
+++ b/src/main/java/com/hcl/appscan/sdk/messages.properties
@@ -8,8 +8,10 @@
transfer.progress={0}% transferred
-message.created.scan=Successfully submitted {0} scan for analysis. Scan ID: {1}
-message.scan.overview={0} scan overview: {1}
+message.created.scan=Successfully submitted {0} scan for analysis. Scan ID:
+message.scan.overview={0} scan overview:
+message.rescan= Successfully submitted rescan for analysis. Execution ID:
+message.rescan.overview= Rescan overview:
message.running.scan=Creating and executing {0} scan...
message.uploading.file=Uploading {0} to the analysis service...
message.done=Done.
@@ -54,6 +56,8 @@ error.login.type.deprectated=The specified login type is deprecated. Please use
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 = Rescan ID {0} not found. It may have been canceled or deleted. Verify the scan status on the AppScan server and retry.
#Presence
error.getting.presence.details=An error occurred retrieving details for Presence with id {0}.
@@ -74,3 +78,5 @@ message.running.job=Executing job...
message.executed.job=Job executed successfully.
error.execute.job=An error occurred executing the job. {0}
error.invalid.details=The job details contain missing or invalid parameters.
+update.postman.collection.success=Successfully updated Postman collection for jobId: {0}.
+error.file.not.found=File {0} not found.
diff --git a/src/main/java/com/hcl/appscan/sdk/results/ASEResultsProvider.java b/src/main/java/com/hcl/appscan/sdk/results/ASEResultsProvider.java
index e84e4398..0bdfbc0e 100644
--- a/src/main/java/com/hcl/appscan/sdk/results/ASEResultsProvider.java
+++ b/src/main/java/com/hcl/appscan/sdk/results/ASEResultsProvider.java
@@ -1,5 +1,5 @@
/**
- * © Copyright HCL Technologies Ltd. 2019, 2020, 2024.
+ * © Copyright HCL Technologies Ltd. 2019, 2025.
* LICENSE: Apache License, Version 2.0 https://www.apache.org/licenses/LICENSE-2.0
*/
@@ -185,6 +185,8 @@ private void loadResults() {
m_message = "";
} else if (RUNNING.equalsIgnoreCase(m_status)) {
m_message = "";
+ } else if (CANCELING.equalsIgnoreCase(m_status)) {
+ m_status = FAILED;
} else if (m_status.startsWith(SUSPENDED)) { // In case of Scan Failure ASE returns Suspended (With Reason) in Status
this.m_message = m_status;
String description = "";
@@ -273,8 +275,8 @@ private void checkResults() {
private String getReportPackId(String scanId) {
return String.valueOf(Integer.parseInt(scanId)+1);
- // please uncomment the below code when you figure out how to parse the reponse.
- // currently the reponse is returned as array which makes no sense.
+ // please uncomment the below code when you figure out how to parse the response.
+ // currently the response is returned as array which makes no sense.
/*IAuthenticationProvider authProvider = m_scanProvider.getAuthenticationProvider();
if(authProvider.isTokenExpired()) {
m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_LOGIN_EXPIRED)));
@@ -401,4 +403,9 @@ private String getStatisticsStatus(String jobId) {
}
return null;
}
+
+ @Override
+ public void getScanLogFile(File file) {
+ // Not applicable for ASE Results Provider
+ }
}
diff --git a/src/main/java/com/hcl/appscan/sdk/results/CloudCombinedResultsProvider.java b/src/main/java/com/hcl/appscan/sdk/results/CloudCombinedResultsProvider.java
index 1c946f5e..56c48d75 100644
--- a/src/main/java/com/hcl/appscan/sdk/results/CloudCombinedResultsProvider.java
+++ b/src/main/java/com/hcl/appscan/sdk/results/CloudCombinedResultsProvider.java
@@ -1,5 +1,5 @@
/**
- * © Copyright HCL Technologies Ltd. 2024.
+ * © Copyright HCL Technologies Ltd. 2024, 2025.
* LICENSE: Apache License, Version 2.0 https://www.apache.org/licenses/LICENSE-2.0
*/
@@ -11,6 +11,7 @@
import com.hcl.appscan.sdk.CoreConstants;
import com.hcl.appscan.sdk.logging.IProgress;
+import com.hcl.appscan.sdk.utils.ServiceUtil;
public class CloudCombinedResultsProvider implements IResultsProvider, Serializable {
@@ -18,6 +19,8 @@ public class CloudCombinedResultsProvider implements IResultsProvider, Serializa
private IResultsProvider m_resultsProvider1;
private IResultsProvider m_resultsProvider2;
+ private String m_status1;
+ private String m_status2;
private String m_reportFormat = DEFAULT_REPORT_FORMAT;
public CloudCombinedResultsProvider(IResultsProvider resultsProvider1, IResultsProvider resultsProvider2) {
@@ -27,22 +30,37 @@ public CloudCombinedResultsProvider(IResultsProvider resultsProvider1, IResultsP
@Override
public boolean hasResults() {
- return m_resultsProvider1.hasResults() || m_resultsProvider2.hasResults();
+ return getStatus().equals(CoreConstants.PARTIAL_SUCCESS) ? (m_resultsProvider1.hasResults() || m_resultsProvider2.hasResults()) : (m_resultsProvider1.hasResults() && m_resultsProvider2.hasResults());
+ }
+
+ public IResultsProvider getResultsProvider1() {
+ return m_resultsProvider1;
+ }
+
+ public IResultsProvider getResultsProvider2() {
+ return m_resultsProvider2;
}
@Override
public String getStatus() {
+ // Default to RUNNING
String combinedStatus = CoreConstants.RUNNING;
- String status1 = m_resultsProvider1.getStatus();
- String status2 = m_resultsProvider2.getStatus();
-
- if(status1.equalsIgnoreCase(CoreConstants.FAILED) || status2.equalsIgnoreCase(CoreConstants.FAILED)) {
- combinedStatus = CoreConstants.FAILED;
+
+ // Fetch individual status
+ if (m_status1 == null || m_status1.equalsIgnoreCase(CoreConstants.RUNNING)) {
+ m_status1 = m_resultsProvider1.getStatus();
}
- else if(status1.equalsIgnoreCase(CoreConstants.READY) && status2.equalsIgnoreCase(CoreConstants.READY)) {
- combinedStatus = CoreConstants.READY;
+ if (m_status2 == null || m_status2.equalsIgnoreCase(CoreConstants.RUNNING)) {
+ m_status2 = m_resultsProvider2.getStatus();
+ }
+
+ // Handle different status combinations
+ if (m_status1.equals(m_status2)) {
+ combinedStatus = m_status1;
+ } else if ((CoreConstants.READY.equalsIgnoreCase(m_status1) || CoreConstants.READY.equalsIgnoreCase(m_status2)) &&
+ (CoreConstants.FAILED.equalsIgnoreCase(m_status1) || CoreConstants.FAILED.equalsIgnoreCase(m_status2))) {
+ combinedStatus = CoreConstants.PARTIAL_SUCCESS;
}
-
return combinedStatus;
}
@@ -89,10 +107,11 @@ public String getType() {
@Override
public void getResultsFile(File destination, String format) {
//Append the technology type to the end of the file name.
- String name = destination.getName();
+ String name1 = ServiceUtil.scanTypeShortForm(m_resultsProvider1.getType()).toUpperCase()+"_"+destination.getName();
+ String name2 = ServiceUtil.scanTypeShortForm(m_resultsProvider2.getType()).toUpperCase()+"_"+destination.getName();
File directory = destination.getParentFile();
- m_resultsProvider1.getResultsFile(new File(directory, name), format);
- m_resultsProvider2.getResultsFile(new File(directory, name), format);
+ m_resultsProvider1.getResultsFile(new File(directory, name1), format);
+ m_resultsProvider2.getResultsFile(new File(directory, name2), format);
}
@Override
@@ -121,4 +140,11 @@ public void setProgress(IProgress progress) {
m_resultsProvider1.setProgress(progress);
m_resultsProvider2.setProgress(progress);
}
+
+ @Override
+ public void getScanLogFile(File file) {
+ if (m_status1 != null && m_status1.equalsIgnoreCase(CoreConstants.READY)) {
+ m_resultsProvider1.getScanLogFile(file);
+ }
+ }
}
diff --git a/src/main/java/com/hcl/appscan/sdk/results/CloudResultsProvider.java b/src/main/java/com/hcl/appscan/sdk/results/CloudResultsProvider.java
index ae77fb80..a0f19c48 100644
--- a/src/main/java/com/hcl/appscan/sdk/results/CloudResultsProvider.java
+++ b/src/main/java/com/hcl/appscan/sdk/results/CloudResultsProvider.java
@@ -1,6 +1,6 @@
/**
* © Copyright IBM Corporation 2016.
- * © Copyright HCL Technologies Ltd. 2017, 2024.
+ * © Copyright HCL Technologies Ltd. 2017, 2025.
* LICENSE: Apache License, Version 2.0 https://www.apache.org/licenses/LICENSE-2.0
*/
@@ -47,10 +47,16 @@ public class CloudResultsProvider implements IResultsProvider, Serializable, Cor
protected int m_mediumFindings;
protected int m_lowFindings;
protected int m_infoFindings;
+ protected String m_executionId;
public CloudResultsProvider(String scanId, String type, IScanServiceProvider provider, IProgress progress) {
+ this(scanId, null, type, provider, progress);
+ }
+
+ public CloudResultsProvider(String scanId, String executionId, String type, IScanServiceProvider provider, IProgress progress) {
m_type = type;
m_scanId = scanId;
+ m_executionId = executionId;
m_hasResults = false;
m_scanProvider = provider;
m_progress = progress;
@@ -241,24 +247,28 @@ protected String getReportStatus(String reportId) throws IOException, JSONExcept
}
- public void getScanLogFile(File file , String executionId) {
-
+ public void getScanLogFile(File file , String scanId) {
if(file != null && !file.exists()) {
try {
- getScanLog(executionId, file);
+ getScanLog(scanId, file);
} catch (IOException | JSONException e) {
m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_GETTING_SCANLOG)), e);
}
}
}
- private void getScanLog(String executionId, File destination) throws IOException, JSONException {
+ @Override
+ public void getScanLogFile(File file) {
+ getScanLogFile(file, m_scanId);
+ }
+
+ private void getScanLog(String scanId, File destination) throws IOException, JSONException {
IAuthenticationProvider authProvider = m_scanProvider.getAuthenticationProvider();
if(authProvider.isTokenExpired()) {
m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_LOGIN_EXPIRED)));
return;
}
- String request_url = authProvider.getServer() + String.format(API_SCANS_SCANLOGS, executionId);
+ String request_url = authProvider.getServer() + String.format(API_SCANS_SCANLOGS, scanId);
Map request_headers = authProvider.getAuthorizationHeader(true);
request_headers.put(CONTENT_LENGTH, "0"); //$NON-NLS-1$
diff --git a/src/main/java/com/hcl/appscan/sdk/results/IResultsProvider.java b/src/main/java/com/hcl/appscan/sdk/results/IResultsProvider.java
index 83c81767..bab389df 100644
--- a/src/main/java/com/hcl/appscan/sdk/results/IResultsProvider.java
+++ b/src/main/java/com/hcl/appscan/sdk/results/IResultsProvider.java
@@ -1,6 +1,6 @@
/**
* © Copyright IBM Corporation 2016.
- * © Copyright HCL Technologies Ltd. 2017, 2024.
+ * © Copyright HCL Technologies Ltd. 2017, 2025.
* LICENSE: Apache License, Version 2.0 https://www.apache.org/licenses/LICENSE-2.0
*/
@@ -109,4 +109,10 @@ public interface IResultsProvider {
* @param progress The IProgress.
*/
public void setProgress(IProgress progress);
+
+ /**
+ * Gets the results in a file.
+ * @param destination The File to store the scan logs.
+ */
+ public void getScanLogFile(File destination);
}
diff --git a/src/main/java/com/hcl/appscan/sdk/results/NonCompliantIssuesResultProvider.java b/src/main/java/com/hcl/appscan/sdk/results/NonCompliantIssuesResultProvider.java
index aef88265..bd31e4ae 100644
--- a/src/main/java/com/hcl/appscan/sdk/results/NonCompliantIssuesResultProvider.java
+++ b/src/main/java/com/hcl/appscan/sdk/results/NonCompliantIssuesResultProvider.java
@@ -1,5 +1,5 @@
/**
- * © Copyright HCL Technologies Ltd. 2018, 2024.
+ * © Copyright HCL Technologies Ltd. 2018, 2025.
*/
package com.hcl.appscan.sdk.results;
@@ -33,6 +33,10 @@ public NonCompliantIssuesResultProvider(String scanId, String type, IScanService
super(scanId, type, provider, progress);
}
+ public NonCompliantIssuesResultProvider(String scanId, String executionId, String type, IScanServiceProvider provider, IProgress progress) {
+ super(scanId, executionId, type, provider, progress);
+ }
+
@Override
protected void loadResults() {
try {
@@ -52,8 +56,19 @@ 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_executionId)));
+ m_status = FAILED;
+ }
+ } else {
+ m_status = obj.getString(STATUS);
+ m_executionId = obj.getString(ID);
+ }
- 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);
@@ -61,38 +76,47 @@ protected void loadResults() {
m_progress.setStatus(new Message(Message.INFO, Messages.getMessage(SUSPEND_JOB_BYUSER, "Scan Id: " + m_scanId)));
m_message = Messages.getMessage(SUSPEND_JOB_BYUSER, "Scan Id: " + m_scanId);
} else if (m_status != null && !(m_status.equalsIgnoreCase(INQUEUE) || m_status.equalsIgnoreCase(RUNNING) || m_status.equalsIgnoreCase(PAUSING))) {
- JSONArray array = m_scanProvider.getNonCompliantIssues(m_scanId);
+ JSONArray array;
+ if(m_executionId != null && !m_executionId.isEmpty()) {
+ array = m_scanProvider.getNonCompliantIssuesUsingExecutionId(m_executionId);
+ } else {
+ array = m_scanProvider.getNonCompliantIssues(m_scanId);
+ }
m_totalFindings = 0;
- for (int i = 0; i < array.length(); i++) {
- JSONObject jobj = array.getJSONObject(i);
- String sev = jobj.getString("Severity");
- int count = jobj.getInt("N");
-
- switch (sev.toLowerCase()) {
- case "critical":
- m_criticalFindings += count;
- m_totalFindings += count;
- break;
- case "high":
- m_highFindings += count;
- m_totalFindings += count;
- break;
- case "medium":
- m_mediumFindings += count;
- m_totalFindings += count;
- break;
- case "low":
- m_lowFindings += count;
- m_totalFindings += count;
- break;
- case "informational":
- m_infoFindings += count;
- m_totalFindings += count;
- break;
- default:
- m_totalFindings += count;
- break;
+ if(array == null) {
+ m_status = FAILED;
+ } else {
+ for (int i = 0; i < array.length(); i++) {
+ JSONObject jobj = array.getJSONObject(i);
+ String sev = jobj.getString("Severity");
+ int count = jobj.getInt("N");
+
+ switch (sev.toLowerCase()) {
+ case "critical":
+ m_criticalFindings += count;
+ m_totalFindings += count;
+ break;
+ case "high":
+ m_highFindings += count;
+ m_totalFindings += count;
+ break;
+ case "medium":
+ m_mediumFindings += count;
+ m_totalFindings += count;
+ break;
+ case "low":
+ m_lowFindings += count;
+ m_totalFindings += count;
+ break;
+ case "informational":
+ m_infoFindings += count;
+ m_totalFindings += count;
+ break;
+ default:
+ m_totalFindings += count;
+ break;
+ }
}
}
setHasResult(true);
@@ -179,7 +203,12 @@ private String createNonCompliantIssuesReport(String scanId, String format) thro
return null;
}
- String request_url = authProvider.getServer() + String.format(API_REPORT_SELECTED_ISSUES, SCOPE, scanId);
+ String request_url;
+ if(m_executionId != null && !m_executionId.isEmpty()) {
+ request_url = authProvider.getServer() + String.format(API_REPORT_SELECTED_ISSUES, "ScanExecution", m_executionId);
+ } else {
+ request_url = authProvider.getServer() + String.format(API_REPORT_SELECTED_ISSUES, SCOPE, scanId);
+ }
Map request_headers = authProvider.getAuthorizationHeader(true);
request_headers.put("Content-Type", "application/json; charset=UTF-8");
request_headers.put("Accept", "application/json");
@@ -233,4 +262,8 @@ private String getScanName() {
}
}
+
+ public void getScanLogs(File file) {
+ getScanLogFile(file);
+ }
}
diff --git a/src/main/java/com/hcl/appscan/sdk/scan/ASEScanServiceProvider.java b/src/main/java/com/hcl/appscan/sdk/scan/ASEScanServiceProvider.java
index b8c10897..93830111 100644
--- a/src/main/java/com/hcl/appscan/sdk/scan/ASEScanServiceProvider.java
+++ b/src/main/java/com/hcl/appscan/sdk/scan/ASEScanServiceProvider.java
@@ -1,5 +1,5 @@
/**
- * © Copyright HCL Technologies Ltd. 2019,2020.
+ * © Copyright HCL Technologies Ltd. 2019,2020, 2025.
* LICENSE: Apache License, Version 2.0 https://www.apache.org/licenses/LICENSE-2.0
*/
@@ -24,6 +24,7 @@
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.HttpsURLConnection;
+
import org.apache.wink.json4j.JSONArray;
import org.apache.wink.json4j.JSONException;
import org.apache.wink.json4j.JSONObject;
@@ -56,7 +57,7 @@ private String createJob(Map params) {
if(loginExpired())
return null;
- Map createJobParams = getcreateJobParams(params);
+ Map createJobParams = getCreateJobParams(params);
m_progress.setStatus(new Message(Message.INFO, Messages.getMessage(CREATING_JOB)));
// TODO : correct it .
@@ -64,44 +65,54 @@ private String createJob(Map params) {
createJobParams.remove("templateId");
String request_url = m_authProvider.getServer() + String.format(ASE_CREATEJOB_TEMPLATE_ID, templateId);
- Map request_headers = m_authProvider.getAuthorizationHeader(true);
- request_headers.put(CONTENT_TYPE, "application/json; utf-8"); //$NON-NLS-1$
- request_headers.put(CHARSET, UTF8);
- request_headers.put("Accept", "application/json"); //$NON-NLS-1$ //$NON-NLS-2$
+ Map request_headers = getRequestHeaders();
HttpsClient client = new HttpsClient();
try {
HttpResponse response = client.postForm(request_url, request_headers, createJobParams);
int status = response.getResponseCode();
-
- // Handle scenarios of invalid input parameters during job creation.
- // Currently ASE APIs do not return a valid response for invalid inputs
- // hence, making the check here for better error handling
- if (status == HttpsURLConnection.HTTP_BAD_REQUEST
- || status == HttpsURLConnection.HTTP_NOT_FOUND) {
- m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(
- ERROR_CREATE_JOB, Messages.getMessage(ERROR_INVALID_DETAILS))));
- return null;
+ JSONObject json = null;
+
+ // Safely parse JSON response if available
+ try {
+ Object responseBody = response.getResponseBodyAsJSON();
+ if (responseBody instanceof JSONObject) {
+ json = (JSONObject) responseBody;
+ }
+ } catch (IOException | JSONException ignored) {
+ // Ignore JSON parsing issues, handled later
}
- JSONObject json = (JSONObject) response.getResponseBodyAsJSON();
-
- if (status == HttpsURLConnection.HTTP_CREATED) {
+ // Success case: 201 + valid ID
+ if (status == HttpsURLConnection.HTTP_CREATED && json != null && json.has(ASE_ID_ATTRIBUTE)) {
+ String jobId = json.getString(ASE_ID_ATTRIBUTE);
m_progress.setStatus(new Message(Message.INFO, Messages.getMessage(CREATE_JOB_SUCCESS)));
- return json.getString(ASE_ID_ATTRIBUTE);
+ return jobId;
}
- else if (json != null && json.has(MESSAGE))
- m_progress.setStatus(new Message(Message.ERROR, json.getString(MESSAGE)));
- else
- m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_CREATE_JOB, status)));
- } catch(IOException | JSONException e) {
+
+ // Invalid input parameters
+ else if (status == HttpsURLConnection.HTTP_BAD_REQUEST || status == HttpsURLConnection.HTTP_NOT_FOUND) {
+ String errorMessage = "";
+ if (json != null) {
+ if (json.has("errorMessage")) {
+ errorMessage = json.optString("errorMessage");
+ } else if (json.has(MESSAGE)) {
+ errorMessage = json.optString(MESSAGE);
+ }
+ }
+ m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_CREATE_JOB, errorMessage.isEmpty() ? Messages.getMessage(ERROR_INVALID_DETAILS) : errorMessage)));
+ } else {
+ m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_CREATE_JOB, Messages.getMessage(ERROR_INVALID_DETAILS))));
+ }
+
+ } catch (IOException | JSONException e) {
m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_CREATE_JOB, e.getLocalizedMessage())));
}
return null;
}
- private Map getcreateJobParams(Map properties) {
+ private Map getCreateJobParams(Map properties) {
Map apiParams= new HashMap<>();
apiParams.put("testPolicyId", properties.get("testPolicyId"));
apiParams.put("folderId",properties.get("folder"));
@@ -114,70 +125,73 @@ private Map getcreateJobParams(Map properties) {
}
private String updateJob(Map params, String jobId) {
+ String scanTypeValue = params.getOrDefault("scanType", "");
- // Starting URL
- if(!params.get("startingURL").isEmpty() && !updatescantJob(getUpdatescantJobParams("StartingUrl", params.get("startingURL"), "false"),jobId)) {
- return null;
- }
+ if (!handleStartingURL(params, jobId, scanTypeValue)) return null;
+ if (!handleAgentServer(params, jobId)) return null;
+ if (!handleLoginManagement(params, jobId)) return null;
+ if (!handleExploreData(params, jobId)) return null;
+ if (!handleScanType(params, jobId, scanTypeValue)) return null;
+ if (!handleTestOptimization(params, jobId)) return null;
+ if (!handlePostmanCollection(params, jobId, scanTypeValue)) return null;
- // Agent Server
- if(!params.get("agentServer").isEmpty() && !updateAgentServer(params, jobId)) {
- return null;
- }
+ return jobId;
+ }
- // Login Management
- if (!params.get("loginType").isEmpty()) {
-
- String loginType = params.get("loginType");
- if(!updatescantJob(getUpdatescantJobParams("LoginMethod", loginType, "false"),jobId)) {
- return null;
- }
-
- if (loginType.equals("Automatic"))
- {
- boolean status = updatescantJob(getUpdatescantJobParams("LoginUsername", params.get("userName"), "false"),jobId );
- if (status) {
- status = updatescantJob(getUpdatescantJobParams("LoginPassword", params.get("password"), "true"),jobId);
- }
- if(!status)
- return null;
- }
-
- if (loginType.equals("Manual") && !updateTrafficJob(getFile(params.get("trafficFile")),jobId,"login")) {
- return null;
- }
- }
+ private boolean handleStartingURL(Map params, String jobId, String scanType) {
+ return scanType.equals(POSTMAN_COLLECTION) || params.get("startingURL").isEmpty() ||
+ updatescantJob(getUpdatescantJobParams("StartingUrl", params.get("startingURL"), "false"), jobId);
+ }
- // Explore Data
- if(!params.get("exploreData").isEmpty() && !updateTrafficJob(getFile(params.get("exploreData")),jobId,"add")) {
- return null;
- }
+ private boolean handleAgentServer(Map params, String jobId) {
+ return params.get("agentServer").isEmpty() || updateAgentServer(params, jobId);
+ }
+
+ private boolean handleLoginManagement(Map params, String jobId) {
+ String loginType = params.getOrDefault("loginType", "");
+ if (loginType.isEmpty()) return true;
- // Scan Type
- if(!params.get("scanType").isEmpty() && !scanTypeJob(params, jobId)) {
- return null;
+ if (!updatescantJob(getUpdatescantJobParams("LoginMethod", loginType, "false"), jobId)) return false;
+
+ if (loginType.equals("Automatic")) {
+ if (!updatescantJob(getUpdatescantJobParams("LoginUsername", params.get("userName"), "false"), jobId)) return false;
+ if (!updatescantJob(getUpdatescantJobParams("LoginPassword", params.get("password"), "true"), jobId)) return false;
}
- // Test Optimization
- if(!params.get("testOptimization").isEmpty() &&
- !updatescantJob(getUpdatescantJobParams("TestOptimization",
- params.get("testOptimization"), "false"), jobId)) {
- return null;
+ if (loginType.equals("Manual")) {
+ File trafficFile = getFile(params.get("trafficFile"));
+ if (trafficFile != null && !updateTrafficJob(trafficFile, jobId, "login")) return false;
}
- return jobId;
+ return true;
+ }
+
+ private boolean handleExploreData(Map params, String jobId) {
+ String exploreData = params.getOrDefault("exploreData", "");
+ return exploreData.isEmpty() || updateTrafficJob(getFile(exploreData), jobId, "add");
+ }
+
+ private boolean handleScanType(Map params, String jobId, String scanType) {
+ return scanType.isEmpty() || scanType.equals(POSTMAN_COLLECTION) || updateScanTypeJob(params, jobId);
+ }
+
+ private boolean handleTestOptimization(Map params, String jobId) {
+ String testOpt = params.getOrDefault("testOptimization", "");
+ return testOpt.isEmpty() || updatescantJob(getUpdatescantJobParams("TestOptimization", testOpt, "false"), jobId);
}
-
- private Boolean updatescantJob(Map params, String jobId) {
+
+ private boolean handlePostmanCollection(Map params, String jobId, String scanType) {
+ return !scanType.equals(POSTMAN_COLLECTION) || createPostmanCollectionJob(params, jobId);
+ }
+
+
+ private boolean updatescantJob(Map params, String jobId) {
if(loginExpired())
return false;
String request_url = m_authProvider.getServer() + String.format(ASE_UPDSCANT, jobId);
- Map request_headers = m_authProvider.getAuthorizationHeader(true);
- request_headers.put(CONTENT_TYPE, "application/json; utf-8"); //$NON-NLS-1$
- request_headers.put(CHARSET, UTF8);
- request_headers.put("Accept", "application/json"); //$NON-NLS-1$ //$NON-NLS-2$
+ Map request_headers = getRequestHeaders();
HttpsClient client = new HttpsClient();
@@ -194,16 +208,13 @@ private Boolean updatescantJob(Map params, String jobId) {
return true;
}
- private Boolean scanTypeJob (Map params, String jobId) {
+ private boolean updateScanTypeJob (Map params, String jobId) {
if(loginExpired())
return false;
- String request_url = m_authProvider.getServer() + String.format(ASE_SCAN_TYPE) + "?scanTypeId=" + params.get("scanType") + "&jobId="+ jobId;
- Map request_headers = m_authProvider.getAuthorizationHeader(true);
- request_headers.put(CONTENT_TYPE, "application/json; utf-8"); //$NON-NLS-1$
- request_headers.put(CHARSET, UTF8);
- request_headers.put("Accept", "application/json"); //$NON-NLS-1$ //$NON-NLS-2$
+ String request_url = m_authProvider.getServer() + String.format(ASE_SCAN_TYPE) + "?scanTypeId=" + ASEScanType.scanTypeCode(params.get("scanType")) + "&jobId="+ jobId;
+ Map request_headers = getRequestHeaders();
HttpsClient client = new HttpsClient();
@@ -220,16 +231,13 @@ private Boolean scanTypeJob (Map params, String jobId) {
return true;
}
- private Boolean updateTrafficJob(File file, String jobId, String action) {
+ private boolean updateTrafficJob(File file, String jobId, String action) {
if(loginExpired() || file == null)
return false;
String request_url = m_authProvider.getServer() + String.format(ASE_UPDTRAFFIC, jobId, action);
- Map request_headers = m_authProvider.getAuthorizationHeader(true);
- request_headers.put(CONTENT_TYPE, "application/json; utf-8"); //$NON-NLS-1$
- request_headers.put(CHARSET, UTF8);
- request_headers.put("Accept", "application/json"); //$NON-NLS-1$ //$NON-NLS-2$
+ Map request_headers = getRequestHeaders();
List parts = new ArrayList();
@@ -264,10 +272,7 @@ private boolean updateAgentServer (Map params, String jobId ) {
return false;
String request_url = m_authProvider.getServer() + String.format(ASE_UPDTAGENT, jobId, params.get("agentServer"));
- Map request_headers = m_authProvider.getAuthorizationHeader(true);
- request_headers.put(CONTENT_TYPE, "application/json; utf-8"); //$NON-NLS-1$
- request_headers.put(CHARSET, UTF8);
- request_headers.put("Accept", "application/json"); //$NON-NLS-1$ //$NON-NLS-2$
+ Map request_headers = getRequestHeaders();
HttpsClient client = new HttpsClient();
@@ -292,16 +297,82 @@ private Map getUpdatescantJobParams(String scantNodeXpath, String
//apiParams.put("allowExploreDataUpdate", "0");
return apiParams;
}
+
+ private boolean createPostmanCollectionJob(Map params, String jobId) {
+
+ if(loginExpired() || params == null)
+ return false;
+
+ String request_url = m_authProvider.getServer() + String.format(ASE_POSTMAN_COLLECTION, jobId);
+ Map request_headers = getRequestHeaders();
+
+ List parts = new ArrayList();
+ HttpsClient client = new HttpsClient();
+
+ try {
+ addAllFileParts(params, parts);
+
+ if(params.containsKey("additionalDomains")) {
+ parts.add(new HttpPart("additionalDomains", params.get("additionalDomains"))); //$NON-NLS-1$
+ }
+ parts.add(new HttpPart("asc_xsrf_token", request_headers.get("asc_xsrf_token"))); //$NON-NLS-1$
+
+
+ HttpResponse response = client.postMultipart(request_url, request_headers, parts);
+ int status = response.getResponseCode();
+ if (status == HttpsURLConnection.HTTP_OK) {
+ m_progress.setStatus(new Message(Message.INFO, Messages.getMessage(UPDATE_POSTMAN_COLLECTION_SUCCESS, jobId)));
+ } else {
+ JSONObject json = (JSONObject) response.getResponseBodyAsJSON();
+ if(json != null && json.has("errorMessage")){
+ m_progress.setStatus(new Message(Message.ERROR, json.getString("errorMessage")));
+ } else {
+ m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_UPDATE_JOB, status)));
+ }
+ return false;
+ }
+ } catch(IOException | JSONException e) {
+ m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_UPDATE_JOB, e.getLocalizedMessage())));
+ return false;
+ }
+ return true;
+ }
private File getFile(String fileLocation) {
if(fileLocation != null && new File(fileLocation).isFile()) {
File file = new File(fileLocation);
return file;
}
+ m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_FILE_NOT_FOUND, fileLocation)));
return null;
}
-
- private boolean runScanJob(String jobId) {
+
+ private void addAllFileParts(Map params, List parts) throws IOException {
+ String[][] filePartMappings = {
+ {"postmanCollectionFile", "postmanCollectionFile"},
+ {"environmentalVariablesFile", "postmanEnvironmentFile"},
+ {"globalVariablesFile", "postmanGlobalFile"},
+ {"additionalFiles", "postmanAdditionalFiles"}
+ };
+
+ for (String[] mapping : filePartMappings) {
+ addFilePart(params, parts, mapping[0], mapping[1]);
+ }
+ }
+
+
+ private void addFilePart(Map params, List parts, String paramKey, String partName) throws IOException {
+ String filePath = params.get(paramKey);
+ if (filePath != null && !filePath.isEmpty()) {
+ File file = getFile(filePath);
+ if (file != null) {
+ parts.add(new HttpPart(partName, file, "multipart/form-data")); //$NON-NLS-1$
+ }
+ }
+ }
+
+
+ private boolean runScanJob(String jobId) {
if(loginExpired())
return false;
@@ -311,10 +382,7 @@ private boolean runScanJob(String jobId) {
String eTag = "";
eTag = getEtag(jobId);
String request_url = m_authProvider.getServer() + String.format(ASE_RUN_JOB_ACTION, jobId);
- Map request_headers = m_authProvider.getAuthorizationHeader(true);
- request_headers.put(CONTENT_TYPE, "application/json; utf-8"); //$NON-NLS-1$
- request_headers.put(CHARSET, UTF8);
- request_headers.put("Accept", "application/json"); //$NON-NLS-1$ //$NON-NLS-2$
+ Map request_headers = getRequestHeaders();
request_headers.put("If-Match", eTag);
Map params= new HashMap<>();
params.put("type", "run");
@@ -342,10 +410,7 @@ private String getEtag(String jobId) {
return null;
String request_url = m_authProvider.getServer() + String.format(ASE_GET_JOB, jobId);
- Map request_headers = m_authProvider.getAuthorizationHeader(true);
- request_headers.put(CONTENT_TYPE, "application/json; utf-8"); //$NON-NLS-1$
- request_headers.put(CHARSET, UTF8);
- request_headers.put("Accept", "application/json"); //$NON-NLS-1$ //$NON-NLS-2$
+ Map request_headers = getRequestHeaders();
HttpsClient client = new HttpsClient();
@@ -380,7 +445,7 @@ public JSONObject getScanDetails(String jobId) throws IOException, JSONException
return null;
String reportPackId=getReportPackId(jobId);
String request_url = m_authProvider.getServer() + String.format(ASE_REPORTS, reportPackId);
- Map request_headers = m_authProvider.getAuthorizationHeader(true);
+ Map request_headers = getRequestHeaders();
HttpsClient client = new HttpsClient();
HttpResponse response = client.get(request_url, request_headers, null);
@@ -399,6 +464,16 @@ public JSONArray getNonCompliantIssues(String scanId) throws IOException, JSONEx
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
+ @Override
+ public JSONArray getNonCompliantIssuesUsingExecutionId(String executionId) throws IOException, JSONException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public String rescan(String scanId, Map params) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
@Override
public IAuthenticationProvider getAuthenticationProvider() {
return m_authProvider;
@@ -409,10 +484,15 @@ public void setProgress(IProgress progress) {
m_progress = progress;
}
+ @Override
+ public JSONArray getBaseScanDetails(String scanId) {
+ return null;
+ }
+
private String getReportPackId(String jobId) {
return String.valueOf(Integer.parseInt(jobId)+1);
- // Uncomment the below code when you figure out how to parse the reponse.
- // currently the reponse is returned as array which makes no sense.
+ // Uncomment the below code when you figure out how to parse the response.
+ // currently the response is returned as array which makes no sense.
/*IAuthenticationProvider authProvider = m_scanProvider.getAuthenticationProvider();
if(authProvider.isTokenExpired()) {
m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_LOGIN_EXPIRED)));
@@ -501,4 +581,12 @@ private JSONObject getResultJson(HttpResponse response) {
}
return null;
}
+
+ private Map getRequestHeaders() {
+ Map request_headers = m_authProvider.getAuthorizationHeader(true);
+ request_headers.put(CONTENT_TYPE, "application/json; utf-8"); //$NON-NLS-1$
+ request_headers.put(CHARSET, UTF8);
+ request_headers.put("Accept", "application/json"); //$NON-NLS-1$ //$NON-NLS-2$
+ return request_headers;
+ }
}
diff --git a/src/main/java/com/hcl/appscan/sdk/scan/ASEScanType.java b/src/main/java/com/hcl/appscan/sdk/scan/ASEScanType.java
new file mode 100644
index 00000000..5fb492ce
--- /dev/null
+++ b/src/main/java/com/hcl/appscan/sdk/scan/ASEScanType.java
@@ -0,0 +1,48 @@
+/**
+ * © Copyright HCL Technologies Ltd. 2025.
+ * LICENSE: Apache License, Version 2.0 https://www.apache.org/licenses/LICENSE-2.0
+ */
+
+package com.hcl.appscan.sdk.scan;
+
+import com.hcl.appscan.sdk.CoreConstants;
+
+public enum ASEScanType {
+ FULL_SCAN(CoreConstants.FULL_SCAN, "1"),
+ TEST_ONLY(CoreConstants.TEST_ONLY, "3"),
+ POSTMAN_COLLECTION(CoreConstants.POSTMAN_COLLECTION, "4");
+
+ private final String type;
+ private final String code;
+
+ ASEScanType(String type, String code) {
+ this.type = type;
+ this.code = code;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public static String scanTypeCode(String type) {
+ for (ASEScanType scanType : values()) {
+ if (scanType.getType().equalsIgnoreCase(type)) {
+ return scanType.getCode();
+ }
+ }
+ return type; // fallback for unknown type
+ }
+
+ public static String scanTypeName(String code) {
+ for (ASEScanType scanType : values()) {
+ if (scanType.getCode().equals(code)) {
+ return scanType.getType();
+ }
+ }
+ return ""; // fallback for unknown code
+ }
+}
diff --git a/src/main/java/com/hcl/appscan/sdk/scan/CloudScanServiceProvider.java b/src/main/java/com/hcl/appscan/sdk/scan/CloudScanServiceProvider.java
index 0618f49c..bc9dfbfa 100644
--- a/src/main/java/com/hcl/appscan/sdk/scan/CloudScanServiceProvider.java
+++ b/src/main/java/com/hcl/appscan/sdk/scan/CloudScanServiceProvider.java
@@ -14,9 +14,11 @@
import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import java.util.HashMap;
import javax.net.ssl.HttpsURLConnection;
+import com.hcl.appscan.sdk.logging.DefaultProgress;
import com.hcl.appscan.sdk.scanners.dynamic.DASTConstants;
import com.hcl.appscan.sdk.utils.FileUtil;
import com.hcl.appscan.sdk.utils.ServiceUtil;
@@ -49,54 +51,85 @@ public CloudScanServiceProvider(IProgress progress, IAuthenticationProvider auth
m_progress = progress;
m_authProvider = authProvider;
}
+
+ public CloudScanServiceProvider(IAuthenticationProvider authProvider) {
+ this(new DefaultProgress(), authProvider);
+ }
@Override
public String createAndExecuteScan(String type, Map params) {
- if(loginExpired() || (params.containsKey(APP_ID) && !verifyApplication(params.get(APP_ID).toString()))) {
+ String requestUrl = m_authProvider.getServer() + String.format(API_SCANNER, type);
+ String progressMessage = Messages.getMessage(CREATE_SCAN_SUCCESS,type.toUpperCase());
+ String overviewMessage = Messages.getMessage(SCAN_OVERVIEW,type.toUpperCase());
+ return executeScan(requestUrl, params, progressMessage, overviewMessage);
+ }
+
+ @Override
+ public String rescan(String scanId, Map params) {
+ String requestUrl = m_authProvider.getServer() + String.format(API_RESCAN, scanId);
+
+ Map updateParams = new HashMap<>();
+ updateParams.put("Name", params.remove(CoreConstants.SCAN_NAME));
+ updateParams.put("EnableMailNotifications", params.remove(CoreConstants.EMAIL_NOTIFICATION));
+ updateParams.put("FullyAutomatic", params.remove("FullyAutomatic"));
+ updateScanData(updateParams, scanId);
+
+ String progressMessage = Messages.getMessage(RESCAN_SUCCESS);
+ String overviewMessage = Messages.getMessage(RESCAN_OVERVIEW);
+ return executeScan(requestUrl, params, progressMessage, overviewMessage);
+ }
+
+ //private method to handle common logic
+ private String executeScan(String requestUrl, Map params, String successMessageKey, String overviewMessageKey) {
+ if (loginExpired() || (params.containsKey(APP_ID) && !verifyApplication(params.get(APP_ID).toString()))) {
return null;
}
- Map request_headers = m_authProvider.getAuthorizationHeader(true);
+ Map requestHeaders = m_authProvider.getAuthorizationHeader(true);
HttpClient client = new HttpClient(m_authProvider.getProxy(), m_authProvider.getacceptInvalidCerts());
try {
- request_headers.put("Content-Type", "application/json");
- request_headers.put("accept", "application/json");
- String request_url = m_authProvider.getServer() + String.format(API_SCANNER, type);
-
- HttpResponse response = client.post(request_url,request_headers,params);
- int status = response.getResponseCode();
+ requestHeaders.put("Content-Type", "application/json");
+ requestHeaders.put("accept", "application/json");
+ HttpResponse response = client.post(requestUrl, requestHeaders, params);
+ int status = response.getResponseCode();
JSONObject json = (JSONObject) response.getResponseBodyAsJSON();
if (status == HttpsURLConnection.HTTP_CREATED || status == HttpsURLConnection.HTTP_OK) {
- String scanId = json.getString(ID);
- m_progress.setStatus(new Message(Message.INFO, Messages.getMessage(CREATE_SCAN_SUCCESS, type.toUpperCase(), scanId)));
- String scanOverviewUrl = m_authProvider.getServer() + "/main/myapps/" + params.get(CoreConstants.APP_ID) + "/scans/" + scanId;
- m_progress.setStatus(new Message(Message.INFO, Messages.getMessage(SCAN_OVERVIEW, type.toUpperCase(), scanOverviewUrl)));
- return scanId;
+ String id = json.getString(ID);
+ String scanOverviewUrl;
+ if(params.containsKey(SCAN_ID)) {
+ String scanId= params.get(SCAN_ID);
+ scanOverviewUrl = m_authProvider.getServer() + "/main/myapps/" + params.get(CoreConstants.APP_ID) + "/scans/" + scanId;
+ } else {
+ scanOverviewUrl = m_authProvider.getServer() + "/main/myapps/" + params.get(CoreConstants.APP_ID) + "/scans/" + id;
+ }
+ m_progress.setStatus(new Message(Message.INFO, successMessageKey + " " + id));
+ m_progress.setStatus(new Message(Message.INFO, overviewMessageKey + " " + scanOverviewUrl));
+ return id;
} else if (json != null && json.has(MESSAGE)) {
String errorResponse = json.getString(MESSAGE);
- if(json.has(FORMAT_PARAMS) && !json.isNull(FORMAT_PARAMS)) {
+ if (json.has(FORMAT_PARAMS) && !json.isNull(FORMAT_PARAMS)) {
JSONArray jsonArray = json.getJSONArray(FORMAT_PARAMS);
- if(jsonArray != null){
+ if (jsonArray != null) {
String[] messageParams = new String[jsonArray.size()];
for (int i = 0; i < jsonArray.size(); i++) {
- messageParams[i] = (String)jsonArray.get(i);
+ messageParams[i] = (String) jsonArray.get(i);
}
errorResponse = MessageFormat.format(errorResponse, (Object[]) messageParams);
}
}
m_progress.setStatus(new Message(Message.ERROR, errorResponse));
- }
- else
+ } else {
m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_SUBMITTING_SCAN, status)));
- } catch(IOException | JSONException e) {
+ }
+ } catch (IOException | JSONException e) {
m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_SUBMITTING_SCAN, e.getLocalizedMessage())));
}
return null;
- }
-
+ }
+
@Override
public String submitFile(File file) throws IOException {
if(loginExpired())
@@ -169,40 +202,74 @@ public JSONObject getScanDetails(String scanId) throws IOException, JSONExceptio
return null;
}
+
+ public JSONObject getScanDetails(String type, String scanId) {
+ if (loginExpired()) {
+ return null;
+ }
+
+ String request_url = m_authProvider.getServer() + String.format(API_SCANNER_DETAILS, ServiceUtil.scanTypeShortForm(type), scanId);
+ Map request_headers = m_authProvider.getAuthorizationHeader(true);
+ request_headers.put("accept", "application/json");
+ request_headers.put("Content-Type", "application/json");
+
+ HttpClient client = new HttpClient(m_authProvider.getProxy(), m_authProvider.getacceptInvalidCerts());
+ try {
+ HttpResponse response = client.get(request_url, request_headers, null);
+
+ if (response.isSuccess()) {
+ return (JSONObject) response.getResponseBodyAsJSON();
+ }
+ } catch (IOException | JSONException e) {
+ // Ignore and move on.
+ }
+
+ return null;
+ }
@Override
public JSONArray getNonCompliantIssues(String scanId) throws IOException, JSONException {
- if(loginExpired())
- return null;
-
- String request_url = m_authProvider.getServer() + String.format(API_ISSUES_COUNT, "Scan", scanId);
- request_url +="?applyPolicies=All&%24filter=Status%20eq%20%27Open%27%20or%20Status%20eq%20%27InProgress%27%20or%20Status%20eq%20%27Reopened%27%20or%20Status%20eq%20%27New%27&%24apply=groupby%28%28Status%2CSeverity%29%2Caggregate%28%24count%20as%20N%29%29";
- Map request_headers = m_authProvider.getAuthorizationHeader(true);
- request_headers.put("Content-Type", "application/json; charset=UTF-8");
- request_headers.put("Accept", "application/json");
-
- HttpClient client = new HttpClient(m_authProvider.getProxy(), m_authProvider.getacceptInvalidCerts());
- HttpResponse response = client.get(request_url, request_headers, null);
-
- if (response.isSuccess()) {
- JSONObject json = (JSONObject) response.getResponseBodyAsJSON();
- return (JSONArray) json.getJSONArray("Items");
- }
+ return getNonCompliantIssues("Scan", scanId);
+ }
- if (response.getResponseCode() == HttpsURLConnection.HTTP_BAD_REQUEST)
- m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_GETTING_INFO, "Scan", scanId)));
- else {
- JSONObject obj=(JSONObject)response.getResponseBodyAsJSON();
- if (obj!=null && obj.has(MESSAGE)){
- m_progress.setStatus(new Message(Message.ERROR, obj.getString(MESSAGE)));
- }
- else {
- m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_GETTING_DETAILS, response.getResponseCode())));
- }
- }
-
- return null;
+ @Override
+ public JSONArray getNonCompliantIssuesUsingExecutionId(String executionId) throws IOException, JSONException {
+ return getNonCompliantIssues("ScanExecution", executionId);
}
+
+ //private method to handle common logic
+ private JSONArray getNonCompliantIssues(String idType, String id) throws IOException, JSONException {
+ if (loginExpired())
+ return null;
+
+ String requestUrl = m_authProvider.getServer() + String.format(API_ISSUES_COUNT, idType, id);
+ requestUrl += "?applyPolicies=All&%24filter=Status%20eq%20%27Open%27%20or%20Status%20eq%20%27InProgress%27%20or%20Status%20eq%20%27Reopened%27&%24apply=groupby%28%28Status%2CSeverity%29%2Caggregate%28%24count%20as%20N%29%29";
+
+ Map requestHeaders = m_authProvider.getAuthorizationHeader(true);
+ requestHeaders.put("Content-Type", "application/json; charset=UTF-8");
+ requestHeaders.put("Accept", "application/json");
+
+ HttpClient client = new HttpClient(m_authProvider.getProxy(), m_authProvider.getacceptInvalidCerts());
+ HttpResponse response = client.get(requestUrl, requestHeaders, null);
+
+ if (response.isSuccess()) {
+ JSONObject json = (JSONObject) response.getResponseBodyAsJSON();
+ return (JSONArray) json.getJSONArray("Items");
+ }
+
+ if (response.getResponseCode() == HttpsURLConnection.HTTP_BAD_REQUEST) {
+ m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_GETTING_INFO, idType, id)));
+ } else {
+ JSONObject obj = (JSONObject) response.getResponseBodyAsJSON();
+ if (obj != null && obj.has(MESSAGE)) {
+ m_progress.setStatus(new Message(Message.ERROR, obj.getString(MESSAGE)));
+ } else {
+ m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_GETTING_DETAILS, response.getResponseCode())));
+ }
+ }
+
+ return null;
+ }
@Override
public IAuthenticationProvider getAuthenticationProvider() {
@@ -231,4 +298,51 @@ private boolean verifyApplication(String appId) {
public void setProgress(IProgress progress) {
m_progress = progress;
}
+
+ @Override
+ public JSONArray getBaseScanDetails(String scanId) {
+ if (loginExpired()) {
+ return null;
+ }
+
+ String request_url = m_authProvider.getServer() + String.format(API_EXECUTION_DETAILS, scanId);
+ request_url += "?$filter=IsValidForIncremental%20eq%20true&%24select=Id%2C%20CreatedAt%2C%20IsValidForIncremental&%24orderby=CreatedAt%20desc";
+ Map request_headers = m_authProvider.getAuthorizationHeader(true);
+ request_headers.put("accept", "application/json");
+ request_headers.put("Content-Type", "application/json");
+
+ HttpClient client = new HttpClient(m_authProvider.getProxy(), m_authProvider.getacceptInvalidCerts());
+ try {
+ HttpResponse response = client.get(request_url, request_headers, null);
+
+ if (response.isSuccess()) {
+ return (JSONArray) response.getResponseBodyAsJSON();
+ }
+ } catch (IOException | JSONException e) {
+ // Ignore and move on.
+ }
+
+ return null;
+ }
+
+ public void updateScanData(Map params, String scanId) {
+ if (loginExpired()) {
+ return;
+ }
+
+ String request_url = m_authProvider.getServer() + String.format(API_SCANNER,scanId);
+ Map request_headers = m_authProvider.getAuthorizationHeader(true);
+ request_headers.put("accept", "application/json");
+ request_headers.put("Content-Type", "application/json");
+
+ HttpClient client = new HttpClient(m_authProvider.getProxy(), m_authProvider.getacceptInvalidCerts());
+ try {
+ HttpResponse response = client.put(request_url, request_headers, params);
+ if (response.getResponseCode() == HttpsURLConnection.HTTP_NO_CONTENT) {
+ m_progress.setStatus(new Message(Message.INFO, Messages.getMessage(UPDATE_JOB)));
+ }
+ } catch (IOException | JSONException e) {
+ m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_UPDATE_JOB, e.getLocalizedMessage())));
+ }
+ }
}
diff --git a/src/main/java/com/hcl/appscan/sdk/scan/IScan.java b/src/main/java/com/hcl/appscan/sdk/scan/IScan.java
index a2a50adf..e3f0fc40 100644
--- a/src/main/java/com/hcl/appscan/sdk/scan/IScan.java
+++ b/src/main/java/com/hcl/appscan/sdk/scan/IScan.java
@@ -8,7 +8,6 @@
import com.hcl.appscan.sdk.error.InvalidTargetException;
import com.hcl.appscan.sdk.error.ScannerException;
-import com.hcl.appscan.sdk.logging.IProgress;
import com.hcl.appscan.sdk.results.IResultsProvider;
public interface IScan {
diff --git a/src/main/java/com/hcl/appscan/sdk/scan/IScanServiceProvider.java b/src/main/java/com/hcl/appscan/sdk/scan/IScanServiceProvider.java
index 42d9eb41..1adb2c2c 100644
--- a/src/main/java/com/hcl/appscan/sdk/scan/IScanServiceProvider.java
+++ b/src/main/java/com/hcl/appscan/sdk/scan/IScanServiceProvider.java
@@ -1,6 +1,6 @@
/**
* © Copyright IBM Corporation 2016.
- * © Copyright HCL Technologies Ltd. 2017,2018.
+ * © Copyright HCL Technologies Ltd. 2017,2024.
* LICENSE: Apache License, Version 2.0 https://www.apache.org/licenses/LICENSE-2.0
*/
@@ -15,7 +15,6 @@
import org.apache.wink.json4j.JSONObject;
import com.hcl.appscan.sdk.auth.IAuthenticationProvider;
-import com.hcl.appscan.sdk.http.HttpResponse;
import com.hcl.appscan.sdk.logging.IProgress;
/**
@@ -31,6 +30,15 @@ public interface IScanServiceProvider {
* @return The id of the submitted scan, if successful. Otherwise, null.
*/
public String createAndExecuteScan(String type, Map params);
+
+ /**
+ * Initiates a Rescan
+ *
+ * @param scanId The ID of the parent scan on which the rescan will be executed.
+ * @param params A Map of rescan parameters.
+ * @return The id of the submitted rescan, if successful. Otherwise, returns null.
+ */
+ public String rescan(String scanId, Map params);
/**
* Submits a file for scanning.
@@ -60,7 +68,16 @@ public interface IScanServiceProvider {
* @throws JSONException If an error occurs.
*/
public JSONArray getNonCompliantIssues(String scanId) throws IOException, JSONException;
-
+
+ /**
+ * Gets the non compliant issues in JSON format.
+ *
+ * @param executionId The id of the scan execution to retrieve all the non compliant issues
+ * @return JSONArray containing the issues as JSON objects.
+ * @throws IOException If an error occurs.
+ * @throws JSONException If an error occurs.
+ */
+ public JSONArray getNonCompliantIssuesUsingExecutionId(String executionId) throws IOException, JSONException;
/**
* Gets the {@link IAuthenticationProvider} used to authenticate with a scanning service.
*
@@ -74,4 +91,12 @@ public interface IScanServiceProvider {
* @param progress The {@link IProgress}.
*/
public void setProgress(IProgress progress);
+
+ /**
+ * Fetch the details of all the executions of a scan.
+ *
+ * @param scanId The scanId to test
+ * @return JSONArray.
+ */
+ public JSONArray getBaseScanDetails(String scanId);
}
diff --git a/src/main/java/com/hcl/appscan/sdk/scanners/ASoCScan.java b/src/main/java/com/hcl/appscan/sdk/scanners/ASoCScan.java
index cb323d45..1f0f3371 100644
--- a/src/main/java/com/hcl/appscan/sdk/scanners/ASoCScan.java
+++ b/src/main/java/com/hcl/appscan/sdk/scanners/ASoCScan.java
@@ -25,6 +25,8 @@ public abstract class ASoCScan implements IScan, ScanConstants, Serializable {
private String m_target;
private String m_scanId;
+ private String m_executionId;
+ private boolean m_rescan;
private IProgress m_progress;
private IScanServiceProvider m_serviceProvider;
private Map m_properties;
@@ -40,12 +42,17 @@ public ASoCScan(Map properties, IProgress progress, IScanService
m_properties.put(CoreConstants.SCAN_NAME, getType() + SystemUtil.getTimeStamp());
m_progress = progress;
m_serviceProvider = provider;
+ m_rescan = m_properties.containsKey(CoreConstants.SCAN_ID);
}
@Override
public String getScanId() {
return m_scanId;
}
+
+ public String getExecutionId() {
+ return m_executionId;
+ }
@Override
public String getName() {
@@ -62,7 +69,7 @@ public IResultsProvider getResultsProvider() {
@Override
public IResultsProvider getResultsProvider(boolean nonCompliantIssues) {
if(nonCompliantIssues) {
- IResultsProvider provider = new NonCompliantIssuesResultProvider(m_scanId, getType(), m_serviceProvider, m_progress);
+ IResultsProvider provider = new NonCompliantIssuesResultProvider(m_scanId, m_executionId, getType(), m_serviceProvider, m_progress);
provider.setReportFormat(getReportFormat());
return provider;
}
@@ -74,6 +81,18 @@ public IResultsProvider getResultsProvider(boolean nonCompliantIssues) {
protected void setScanId(String id) {
m_scanId = id;
}
+
+ protected void setExecutionId(String id){
+ m_executionId = id;
+ }
+
+ public void setRescan(boolean rescan){
+ m_rescan = rescan;
+ }
+
+ public boolean getRescan() {
+ return m_rescan;
+ }
protected String getAppId() {
return m_properties.get(CoreConstants.APP_ID);
@@ -104,5 +123,9 @@ protected Map getProperties() {
return m_properties;
}
+ protected void submitRescan() {
+ setExecutionId(getServiceProvider().rescan(getScanId(),getProperties()));
+ }
+
public abstract String getReportFormat();
}
\ No newline at end of file
diff --git a/src/main/java/com/hcl/appscan/sdk/scanners/dynamic/DASTScan.java b/src/main/java/com/hcl/appscan/sdk/scanners/dynamic/DASTScan.java
index 6d357c01..abfa77f4 100644
--- a/src/main/java/com/hcl/appscan/sdk/scanners/dynamic/DASTScan.java
+++ b/src/main/java/com/hcl/appscan/sdk/scanners/dynamic/DASTScan.java
@@ -18,7 +18,6 @@
import com.hcl.appscan.sdk.logging.DefaultProgress;
import com.hcl.appscan.sdk.logging.IProgress;
import com.hcl.appscan.sdk.scan.IScanServiceProvider;
-import com.hcl.appscan.sdk.scan.CloudScanServiceProvider;
import com.hcl.appscan.sdk.scanners.ASoCScan;
import com.hcl.appscan.sdk.utils.ServiceUtil;
import org.apache.wink.json4j.JSONException;
@@ -94,13 +93,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 params) throws JSONException {
diff --git a/src/main/java/com/hcl/appscan/sdk/scanners/sast/SAClient.java b/src/main/java/com/hcl/appscan/sdk/scanners/sast/SAClient.java
index 0684738b..6bd7e9f4 100644
--- a/src/main/java/com/hcl/appscan/sdk/scanners/sast/SAClient.java
+++ b/src/main/java/com/hcl/appscan/sdk/scanners/sast/SAClient.java
@@ -1,6 +1,6 @@
/**
* © Copyright IBM Corporation 2016.
- * © Copyright HCL Technologies Ltd. 2017, 2024.
+ * © Copyright HCL Technologies Ltd. 2017, 2026.
* LICENSE: Apache License, Version 2.0 https://www.apache.org/licenses/LICENSE-2.0
*/
@@ -10,6 +10,7 @@
import java.io.File;
import java.io.FileReader;
import java.io.FilenameFilter;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Proxy;
@@ -24,6 +25,7 @@
import com.hcl.appscan.sdk.logging.IProgress;
import com.hcl.appscan.sdk.logging.Message;
import com.hcl.appscan.sdk.utils.ArchiveUtil;
+import com.hcl.appscan.sdk.utils.ArchiveUtilSymlinks;
import com.hcl.appscan.sdk.utils.FileUtil;
import com.hcl.appscan.sdk.utils.ServiceUtil;
import com.hcl.appscan.sdk.utils.SystemUtil;
@@ -165,8 +167,8 @@ public String getClientScript(String serverURL, String acceptInvalidCerts) throw
//See if we already have the client package.
String scriptPath = "bin" + File.separator + getScriptName(); //$NON-NLS-1$
File install = findClientInstall();
-
- if(install != null && new File(install, scriptPath).isFile() && !shouldUpdateClient(serverURL))
+
+ if(install != null && new File(install, scriptPath).isFile() && !shouldUpdateClient(serverURL, Boolean.parseBoolean(acceptInvalidCerts)))
return new File(install, scriptPath).getAbsolutePath();
//Download it.
@@ -189,10 +191,19 @@ public String getClientScript(String serverURL, String acceptInvalidCerts) throw
if(clientZip.isFile()) {
m_progress.setStatus(new Message(Message.INFO, Messages.getMessage(DOWNLOAD_COMPLETE)));
m_progress.setStatus(new Message(Message.INFO, Messages.getMessage(EXTRACTING_CLIENT)));
- ArchiveUtil.unzip(clientZip, m_installDir);
- m_progress.setStatus(new Message(Message.INFO, Messages.getMessage(DONE)));
}
+ // Handle Mac bundle release (which contains symlinks that aren't handled by the Java zip class)
+ if (SystemUtil.isMac()) {
+ ArchiveUtilSymlinks aus = new ArchiveUtilSymlinks();
+ aus.unzip(clientZip, m_installDir);
+ }
+ else {
+ ArchiveUtil au = new ArchiveUtil();
+ au.unzip(clientZip, m_installDir);
+ }
+ m_progress.setStatus(new Message(Message.INFO, Messages.getMessage(DONE)));
+
return new File(findClientInstall(), scriptPath).getAbsolutePath();
}
@@ -215,12 +226,16 @@ public boolean majorVersionChanged() throws IOException {
}
}
- public boolean shouldUpdateClient() throws IOException {
- return shouldUpdateClient("");
- }
-
+ public boolean shouldUpdateClient() throws IOException {
+ return shouldUpdateClient("");
+ }
+
public boolean shouldUpdateClient(String serverURL) throws IOException {
- String serverVersion = ServiceUtil.getSAClientVersion(m_proxy,serverURL);
+ return shouldUpdateClient(serverURL, false);
+ }
+
+ public boolean shouldUpdateClient(String serverURL, boolean acceptInvalidCerts) throws IOException {
+ String serverVersion = ServiceUtil.getSAClientVersion(m_proxy,serverURL, acceptInvalidCerts);
String localVersion = getLocalClientVersion();
if(compareVersions(localVersion, serverVersion) && System.getProperty(CoreConstants.SKIP_UPDATE) == null) {
@@ -264,14 +279,17 @@ public boolean accept(File dir, String name) {
private String getLocalClientVersion() {
File versionInfo = new File(findClientInstall(), VERSION_INFO);
+
String version = null;
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(versionInfo));
version = reader.readLine(); //The version is the first line of the version.info file.
+ } catch (FileNotFoundException ignore) {
+ // Expected before first installation
} catch (IOException e) {
- m_progress.setStatus(new Message(Message.ERROR, Messages.getMessage(ERROR_CHECKING_SACLIENT_VER, e.getLocalizedMessage())));
+ m_progress.setStatus(new Message(Message.WARNING, Messages.getMessage(ERROR_CHECKING_SACLIENT_VER, e.getLocalizedMessage())));
} finally {
try {
if(reader != null)
@@ -358,34 +376,19 @@ private List getClientArgs(Map properties) {
if(properties.containsKey(SECRETS_ONLY) || System.getProperty(SECRETS_ONLY) != null) {
args.add(OPT_SECRETS_ONLY);
}
+ //For AppScan 360 support.
+ if(Boolean.parseBoolean(properties.getOrDefault(CoreConstants.ACCEPT_INVALID_CERTS, Boolean.toString(false)))) {
+ args.add(OPT_ACCEPTS_SSL);
+ }
+ if(properties.get(CoreConstants.SERVER_URL) != null && properties.get(CoreConstants.SERVER_URL).trim() != "") { //$NON-NLS-1$
+ args.add("-D" + CoreConstants.BLUEMIX_SERVER + "=" + properties.get(CoreConstants.SERVER_URL)); //$NON-NLS-1$ //$NON-NLS-2$
+ }
return args;
}
- private boolean compareVersions(String baseVersion, String newVersion) {
- if(baseVersion == null)
- return true;
-
- if(baseVersion != null && newVersion != null) {
- String[] base = baseVersion.split("\\."); //$NON-NLS-1$
- String[] next = newVersion.split("\\."); //$NON-NLS-1$
-
- try {
- for(int iter = 0; iter < base.length && iter < next.length; iter++) {
- int lVersion = Integer.parseInt(base[iter]);
- int sVersion = Integer.parseInt(next[iter]);
-
- if (((iter==0) && lVersion params = getProperties();
- params.put(FILE_ID, fileId);
-
- submitScan();
- if(getScanId() == null)
- throw new ScannerException(Messages.getMessage(ERROR_SUBMITTING_IRX));
+
+ if (getRescan()) {
+ 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(!getProperties().containsKey(CoreConstants.INCLUDE_SCA) && getScanId() == null)
+ throw new ScannerException(Messages.getMessage(ERROR_CREATING_SCAN));
+ }
}
-
+
protected void submitScan() {
setScanId(getServiceProvider().createAndExecuteScan(STATIC_ANALYZER, getProperties()));
}
diff --git a/src/main/java/com/hcl/appscan/sdk/scanners/sast/SASTScanManager.java b/src/main/java/com/hcl/appscan/sdk/scanners/sast/SASTScanManager.java
index b338bdb4..e4438117 100644
--- a/src/main/java/com/hcl/appscan/sdk/scanners/sast/SASTScanManager.java
+++ b/src/main/java/com/hcl/appscan/sdk/scanners/sast/SASTScanManager.java
@@ -27,6 +27,7 @@
import com.hcl.appscan.sdk.scanners.sast.xml.ModelWriter;
import com.hcl.appscan.sdk.scanners.sast.xml.XmlWriter;
import com.hcl.appscan.sdk.scanners.sca.SCAScan;
+import com.hcl.appscan.sdk.utils.ServiceUtil;
import com.hcl.appscan.sdk.utils.SystemUtil;
public class SASTScanManager implements IScanManager{
@@ -38,7 +39,8 @@ public class SASTScanManager implements IScanManager{
private boolean m_isOpenSourceOnlyEnabled = false;
private boolean m_isSourceCodeOnlyEnabled = false;
private boolean m_isStaticAnalysisOnlyEnabled = false;
- private boolean m_isSecretsScanningEnabled = false;
+ private boolean m_isSecretsScanningDisabled = false;
+ private boolean m_isSecretsScanningEnabled = false;
private boolean m_isSecretsScanningOnlyEnabled = false;
public SASTScanManager(String workingDir) {
@@ -110,12 +112,22 @@ public void setIsThirdPartyScanningEnabled(boolean isThirdPartyScanningEnabled)
m_isThirdPartyScanningEnabled = isThirdPartyScanningEnabled;
}
+ /**
+ * Disables scanning for secrets.
+ * @param isSecretsScanningDisabled - True to skip scanning for secrets vulnerabilities.
+ */
+ public void setIsSecretsScanningDisabled(boolean isSecretsScanningDisabled) {
+ m_isSecretsScanningDisabled = isSecretsScanningDisabled;
+ m_isSecretsScanningEnabled = !isSecretsScanningDisabled;
+ }
+
/**
* Enables scanning for secrets.
* @param isSecretsScanningEnabled - True to scan for secrets vulnerabilities.
*/
public void setIsSecretsScanningEnabled(boolean isSecretsScanningEnabled) {
- m_isSecretsScanningEnabled = isSecretsScanningEnabled;
+ m_isSecretsScanningDisabled = !isSecretsScanningEnabled;
+ m_isSecretsScanningEnabled = isSecretsScanningEnabled;
}
/**
@@ -160,7 +172,7 @@ public void createConfig(boolean useRelativeTargetPaths) throws AppScanException
try {
ModelWriter writer = new XmlWriter(useRelativeTargetPaths);
writer.initWriters(new File(m_workingDirectory));
- writer.visit(m_targets, m_isThirdPartyScanningEnabled, m_isOpenSourceOnlyEnabled, m_isSourceCodeOnlyEnabled, m_isStaticAnalysisOnlyEnabled, m_isSecretsScanningEnabled, m_isSecretsScanningOnlyEnabled);
+ writer.visit(m_targets, m_isThirdPartyScanningEnabled, m_isOpenSourceOnlyEnabled, m_isSourceCodeOnlyEnabled, m_isStaticAnalysisOnlyEnabled, m_isSecretsScanningDisabled, m_isSecretsScanningEnabled, m_isSecretsScanningOnlyEnabled);
writer.write();
} catch (IOException | TransformerException e) {
throw new AppScanException(e.getLocalizedMessage(), e);
@@ -172,12 +184,12 @@ private String getDefaultScanName() {
}
private void createScan(Map properties, IProgress progress, IScanServiceProvider provider) {
- if(m_isStaticAnalysisOnlyEnabled) {
- m_scan = new SASTScan(properties, progress, provider);
- }
- else if(m_isOpenSourceOnlyEnabled ) {
+ if(m_isOpenSourceOnlyEnabled ) {
m_scan = new SCAScan(properties, progress, provider);
}
+ else if(m_isStaticAnalysisOnlyEnabled || (provider != null && !ServiceUtil.hasScaEntitlement(provider.getAuthenticationProvider()))) {
+ m_scan = new SASTScan(properties, progress, provider);
+ }
else {
m_scan = new SAST_SCA_Scan(properties, progress, provider);
}
diff --git a/src/main/java/com/hcl/appscan/sdk/scanners/sast/SAST_SCA_Scan.java b/src/main/java/com/hcl/appscan/sdk/scanners/sast/SAST_SCA_Scan.java
index 4027cac5..0424c2ca 100644
--- a/src/main/java/com/hcl/appscan/sdk/scanners/sast/SAST_SCA_Scan.java
+++ b/src/main/java/com/hcl/appscan/sdk/scanners/sast/SAST_SCA_Scan.java
@@ -44,11 +44,10 @@ public void run() throws ScannerException, InvalidTargetException {
//Avoid generating 2 .irx files.
return;
}
- else {
- m_sastScanId = getScanId();
- m_scaScan.run();
- m_scaScanId = m_scaScan.getScanId();
- }
+
+ m_sastScanId = getScanId();
+ m_scaScan.run();
+ m_scaScanId = m_scaScan.getScanId();
}
@Override
diff --git a/src/main/java/com/hcl/appscan/sdk/scanners/sast/targets/GenericTarget.java b/src/main/java/com/hcl/appscan/sdk/scanners/sast/targets/GenericTarget.java
index c5e2db45..824ecad2 100644
--- a/src/main/java/com/hcl/appscan/sdk/scanners/sast/targets/GenericTarget.java
+++ b/src/main/java/com/hcl/appscan/sdk/scanners/sast/targets/GenericTarget.java
@@ -1,7 +1,6 @@
package com.hcl.appscan.sdk.scanners.sast.targets;
import java.io.File;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
diff --git a/src/main/java/com/hcl/appscan/sdk/scanners/sast/xml/IModelXMLConstants.java b/src/main/java/com/hcl/appscan/sdk/scanners/sast/xml/IModelXMLConstants.java
index a7e86076..69f36aba 100644
--- a/src/main/java/com/hcl/appscan/sdk/scanners/sast/xml/IModelXMLConstants.java
+++ b/src/main/java/com/hcl/appscan/sdk/scanners/sast/xml/IModelXMLConstants.java
@@ -25,6 +25,7 @@ public interface IModelXMLConstants {
String A_SOURCE_CODE_ONLY = "sourceCodeOnly"; //$NON-NLS-1$
String A_STATIC_ANALYSIS_ONLY = "staticAnalysisOnly"; //$NON-NLS-1$
String A_SECRETS_ENABLED = "enableSecrets"; //$NON-NLS-1$
+ String A_SECRETS_DISABLED = "noSecrets"; //$NON-NLS-1$
String A_SECRETS_ONLY = "secretsOnly"; //$NON-NLS-1$
//Java
diff --git a/src/main/java/com/hcl/appscan/sdk/scanners/sast/xml/ModelWriter.java b/src/main/java/com/hcl/appscan/sdk/scanners/sast/xml/ModelWriter.java
index 8c658f99..dc162c92 100644
--- a/src/main/java/com/hcl/appscan/sdk/scanners/sast/xml/ModelWriter.java
+++ b/src/main/java/com/hcl/appscan/sdk/scanners/sast/xml/ModelWriter.java
@@ -120,5 +120,5 @@ private void initDocumentBuilder() throws ParserConfigurationException {
public abstract String getOutputLocation();
- public abstract void visit(List targets, boolean isThirdPartyScanningEnabled, boolean isOpenSourceOnlyEnabled, boolean isSourceCodeOnlyEnabled, boolean isStaticAnalysisOnlyEnabled, boolean isSecretsScanningEnabled, boolean isSecretsScanningOnlyEnabled);
+ public abstract void visit(List targets, boolean isThirdPartyScanningEnabled, boolean isOpenSourceOnlyEnabled, boolean isSourceCodeOnlyEnabled, boolean isStaticAnalysisOnlyEnabled, boolean isSecretsScanningDisabled, boolean isSecretsScanningEnabled, boolean isSecretsScanningOnlyEnabled);
}
diff --git a/src/main/java/com/hcl/appscan/sdk/scanners/sast/xml/XmlWriter.java b/src/main/java/com/hcl/appscan/sdk/scanners/sast/xml/XmlWriter.java
index df3d02bb..805cf970 100644
--- a/src/main/java/com/hcl/appscan/sdk/scanners/sast/xml/XmlWriter.java
+++ b/src/main/java/com/hcl/appscan/sdk/scanners/sast/xml/XmlWriter.java
@@ -52,7 +52,7 @@ public void initWriters(File directory) throws IOException {
@Override
public void visit(List targets, boolean isThirdPartyScanningEnabled,
- boolean isOpenSourceOnlyEnabled, boolean isSourceCodeOnlyEnabled, boolean isStaticAnalysisOnlyEnabled, boolean isSecretsScanningEnabled, boolean isSecretsScanningOnlyEnabled) {
+ boolean isOpenSourceOnlyEnabled, boolean isSourceCodeOnlyEnabled, boolean isStaticAnalysisOnlyEnabled, boolean isSecretsScanningDisabled, boolean isSecretsScanningEnabled, boolean isSecretsScanningOnlyEnabled) {
m_config.beginElement(E_CONFIGURATION);
if (isThirdPartyScanningEnabled) {
@@ -70,11 +70,13 @@ public void visit(List targets, boolean isThirdPartyScanningEnabled
if (isStaticAnalysisOnlyEnabled) {
m_config.setAttribute(A_STATIC_ANALYSIS_ONLY, "true");
}
-
+
+ if (isSecretsScanningDisabled) {
+ m_config.setAttribute(A_SECRETS_DISABLED, "true");
+ }
if (isSecretsScanningEnabled) {
m_config.setAttribute(A_SECRETS_ENABLED, "true");
}
-
if (isSecretsScanningOnlyEnabled) {
m_config.setAttribute(A_SECRETS_ONLY, "true");
}
@@ -122,6 +124,7 @@ public void write() throws TransformerException {
m_config.write(m_transformer);
}
+
/**
* Returns the location of the generated configuration file.
* @return The location of the generated configuration file.
diff --git a/src/main/java/com/hcl/appscan/sdk/utils/ArchiveUtil.java b/src/main/java/com/hcl/appscan/sdk/utils/ArchiveUtil.java
index aad9f8c0..ad11fa49 100644
--- a/src/main/java/com/hcl/appscan/sdk/utils/ArchiveUtil.java
+++ b/src/main/java/com/hcl/appscan/sdk/utils/ArchiveUtil.java
@@ -16,9 +16,7 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
-
import com.hcl.appscan.sdk.Messages;
-import com.hcl.appscan.sdk.scanners.sast.SASTConstants;
public class ArchiveUtil {
@@ -123,9 +121,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(".")) {
- return;
- }
if (fileToZip.isDirectory()) {
File[] children = fileToZip.listFiles();
for (File childFile : children) {
diff --git a/src/main/java/com/hcl/appscan/sdk/utils/ArchiveUtilSymlinks.java b/src/main/java/com/hcl/appscan/sdk/utils/ArchiveUtilSymlinks.java
new file mode 100644
index 00000000..78403a66
--- /dev/null
+++ b/src/main/java/com/hcl/appscan/sdk/utils/ArchiveUtilSymlinks.java
@@ -0,0 +1,116 @@
+/*************************************************************************
+* IBM and/or HCL Confidential
+* AppScan Static Analyzer
+* (c) Copyright IBM Corp. 2013, 2017 All Rights Reserved.
+* (c) Copyright HCL Technologies, Ltd. 2023, 2026 All Rights Reserved.
+*
+* The source code for this program is not published or otherwise
+* divested of its trade secrets, irrespective of what has been
+* deposited with the U.S. Copyright Office.
+*/
+
+package com.hcl.appscan.sdk.utils;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.Enumeration;
+
+import org.apache.commons.compress.archivers.zip.ZipFile;
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.io.IOUtils;
+
+import com.hcl.appscan.sdk.Messages;
+import com.hcl.appscan.sdk.utils.SystemUtil;
+
+/**
+ * Utility to unzip Zip archives that contain symlinks.
+ */
+public class ArchiveUtilSymlinks {
+
+ private static Boolean processEntry(ZipFile zipFile, ZipArchiveEntry entry, File dest, boolean setPermissions) throws IOException {
+ try {
+ final File f = new File(dest, entry.getName());
+
+ if (entry.isDirectory()) {
+ if (!f.isDirectory() && !f.mkdirs()) {
+ return false;
+ }
+ }
+ else {
+ final File parent = f.getParentFile();
+ if (!parent.isDirectory() && !parent.mkdirs()) {
+ return false;
+ }
+
+ if (entry.isUnixSymlink()) {
+ // Skip if Windows (or make copy or abort ?)
+ if (! SystemUtil.isWindows()) {
+ final String target = zipFile.getUnixSymlink(entry);
+ if (target == null) {
+ return false;
+ }
+ final Path targetPath = Paths.get(target);
+ Files.createSymbolicLink(f.toPath(), targetPath);
+ }
+ }
+ else {
+ try ( InputStream content = zipFile.getInputStream(entry);
+ OutputStream o = Files.newOutputStream(f.toPath()) )
+ {
+ IOUtils.copyLarge(content, o);
+ }
+ }
+ }
+
+ if (setPermissions) {
+ //Set rwx permissions
+ f.setExecutable(true, false);
+ f.setReadable(true, false);
+ f.setWritable(true);
+ }
+
+ } catch(IOException e) {
+ throw new IOException(e);
+ }
+ return true;
+ }
+
+ /**
+ * Unzip an archive, immediately halting upon error.
+ *
+ * @param source The source archive.
+ * @param dest The destination directory to unzip to.
+ * @throws IOException If an error occurs during the unzip operation.
+ */
+ public void unzip(File source, File dest) throws IOException {
+
+ // See https://commons.apache.org/proper/commons-compress/examples.html
+ // and https://issues.apache.org/jira/browse/COMPRESS-689 for why this
+ // handling must use Apache's ZipFile rather than ArchiveInputStream/ZipArchiveInputStream
+ try ( ZipFile zipFile = ZipFile.builder().setFile(source).get() )
+ {
+ Enumeration entries = zipFile.getEntries();
+ Collections.list(entries).forEach(entry -> {
+ try {
+ if (! processEntry(zipFile, entry, dest, true)) {
+ final File f = new File(dest, entry.getName());
+ throw new IOException(Messages.getMessage("err.invalid.path", f.getPath())); //$NON-NLS-1$
+ }
+ }
+ catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ });
+ }
+ catch (IOException | UncheckedIOException e) {
+ throw new IOException(e);
+ }
+ }
+}
diff --git a/src/main/java/com/hcl/appscan/sdk/utils/ServiceUtil.java b/src/main/java/com/hcl/appscan/sdk/utils/ServiceUtil.java
index a57c0527..a6f1a59a 100644
--- a/src/main/java/com/hcl/appscan/sdk/utils/ServiceUtil.java
+++ b/src/main/java/com/hcl/appscan/sdk/utils/ServiceUtil.java
@@ -1,6 +1,6 @@
/**
* © Copyright IBM Corporation 2016.
- * © Copyright HCL Technologies Ltd. 2017, 2020, 2024.
+ * © Copyright HCL Technologies Ltd. 2017, 2026.
* LICENSE: Apache License, Version 2.0 https://www.apache.org/licenses/LICENSE-2.0
*/
@@ -10,10 +10,12 @@
import java.io.IOException;
import java.net.Proxy;
import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import javax.net.ssl.HttpsURLConnection;
-import com.hcl.appscan.sdk.http.HttpsClient;
+import org.apache.wink.json4j.JSONArray;
import org.apache.wink.json4j.JSONArtifact;
import org.apache.wink.json4j.JSONException;
import org.apache.wink.json4j.JSONObject;
@@ -47,11 +49,18 @@ public static void getSAClientUtil(File destination, Proxy proxy) throws IOExcep
*
* @param destination The file to save the package to.
* @param proxy The proxy for the connection, if required.
+ * @param serverURL The URL of the server.
+ * @param acceptInvalidCerts To allow untrusted connection.
* @throws IOException If an error occurs.
*/
public static void getSAClientUtil(File destination, Proxy proxy, String serverURL, String acceptInvalidCerts) throws IOException {
- String request_url = requiredServerURL(serverURL);
- request_url += String.format(API_SACLIENT_DOWNLOAD, SystemUtil.getOS());
+
+ // Use override URL for testing
+ String request_url = System.getenv("SACLIENTUTIL_DOWNLOAD_URL");
+ if (request_url == null) {
+ request_url = requiredServerURL(serverURL);
+ request_url += String.format(API_SACLIENT_DOWNLOAD, SystemUtil.getOS());
+ }
HttpClient client = new HttpClient(proxy,acceptInvalidCerts.equals("true"));
HttpResponse response = client.get(request_url, null, null);
@@ -84,22 +93,34 @@ public static String getSAClientVersion() throws IOException {
return getSAClientVersion(Proxy.NO_PROXY);
}
- public static String getSAClientVersion(Proxy proxy) throws IOException {
- return getSAClientVersion(proxy, "");
- }
+ public static String getSAClientVersion(Proxy proxy) throws IOException {
+ return getSAClientVersion(proxy, "");
+ }
+
+ public static String getSAClientVersion(Proxy proxy, String serverURL) throws IOException {
+ return getSAClientVersion(Proxy.NO_PROXY, serverURL, false);
+ }
/**
* Gets the latest available version of the SAClientUtil package used for running static analysis.
*
* @param proxy The {@link Proxy} to use.
+ * @param serverURL The URL of the server.
+ * @param acceptInvalidCerts To allow the untrusted connection.
* @return The current version of the package.
* @throws IOException If an error occurs.
*/
- public static String getSAClientVersion(Proxy proxy, String serverURL) throws IOException {
+ public static String getSAClientVersion(Proxy proxy, String serverURL, boolean acceptInvalidCerts) throws IOException {
+
+ final String versionEV = System.getenv("SACLIENTUTIL_DOWNLOAD_VERSION"); //$NON-NLS-1$
+ if (versionEV != null) {
+ return versionEV;
+ }
+
String request_url = requiredServerURL(serverURL);
request_url += String.format(API_SACLIENT_VERSION, SystemUtil.getOS(), "true");
- HttpClient client = new HttpClient(proxy);
+ HttpClient client = new HttpClient(proxy, acceptInvalidCerts);
HttpResponse response = client.get(request_url, null, null);
if (response.getResponseCode() == HttpsURLConnection.HTTP_OK || response.getResponseCode() == HttpsURLConnection.HTTP_CREATED) {
@@ -160,8 +181,38 @@ public static boolean isValidUrl(String url, IAuthenticationProvider provider, P
return false;
}
+
+ /**
+ * Checks if the user has entitlement to run SCA scans.
+ *
+ * @param provider The IAuthenticationProvider for authentication.
+ * @return true if the user has SCA entitlement.
+ */
+ public static boolean hasScaEntitlement(IAuthenticationProvider provider) {
+ return hasEntitlement(SCA_TECH, provider);
+ }
+
+ /**
+ * Checks if the user has entitlement to run SAST scans.
+ *
+ * @param provider The IAuthenticationProvider for authentication.
+ * @return true if the user has SAST entitlement.
+ */
+ public static boolean hasSastEntitlement(IAuthenticationProvider provider) {
+ return hasEntitlement(STATIC_TECH, provider);
+ }
+
+ /**
+ * Checks if the user has entitlement to run DAST scans.
+ *
+ * @param provider The IAuthenticationProvider for authentication.
+ * @return true if the user has DAST entitlement.
+ */
+ public static boolean hasDastEntitlement(IAuthenticationProvider provider) {
+ return hasEntitlement(DYNAMIC_TECH, provider);
+ }
- public static boolean activeSubscriptionsCheck(String scanType, IAuthenticationProvider provider) {
+ private static boolean hasEntitlement(String scanType, IAuthenticationProvider provider) {
if(provider.isTokenExpired()) {
return true;
}
@@ -169,7 +220,7 @@ public static boolean activeSubscriptionsCheck(String scanType, IAuthenticationP
String request_url = provider.getServer() + API_TENANT_INFO;
try {
- HttpClient client = new HttpClient(provider.getProxy(), false);
+ HttpClient client = new HttpClient(provider.getProxy(), provider.getacceptInvalidCerts());
Map requestHeaders= provider.getAuthorizationHeader(false);
requestHeaders.put("Content-Type", "application/json");
requestHeaders.put("accept", "application/json");
@@ -189,4 +240,148 @@ public static boolean activeSubscriptionsCheck(String scanType, IAuthenticationP
return false;
}
+
+ /**
+ * Checks if the given scanId is valid for scanning.
+ *
+ * @param scanId The scanId to test.
+ * @param applicationId The applicationId to verify.
+ * @param type The scanType to verify.
+ * @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.
+ */
+ public static boolean isValidScanId(String scanId, String applicationId, String type, IAuthenticationProvider provider) throws IOException{
+ if (provider.isTokenExpired()) {
+ return true;
+ }
+
+ String request_url = provider.getServer() + API_BASIC_DETAILS;
+ request_url += "?$filter=Id%20eq%20" + scanId + "&%24select=AppId%2C%20Technology";
+ Map request_headers = provider.getAuthorizationHeader(true);
+
+ 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));
+ }
+ }
+ } catch (JSONException e) {
+ Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, e);
+ }
+
+ 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;
+ }
+
+ public static String scanTypeShortForm(String type) {
+ switch (type) {
+ case "Static Analyzer":
+ return "Sast";
+ case "Dynamic Analyzer":
+ return "Dast";
+ case CoreConstants.SOFTWARE_COMPOSITION_ANALYZER:
+ return "Sca";
+ }
+ return type;
+ }
+
+ /**
+ * Fetch the build version of the A360 server.
+ *
+ * @param provider The IAuthenticationProvider for authentication.
+ * @return The build server of the server.
+ */
+ public static String getServiceVersion(IAuthenticationProvider provider) {
+ String request_url = provider.getServer() + "/assets/versions.json";
+ HttpClient client = new HttpClient(provider.getProxy(), provider.getacceptInvalidCerts());
+ try {
+ HttpResponse response = client.get(request_url, null, null);
+ if (response.isSuccess()) {
+ JSONObject body = (JSONObject) response.getResponseBodyAsJSON();
+ return body.getString("MainVersion");
+ }
+ } catch (IOException | JSONException e) {
+ return "0"; //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ /**
+ * Checks if the given url is valid for scanning.
+ *
+ * @param url The url to test.
+ * @param provider The IAuthenticationProvider for authentication.
+ * @param proxy The proxy to use for the connection.
+ * @return True if the url is valid. False is returned if the url is not valid, the request fails, or an exception occurs.
+ */
+ public static boolean isValidDomain(String url, String appId, IAuthenticationProvider provider, Proxy proxy) {
+ String request_url = provider.getServer() + API_IS_VALID_DOMAIN;
+
+ try {
+ JSONObject body = new JSONObject();
+ body.put(CoreConstants.APP_ID, appId);
+ body.put(CoreConstants.STP, url);
+
+ HttpClient client = new HttpClient(proxy, provider.getacceptInvalidCerts());
+ Map requestHeaders= provider.getAuthorizationHeader(false);
+ requestHeaders.put("Content-Type", "application/json");
+ HttpResponse response = client.post(request_url, requestHeaders, body.toString());
+
+ if (response.isSuccess()) {
+ //response body is a boolean value
+ String responseContent = response.getResponseBodyAsString();
+ if (responseContent != null) {
+ return Boolean.parseBoolean(responseContent.trim());
+ }
+ }
+ } catch (IOException | JSONException e) {
+ // Ignore and return false.
+ }
+ return false;
+ }
+
+ public static boolean compareVersions(String baseVersion, String newVersion) {
+ if(baseVersion == null)
+ return true;
+
+ if(newVersion != null) {
+ String[] base = baseVersion.split("\\."); //$NON-NLS-1$
+ String[] next = newVersion.split("\\."); //$NON-NLS-1$
+
+ try {
+ for(int iter = 0; iter < base.length && iter < next.length; iter++) {
+ int lVersion = Integer.parseInt(base[iter]);
+ int sVersion = Integer.parseInt(next[iter]);
+
+ if (((iter==0) && lVersion