diff --git a/.github/workflows/_build+publish-pds-solution.yml b/.github/workflows/_build+publish-pds-solution.yml index 62b03b7f65..22733150b8 100644 --- a/.github/workflows/_build+publish-pds-solution.yml +++ b/.github/workflows/_build+publish-pds-solution.yml @@ -37,10 +37,10 @@ jobs: echo "pds-version '${{ inputs.pds-version }}'" - name: Checkout git repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Docker login to ghcr.io - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} diff --git a/.github/workflows/github-action-scan.yml b/.github/workflows/github-action-scan.yml index 18a20edab2..94d72885ca 100644 --- a/.github/workflows/github-action-scan.yml +++ b/.github/workflows/github-action-scan.yml @@ -11,7 +11,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Use Node.js # We do not define a dedicated node version here, we just use the default environment diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 58591f7677..9164eb65b3 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -19,7 +19,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK 17 uses: actions/setup-java@v3 @@ -33,7 +33,7 @@ jobs: with: go-version: 1.20.4 - - uses: actions/cache@v3.3.1 + - uses: actions/cache@v3.3.2 with: path: | ~/.cache/go-build diff --git a/.github/workflows/publish-libraries.yml b/.github/workflows/publish-libraries.yml index 645a4bd8cf..0be93877b0 100644 --- a/.github/workflows/publish-libraries.yml +++ b/.github/workflows/publish-libraries.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout master - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: master # Create temporary local tags, so we build documentation for this tag... diff --git a/.github/workflows/release-client-server-pds.yml b/.github/workflows/release-client-server-pds.yml index 6668cf370e..472a906506 100644 --- a/.github/workflows/release-client-server-pds.yml +++ b/.github/workflows/release-client-server-pds.yml @@ -63,7 +63,7 @@ jobs: exit 1 - name: Checkout master - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: master # Create temporary local tags, so we build documentation for this tag... @@ -97,7 +97,7 @@ jobs: go-version: 1.20.4 - name: Set up Go caching - uses: actions/cache@v3.3.1 + uses: actions/cache@v3.3.2 id: go-cache with: path: | @@ -108,7 +108,7 @@ jobs: ${{ runner.os }}-go- - name: Docker login to ghcr.io - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} diff --git a/.github/workflows/release-pds-tools.yml b/.github/workflows/release-pds-tools.yml index 47e1c6ad55..398c01ea93 100644 --- a/.github/workflows/release-pds-tools.yml +++ b/.github/workflows/release-pds-tools.yml @@ -28,7 +28,7 @@ jobs: exit 1 - name: Checkout master - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: master diff --git a/.github/workflows/release-wrapper-checkmarx.yml b/.github/workflows/release-wrapper-checkmarx.yml index fc7b152562..6d0c0c25e4 100644 --- a/.github/workflows/release-wrapper-checkmarx.yml +++ b/.github/workflows/release-wrapper-checkmarx.yml @@ -20,7 +20,7 @@ jobs: echo "Checkmarx-wrapper '${{ inputs.checkmarx-wrapper-version }}' - Milestone '${{ inputs.checkmarx-wrapper-milestone-number }}'" - name: Checkout branch master - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: master diff --git a/.github/workflows/release-wrapper-owaspzap.yml b/.github/workflows/release-wrapper-owaspzap.yml index 53df4be9e7..e959d02641 100644 --- a/.github/workflows/release-wrapper-owaspzap.yml +++ b/.github/workflows/release-wrapper-owaspzap.yml @@ -21,7 +21,7 @@ jobs: echo "OWASP-ZAP Wrapper '${{ inputs.owaspzap-wrapper-version }}' - Milestone '${{ inputs.owaspzap-wrapper-milestone-number }}'" - name: Checkout branch master - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: master diff --git a/MAINTAINERS.md b/MAINTAINERS.md index c8130080ab..cb450ab197 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -10,6 +10,7 @@ | Jeremias Eppler | | [jeeppler](https://github.com/jeeppler) | Mercedes-Benz Tech Innovation GmbH, [imprint](https://github.com/mercedes-benz/foss/blob/master/PROVIDER_INFORMATION.md) | 2021-01-01 | | Jan Winz | | [winzj](https://github.com/winzj) | Mercedes-Benz Tech Innovation GmbH, [imprint](https://github.com/mercedes-benz/foss/blob/master/PROVIDER_INFORMATION.md) | 2021-07-01 | | Rouven Härtel | | [haerter-tss](https://github.com/haerter-tss) | Mercedes-Benz Tech Innovation GmbH, [imprint](https://github.com/mercedes-benz/foss/blob/master/PROVIDER_INFORMATION.md) | 2022-02-01 | +| Laura Bottner | | [lorriborri](hhttps://github.com/lorriborri) | Mercedes-Benz Tech Innovation GmbH, [imprint](https://github.com/mercedes-benz/foss/blob/master/PROVIDER_INFORMATION.md) | 2023-09-06 | ## Emeritus Maintainers diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 4e057b3241..ee4399a176 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -49,7 +49,7 @@ ext { apache_commons_io: "2.11.0", apache_commons_validator: "1.7", apache_commons_fileupload: "1.5", - apache_commons_compress: "1.23.0", + apache_commons_compress: "1.24.0", apache_commons_lang3: "3.12.0", /* testing */ @@ -68,7 +68,7 @@ ext { restDocsApiSpec: "0.16.4", // newest version compatible with Spring Boot 2.x /* Owasp Zap wrapper */ - owaspzap_client_api: "1.11.0", + owaspzap_client_api: "1.12.0", jcommander: "1.82", thymeleaf_extras_springsecurity5: "3.1.1.RELEASE", diff --git a/sechub-api-java/README.adoc b/sechub-api-java/README.adoc index 3b1d060c98..d3ea6bea0b 100644 --- a/sechub-api-java/README.adoc +++ b/sechub-api-java/README.adoc @@ -14,7 +14,7 @@ The goal of the API is to: === Usage -Create an instance of `com.mercedesbenz.sechub.api.SecHubClient` and use the client methods. +Create an instance of `com.mercedesbenz.sechub.api.DefaultSecHubClient` and use the client methods. For a working example please look into `sechub-examples/example-sechub-api-java`. diff --git a/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/AbstractSecHubClient.java b/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/AbstractSecHubClient.java new file mode 100644 index 0000000000..915b4df0a2 --- /dev/null +++ b/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/AbstractSecHubClient.java @@ -0,0 +1,101 @@ +package com.mercedesbenz.sechub.api; + +import java.net.URI; +import java.util.LinkedHashSet; +import java.util.Set; + +import javax.crypto.SealedObject; + +import com.mercedesbenz.sechub.commons.core.security.CryptoAccess; + +public abstract class AbstractSecHubClient implements SecHubClient { + + private boolean trustAll; + private String username; + private SealedObject sealedApiToken; + private URI serverUri; + private CryptoAccess apiTokenAccess = new CryptoAccess<>(); + + private Set secHubClientListeners; + + public AbstractSecHubClient() { + secHubClientListeners = new LinkedHashSet<>(); + } + + public void setUsername(String username) { + this.username = username; + } + + public void setApiToken(String apiToken) { + this.sealedApiToken = apiTokenAccess.seal(apiToken); + } + + public void setServerUri(URI serverUri) { + this.serverUri = serverUri; + } + + public void setTrustAll(boolean trustAll) { + this.trustAll = trustAll; + } + + @Override + public boolean isTrustAll() { + return trustAll; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public String getSealedApiToken() { + return apiTokenAccess.unseal(sealedApiToken); + } + + @Override + public URI getServerUri() { + return serverUri; + } + + /** + * Adds a listener to the client. For some action on client side the listener + * will be informed. A listener can be added only one time no matter how many + * times this method is called. + * + * @param listener + */ + @Override + public void addListener(SecHubClientListener listener) { + if (listener == null) { + return; + } + this.secHubClientListeners.add(listener); + } + + /** + * Removes a listener from the client (if added). + * + * @param listener + */ + @Override + public void removeListener(SecHubClientListener listener) { + if (listener == null) { + return; + } + this.secHubClientListeners.remove(listener); + } + + void inform(SecHubClientListenerCaller r) { + for (SecHubClientListener listener : secHubClientListeners) { + r.inform(listener); + } + } + + interface SecHubClientListenerCaller { + + public void inform(SecHubClientListener listener); + + } + +} \ No newline at end of file diff --git a/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/DefaultSecHubClient.java b/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/DefaultSecHubClient.java new file mode 100644 index 0000000000..4df61339bb --- /dev/null +++ b/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/DefaultSecHubClient.java @@ -0,0 +1,468 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.api; + +import static java.util.Objects.*; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.Callable; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.mercedesbenz.sechub.api.internal.ApiClientBuilder; +import com.mercedesbenz.sechub.api.internal.OpenApiSecHubClientConversionHelper; +import com.mercedesbenz.sechub.api.internal.WorkaroundAdminApi; +import com.mercedesbenz.sechub.api.internal.WorkaroundProjectApi; +import com.mercedesbenz.sechub.api.internal.gen.AdminApi; +import com.mercedesbenz.sechub.api.internal.gen.AnonymousApi; +import com.mercedesbenz.sechub.api.internal.gen.ProjectApi; +import com.mercedesbenz.sechub.api.internal.gen.invoker.ApiClient; +import com.mercedesbenz.sechub.api.internal.gen.invoker.ApiException; +import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiExecutionProfileFetch; +import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiExecutionProfileUpdate; +import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiExecutionProfileUpdateConfigurationsInner; +import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiExecutorConfiguration; +import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiExecutorConfigurationSetup; +import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiJobId; +import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiJobStatus; +import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiListOfExecutorConfigurations; +import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiListOfExecutorConfigurationsExecutorConfigurationsInner; +import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiProjectDetails; +import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiScanJob; +import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiStatusInformationInner; +import com.mercedesbenz.sechub.commons.archive.ArchiveSupport; +import com.mercedesbenz.sechub.commons.archive.ArchiveSupport.ArchivesCreationResult; +import com.mercedesbenz.sechub.commons.core.RunOrFail; +import com.mercedesbenz.sechub.commons.core.security.CheckSumSupport; +import com.mercedesbenz.sechub.commons.model.JSONConverter; +import com.mercedesbenz.sechub.commons.model.JsonMapperFactory; +import com.mercedesbenz.sechub.commons.model.SecHubConfigurationModel; + +public class DefaultSecHubClient extends AbstractSecHubClient { + + private static final Logger LOG = LoggerFactory.getLogger(DefaultSecHubClient.class); + + private static JsonMapper mapper = JsonMapperFactory.createMapper(); + + private ArchiveSupport archiveSupport = new ArchiveSupport(); + private CheckSumSupport checkSumSupport = new CheckSumSupport(); + + private ApiClient apiClient; + private AnonymousApi anonymousApi; + private AdminApi adminApi; + private ProjectApi projectApi; + + private WorkaroundAdminApi workaroundAdminApi; + + private OpenApiSecHubClientConversionHelper conversionHelper; + + private WorkaroundProjectApi workaroundProjectApi; + + public DefaultSecHubClient(URI serverUri, String username, String apiToken) { + this(serverUri, username, apiToken, false); + } + + public DefaultSecHubClient(URI serverUri, String username, String apiToken, boolean trustAll) { + setUsername(username); + setApiToken(apiToken); + setServerUri(serverUri); + setTrustAll(trustAll); + + apiClient = new ApiClientBuilder().createApiClient(this, mapper); + + anonymousApi = new AnonymousApi(getApiClient()); + + adminApi = new AdminApi(getApiClient()); + workaroundAdminApi = new WorkaroundAdminApi(getApiClient()); + + projectApi = new ProjectApi(getApiClient()); + workaroundProjectApi = new WorkaroundProjectApi(getApiClient()); + + conversionHelper = new OpenApiSecHubClientConversionHelper(adminApi); + + } + + private ApiClient getApiClient() { + return apiClient; + } + + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + /* + ................Create.......................... + */ + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + @Override + public void createSignup(UserSignup signUp) throws SecHubClientException { + requireNonNull(signUp, "signUp may not be null!"); + + runOrFail(() -> anonymousApi.userSignup(signUp.getDelegate()), "User signup failed"); + } + + @Override + public void createProject(Project project) throws SecHubClientException { + requireNonNull(project, "project may not be null!"); + + runOrFail(() -> adminApi.adminCreatesProject(project.getDelegate()), "Cannot create project:" + project.getName()); + } + + @Override + public UUID createExecutorConfiguration(ExecutorConfiguration config) throws SecHubClientException { + requireNonNull(config, "config may not be null!"); + + return runOrFail(() -> { + OpenApiExecutorConfiguration delegate = config.getDelegate(); + OpenApiExecutorConfigurationSetup setup = delegate.getSetup(); + /* + * necessary because two different lists - delegate has its own, we overwrite + * here + */ + setup.setJobParameters(ExecutorConfigurationSetupJobParameter.toDelegates(config.getSetup().getJobParameters())); + UUID result = workaroundAdminApi.adminCreatesExecutorConfiguration(delegate); + return result; + }, "Cannot create executor configuration"); + } + + @Override + public void createExecutionProfile(String profileName, ExecutionProfileCreate profile) throws SecHubClientException { + requireNonNull(profileName, "profileName may not be null!"); + requireNonNull(profile, "profile may not be null!"); + + runOrFail(() -> adminApi.adminCreatesExecutionProfile(profileName, profile.getDelegate()), "Was not able to create profile:" + profileName); + } + + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + /* + ................Upload.......................... + */ + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + + /** + * Uploads data as defined in given configuration + * + * @param projectId the project id + * @param jobUUID SecHub Job UUID + * @param configuration SecHub Job configuration (contains information about + * upload behavior (e.g. paths etc.) + * @param workingDirectory directory where the relative paths inside + * configuration model shall start from + * @throws SecHubClientException + */ + @Override + public void upload(String projectId, UUID jobUUID, SecHubConfigurationModel configuration, Path workingDirectory) throws SecHubClientException { + requireNonNull(projectId, "projectId may not be null!"); + requireNonNull(configuration, "configuration may not be null!"); + + Path uploadDirectory = runOrFail(() -> Files.createTempDirectory("sechub_client_upload"), "Temp directory creation was not possible"); + ArchivesCreationResult createArchiveResult = runOrFail(() -> archiveSupport.createArchives(configuration, workingDirectory, uploadDirectory), + "Cannot create archives!"); + + inform((listener) -> listener.beforeUpload(jobUUID, configuration, createArchiveResult)); + + try { + uploadSources(projectId, jobUUID, createArchiveResult); + uploadBinaries(projectId, jobUUID, createArchiveResult); + + inform((listener) -> listener.afterUpload(jobUUID, configuration, createArchiveResult)); + + } finally { + LOG.debug("Remove temporary data from: {}", uploadDirectory); + try { + archiveSupport.deleteArchives(createArchiveResult); + } catch (IOException e) { + throw new IllegalStateException("Was not able to remove temporary archive data!", e); + } + } + } + + private void uploadBinaries(String projectId, UUID jobUUID, ArchivesCreationResult createArchiveResult) throws SecHubClientException { + if (!createArchiveResult.isBinaryArchiveCreated()) { + return; + } + Path tarFile = createArchiveResult.getBinaryArchiveFile(); + + String filesize = String.valueOf(tarFile.toFile().length()); + String checksum = checkSumSupport.createSha256Checksum(tarFile); + + runOrFail(() -> workaroundProjectApi.userUploadsBinaries(projectId, jobUUID.toString(), checksum, filesize, tarFile), "Binary upload (tar)"); + } + + private void uploadSources(String projectId, UUID jobUUID, ArchivesCreationResult createArchiveResult) throws SecHubClientException { + if (!createArchiveResult.isSourceArchiveCreated()) { + return; + } + Path zipFile = createArchiveResult.getSourceArchiveFile(); + String checksum = checkSumSupport.createSha256Checksum(zipFile); + + runOrFail(() -> workaroundProjectApi.userUploadsSourceCode(projectId, jobUUID.toString(), checksum, zipFile), "Source upload (zip)"); + } + + @Override + public List fetchAllExecutorConfigurationInfo() throws SecHubClientException { + OpenApiListOfExecutorConfigurations configList = runOrFail(() -> adminApi.adminFetchesExecutorConfigurationList(), "Fetch executor configurations"); + + List list = configList.getExecutorConfigurations(); + List result = new ArrayList<>(); + + for (OpenApiListOfExecutorConfigurationsExecutorConfigurationsInner inner : list) { + + ExecutorConfigurationInfo info = new ExecutorConfigurationInfo(); + info.setEnabled(inner.getEnabled() == null ? false : inner.getEnabled()); + info.setName(inner.getName()); + info.setUuid(UUID.fromString(inner.getUuid())); + + result.add(info); + } + return result; + } + + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + /* + ................Status........................... + */ + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + @Override + public SecHubStatus fetchSecHubStatus() throws SecHubClientException { + SecHubStatus status = new SecHubStatus(); + runOrFail(() -> { + List statusInformationList = adminApi.adminListsStatusInformation(); + for (OpenApiStatusInformationInner info : statusInformationList) { + String key = info.getKey(); + if (key != null) { + status.statusInformation.put(key, info.getValue()); + } + } + }, "Was not able to fetch SecHub status!"); + return status; + } + + @Override + public void triggerRefreshOfSecHubSchedulerStatus() throws SecHubClientException { + runOrFail(() -> adminApi.adminTriggersRefreshOfSchedulerStatus(), "Was not able to trigger scheduler refresh"); + } + + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + /* + ................Check........................... + */ + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + @Override + public boolean isServerAlive() throws SecHubClientException { + try { + anonymousApi.anonymousCheckAliveGet(); + return true; + } catch (ApiException e) { + return false; + } + } + + @Override + public boolean isProjectExisting(String projectId) throws SecHubClientException { + requireNonNull(projectId, "projectId may not be null!"); + return runOrFail(() -> adminApi.adminListsAllProjects().contains(projectId), + + "Cannot check if project '" + projectId + "' exists!"); + } + + @Override + public boolean isUserAssignedToProject(String userId, String projectId) throws SecHubClientException { + requireNonNull(userId, "userId may not be null!"); + requireNonNull(projectId, "projectId may not be null!"); + + return runOrFail(() -> { + /* not very smart... but works : */ + OpenApiProjectDetails details = adminApi.adminShowsProjectDetails(projectId); + List userIds = details.getUsers(); + return userIds.contains(userId); + }, "Cannot check if user '" + userId + "' is assigned to project '" + projectId + "'"); + } + + @Override + public boolean isExecutionProfileExisting(String profileId) throws SecHubClientException { + try { + OpenApiExecutionProfileFetch result = adminApi.adminFetchesExecutionProfile(profileId); + return result != null; + } catch (ApiException e) { + if (e.getCode() == 404) { + /* not found */ + return false; + } + throw new SecHubClientException("Was not able check if profile " + profileId + " does exist.", e); + } + } + + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + /* + ................Fetch........................... + */ + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + @Override + public List fetchAllOpenSignups() throws SecHubClientException { + return runOrFail(() -> OpenUserSignup.fromDelegates(adminApi.adminListsOpenUserSignups()), "Cannot fetch open signups"); + } + + @Override + public List fetchAllProjectIds() throws SecHubClientException { + return runOrFail(() -> adminApi.adminListsAllProjects(), "Cannot fetch all project names"); + } + + @Override + public List fetchAllUserIds() throws SecHubClientException { + return runOrFail(() -> adminApi.adminListsAllUsers(), "Cannot fetch all user names"); + } + + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + /* + ................Assign/Unassign................. + */ + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + @Override + public void acceptOpenSignup(String signupUsername) throws SecHubClientException { + requireNonNull(signupUsername, "signupUsername may not be null!"); + + runOrFail(() -> adminApi.adminAcceptsSignup(signupUsername), "Cannot accept open signups"); + } + + @Override + public void assignUserToProject(String userId, String projectId) throws SecHubClientException { + requireNonNull(userId, "userId may not be null!"); + requireNonNull(projectId, "projectId may not be null!"); + + runOrFail(() -> adminApi.adminAssignsUserToProject(projectId, userId), + + "Was not able to assign user '" + userId + "' to project '" + projectId + "'"); + + } + + @Override + public void unassignUserFromProject(String userId, String projectId) throws SecHubClientException { + requireNonNull(userId, "userId may not be null!"); + requireNonNull(projectId, "projectId may not be null!"); + + runOrFail(() -> adminApi.adminUnassignsUserFromProject(projectId, userId), + + "Was not able to unassign user '" + userId + "' from project '" + projectId + "'"); + + } + + @Override + public void addExecutorConfigurationToProfile(UUID uuidOfExecutorConfigToAdd, String profileId) throws SecHubClientException { + requireNonNull(uuidOfExecutorConfigToAdd, "uuidOfExecutorConfigToAdd may not be null!"); + requireNonNull(profileId, "profileId may not be null!"); + + runOrFail(() -> { + OpenApiExecutionProfileUpdate update = conversionHelper.fetchProfileAndConvertToUpdateObject(profileId); + + OpenApiExecutionProfileUpdateConfigurationsInner newItem = new OpenApiExecutionProfileUpdateConfigurationsInner(); + newItem.setUuid(uuidOfExecutorConfigToAdd.toString()); + update.addConfigurationsItem(newItem); + + adminApi.adminUpdatesExecutionProfile(profileId, update); + + }, "Cannot add executor config: " + uuidOfExecutorConfigToAdd + " to profile:" + profileId); + } + + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + /* + ................Delete.......................... + */ + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + + @Override + public void deleteProject(String projectId) throws SecHubClientException { + requireNonNull(projectId, "projectId may not be null!"); + + runOrFail(() -> adminApi.adminDeleteProject(projectId), "Was not able to delete project: " + projectId); + } + + @Override + public void deleteExecutionProfile(String profileId) throws SecHubClientException { + requireNonNull(profileId, "profileId may not be null!"); + + runOrFail(() -> adminApi.adminDeletesExecutionProfile(profileId), "Was not able to delete execution profile: " + profileId); + } + + @Override + public void deleteExecutorConfiguration(UUID executorUUID) throws SecHubClientException { + requireNonNull(executorUUID, "executor uuid may not be null!"); + + runOrFail(() -> adminApi.adminDeletesExecutorConfiguration(executorUUID.toString()), "Was not able to delete executor configuration: " + executorUUID); + } + + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + /* + ................Scheduling...................... + */ + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + @Override + public UUID createJob(SecHubConfigurationModel configuration) throws SecHubClientException { + requireNonNull(configuration, "configuration may not be null!"); + String projectId = configuration.getProjectId(); + if (projectId == null) { + throw new IllegalStateException("Project id missing inside configuration!"); + } + + String configAsJson = JSONConverter.get().toJSON(configuration, true); + LOG.debug("configAsJson=\n{}", configAsJson); + + OpenApiScanJob openApiScanJob = JSONConverter.get().fromJSON(OpenApiScanJob.class, configAsJson); + if (LOG.isDebugEnabled()) { + String openApiJSON = JSONConverter.get().toJSON(openApiScanJob, true); + LOG.debug("openApiJSON=\n{}", openApiJSON); + } + OpenApiJobId openApiJobId = runOrFail(() -> projectApi.userCreatesNewJob(projectId, openApiScanJob), + "Was not able to create a SecHub job for project:" + projectId); + String jobIdAsString = openApiJobId.getJobId(); + + UUID uuid = UUID.fromString(jobIdAsString); + return uuid; + } + + @Override + public JobStatus fetchJobStatus(String projectId, UUID jobUUID) throws SecHubClientException { + OpenApiJobStatus status = runOrFail(() -> projectApi.userChecksJobStatus(projectId, jobUUID.toString()), "Fetch status"); + return JobStatus.from(status); + } + + @Override + public SecHubReport downloadSecHubReportAsJson(String projectId, UUID jobUUID) throws SecHubClientException { + SecHubReport report = runOrFail(() -> workaroundProjectApi.userDownloadsJobReport(projectId, jobUUID.toString()), "Download SecHub report (JSON)"); + inform((listener) -> listener.afterReportDownload(jobUUID, report)); + + return report; + } + + /** + * Approve SecHub job for project. This will mark the job as ready to start + * inside SecHub + * + * @param projectId + * @param jobUUID + * @throws SecHubClientException + */ + @Override + public void approveJob(String projectId, UUID jobUUID) throws SecHubClientException { + runOrFail(() -> projectApi.userApprovesJob(projectId, jobUUID.toString()), "Job approve"); + } + + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + /* + ................Helpers......................... + */ + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + + private void runOrFail(RunOrFail failable, String failureMessage) throws SecHubClientException { + try { + failable.runOrFail(); + } catch (ApiException e) { + throw createClientException(failureMessage, e); + } + } + + private SecHubClientException createClientException(String message, Exception cause) throws SecHubClientException { + return new SecHubClientException(message + " - " + cause.getMessage(), cause); + } + + private T runOrFail(Callable callable, String failureMessage) throws SecHubClientException { + try { + return callable.call(); + } catch (ApiException e) { + throw createClientException(failureMessage, e); + } catch (Exception e) { + if (e instanceof RuntimeException) { + RuntimeException re = (RuntimeException) e; + throw re; + } + throw new IllegalStateException("Unhandled exception - should not happen", e); + } + } + +} diff --git a/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/ExecutionProfile.java b/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/ExecutionProfile.java new file mode 100644 index 0000000000..95cecebff0 --- /dev/null +++ b/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/ExecutionProfile.java @@ -0,0 +1,38 @@ +package com.mercedesbenz.sechub.api; + +import java.util.HashSet; +import java.util.Set; +import java.util.TreeSet; + +public class ExecutionProfile { + + private Set projectIds = new TreeSet<>(); + + private Set configurations = new HashSet<>(); + private String description; + private boolean enabled; + + public Set getProjectIds() { + return projectIds; + } + + public Set getConfigurations() { + return configurations; + } + + public boolean isEnabled() { + return enabled; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } +} diff --git a/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/Job.java b/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/Job.java new file mode 100644 index 0000000000..9655db8748 --- /dev/null +++ b/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/Job.java @@ -0,0 +1,23 @@ +package com.mercedesbenz.sechub.api; + +import java.util.UUID; + +public class Job { + + private UUID uuid; + private JobStatus status; + + public Job(UUID uuid) { + this.uuid = uuid; + this.status = new JobStatus(); + } + + public UUID getUuid() { + return uuid; + } + + public JobStatus getStatus() { + return status; + } + +} diff --git a/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/JobStatus.java b/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/JobStatus.java index 5a9205822d..25ce22451f 100644 --- a/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/JobStatus.java +++ b/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/JobStatus.java @@ -13,7 +13,7 @@ public class JobStatus extends JobStatusInfo { - public static JobStatus from(OpenApiJobStatus status) { + static JobStatus from(OpenApiJobStatus status) { JobStatus result = new JobStatus(); diff --git a/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/MockedSecHubClient.java b/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/MockedSecHubClient.java new file mode 100644 index 0000000000..615fcb082b --- /dev/null +++ b/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/MockedSecHubClient.java @@ -0,0 +1,313 @@ +package com.mercedesbenz.sechub.api; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.UUID; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.mercedesbenz.sechub.commons.model.SecHubConfigurationModel; +import com.mercedesbenz.sechub.commons.model.job.ExecutionState; + +public class MockedSecHubClient extends AbstractSecHubClient { + + private static final Logger LOG = LoggerFactory.getLogger(MockedSecHubClient.class); + + private static final String REF_MARKER = "->"; + + private Map executionProfiles = new HashMap<>(); + private Map executorConfigurations = new HashMap<>(); + private Map jobs = new HashMap<>(); + private Map projects = new TreeMap<>(); + private Map openSignups = new TreeMap<>(); + private MockDataAccess mockDataAccess; + private Map users = new TreeMap<>(); + + private Set userToProjectAssignments = new HashSet<>(); + + public MockedSecHubClient() { + mockDataAccess = new MockDataAccess(); + } + + @Override + public void acceptOpenSignup(String signupUsername) throws SecHubClientException { + OpenUserSignup signup = openSignups.get(signupUsername); + if (signup == null) { + throw new SecHubClientException("Signup for user:" + signupUsername + " not found!"); + } + User user = createUser(signup); + users.put(user.getUserId(), user); + + openSignups.remove(signupUsername); + } + + @Override + public void addExecutorConfigurationToProfile(UUID uuidOfExecutorConfigToAdd, String profileId) throws SecHubClientException { + ExecutorConfiguration configuration = findConfigurationOrFail(uuidOfExecutorConfigToAdd); + ExecutionProfile profile = findProfileOrFail(profileId); + profile.getConfigurations().add(configuration); + } + + private ExecutionProfile findProfileOrFail(String profileId) throws SecHubClientException { + ExecutionProfile profile = executionProfiles.get(profileId); + if (profile == null) { + throw new SecHubClientException("Did not find profile for id:" + profileId); + } + return profile; + } + + private ExecutorConfiguration findConfigurationOrFail(UUID uuidOfExecutorConfigToAdd) throws SecHubClientException { + ExecutorConfiguration configuration = executorConfigurations.get(uuidOfExecutorConfigToAdd); + if (configuration == null) { + throw new SecHubClientException("executor configuration not found:" + uuidOfExecutorConfigToAdd); + } + return configuration; + } + + @Override + public void approveJob(String projectId, UUID jobUUID) throws SecHubClientException { + Job job = findJobOrFail(jobUUID); + job.getStatus().setState(ExecutionState.READY_TO_START); + } + + @Override + public void assignUserToProject(String userId, String projectId) throws SecHubClientException { + userToProjectAssignments.add(createUserToProjectUniqueIdentifier(userId, projectId)); + } + + @Override + public void createExecutionProfile(String profileName, ExecutionProfileCreate profileToCreate) throws SecHubClientException { + + ExecutionProfile profile = new ExecutionProfile(); + profile.setEnabled(profileToCreate.isEnabled()); + profile.setDescription(profileToCreate.getDescription()); + profile.getProjectIds().addAll(profileToCreate.getProjectIds()); + + executionProfiles.put(profileName, profile); + } + + @Override + public UUID createExecutorConfiguration(ExecutorConfiguration config) throws SecHubClientException { + UUID uuid = UUID.randomUUID(); + executorConfigurations.put(uuid, config); + return uuid; + } + + @Override + public UUID createJob(SecHubConfigurationModel configuration) throws SecHubClientException { + UUID uuid = UUID.randomUUID(); + Job job = new Job(uuid); + jobs.put(uuid, job); + return uuid; + } + + @Override + public void createProject(Project project) throws SecHubClientException { + String projectName = project.getName(); + + if (projects.containsKey(projectName)) { + throw new SecHubClientException("Project:" + projectName + " already exists!"); + } + projects.put(projectName, project); + + } + + @Override + public void createSignup(UserSignup signUp) throws SecHubClientException { + String userId = signUp.getUserId(); + if (openSignups.containsKey(userId)) { + throw new SecHubClientException("User already exists!"); + } + OpenUserSignup openSignup = new OpenUserSignup(); + openSignup.setEmailAdress(signUp.getEmailAdress()); + openSignup.setUserId(userId); + openSignups.put(userId, openSignup); + } + + @Override + public void deleteExecutionProfile(String profileId) throws SecHubClientException { + executionProfiles.remove(profileId); + } + + @Override + public void deleteExecutorConfiguration(UUID executorUUID) throws SecHubClientException { + ExecutorConfiguration removed = executorConfigurations.remove(executorUUID); + if (removed == null) { + LOG.warn("Executor configuration did not exist for uuid:" + executorUUID + " - cannot remove"); + return; + } + for (ExecutionProfile executionProfile : executionProfiles.values()) { + executionProfile.getConfigurations().remove(removed); + } + } + + @Override + public void deleteProject(String projectId) throws SecHubClientException { + projects.remove(projectId); + + removeReferenceEntries(projectId, userToProjectAssignments); + } + + private void removeReferenceEntries(String referenceId, Set all) { + Set assignmentIdToRemove = new HashSet<>(all); + for (String id : all) { + if (id.endsWith(REF_MARKER + referenceId)) { + assignmentIdToRemove.add(id); + } + } + + all.removeAll(assignmentIdToRemove); + } + + @Override + public SecHubReport downloadSecHubReportAsJson(String projectId, UUID jobUUID) throws SecHubClientException { + SecHubReport secHubReport = mockDataAccess.reports.get(jobUUID); + if (secHubReport == null) { + throw new SecHubClientException("No sechub report available for job uuid:" + jobUUID); + } + return secHubReport; + } + + @Override + public List fetchAllExecutorConfigurationInfo() throws SecHubClientException { + List result = new ArrayList<>(); + for (ExecutorConfiguration executorConfiguration : executorConfigurations.values()) { + ExecutorConfigurationInfo info = new ExecutorConfigurationInfo(); + info.setEnabled(executorConfiguration.isEnabled()); + info.setName(executorConfiguration.getName()); + /* + * TODO Albert Tregnaghi, 2023-09-08: set UUID to info when + * https://github.com/mercedes-benz/sechub/issues/2537 is done + */ + result.add(info); + } + return result; + } + + @Override + public List fetchAllOpenSignups() throws SecHubClientException { + return new ArrayList<>(openSignups.values()); + } + + @Override + public List fetchAllProjectIds() throws SecHubClientException { + return new ArrayList<>(projects.keySet()); + } + + @Override + public List fetchAllUserIds() throws SecHubClientException { + return new ArrayList<>(users.keySet()); + } + + @Override + public JobStatus fetchJobStatus(String projectId, UUID jobUUID) throws SecHubClientException { + Job job = findJobOrFail(jobUUID); + return job.getStatus(); + } + + @Override + public SecHubStatus fetchSecHubStatus() throws SecHubClientException { + SecHubStatus statusCopy = new SecHubStatus(); + statusCopy.statusInformation.putAll(getMockDataAccess().getSecHubStatus().getStatusInformationMap()); + return statusCopy; + } + + public MockDataAccess getMockDataAccess() { + return mockDataAccess; + } + + @Override + public boolean isExecutionProfileExisting(String profileId) throws SecHubClientException { + return executionProfiles.containsKey(profileId); + } + + @Override + public boolean isProjectExisting(String projectId) throws SecHubClientException { + return projects.containsKey(projectId); + } + + @Override + public boolean isServerAlive() throws SecHubClientException { + return mockDataAccess.serverAlive; + } + + @Override + public boolean isUserAssignedToProject(String userId, String projectId) throws SecHubClientException { + String id = createUserToProjectUniqueIdentifier(userId, projectId); + return userToProjectAssignments.contains(id); + } + + @Override + public void triggerRefreshOfSecHubSchedulerStatus() throws SecHubClientException { + informNothingDoneButOnlySimulated("trigger refresh sechub scheduler status"); + } + + @Override + public void unassignUserFromProject(String userId, String projectId) throws SecHubClientException { + userToProjectAssignments.remove(createUserToProjectUniqueIdentifier(userId, projectId)); + } + + @Override + public void upload(String projectId, UUID jobUUID, SecHubConfigurationModel configuration, Path workingDirectory) throws SecHubClientException { + informNothingDoneButOnlySimulated("upload"); + } + + private User createUser(OpenUserSignup found) { + return new User(found.getUserId(), found.getEmailAdress()); + } + + private String createUserToProjectUniqueIdentifier(String user, String projectId) { + return "u2p:" + user + REF_MARKER + projectId; + } + + private Job findJobOrFail(UUID jobUUID) throws SecHubClientException { + Job job = jobs.get(jobUUID); + if (job == null) { + throw new SecHubClientException("Did not find job with uuid:" + jobUUID); + } + return job; + } + + private void informNothingDoneButOnlySimulated(String what) { + LOG.info("Simulate {}", what); + } + + /** + * This class is an access point for simulated data which has no official API + * method to change it, but can be changed for the mock. + * + * @author Albert Tregnaghi + * + */ + public class MockDataAccess { + + private SecHubStatus sechubStatus; + private Map reports = new HashMap<>(); + + private boolean serverAlive; + + public MockDataAccess() { + sechubStatus = new SecHubStatus(); + } + + public SecHubStatus getSecHubStatus() { + return sechubStatus; + } + + public void setServerAlive(boolean serverAlive) { + this.serverAlive = serverAlive; + } + + public void setSecHubReportForJob(UUID jobUUID, SecHubReport report) { + reports.put(jobUUID, report); + } + } + +} diff --git a/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/SecHubClient.java b/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/SecHubClient.java index 63436eb80b..9473190224 100644 --- a/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/SecHubClient.java +++ b/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/SecHubClient.java @@ -1,52 +1,10 @@ -// SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.api; -import static java.util.Objects.*; - -import java.io.IOException; import java.net.URI; -import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.LinkedList; import java.util.List; import java.util.UUID; -import java.util.concurrent.Callable; - -import javax.crypto.SealedObject; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.json.JsonMapper; -import com.mercedesbenz.sechub.api.internal.ApiClientBuilder; -import com.mercedesbenz.sechub.api.internal.OpenApiSecHubClientConversionHelper; -import com.mercedesbenz.sechub.api.internal.WorkaroundAdminApi; -import com.mercedesbenz.sechub.api.internal.WorkaroundProjectApi; -import com.mercedesbenz.sechub.api.internal.gen.AdminApi; -import com.mercedesbenz.sechub.api.internal.gen.AnonymousApi; -import com.mercedesbenz.sechub.api.internal.gen.ProjectApi; -import com.mercedesbenz.sechub.api.internal.gen.invoker.ApiClient; -import com.mercedesbenz.sechub.api.internal.gen.invoker.ApiException; -import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiExecutionProfileFetch; -import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiExecutionProfileUpdate; -import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiExecutionProfileUpdateConfigurationsInner; -import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiExecutorConfiguration; -import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiExecutorConfigurationSetup; -import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiJobId; -import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiJobStatus; -import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiListOfExecutorConfigurations; -import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiListOfExecutorConfigurationsExecutorConfigurationsInner; -import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiProjectDetails; -import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiScanJob; -import com.mercedesbenz.sechub.api.internal.gen.model.OpenApiStatusInformationInner; -import com.mercedesbenz.sechub.commons.archive.ArchiveSupport; -import com.mercedesbenz.sechub.commons.archive.ArchiveSupport.ArchivesCreationResult; -import com.mercedesbenz.sechub.commons.core.RunOrFail; -import com.mercedesbenz.sechub.commons.core.security.CheckSumSupport; -import com.mercedesbenz.sechub.commons.core.security.CryptoAccess; -import com.mercedesbenz.sechub.commons.model.JSONConverter; -import com.mercedesbenz.sechub.commons.model.JsonMapperFactory; + import com.mercedesbenz.sechub.commons.model.SecHubConfigurationModel; /** @@ -55,58 +13,7 @@ * @author Albert Tregnaghi * */ -public class SecHubClient { - - private static final Logger LOG = LoggerFactory.getLogger(SecHubClient.class); - - private static JsonMapper mapper = JsonMapperFactory.createMapper(); - - private String username; - private SealedObject sealedApiToken; - private URI serverUri; - private boolean trustAll; - - private CryptoAccess apiTokenAccess = new CryptoAccess<>(); - private ArchiveSupport archiveSupport = new ArchiveSupport(); - private CheckSumSupport checkSumSupport = new CheckSumSupport(); - - private ApiClient apiClient; - private AnonymousApi anonymousApi; - private AdminApi adminApi; - private ProjectApi projectApi; - - private WorkaroundAdminApi workaroundAdminApi; - - private OpenApiSecHubClientConversionHelper conversionHelper; - - private WorkaroundProjectApi workaroundProjectApi; - - private List secHubClientListeners; - - public SecHubClient(URI serverUri, String username, String apiToken) { - this(serverUri, username, apiToken, false); - } - - public SecHubClient(URI serverUri, String username, String apiToken, boolean trustAll) { - - this.username = username; - this.sealedApiToken = apiTokenAccess.seal(apiToken); - this.serverUri = serverUri; - this.trustAll = trustAll; - - apiClient = new ApiClientBuilder().createApiClient(this, mapper); - - anonymousApi = new AnonymousApi(getApiClient()); - - adminApi = new AdminApi(getApiClient()); - workaroundAdminApi = new WorkaroundAdminApi(getApiClient()); - - projectApi = new ProjectApi(getApiClient()); - workaroundProjectApi = new WorkaroundProjectApi(getApiClient()); - - conversionHelper = new OpenApiSecHubClientConversionHelper(adminApi); - secHubClientListeners = new LinkedList<>(); - } +public interface SecHubClient { /** * Adds an listener to the client. For some action on client side the listener @@ -115,84 +22,33 @@ public SecHubClient(URI serverUri, String username, String apiToken, boolean tru * * @param listener */ - public void addListener(SecHubClientListener listener) { - if (secHubClientListeners.contains(listener)) { - /* already added - ignore */ - return; - } - this.secHubClientListeners.add(listener); - } + void addListener(SecHubClientListener listener); /** * Removes a listener from the client (if added). * * @param listener */ - public void removeListener(SecHubClientListener listener) { - this.secHubClientListeners.remove(listener); - } + void removeListener(SecHubClientListener listener); - private ApiClient getApiClient() { - return apiClient; - } + String getUsername(); - public String getUsername() { - return username; - } + String getSealedApiToken(); - public String getSealedApiToken() { - return apiTokenAccess.unseal(sealedApiToken); - } + URI getServerUri(); - public URI getServerUri() { - return serverUri; - } - - public boolean isTrustAll() { - return trustAll; - } + boolean isTrustAll(); /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* + ................Create.......................... + */ /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - public void createSignup(UserSignup signUp) throws SecHubClientException { - requireNonNull(signUp, "signUp may not be null!"); - - runOrFail(() -> anonymousApi.userSignup(signUp.getDelegate()), "User signup failed"); - } - - public void createProject(Project project) throws SecHubClientException { - requireNonNull(project, "project may not be null!"); - - runOrFail(() -> adminApi.adminCreatesProject(project.getDelegate()), "Cannot create project:" + project.getName()); - } - - public UUID createExecutorConfiguration(ExecutorConfiguration config) throws SecHubClientException { - requireNonNull(config, "config may not be null!"); - - return runOrFail(() -> { - OpenApiExecutorConfiguration delegate = config.getDelegate(); - OpenApiExecutorConfigurationSetup setup = delegate.getSetup(); - /* - * necessary because two different lists - delegate has its own, we overwrite - * here - */ - setup.setJobParameters(ExecutorConfigurationSetupJobParameter.toDelegates(config.getSetup().getJobParameters())); - UUID result = workaroundAdminApi.adminCreatesExecutorConfiguration(delegate); - return result; - }, "Cannot create executor configuration"); - } + void createSignup(UserSignup signUp) throws SecHubClientException; - public void createExecutionProfile(String profileName, ExecutionProfileCreate profile) throws SecHubClientException { - requireNonNull(profileName, "profileName may not be null!"); - requireNonNull(profile, "profile may not be null!"); + void createProject(Project project) throws SecHubClientException; - runOrFail(() -> adminApi.adminCreatesExecutionProfile(profileName, profile.getDelegate()), "Was not able to create profile:" + profileName); - } + UUID createExecutorConfiguration(ExecutorConfiguration config) throws SecHubClientException; - /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - /* + ................Upload.......................... + */ - /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + void createExecutionProfile(String profileName, ExecutionProfileCreate profile) throws SecHubClientException; /** * Uploads data as defined in given configuration @@ -205,256 +61,62 @@ public void createExecutionProfile(String profileName, ExecutionProfileCreate pr * configuration model shall start from * @throws SecHubClientException */ - public void upload(String projectId, UUID jobUUID, SecHubConfigurationModel configuration, Path workingDirectory) throws SecHubClientException { - requireNonNull(projectId, "projectId may not be null!"); - requireNonNull(configuration, "configuration may not be null!"); - - Path uploadDirectory = runOrFail(() -> Files.createTempDirectory("sechub_client_upload"), "Temp directory creation was not possible"); - ArchivesCreationResult createArchiveResult = runOrFail(() -> archiveSupport.createArchives(configuration, workingDirectory, uploadDirectory), - "Cannot create archives!"); - - inform((listener) -> listener.beforeUpload(jobUUID, configuration, createArchiveResult)); - - try { - uploadSources(projectId, jobUUID, createArchiveResult); - uploadBinaries(projectId, jobUUID, createArchiveResult); - - inform((listener) -> listener.afterUpload(jobUUID, configuration, createArchiveResult)); - - } finally { - LOG.debug("Remove temporary data from: {}", uploadDirectory); - try { - archiveSupport.deleteArchives(createArchiveResult); - } catch (IOException e) { - throw new IllegalStateException("Was not able to remove temporary archive data!", e); - } - } - } - - private void uploadBinaries(String projectId, UUID jobUUID, ArchivesCreationResult createArchiveResult) throws SecHubClientException { - if (!createArchiveResult.isBinaryArchiveCreated()) { - return; - } - Path tarFile = createArchiveResult.getBinaryArchiveFile(); + void upload(String projectId, UUID jobUUID, SecHubConfigurationModel configuration, Path workingDirectory) throws SecHubClientException; - String filesize = String.valueOf(tarFile.toFile().length()); - String checksum = checkSumSupport.createSha256Checksum(tarFile); - - runOrFail(() -> workaroundProjectApi.userUploadsBinaries(projectId, jobUUID.toString(), checksum, filesize, tarFile), "Binary upload (tar)"); - } - - private void uploadSources(String projectId, UUID jobUUID, ArchivesCreationResult createArchiveResult) throws SecHubClientException { - if (!createArchiveResult.isSourceArchiveCreated()) { - return; - } - Path zipFile = createArchiveResult.getSourceArchiveFile(); - String checksum = checkSumSupport.createSha256Checksum(zipFile); - - runOrFail(() -> workaroundProjectApi.userUploadsSourceCode(projectId, jobUUID.toString(), checksum, zipFile), "Source upload (zip)"); - } - - public List fetchAllExecutorConfigurationInfo() throws SecHubClientException { - OpenApiListOfExecutorConfigurations configList = runOrFail(() -> adminApi.adminFetchesExecutorConfigurationList(), "Fetch executor configurations"); - - List list = configList.getExecutorConfigurations(); - List result = new ArrayList<>(); - - for (OpenApiListOfExecutorConfigurationsExecutorConfigurationsInner inner : list) { - - ExecutorConfigurationInfo info = new ExecutorConfigurationInfo(); - info.setEnabled(inner.getEnabled() == null ? false : inner.getEnabled()); - info.setName(inner.getName()); - info.setUuid(UUID.fromString(inner.getUuid())); - - result.add(info); - } - return result; - } + List fetchAllExecutorConfigurationInfo() throws SecHubClientException; /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* + ................Status........................... + */ /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - public SecHubStatus fetchSecHubStatus() throws SecHubClientException { - SecHubStatus status = new SecHubStatus(); - runOrFail(() -> { - List statusInformationList = adminApi.adminListsStatusInformation(); - for (OpenApiStatusInformationInner info : statusInformationList) { - String key = info.getKey(); - if (key != null) { - status.statusInformation.put(key, info.getValue()); - } - } - }, "Was not able to fetch SecHub status!"); - return status; - } - - public void triggerRefreshOfSecHubSchedulerStatus() throws SecHubClientException { - runOrFail(() -> adminApi.adminTriggersRefreshOfSchedulerStatus(), "Was not able to trigger scheduler refresh"); - } + SecHubStatus fetchSecHubStatus() throws SecHubClientException; + + void triggerRefreshOfSecHubSchedulerStatus() throws SecHubClientException; /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* + ................Check........................... + */ /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - public boolean isServerAlive() throws SecHubClientException { - try { - anonymousApi.anonymousCheckAliveGet(); - return true; - } catch (ApiException e) { - return false; - } - } - - public boolean isProjectExisting(String projectId) throws SecHubClientException { - requireNonNull(projectId, "projectId may not be null!"); - return runOrFail(() -> adminApi.adminListsAllProjects().contains(projectId), - - "Cannot check if project '" + projectId + "' exists!"); - } - - public boolean isUserAssignedToProject(String userId, String projectId) throws SecHubClientException { - requireNonNull(userId, "userId may not be null!"); - requireNonNull(projectId, "projectId may not be null!"); - - return runOrFail(() -> { - /* not very smart... but works : */ - OpenApiProjectDetails details = adminApi.adminShowsProjectDetails(projectId); - List userIds = details.getUsers(); - return userIds.contains(userId); - }, ""); - } - - public boolean isExecutionProfileExisting(String profileId) throws SecHubClientException { - try { - OpenApiExecutionProfileFetch result = adminApi.adminFetchesExecutionProfile(profileId); - return result != null; - } catch (ApiException e) { - if (e.getCode() == 404) { - /* not found */ - return false; - } - throw new SecHubClientException("Was not able check if profile " + profileId + " does exist.", e); - } - } + boolean isServerAlive() throws SecHubClientException; - /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - /* + ................Fetch........................... + */ - /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - public List fetchAllOpenSignups() throws SecHubClientException { - return runOrFail(() -> OpenUserSignup.fromDelegates(adminApi.adminListsOpenUserSignups()), "Cannot fetch open signups"); - } + boolean isProjectExisting(String projectId) throws SecHubClientException; - public List fetchAllProjectIds() throws SecHubClientException { - return runOrFail(() -> adminApi.adminListsAllProjects(), "Cannot fetch all project names"); - } + boolean isUserAssignedToProject(String userId, String projectId) throws SecHubClientException; - public List fetchAllUserIds() throws SecHubClientException { - return runOrFail(() -> adminApi.adminListsAllUsers(), "Cannot fetch all user names"); - } + boolean isExecutionProfileExisting(String profileId) throws SecHubClientException; /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - /* + ................Assign/Unassign................. + */ + /* + ................Fetch........................... + */ /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - public void acceptOpenSignup(String signupUsername) throws SecHubClientException { - requireNonNull(signupUsername, "signupUsername may not be null!"); - - runOrFail(() -> adminApi.adminAcceptsSignup(signupUsername), "Cannot accept open signups"); - } - - public void assignUserToProject(String userId, String projectId) throws SecHubClientException { - requireNonNull(userId, "userId may not be null!"); - requireNonNull(projectId, "projectId may not be null!"); + List fetchAllOpenSignups() throws SecHubClientException; - runOrFail(() -> adminApi.adminAssignsUserToProject(projectId, userId), + List fetchAllProjectIds() throws SecHubClientException; - "Was not able to assign user '" + userId + "' to project '" + projectId + "'"); - - } - - public void unassignUserFromProject(String userId, String projectId) throws SecHubClientException { - requireNonNull(userId, "userId may not be null!"); - requireNonNull(projectId, "projectId may not be null!"); - - runOrFail(() -> adminApi.adminUnassignsUserFromProject(projectId, userId), - - "Was not able to unassign user '" + userId + "' from project '" + projectId + "'"); - - } - - public void addExecutorConfigurationToProfile(UUID uuidOfExecutorConfigToAdd, String profileId) throws SecHubClientException { - requireNonNull(uuidOfExecutorConfigToAdd, "uuidOfExecutorConfigToAdd may not be null!"); - requireNonNull(profileId, "profileId may not be null!"); - - runOrFail(() -> { - OpenApiExecutionProfileUpdate update = conversionHelper.fetchProfileAndConvertToUpdateObject(profileId); - - OpenApiExecutionProfileUpdateConfigurationsInner newItem = new OpenApiExecutionProfileUpdateConfigurationsInner(); - newItem.setUuid(uuidOfExecutorConfigToAdd.toString()); - update.addConfigurationsItem(newItem); - - adminApi.adminUpdatesExecutionProfile(profileId, update); - - }, "Cannot add executor config: " + uuidOfExecutorConfigToAdd + " to profile:" + profileId); - } + List fetchAllUserIds() throws SecHubClientException; /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - /* + ................Delete.......................... + */ + /* + ................Assign/Unassign................. + */ /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + void acceptOpenSignup(String signupUsername) throws SecHubClientException; - public void deleteProject(String projectId) throws SecHubClientException { - requireNonNull(projectId, "projectId may not be null!"); + void assignUserToProject(String userId, String projectId) throws SecHubClientException; - runOrFail(() -> adminApi.adminDeleteProject(projectId), "Was not able to delete project: " + projectId); - } + void unassignUserFromProject(String userId, String projectId) throws SecHubClientException; - public void deleteExecutionProfile(String profileId) throws SecHubClientException { - requireNonNull(profileId, "profileId may not be null!"); + void addExecutorConfigurationToProfile(UUID uuidOfExecutorConfigToAdd, String profileId) throws SecHubClientException; - runOrFail(() -> adminApi.adminDeletesExecutionProfile(profileId), "Was not able to delete execution profile: " + profileId); - } + void deleteProject(String projectId) throws SecHubClientException; - public void deleteExecutorConfiguration(UUID executorUUID) throws SecHubClientException { - requireNonNull(executorUUID, "executor uuid may not be null!"); + void deleteExecutionProfile(String profileId) throws SecHubClientException; - runOrFail(() -> adminApi.adminDeletesExecutorConfiguration(executorUUID.toString()), "Was not able to delete executor configuration: " + executorUUID); - } + void deleteExecutorConfiguration(UUID executorUUID) throws SecHubClientException; /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* + ................Scheduling...................... + */ /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - public UUID createJob(SecHubConfigurationModel configuration) throws SecHubClientException { - requireNonNull(configuration, "configuration may not be null!"); - String projectId = configuration.getProjectId(); - if (projectId == null) { - throw new IllegalStateException("Project id missing inside configuration!"); - } - - String configAsJson = JSONConverter.get().toJSON(configuration, true); - LOG.debug("configAsJson=\n{}", configAsJson); - - OpenApiScanJob openApiScanJob = JSONConverter.get().fromJSON(OpenApiScanJob.class, configAsJson); - if (LOG.isDebugEnabled()) { - String openApiJSON = JSONConverter.get().toJSON(openApiScanJob, true); - LOG.debug("openApiJSON=\n{}", openApiJSON); - } - OpenApiJobId openApiJobId = runOrFail(() -> projectApi.userCreatesNewJob(projectId, openApiScanJob), - "Was not able to create a SecHub job for project:" + projectId); - String jobIdAsString = openApiJobId.getJobId(); - - UUID uuid = UUID.fromString(jobIdAsString); - return uuid; - } - - public JobStatus fetchJobStatus(String projectId, UUID jobUUID) throws SecHubClientException { - OpenApiJobStatus status = runOrFail(() -> projectApi.userChecksJobStatus(projectId, jobUUID.toString()), "Fetch status"); - return JobStatus.from(status); - } - - public SecHubReport downloadSecHubReportAsJson(String projectId, UUID jobUUID) throws SecHubClientException { - SecHubReport report = runOrFail(() -> workaroundProjectApi.userDownloadsJobReport(projectId, jobUUID.toString()), "Download SecHub report (JSON)"); - inform((listener) -> listener.afterReportDownload(jobUUID, report)); - - return report; - } + UUID createJob(SecHubConfigurationModel configuration) throws SecHubClientException; + + JobStatus fetchJobStatus(String projectId, UUID jobUUID) throws SecHubClientException; + + SecHubReport downloadSecHubReportAsJson(String projectId, UUID jobUUID) throws SecHubClientException; /** * Approve SecHub job for project. This will mark the job as ready to start @@ -464,49 +126,6 @@ public SecHubReport downloadSecHubReportAsJson(String projectId, UUID jobUUID) t * @param jobUUID * @throws SecHubClientException */ - public void approveJob(String projectId, UUID jobUUID) throws SecHubClientException { - runOrFail(() -> projectApi.userApprovesJob(projectId, jobUUID.toString()), "Job approve"); - } - - /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - /* + ................Helpers......................... + */ - /* ++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + void approveJob(String projectId, UUID jobUUID) throws SecHubClientException; - private void runOrFail(RunOrFail failable, String failureMessage) throws SecHubClientException { - try { - failable.runOrFail(); - } catch (ApiException e) { - throw createClientException(failureMessage, e); - } - } - - private SecHubClientException createClientException(String message, Exception cause) throws SecHubClientException { - return new SecHubClientException(message + " - " + cause.getMessage(), cause); - } - - private T runOrFail(Callable callable, String failureMessage) throws SecHubClientException { - try { - return callable.call(); - } catch (ApiException e) { - throw createClientException(failureMessage, e); - } catch (Exception e) { - if (e instanceof RuntimeException) { - RuntimeException re = (RuntimeException) e; - throw re; - } - throw new IllegalStateException("Unhandled exception - should not happen", e); - } - } - - private void inform(SecHubClientListenerCaller r) { - for (SecHubClientListener listener : secHubClientListeners) { - r.inform(listener); - } - } - - private interface SecHubClientListenerCaller { - - public void inform(SecHubClientListener listener); - - } -} +} \ No newline at end of file diff --git a/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/User.java b/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/User.java new file mode 100644 index 0000000000..7ceed78343 --- /dev/null +++ b/sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/User.java @@ -0,0 +1,22 @@ +package com.mercedesbenz.sechub.api; + +public class User { + + private String userId; + + private String email; + + public User(String userId, String email) { + this.userId = userId; + this.email = email; + } + + public String getUserId() { + return userId; + } + + public String getEmail() { + return email; + } + +} diff --git a/sechub-api-java/src/test/java/com/mercedesbenz/sechub/api/MockedSecHubClientTest.java b/sechub-api-java/src/test/java/com/mercedesbenz/sechub/api/MockedSecHubClientTest.java new file mode 100644 index 0000000000..57df05b663 --- /dev/null +++ b/sechub-api-java/src/test/java/com/mercedesbenz/sechub/api/MockedSecHubClientTest.java @@ -0,0 +1,124 @@ +package com.mercedesbenz.sechub.api; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; +import java.util.UUID; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import com.mercedesbenz.sechub.commons.model.SecHubConfigurationModel; +import com.mercedesbenz.sechub.commons.model.job.ExecutionState; + +class MockedSecHubClientTest { + + private MockedSecHubClient clientToTest; + + @BeforeEach + void beforeEach() { + clientToTest = new MockedSecHubClient(); + } + + @Test + void mock_initial_behavior() throws Exception { + + /* test */ + assertTrue(clientToTest.fetchAllExecutorConfigurationInfo().isEmpty()); + assertTrue(clientToTest.fetchAllOpenSignups().isEmpty()); + assertTrue(clientToTest.fetchAllProjectIds().isEmpty()); + assertTrue(clientToTest.fetchAllUserIds().isEmpty()); + + } + + @Test + void mock_jobs() throws Exception { + /* prepare */ + SecHubConfigurationModel configuration = new SecHubConfigurationModel(); + configuration.setProjectId("project1"); + + /* execute */ + UUID uuid = clientToTest.createJob(configuration); + + /* test */ + assertNotNull(uuid); + JobStatus jobStatus = clientToTest.fetchJobStatus("project1", uuid); + jobStatus.getState().equals(ExecutionState.INITIALIZING); + } + + @Test + void mock_project() throws Exception { + Project project = new Project(); + project.setName("projectname"); + + /* execute */ + clientToTest.createProject(project); + + /* test */ + List allProjects = clientToTest.fetchAllProjectIds(); + assertEquals(1, allProjects.size()); + assertTrue(allProjects.contains("projectname")); + } + + @Test + void mock_user_signup() throws Exception { + /* execute */ + UserSignup signup = new UserSignup(); + signup.setUserId("somebody"); + signup.setEmailAdress("somebody@example.org"); + + clientToTest.createSignup(signup); + + /* test */ + List signups = clientToTest.fetchAllOpenSignups(); + assertEquals(1, signups.size()); + assertTrue(clientToTest.fetchAllUserIds().isEmpty()); + + /* execute 2 */ + clientToTest.acceptOpenSignup("somebody"); + assertTrue(clientToTest.fetchAllOpenSignups().isEmpty()); + + /* test 2 */ + List userIds = clientToTest.fetchAllUserIds(); + assertEquals(1, userIds.size()); + assertTrue(userIds.contains("somebody")); + + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + void mock_profiles_and_configurations(boolean enabled) throws Exception { + + /* check precondition */ + assertFalse(clientToTest.isExecutionProfileExisting("testprofile")); + + /* execute */ + ExecutionProfileCreate create = new ExecutionProfileCreate(); + create.setDescription("d1"); + create.setEnabled(enabled); + clientToTest.createExecutionProfile("testprofile", create); + + /* execute 2 */ + ExecutorConfiguration config = new ExecutorConfiguration(); + config.setEnabled(enabled); + UUID configUUID = clientToTest.createExecutorConfiguration(config); + + /* test */ + List info = clientToTest.fetchAllExecutorConfigurationInfo(); + assertEquals(1, info.size()); + ExecutorConfigurationInfo configuration = info.iterator().next(); + assertEquals(enabled, configuration.isEnabled()); + + clientToTest.addExecutorConfigurationToProfile(configUUID, "testprofile"); + + /* test 2 */ + assertTrue(clientToTest.isExecutionProfileExisting("testprofile")); + assertEquals(1, info.size()); + ExecutorConfigurationInfo profile = info.iterator().next(); + assertEquals(enabled, profile.isEnabled()); + + } + +} diff --git a/sechub-api-java/src/test/java/com/mercedesbenz/sechub/api/generator/InternalAccessModelFileGenerator.java b/sechub-api-java/src/test/java/com/mercedesbenz/sechub/api/generator/InternalAccessModelFileGenerator.java index 29974a0561..b94fad9414 100644 --- a/sechub-api-java/src/test/java/com/mercedesbenz/sechub/api/generator/InternalAccessModelFileGenerator.java +++ b/sechub-api-java/src/test/java/com/mercedesbenz/sechub/api/generator/InternalAccessModelFileGenerator.java @@ -9,7 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.mercedesbenz.sechub.api.SecHubClient; +import com.mercedesbenz.sechub.api.DefaultSecHubClient; public class InternalAccessModelFileGenerator { @@ -49,7 +49,7 @@ private void generateAbstractModel(MapGenInfo info) throws Exception { template.addLine("import java.util.List;"); template.addLine(""); template.addLine("/**"); - template.addLine(" * " + info.targetInternalAccessClassName + " is a model class for " + SecHubClient.class.getSimpleName() + template.addLine(" * " + info.targetInternalAccessClassName + " is a model class for " + DefaultSecHubClient.class.getSimpleName() + ". It uses internally the generated class"); template.addLine(" * " + fromGenclazz.getName() + ".
"); template.addLine(" *
"); diff --git a/sechub-api-java/src/test/java/com/mercedesbenz/sechub/api/generator/PublicModelFileGenerator.java b/sechub-api-java/src/test/java/com/mercedesbenz/sechub/api/generator/PublicModelFileGenerator.java index fcfec18d65..6bdd03a235 100644 --- a/sechub-api-java/src/test/java/com/mercedesbenz/sechub/api/generator/PublicModelFileGenerator.java +++ b/sechub-api-java/src/test/java/com/mercedesbenz/sechub/api/generator/PublicModelFileGenerator.java @@ -9,7 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.mercedesbenz.sechub.api.SecHubClient; +import com.mercedesbenz.sechub.api.DefaultSecHubClient; public class PublicModelFileGenerator { @@ -55,15 +55,15 @@ private void generatetPublicModel(MapGenInfo info, boolean overwritePublicModelF template.addLine(""); template.addLine("/**"); - template.addLine( - " * " + info.targetClassName + " is a model class for " + SecHubClient.class.getSimpleName() + ". It uses internally the generated class"); + template.addLine(" * " + info.targetClassName + " is a model class for " + DefaultSecHubClient.class.getSimpleName() + + ". It uses internally the generated class"); template.addLine(" * " + fromGenclazz.getName() + ".
"); template.addLine(" *
"); template.addLine(" * The wrapper class itself was initial generated with"); template.addLine(" * " + getClass().getName() + "."); template.addLine(" */"); template.addLine("public class " + info.targetClassName + " {"); - template.addLine(" // only for usage by " + SecHubClient.class.getSimpleName()); + template.addLine(" // only for usage by " + DefaultSecHubClient.class.getSimpleName()); template.addLine(" static List<" + info.targetClassName + "> fromDelegates(List<" + info.fromGenclazz.getName() + "> delegates) {"); template.addLine(" List<" + info.targetClassName + "> resultList = new ArrayList<>();"); template.addLine(" if (delegates != null) {"); @@ -75,7 +75,7 @@ private void generatetPublicModel(MapGenInfo info, boolean overwritePublicModelF template.addLine(" }"); template.addLine(""); template.addLine(""); - template.addLine(" // only for usage by " + SecHubClient.class.getSimpleName()); + template.addLine(" // only for usage by " + DefaultSecHubClient.class.getSimpleName()); template.addLine(" static List<" + info.fromGenclazz.getName() + "> toDelegates(List<" + info.targetClassName + "> wrappers) {"); template.addLine(" List<" + info.fromGenclazz.getName() + "> resultList = new ArrayList<>();"); template.addLine(" if (wrappers != null) {"); @@ -98,7 +98,7 @@ private void generatetPublicModel(MapGenInfo info, boolean overwritePublicModelF template.addLine(" this.internalAccess= new " + internalAccessClass + "(delegate);"); template.addLine(" }"); template.addLine(""); - template.addLine(" // only for usage by " + SecHubClient.class.getSimpleName()); + template.addLine(" // only for usage by " + DefaultSecHubClient.class.getSimpleName()); template.addLine(" " + info.fromGenclazz.getName() + " getDelegate() {"); template.addLine(" return internalAccess.getDelegate();"); template.addLine(" }"); diff --git a/sechub-doc/src/docs/asciidoc/images/eclipse-choose-workspaces-folder.png b/sechub-doc/src/docs/asciidoc/images/eclipse-choose-workspaces-folder.png new file mode 100644 index 0000000000..2c6fb0c6d3 Binary files /dev/null and b/sechub-doc/src/docs/asciidoc/images/eclipse-choose-workspaces-folder.png differ diff --git a/sechub-doc/src/docs/asciidoc/images/eclipse-dark-theme.png b/sechub-doc/src/docs/asciidoc/images/eclipse-dark-theme.png new file mode 100644 index 0000000000..e7feed6006 Binary files /dev/null and b/sechub-doc/src/docs/asciidoc/images/eclipse-dark-theme.png differ diff --git a/sechub-doc/src/docs/asciidoc/images/eclipse-egradle-import-file-dialog.png b/sechub-doc/src/docs/asciidoc/images/eclipse-egradle-import-file-dialog.png new file mode 100644 index 0000000000..895e344628 Binary files /dev/null and b/sechub-doc/src/docs/asciidoc/images/eclipse-egradle-import-file-dialog.png differ diff --git a/sechub-doc/src/docs/asciidoc/images/eclipse-egradle-sechub-imported.png b/sechub-doc/src/docs/asciidoc/images/eclipse-egradle-sechub-imported.png new file mode 100644 index 0000000000..5f11a8ca83 Binary files /dev/null and b/sechub-doc/src/docs/asciidoc/images/eclipse-egradle-sechub-imported.png differ diff --git a/sechub-doc/src/docs/asciidoc/images/eclipse-help-menu-marketplace.png b/sechub-doc/src/docs/asciidoc/images/eclipse-help-menu-marketplace.png new file mode 100644 index 0000000000..c61d980548 Binary files /dev/null and b/sechub-doc/src/docs/asciidoc/images/eclipse-help-menu-marketplace.png differ diff --git a/sechub-doc/src/docs/asciidoc/images/eclipse-import-egradle.png b/sechub-doc/src/docs/asciidoc/images/eclipse-import-egradle.png new file mode 100644 index 0000000000..9e1e08ebbf Binary files /dev/null and b/sechub-doc/src/docs/asciidoc/images/eclipse-import-egradle.png differ diff --git a/sechub-doc/src/docs/asciidoc/images/eclipse-import-gradle-projects-sechub-selected.png b/sechub-doc/src/docs/asciidoc/images/eclipse-import-gradle-projects-sechub-selected.png new file mode 100644 index 0000000000..2657186e1e Binary files /dev/null and b/sechub-doc/src/docs/asciidoc/images/eclipse-import-gradle-projects-sechub-selected.png differ diff --git a/sechub-doc/src/docs/asciidoc/images/eclipse-import-gradle-projects-wizard.png b/sechub-doc/src/docs/asciidoc/images/eclipse-import-gradle-projects-wizard.png new file mode 100644 index 0000000000..6e82fc6ef3 Binary files /dev/null and b/sechub-doc/src/docs/asciidoc/images/eclipse-import-gradle-projects-wizard.png differ diff --git a/sechub-doc/src/docs/asciidoc/images/eclipse-import-menu.png b/sechub-doc/src/docs/asciidoc/images/eclipse-import-menu.png new file mode 100644 index 0000000000..d5302693a9 Binary files /dev/null and b/sechub-doc/src/docs/asciidoc/images/eclipse-import-menu.png differ diff --git a/sechub-doc/src/docs/asciidoc/images/eclipse-marketplace-egradle-ide.png b/sechub-doc/src/docs/asciidoc/images/eclipse-marketplace-egradle-ide.png new file mode 100644 index 0000000000..36bd30dd7a Binary files /dev/null and b/sechub-doc/src/docs/asciidoc/images/eclipse-marketplace-egradle-ide.png differ diff --git a/sechub-doc/src/docs/asciidoc/images/eclipse-new-configuration.png b/sechub-doc/src/docs/asciidoc/images/eclipse-new-configuration.png new file mode 100644 index 0000000000..d4c70a6c0e Binary files /dev/null and b/sechub-doc/src/docs/asciidoc/images/eclipse-new-configuration.png differ diff --git a/sechub-doc/src/docs/asciidoc/images/eclipse-preferences.png b/sechub-doc/src/docs/asciidoc/images/eclipse-preferences.png new file mode 100644 index 0000000000..750a62a836 Binary files /dev/null and b/sechub-doc/src/docs/asciidoc/images/eclipse-preferences.png differ diff --git a/sechub-doc/src/docs/asciidoc/images/eclipse-run-configuration-server-arguments-tab.png b/sechub-doc/src/docs/asciidoc/images/eclipse-run-configuration-server-arguments-tab.png new file mode 100644 index 0000000000..98c577addd Binary files /dev/null and b/sechub-doc/src/docs/asciidoc/images/eclipse-run-configuration-server-arguments-tab.png differ diff --git a/sechub-doc/src/docs/asciidoc/images/eclipse-run-configuration-server-main-tab.png b/sechub-doc/src/docs/asciidoc/images/eclipse-run-configuration-server-main-tab.png new file mode 100644 index 0000000000..5cf5cb13fc Binary files /dev/null and b/sechub-doc/src/docs/asciidoc/images/eclipse-run-configuration-server-main-tab.png differ diff --git a/sechub-doc/src/docs/asciidoc/images/eclipse-run-configurations.png b/sechub-doc/src/docs/asciidoc/images/eclipse-run-configurations.png new file mode 100644 index 0000000000..58dcb2b001 Binary files /dev/null and b/sechub-doc/src/docs/asciidoc/images/eclipse-run-configurations.png differ diff --git a/sechub-doc/src/docs/asciidoc/images/eclipse-run-server-integrationtest.png b/sechub-doc/src/docs/asciidoc/images/eclipse-run-server-integrationtest.png new file mode 100644 index 0000000000..0587da6e39 Binary files /dev/null and b/sechub-doc/src/docs/asciidoc/images/eclipse-run-server-integrationtest.png differ diff --git a/sechub-doc/src/docs/asciidoc/images/github-fork-sechub.png b/sechub-doc/src/docs/asciidoc/images/github-fork-sechub.png new file mode 100644 index 0000000000..0a1535b549 Binary files /dev/null and b/sechub-doc/src/docs/asciidoc/images/github-fork-sechub.png differ diff --git a/sechub-doc/src/docs/asciidoc/sechub-developer-quickstart-guide.adoc b/sechub-doc/src/docs/asciidoc/sechub-developer-quickstart-guide.adoc index 4067d82d3b..ed27a4b913 100644 --- a/sechub-doc/src/docs/asciidoc/sechub-developer-quickstart-guide.adoc +++ b/sechub-doc/src/docs/asciidoc/sechub-developer-quickstart-guide.adoc @@ -14,11 +14,14 @@ include::documents/shared/about_documentation_all.adoc[] == Target audience -This guide is designed to help you if your are a developer or administrator and want to build, start and use the SecHub server either to help you with testing when writing new features or to test the integration into your own environment. If you are a enduser and want to use the SecHub client please have a look at our https://mercedes-benz.github.io/sechub/latest/sechub-client.html[client documentation]. +In case you are a **developer**, this guide is for you. + +* Users: In case, you are an enduser and want to use the SecHub client please have a look at our https://mercedes-benz.github.io/sechub/latest/sechub-client.html[client documentation] +* Operations: In case, you are an administrator or operation engineers, who just wants to run SecHub have a look at the SecHub Getting Started Guide: https://mercedes-benz.github.io/sechub/latest/sechub-getting-started.html == Guide -This guide describes how to get started with SecHub. +This guide describes how to get started with SecHub from a developer perspective. The following topics are covered: @@ -241,3 +244,345 @@ For real results, you have to define an 'execution profile' with a scanner (via ===== Log files Open the log file `./sechub-integrationtest/integrationtest-server.log` to get more details about the problem. + +== Start Contributing + +. Fork SecHub: https://github.com/mercedes-benz/sechub/fork + +. Select a SecHub issue you want to work on: https://github.com/mercedes-benz/sechub/issues ++ +[TIP] +Issues have labels a good way to start is to look for issues with https://github.com/mercedes-benz/sechub/labels/good%20first%20issue[`good first issue`] or https://github.com/mercedes-benz/sechub/labels/help%20wanted[`help wanted`]. +Issues with labels https://github.com/mercedes-benz/sechub/labels/beginner[`beginner`], https://github.com/mercedes-benz/sechub/labels/intermediate[`intermediate`], https://github.com/mercedes-benz/sechub/labels/advanced[`advanced`] indicate the level of difficulty. +However, not all issues are labeled. In addition, if you like an issue just comment on it, so that we can assign you to it. + +** In case, the issue you want to work on does not yet exists, please create an issue. + +. Create a new branch on your local fork following the naming pattern `feature--` ++ +TIP: Example: `feature-36-go-client-supports-env-variable`. + +. Implement your changes ++ +TIP: In case, you have any questions or need clarification ask inside the issues + +. Run the tests locally + +** From within the (Eclipse) IDE +** Using the `sdc.sh` helper script (located in the `sechub` repository folder) ++ +---- +# Run all Unit Tests +./sechub-developertools/scripts/sdc.sh -u + +# Run all Integration Tests +./sechub-developertools/scripts/sdc.sh -i +---- ++ +NOTE: `sdc.sh` is a convenience wrapper around the `gradlew` tool, which bundles the CLI calls into use cases. + +. Create a pull-request and merge your changes into SecHub + +== Setup IDE for SecHub + +Our supported setup is: + +* Eclipse IDE +* Git +* Debian based GNU/Linux +* x86 64-bit CPU +* Docker + +In case your setup differs, please try to adjust the guides to your setup. Any contributions for other setups are welcome. Feel free to create pull requests for this guide with your setup. + +=== Setup SecHub in Eclipse IDE + +. Please, first create a fork of SecHub on GitHub: https://github.com/mercedes-benz/sechub/fork ++ +image::github-fork-sechub.png[] + +. On your local Linux computer create a new folder `Development` in your home folder ++ +---- +$ mkdir "$HOME/Development" +---- + +. Change into the `Development` folder ++ +---- +cd "$HOME/Development" +---- + +. Download https://www.eclipse.org/downloads/packages/[`Eclipse IDE for Java Developers` or `Eclipse IDE for Enterprise Java and Web Developers`] ++ +---- +# Download Eclipse IDE for Enterprise Java and Web Developers +wget http://www.mirrorservice.org/sites/download.eclipse.org/eclipseMirror/technology/epp/downloads/release/2023-09/R/eclipse-jee-2023-09-R-linux-gtk-x86_64.tar.gz + +# Download checksum +wget http://www.mirrorservice.org/sites/download.eclipse.org/eclipseMirror/technology/epp/downloads/release/2023-09/R/eclipse-jee-2023-09-R-linux-gtk-x86_64.tar.gz.sha512 + +# Verify checksum +sha512sum -c eclipse*.sha512 + +# Extract archive +tar -xf eclipse-jee-2023-09-R-linux-gtk-x86_64.tar.gz + +# Remove downloaded files +rm eclipse-jee-* +---- ++ +As end result an `eclipse` folder containing the `eclipse` executable should be available. ++ +NOTE: http://www.mirrorservice.org/[www.mirrorservice.org] is provided by the University of Kent School of Computing. + +. Create a `projects` folder ++ +---- +mkdir projects +---- + +. Switch into the project folder ++ +---- +mkdir projects +cd projects/ +---- ++ +NOTE: We create a `projects` folder, because there are several SecHub projects. For example, the "sechub-` plugins are separated into different repositories. + +. Clone the SecHub repository (your fork) ++ +---- +git clone https://github.com//sechub.git +---- ++ +After, successfully cloning the repository. There should be a folder named `sechub` containing the source code. + +. Go one level up into to the `Development` folder ++ +---- +$ cd .. +$ pwd +/home//Development +$ ls +eclipse projects +---- ++ + +. Create a `workspaces/sechub` folder for the Eclipse IDE to store settings in ++ +---- +mkdir -p workspaces/sechub +---- + +. Check the folder structure ++ +The folder structure should look like this: ++ +---- +$ pwd +/home/user/Development +$ tree -L 2 +. +├── eclipse +│   ├── artifacts.xml +│   ├── configuration +│   ├── dropins +│   ├── eclipse +│   ├── eclipse.ini +│   ├── features +│   ├── icon.xpm +│   ├── p2 +│   ├── plugins +│   └── readme +├── projects +│   └── sechub +└── workspaces + └── sechub +---- + +. Go into the `eclipse` folder and start `eclipse` ++ +---- +cd eclipse +./eclipse +---- + +. Select the `workspaces/sechub` folder as workspace folder and press the `Launch` button ++ +image::eclipse-choose-workspaces-folder.png[] + +. Install the https://marketplace.eclipse.org/content/egradle-ide[EGradle IDE Plugin] +.. In the Eclipse IDE menu click the help menu and select marketplace ++ +image::eclipse-help-menu-marketplace.png[] + +.. To search for the EGradle IDE Plugin, type `egradle ide` into the `Find` intput box and press enter ++ +image::eclipse-marketplace-egradle-ide.png[] + +.. Select the EGradle IDE Plugin and press install. Next follow the installation wizard. ++ +[NOTE] +The creator and developer of the EGradle IDE Plugin is a SecHub developer. +However, the EGradle IDE Plugin is a private project and not affiliated with SecHub. + + +. Import the SecHub project into the workspace +.. Select `Import` from the `File` menu ++ +image::eclipse-import-menu.png[] + +.. Select the `EGradle -> Import gradle root project with all subprojects` option and select next ++ +image::eclipse-import-egradle.png[] + +.. The EGradle Import Wizard opens up. Next, click `Browse…` after the `Gradle root project path` input box ++ +image::eclipse-import-gradle-projects-wizard.png[] + +.. A file dialog opens, select the `Development/projects/sechub` folder (previously cloned) ++ +image::eclipse-egradle-import-file-dialog.png[] + +.. The `sechub` folder is selected. Next, click the `Finish` button to import the SecHub project ++ +image::eclipse-import-gradle-projects-sechub-selected.png[] + +.. The import will take some time. Once, successfully imported all SecHub sub-projects, a `Virtual Root` and the success message in the console should be visible ++ +image::eclipse-egradle-sechub-imported.png[] + +==== Switch to `Dark` theme (Optional) + +Needs to be done for every new workspace. + +. Select `Preferences` from the `Window` menu ++ +image::eclipse-preferences.png[] + +. Search for `Dark` in the input box. The menu point `General -> Appearance` should appear as an option ++ +image::eclipse-dark-theme.png[] + +. Select `Dark` from the theme drop-down menu + +. Press the `Apply and Close` button + +== Run Integration Tests From IDE + +We explain the setup based on the Free and Open Source Software (FOSS) https://eclipseide.org/[Eclipse IDE]. + +=== SecHub Server + +Run a SecHub server integration test. + +[#configure-sechub-server] +==== Configure SecHub Server + +Download the launch configuration for the Eclipse IDE: https://raw.githubusercontent.com/mercedes-benz/sechub/develop/sechub-examples/eclipse/SecHubServerApplication_(INTEGRATION_TEST-H2).launch[SecHubServerApplication (INTEGRATION TEST - H2)] + +. Open the `Run Configurations…` in the toolbar of the Eclipse IDE ++ +image::eclipse-run-configurations.png[] + +. Right-click on `Java Application` and select `New Configuration` from the context menu. ++ +image::eclipse-new-configuration.png[] + +. Name the new configuration `SecHubServerApplication_(INTEGRATION_TEST-H2)` + +. In the tab `Main`: +** `Project:` Select the `sechub-server` project. +** `Main class: com.mercedesbenz.sechub.SecHubServerApplication` ++ +image::eclipse-run-configuration-server-main-tab.png[] + +. Next open the `Arguments` tab and add the following arguments into the `VM arguments` section: ++ +---- +-Dspring.profiles.active=mocked_products,h2,integrationtest +-Dsechub.server.debug=true +-Dsechub.storage.sharedvolume.upload.dir=/home//.sechub/sharedvolume +-Dsechub.targettype.detection.intranet.hostname.endswith=intranet.example.org +-Dsechub.config.trigger.nextjob.initialdelay=0 +---- ++ +NOTE: Ensure you replace the `` with your own user. Additionally, set the `sechub.storage.sharedvolume.upload.dir` parameter to a folder with read and write access on the system. ++ +image::eclipse-run-configuration-server-arguments-tab.png[] + +==== Run a SecHub server integration test + +This section demonstrate how to run an integration test for the SecHub server using `UserRegistrationScenario1IntTest.java` as example. +Other SecHub server integration tests can be run in the same way. + +. Start SecHub server in integration test mode using the SecHub integration test launch configuration as explained in <> + +. Select `sechub-integrationtest/src/test/java/com/mercedesbenz/sechub/integrationtest/scenario1/UserRegistrationScenario1IntTest.java` in the `Project Explorer` + +. Right-click on `UserRegistrationScenario1IntTest.java` to open the context menu and select `Run As` and select `JUnit Test` in the submenu. ++ +image::eclipse-run-server-integrationtest.png[] + +. Check the JUnit tab, the result should be green indicating a successful run. + +=== Product Delegation Server (PDS) + +Run a Product Delegation Server (PDS) integration test. + +[#configure-pds] +==== Configure Product Delegation Server (PDS) + +Download the launch configure for the Eclipse IDE: https://raw.githubusercontent.com/mercedes-benz/sechub/develop/sechub-examples/eclipse/ProductDelegationServerApplication_(INTEGRATION_TEST-H2).launch[ProductDelegationServerApplication (INTEGRATION TEST - H2)] + +. Open the `Run Configurations…` in the toolbar of the Eclipse IDE ++ +image::eclipse-run-configurations.png[] + +. Right-click on `Java Application` and select `New Configuration` from the context menu. ++ +image::eclipse-new-configuration.png[] + +. Name the new configuration `ProductDelegationServerApplication_(INTEGRATION_TEST-H2)` + +. In the tab `Main`: +** `Project:` Select the `sechub-pds` project. +** `Main class: com.mercedesbenz.sechub.pds.ProductDelegationServerApplication` + +. Next open the `Arguments` tab and add the following arguments into the `VM arguments` section: ++ +---- +-Dspring.profiles.active=pds_integrationtest,pds_h2 +-Dpds.storage.sharedvolume.upload.dir=/home//.sechub/sharedvolume +-Dpds.workspace.rootfolder=/home//.pds/workspace +---- ++ +NOTE: Ensure you replace the `` with your own user. It is necessary to set the folder `sechub.pds.storage.sharedvolume.upload.dir` to the same folder as configured for the <>. + +==== Run a PDS integration test + +This section demonstrate how to run an integration test for the PDS server using `DirectPDSAPICheckAliveScenario6IntTest.java` as example. +Other PDS integration tests can be run in the same way. + +. Start PDS in integration test mode using the SecHub integration test launch configuration as explained in <> + +. Select `sechub-integrationtest/src/test/java/com/mercedesbenz/sechub/integrationtest/scenario6/DirectPDSAPICheckAliveScenario6IntTest.java` in the `Project Explorer` + +. Right-click on `DirectPDSAPICheckAliveScenario6IntTest.java` to open the context menu and select `Run As` and select `JUnit Test` in the submenu. + +. Check the JUnit tab, the result should be green indicating a successful run. + +==== Run a SecHub + PDS integration test + +This section demonstrate how to run an integration test for the SecHub + PDS server using `PDSCodeScanJobScenario5IntTest.java` as example. +Other PDS integration tests can be run in the same way. + +. Start PDS and SecHub server in integration test mode using the launch configurations created in <> and <> + +. Select `sechub-integrationtest/src/test/java/com/mercedesbenz/sechub/integrationtest/scenario5/PDSCodeScanJobScenario5IntTest.java` in the `Project Explorer` + +. Right-click on `PDSCodeScanJobScenario5IntTest.java` to open the context menu and select `Run As` and select `JUnit Test` in the submenu. + +. Check the JUnit tab, the result should be green indicating a successful run. diff --git a/sechub-examples/eclipse/ProductDelegationServerApplication_(INTEGRATION_TEST-H2).launch b/sechub-examples/eclipse/ProductDelegationServerApplication_(INTEGRATION_TEST-H2).launch new file mode 100644 index 0000000000..5d5e602dd3 --- /dev/null +++ b/sechub-examples/eclipse/ProductDelegationServerApplication_(INTEGRATION_TEST-H2).launch @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/sechub-examples/eclipse/SecHubServerApplication_(INTEGRATION_TEST-H2).launch b/sechub-examples/eclipse/SecHubServerApplication_(INTEGRATION_TEST-H2).launch new file mode 100644 index 0000000000..39f60ed72b --- /dev/null +++ b/sechub-examples/eclipse/SecHubServerApplication_(INTEGRATION_TEST-H2).launch @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/sechub-examples/example-sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/java/demo/OpenAPITestTool.java b/sechub-examples/example-sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/java/demo/OpenAPITestTool.java index 8b9a82580f..82a45caf76 100644 --- a/sechub-examples/example-sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/java/demo/OpenAPITestTool.java +++ b/sechub-examples/example-sechub-api-java/src/main/java/com/mercedesbenz/sechub/api/java/demo/OpenAPITestTool.java @@ -8,6 +8,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.mercedesbenz.sechub.api.DefaultSecHubClient; import com.mercedesbenz.sechub.api.SecHubClient; import com.mercedesbenz.sechub.api.java.demo.config.ConfigurationProvider; import com.mercedesbenz.sechub.api.java.demo.playground.AdminApiPlayground; @@ -35,7 +36,7 @@ private void start(String[] args) { LOG.trace("*** Privileged user's API token: {}", "*".repeat(apiToken.length())); LOG.trace("*** trustAll: {}", trustAll); - SecHubClient client = new SecHubClient(serverUri, userName, apiToken, trustAll); + SecHubClient client = new DefaultSecHubClient(serverUri, userName, apiToken, trustAll); // simple test here testAnonymousApi(client); diff --git a/sechub-pds/src/main/resources/application.yml b/sechub-pds/src/main/resources/application.yml index 4de1b93c86..fae4b0b339 100644 --- a/sechub-pds/src/main/resources/application.yml +++ b/sechub-pds/src/main/resources/application.yml @@ -41,6 +41,9 @@ spring: jdbc.lob.non_contextual_creation: true datasource: initialization-mode: always + hikari: + minimumidle: 1 + maximumpoolsize: 2 main: # see https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.1-Release-Notes#bean-overriding allow-bean-definition-overriding: true diff --git a/sechub-systemtest/src/main/java/com/mercedesbenz/sechub/systemtest/runtime/SystemTestRuntimeContext.java b/sechub-systemtest/src/main/java/com/mercedesbenz/sechub/systemtest/runtime/SystemTestRuntimeContext.java index 6d740db00d..977ce8d8a9 100644 --- a/sechub-systemtest/src/main/java/com/mercedesbenz/sechub/systemtest/runtime/SystemTestRuntimeContext.java +++ b/sechub-systemtest/src/main/java/com/mercedesbenz/sechub/systemtest/runtime/SystemTestRuntimeContext.java @@ -17,6 +17,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.mercedesbenz.sechub.api.DefaultSecHubClient; import com.mercedesbenz.sechub.api.SecHubClient; import com.mercedesbenz.sechub.commons.model.ScanType; import com.mercedesbenz.sechub.pds.commons.core.config.PDSProductSetup; @@ -296,7 +297,7 @@ private SecHubClient createSecHubClient(AbstractSecHubDefinition secHubDefinitio String userId = getTemplateEngine().replaceSecretEnvironmentVariablesWithValues(credentials.getUserId(), getEnvironmentProvider()); String apiToken = getTemplateEngine().replaceSecretEnvironmentVariablesWithValues(credentials.getApiToken(), getEnvironmentProvider()); - client = new SecHubClient(serverUri, userId, apiToken, TRUST_ALL); + client = new DefaultSecHubClient(serverUri, userId, apiToken, TRUST_ALL); client.addListener(new ArtifactStorageSecHubClientListener(this)); LOG.info("Created SecHub client for user: '{}', apiToken: '{}'", client.getUsername(), "*".repeat(client.getSealedApiToken().length())); } catch (RuntimeException e) { diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/OwaspZapScanExecutor.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/OwaspZapScanExecutor.java deleted file mode 100644 index 27260b2657..0000000000 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/OwaspZapScanExecutor.java +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.cli; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.zaproxy.clientapi.core.ClientApi; - -import com.mercedesbenz.sechub.owaspzapwrapper.config.OwaspZapClientApiFactory; -import com.mercedesbenz.sechub.owaspzapwrapper.config.OwaspZapScanContext; -import com.mercedesbenz.sechub.owaspzapwrapper.scan.OwaspZapScan; -import com.mercedesbenz.sechub.owaspzapwrapper.util.TargetConnectionChecker; - -public class OwaspZapScanExecutor { - private static final Logger LOG = LoggerFactory.getLogger(OwaspZapScanExecutor.class); - - OwaspZapScanResolver resolver; - OwaspZapClientApiFactory clientApiFactory; - - TargetConnectionChecker connectionChecker; - - public OwaspZapScanExecutor() { - clientApiFactory = new OwaspZapClientApiFactory(); - resolver = new OwaspZapScanResolver(); - connectionChecker = new TargetConnectionChecker(); - } - - public void execute(OwaspZapScanContext scanContext) throws ZapWrapperRuntimeException { - if (scanContext.connectionCheckEnabled()) { - connectionChecker.assertApplicationIsReachable(scanContext); - } - - ClientApi clientApi = clientApiFactory.create(scanContext.getServerConfig()); - - OwaspZapScan owaspZapScan = resolver.resolveScanImplementation(scanContext, clientApi); - LOG.info("Starting Owasp Zap scan."); - owaspZapScan.scan(); - } -} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/OwaspZapScanResolver.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/OwaspZapScanResolver.java deleted file mode 100644 index f5937eedc2..0000000000 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/OwaspZapScanResolver.java +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.cli; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.zaproxy.clientapi.core.ClientApi; - -import com.mercedesbenz.sechub.owaspzapwrapper.config.OwaspZapScanContext; -import com.mercedesbenz.sechub.owaspzapwrapper.config.auth.AuthenticationType; -import com.mercedesbenz.sechub.owaspzapwrapper.scan.OwaspZapScan; -import com.mercedesbenz.sechub.owaspzapwrapper.scan.UnauthenticatedScan; -import com.mercedesbenz.sechub.owaspzapwrapper.scan.auth.HTTPBasicAuthScan; - -public class OwaspZapScanResolver { - private static final Logger LOG = LoggerFactory.getLogger(OwaspZapScanResolver.class); - - public OwaspZapScan resolveScanImplementation(OwaspZapScanContext scanContext, ClientApi clientApi) { - LOG.info("Resolve scan implementation."); - OwaspZapScan scan; - AuthenticationType authenticationType = scanContext.getAuthenticationType(); - if (authenticationType == null) { - throw new ZapWrapperRuntimeException("No matching scan type could be found.", ZapWrapperExitCode.UNSUPPORTED_CONFIGURATION); - } - - switch (authenticationType) { - case UNAUTHENTICATED: - scan = new UnauthenticatedScan(clientApi, scanContext); - LOG.info("Using unauthenticated scan"); - break; - case HTTP_BASIC_AUTHENTICATION: - scan = new HTTPBasicAuthScan(clientApi, scanContext); - LOG.info("Using http basic authentication scan"); - break; - default: - throw new ZapWrapperRuntimeException("No matching scan type could be found.", ZapWrapperExitCode.UNSUPPORTED_CONFIGURATION); - } - return scan; - } - -} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/ApiDefinitionFileProvider.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/ApiDefinitionFileProvider.java deleted file mode 100644 index f82c3e49d4..0000000000 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/ApiDefinitionFileProvider.java +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config; - -import java.io.File; -import java.nio.file.Path; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.mercedesbenz.sechub.commons.model.SecHubScanConfiguration; -import com.mercedesbenz.sechub.commons.model.SecHubSourceDataConfiguration; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperExitCode; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; - -public class ApiDefinitionFileProvider { - private static final Logger LOG = LoggerFactory.getLogger(ApiDefinitionFileProvider.class); - - /** - * - * This method takes the extracted sources folder path and the SecHub scan - * configuration (both usually provided by SecHub). It makes sure, that exactly - * one file is provided to use as file containing the API definition, since we - * currently allow only a single file. - * - * @param extractedSourcesFolderPath - * @param sechubConfig - * @return Path to API definition file or null if parameters are - * null or no data section is found - */ - public Path fetchApiDefinitionFile(String extractedSourcesFolderPath, SecHubScanConfiguration sechubConfig) { - if (extractedSourcesFolderPath == null) { - LOG.info("Extracted sources folder path env variable was not set."); - return null; - } - if (sechubConfig == null) { - LOG.info("SecHub scan configuration was not set."); - return null; - } - - if (!sechubConfig.getData().isPresent()) { - LOG.info("No data section was found. Continuing without searching for API definition."); - return null; - } - - List sourceData = sechubConfig.getData().get().getSources(); - if (sourceData.size() != 1) { - throw new ZapWrapperRuntimeException("Sources must contain exactly 1 entry.", ZapWrapperExitCode.API_DEFINITION_CONFIG_INVALID); - } - - if (!sourceData.get(0).getFileSystem().isPresent()) { - throw new ZapWrapperRuntimeException("Sources filesystem part must be set at this stage.", ZapWrapperExitCode.API_DEFINITION_CONFIG_INVALID); - } - - List files = sourceData.get(0).getFileSystem().get().getFiles(); - if (files.size() != 1) { - throw new ZapWrapperRuntimeException("Sources filesystem files part must contain exactly 1 entry.", - ZapWrapperExitCode.API_DEFINITION_CONFIG_INVALID); - } - - File result = new File(extractedSourcesFolderPath, files.get(0)); - return result.toPath(); - } - -} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/OwaspZapClientApiFactory.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/OwaspZapClientApiFactory.java deleted file mode 100644 index fc234a080a..0000000000 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/OwaspZapClientApiFactory.java +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.zaproxy.clientapi.core.ClientApi; - -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperExitCode; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; - -public class OwaspZapClientApiFactory { - private static final Logger LOG = LoggerFactory.getLogger(OwaspZapClientApiFactory.class); - - public ClientApi create(OwaspZapServerConfiguration serverConfig) { - LOG.info("Creating Owasp Zap ClientApi."); - assertValidServerConfig(serverConfig); - String zaproxyHost = serverConfig.getZaproxyHost(); - int zaproxyPort = serverConfig.getZaproxyPort(); - String zaproxyApiKey = serverConfig.getZaproxyApiKey(); - - ClientApi clientApi = new ClientApi(zaproxyHost, zaproxyPort, zaproxyApiKey); - - return clientApi; - } - - private void assertValidServerConfig(OwaspZapServerConfiguration serverConfig) { - if (serverConfig == null) { - throw new ZapWrapperRuntimeException("Owasp Zap server configuration may not be null!", ZapWrapperExitCode.PDS_CONFIGURATION_ERROR); - } - if (serverConfig.getZaproxyHost() == null) { - throw new ZapWrapperRuntimeException("Owasp Zap host configuration may not be null!", ZapWrapperExitCode.PDS_CONFIGURATION_ERROR); - } - if (serverConfig.getZaproxyPort() <= 0) { - throw new ZapWrapperRuntimeException("Owasp Zap host configuration ahs to be a valid port number!", ZapWrapperExitCode.PDS_CONFIGURATION_ERROR); - } - if (serverConfig.getZaproxyApiKey() == null) { - throw new ZapWrapperRuntimeException("Owasp Zap api-key configuration may not be null!", ZapWrapperExitCode.PDS_CONFIGURATION_ERROR); - } - } -} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/OwaspZapScanContext.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/OwaspZapScanContext.java deleted file mode 100644 index 3de09dbfc9..0000000000 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/OwaspZapScanContext.java +++ /dev/null @@ -1,329 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config; - -import java.net.URL; -import java.nio.file.Path; -import java.util.HashSet; -import java.util.Set; - -import com.mercedesbenz.sechub.commons.model.SecHubWebScanConfiguration; -import com.mercedesbenz.sechub.owaspzapwrapper.config.auth.AuthenticationType; -import com.mercedesbenz.sechub.owaspzapwrapper.config.data.DeactivatedRuleReferences; -import com.mercedesbenz.sechub.owaspzapwrapper.config.data.OwaspZapFullRuleset; -import com.mercedesbenz.sechub.owaspzapwrapper.helper.OwaspZapProductMessageHelper; - -public class OwaspZapScanContext { - private OwaspZapServerConfiguration serverConfig; - private boolean verboseOutput = false; - - private boolean ajaxSpiderEnabled; - private boolean activeScanEnabled; - - private Path reportFile; - - private String contextName; - - private URL targetUrl; - - private AuthenticationType authenticationType; - - private long maxScanDurationInMillis; - - private SecHubWebScanConfiguration secHubWebScanConfiguration; - - private ProxyInformation proxyInformation; - - private OwaspZapFullRuleset fullRuleset; - - private DeactivatedRuleReferences deactivatedRuleReferences; - - private Path apiDefinitionFile; - - // Using Set here to avoid duplicates - private Set owaspZapURLsIncludeList = new HashSet<>(); - private Set owaspZapURLsExcludeList = new HashSet<>(); - - private boolean connectionCheckEnabled; - - private int maxNumberOfConnectionRetries; - private int retryWaittimeInMilliseconds; - - private OwaspZapProductMessageHelper owaspZapProductMessageHelper; - - private OwaspZapScanContext() { - } - - public OwaspZapServerConfiguration getServerConfig() { - return serverConfig; - } - - public boolean isVerboseOutput() { - return verboseOutput; - } - - public boolean isAjaxSpiderEnabled() { - return ajaxSpiderEnabled; - } - - public boolean isActiveScanEnabled() { - return activeScanEnabled; - } - - public Path getReportFile() { - return reportFile; - } - - public String getContextName() { - return contextName; - } - - public String getTargetUrlAsString() { - return getTargetUrl().toString(); - } - - public URL getTargetUrl() { - return targetUrl; - } - - public AuthenticationType getAuthenticationType() { - return authenticationType; - } - - public long getMaxScanDurationInMillis() { - return maxScanDurationInMillis; - } - - public SecHubWebScanConfiguration getSecHubWebScanConfiguration() { - return secHubWebScanConfiguration; - } - - /** - * Resolves proxy information if available - * - * @return proxy information or null when no proxy information - * available - */ - public ProxyInformation getProxyInformation() { - return proxyInformation; - } - - public OwaspZapFullRuleset getFullRuleset() { - return fullRuleset; - } - - public DeactivatedRuleReferences getDeactivatedRuleReferences() { - return deactivatedRuleReferences; - } - - /** - * - * @return api defintion file or null if not available - */ - public Path getApiDefinitionFile() { - return apiDefinitionFile; - } - - public Set getOwaspZapURLsIncludeList() { - return owaspZapURLsIncludeList; - } - - public Set getOwaspZapURLsExcludeList() { - return owaspZapURLsExcludeList; - } - - public boolean connectionCheckEnabled() { - return connectionCheckEnabled; - } - - public int getMaxNumberOfConnectionRetries() { - return maxNumberOfConnectionRetries; - } - - public int getRetryWaittimeInMilliseconds() { - return retryWaittimeInMilliseconds; - } - - public OwaspZapProductMessageHelper getOwaspZapProductMessageHelper() { - return owaspZapProductMessageHelper; - } - - public static OwaspZapBasicScanContextBuilder builder() { - return new OwaspZapBasicScanContextBuilder(); - } - - public static class OwaspZapBasicScanContextBuilder { - private OwaspZapServerConfiguration serverConfig; - - private boolean verboseOutput = false; - - private boolean ajaxSpiderEnabled; - private boolean activeScanEnabled; - - private Path reportFile; - - private String contextName; - - private URL targetUrl; - - private AuthenticationType authenticationType; - - private long maxScanDurationInMillis; - - private SecHubWebScanConfiguration secHubWebScanConfiguration; - - private ProxyInformation proxyInformation; - - private OwaspZapFullRuleset fullRuleset; - - private DeactivatedRuleReferences deactivatedRuleReferences; - - private Path apiDefinitionFile; - - // Using Set here to avoid duplicates - private Set owaspZapURLsIncludeList = new HashSet<>(); - private Set owaspZapURLsExcludeList = new HashSet<>(); - - private boolean connectionCheckEnabled; - - private int maxNumberOfConnectionRetries; - private int setRetryWaittimeInMilliseconds; - - private OwaspZapProductMessageHelper owaspZapProductMessageHelper; - - public OwaspZapBasicScanContextBuilder setServerConfig(OwaspZapServerConfiguration serverConfig) { - this.serverConfig = serverConfig; - return this; - } - - public OwaspZapBasicScanContextBuilder setVerboseOutput(boolean verboseOutput) { - this.verboseOutput = verboseOutput; - return this; - } - - public OwaspZapBasicScanContextBuilder setAjaxSpiderEnabled(boolean ajaxSpiderEnabled) { - this.ajaxSpiderEnabled = ajaxSpiderEnabled; - return this; - } - - public OwaspZapBasicScanContextBuilder setActiveScanEnabled(boolean activeScanEnabled) { - this.activeScanEnabled = activeScanEnabled; - return this; - } - - public OwaspZapBasicScanContextBuilder setReportFile(Path reportFile) { - this.reportFile = reportFile; - return this; - } - - public OwaspZapBasicScanContextBuilder setContextName(String contextName) { - this.contextName = contextName; - return this; - } - - public OwaspZapBasicScanContextBuilder setTargetUrl(URL targetUrl) { - this.targetUrl = targetUrl; - return this; - } - - public OwaspZapBasicScanContextBuilder setAuthenticationType(AuthenticationType authenticationType) { - this.authenticationType = authenticationType; - return this; - } - - public OwaspZapBasicScanContextBuilder setMaxScanDurationInMillis(long maxScanDurationInMillis) { - this.maxScanDurationInMillis = maxScanDurationInMillis; - return this; - } - - public OwaspZapBasicScanContextBuilder setSecHubWebScanConfiguration(SecHubWebScanConfiguration secHubWebScanConfiguration) { - this.secHubWebScanConfiguration = secHubWebScanConfiguration; - return this; - } - - public OwaspZapBasicScanContextBuilder setProxyInformation(ProxyInformation proxyInformation) { - this.proxyInformation = proxyInformation; - return this; - } - - public OwaspZapBasicScanContextBuilder setFullRuleset(OwaspZapFullRuleset fullRuleset) { - this.fullRuleset = fullRuleset; - return this; - } - - public OwaspZapBasicScanContextBuilder setDeactivatedRuleReferences(DeactivatedRuleReferences deactivatedRuleReferences) { - this.deactivatedRuleReferences = deactivatedRuleReferences; - return this; - } - - public OwaspZapBasicScanContextBuilder setApiDefinitionFile(Path apiDefinitionFile) { - this.apiDefinitionFile = apiDefinitionFile; - return this; - } - - public OwaspZapBasicScanContextBuilder setOwaspZapURLsIncludeSet(Set owaspZapURLsIncludeList) { - this.owaspZapURLsIncludeList.addAll(owaspZapURLsIncludeList); - return this; - } - - public OwaspZapBasicScanContextBuilder setOwaspZapURLsExcludeSet(Set owaspZapURLsExcludeList) { - this.owaspZapURLsExcludeList.addAll(owaspZapURLsExcludeList); - return this; - } - - public OwaspZapBasicScanContextBuilder setConnectionCheckEnabled(boolean connectionCheckEnabled) { - this.connectionCheckEnabled = connectionCheckEnabled; - return this; - } - - public OwaspZapBasicScanContextBuilder setMaxNumberOfConnectionRetries(int maxNumberOfConnectionRetries) { - this.maxNumberOfConnectionRetries = maxNumberOfConnectionRetries; - return this; - } - - public OwaspZapBasicScanContextBuilder setRetryWaittimeInMilliseconds(int retryWaittimeInMilliseconds) { - this.setRetryWaittimeInMilliseconds = retryWaittimeInMilliseconds; - return this; - } - - public OwaspZapBasicScanContextBuilder setOwaspZapProductMessageHelper(OwaspZapProductMessageHelper owaspZapProductMessageHelper) { - this.owaspZapProductMessageHelper = owaspZapProductMessageHelper; - return this; - } - - public OwaspZapScanContext build() { - OwaspZapScanContext owaspZapBasicScanConfiguration = new OwaspZapScanContext(); - owaspZapBasicScanConfiguration.serverConfig = this.serverConfig; - owaspZapBasicScanConfiguration.verboseOutput = this.verboseOutput; - owaspZapBasicScanConfiguration.ajaxSpiderEnabled = this.ajaxSpiderEnabled; - owaspZapBasicScanConfiguration.activeScanEnabled = this.activeScanEnabled; - owaspZapBasicScanConfiguration.reportFile = this.reportFile; - owaspZapBasicScanConfiguration.contextName = this.contextName; - owaspZapBasicScanConfiguration.targetUrl = this.targetUrl; - owaspZapBasicScanConfiguration.authenticationType = this.authenticationType; - - owaspZapBasicScanConfiguration.maxScanDurationInMillis = this.maxScanDurationInMillis; - - owaspZapBasicScanConfiguration.secHubWebScanConfiguration = this.secHubWebScanConfiguration; - - owaspZapBasicScanConfiguration.proxyInformation = this.proxyInformation; - - owaspZapBasicScanConfiguration.fullRuleset = this.fullRuleset; - owaspZapBasicScanConfiguration.deactivatedRuleReferences = this.deactivatedRuleReferences; - - owaspZapBasicScanConfiguration.apiDefinitionFile = this.apiDefinitionFile; - - owaspZapBasicScanConfiguration.owaspZapURLsIncludeList.addAll(this.owaspZapURLsIncludeList); - owaspZapBasicScanConfiguration.owaspZapURLsExcludeList.addAll(this.owaspZapURLsExcludeList); - - owaspZapBasicScanConfiguration.connectionCheckEnabled = this.connectionCheckEnabled; - - owaspZapBasicScanConfiguration.maxNumberOfConnectionRetries = this.maxNumberOfConnectionRetries; - owaspZapBasicScanConfiguration.retryWaittimeInMilliseconds = this.setRetryWaittimeInMilliseconds; - - owaspZapBasicScanConfiguration.owaspZapProductMessageHelper = this.owaspZapProductMessageHelper; - - return owaspZapBasicScanConfiguration; - } - - } -} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/auth/SessionManagementType.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/auth/SessionManagementType.java deleted file mode 100644 index 46afb67042..0000000000 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/auth/SessionManagementType.java +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config.auth; - -/** - * Representing the different session management types available to Owasp Zap. - * Makes the OWASP ZAP API easier to use. - * - */ -public enum SessionManagementType { - - HTTP_AUTH_SESSION_MANAGEMENT("httpAuthSessionManagement"), - - COOKIE_BASED_SESSION_MANAGEMENT("cookieBasedSessionManagement"), - - SCRIPT_BASED_SESSION_MANAGEMENT("scriptBasedSessionManagement"), - - ; - - private String owaspZapSessionManagementMethod; - - private SessionManagementType(String owaspZapSessionManagementMethod) { - this.owaspZapSessionManagementMethod = owaspZapSessionManagementMethod; - } - - public String getOwaspZapSessionManagementMethod() { - return owaspZapSessionManagementMethod; - } -} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapApiResponseHelper.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapApiResponseHelper.java deleted file mode 100644 index 361e469c75..0000000000 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapApiResponseHelper.java +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.helper; - -import org.zaproxy.clientapi.core.ApiResponse; -import org.zaproxy.clientapi.core.ApiResponseElement; - -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperExitCode; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; - -public class OwaspZapApiResponseHelper { - - public String getIdOfApiRepsonse(ApiResponse response) { - if (response instanceof ApiResponseElement) { - return ((ApiResponseElement) response).getValue(); - } else { - throw new ZapWrapperRuntimeException("Parameter \"response\" is not an instance of ApiResponseElement.", - ZapWrapperExitCode.PRODUCT_EXECUTION_ERROR); - } - } -} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapEventHandler.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapEventHandler.java deleted file mode 100644 index 5b4dba2217..0000000000 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapEventHandler.java +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.helper; - -import java.io.File; - -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperExitCode; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; -import com.mercedesbenz.sechub.owaspzapwrapper.util.EnvironmentVariableConstants; -import com.mercedesbenz.sechub.owaspzapwrapper.util.EnvironmentVariableReader; - -public class OwaspZapEventHandler { - - File cancelEventFile; - - public OwaspZapEventHandler() { - this.cancelEventFile = new File(new EnvironmentVariableReader().readAsString(EnvironmentVariableConstants.PDS_JOB_EVENTS_FOLDER), - "cancel_requested.json"); - } - - public boolean isScanCancelled() { - return cancelEventFile.exists(); - } - - public void cancelScan(String scanContextName) { - if (isScanCancelled()) { - throw new ZapWrapperRuntimeException("Scan job: " + scanContextName + " was cancelled!", ZapWrapperExitCode.SCAN_JOB_CANCELLED); - } - } -} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/scan/AbstractScan.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/scan/AbstractScan.java deleted file mode 100644 index 9a7ca8de22..0000000000 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/scan/AbstractScan.java +++ /dev/null @@ -1,594 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.scan; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.List; -import java.util.Optional; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.zaproxy.clientapi.core.ApiResponse; -import org.zaproxy.clientapi.core.ApiResponseElement; -import org.zaproxy.clientapi.core.ApiResponseList; -import org.zaproxy.clientapi.core.ClientApi; -import org.zaproxy.clientapi.core.ClientApiException; - -import com.mercedesbenz.sechub.commons.model.HTTPHeaderConfiguration; -import com.mercedesbenz.sechub.commons.model.SecHubMessage; -import com.mercedesbenz.sechub.commons.model.SecHubMessageType; -import com.mercedesbenz.sechub.commons.model.SecHubWebScanApiConfiguration; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperExitCode; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; -import com.mercedesbenz.sechub.owaspzapwrapper.config.OwaspZapScanContext; -import com.mercedesbenz.sechub.owaspzapwrapper.config.ProxyInformation; -import com.mercedesbenz.sechub.owaspzapwrapper.config.data.DeactivatedRuleReferences; -import com.mercedesbenz.sechub.owaspzapwrapper.config.data.OwaspZapFullRuleset; -import com.mercedesbenz.sechub.owaspzapwrapper.config.data.Rule; -import com.mercedesbenz.sechub.owaspzapwrapper.config.data.RuleReference; -import com.mercedesbenz.sechub.owaspzapwrapper.helper.OwaspZapApiResponseHelper; -import com.mercedesbenz.sechub.owaspzapwrapper.helper.OwaspZapEventHandler; -import com.mercedesbenz.sechub.owaspzapwrapper.helper.ScanDurationHelper; -import com.mercedesbenz.sechub.owaspzapwrapper.util.UrlUtil; - -public abstract class AbstractScan implements OwaspZapScan { - private static final Logger LOG = LoggerFactory.getLogger(AbstractScan.class); - - private static final int CHECK_SCAN_STATUS_TIME_IN_MILLISECONDS = 3000; - - protected ClientApi clientApi; - protected OwaspZapScanContext scanContext; - - protected String contextId; - protected OwaspZapApiResponseHelper apiResponseHelper; - - private ScanDurationHelper scanDurationHelper; - private long remainingScanTime; - - private OwaspZapEventHandler owaspZapEventHandler; - - private UrlUtil urlUtil; - - public AbstractScan(ClientApi clientApi, OwaspZapScanContext scanContext) { - this.clientApi = clientApi; - this.scanContext = scanContext; - this.scanDurationHelper = new ScanDurationHelper(); - this.remainingScanTime = scanContext.getMaxScanDurationInMillis(); - this.apiResponseHelper = new OwaspZapApiResponseHelper(); - this.owaspZapEventHandler = new OwaspZapEventHandler(); - this.urlUtil = new UrlUtil(); - } - - @Override - public void scan() { - try { - scanUnsafe(); - } catch (ClientApiException e) { - cleanUp(); - throw new ZapWrapperRuntimeException("For scan: " + scanContext.getContextName() + ". An error occured while scanning!", e, - ZapWrapperExitCode.PRODUCT_EXECUTION_ERROR); - } - } - - /** - * Creates a new scan context. - * - * @throws ClientApiException - */ - protected void createContext() throws ClientApiException { - LOG.info("Creating context: {}", scanContext.getContextName()); - ApiResponse createContextRepsonse = clientApi.context.newContext(scanContext.getContextName()); - this.contextId = apiResponseHelper.getIdOfApiRepsonse(createContextRepsonse); - } - - /** - * Adds all included and excluded URL into scan context. - * - * @throws ClientApiException - */ - protected void addIncludedAndExcludedUrlsToContext() throws ClientApiException { - LOG.info("For scan {}: Adding include and exclude parts.", scanContext.getContextName()); - registerUrlsIncludedInContext(); - registerUrlsExcludedFromContext(); - } - - /** - * Wait for the results of the spider. Periodically checks the progress of the - * spider. - * - * @param response - * @throws ClientApiException - */ - protected void waitForSpiderResults(ApiResponse response) throws ClientApiException { - String scanId = ((ApiResponseElement) response).getValue(); - int progressSpider = 0; - - long startTime = System.currentTimeMillis(); - long maxDuration = scanDurationHelper.computeSpiderMaxScanDuration(scanContext.isActiveScanEnabled(), scanContext.isAjaxSpiderEnabled(), - remainingScanTime); - - boolean timeOut = false; - - while (progressSpider < 100 && !timeOut) { - if (owaspZapEventHandler.isScanCancelled()) { - List spiderResults = ((ApiResponseList) clientApi.spider.allUrls()).getItems(); - writeUserMessagesWithScannedURLs(spiderResults); - clientApi.spider.stop(scanId); - owaspZapEventHandler.cancelScan(scanContext.getContextName()); - } - waitForNextCheck(); - progressSpider = Integer.parseInt(((ApiResponseElement) clientApi.spider.status(scanId)).getValue()); - LOG.info("For scan {}: Spider progress {}%", scanContext.getContextName(), progressSpider); - timeOut = System.currentTimeMillis() - startTime > maxDuration; - } - /* stop spider - otherwise running in background */ - clientApi.spider.stop(scanId); - - List spiderResults = ((ApiResponseList) clientApi.spider.allUrls()).getItems(); - writeUserMessagesWithScannedURLs(spiderResults); - LOG.info("For scan {}: Spider completed.", scanContext.getContextName()); - remainingScanTime = remainingScanTime - (System.currentTimeMillis() - startTime); - } - - /** - * Wait for the results of the ajax spider. Periodically checks the progress of - * the ajax spider. - * - * @throws ClientApiException - */ - protected void waitForAjaxSpiderResults() throws ClientApiException { - String ajaxSpiderStatus = null; - - long startTime = System.currentTimeMillis(); - long maxDuration = scanDurationHelper.computeAjaxSpiderMaxScanDuration(scanContext.isActiveScanEnabled(), remainingScanTime); - - boolean timeOut = false; - - while (!isAjaxSpiderStopped(ajaxSpiderStatus) && !timeOut) { - if (owaspZapEventHandler.isScanCancelled()) { - clientApi.ajaxSpider.stop(); - owaspZapEventHandler.cancelScan(scanContext.getContextName()); - } - waitForNextCheck(); - ajaxSpiderStatus = ((ApiResponseElement) clientApi.ajaxSpider.status()).getValue(); - LOG.info("For scan {}: AjaxSpider status {}", scanContext.getContextName(), ajaxSpiderStatus); - timeOut = (System.currentTimeMillis() - startTime) > maxDuration; - } - /* stop spider - otherwise running in background */ - clientApi.ajaxSpider.stop(); - LOG.info("For scan {}: AjaxSpider completed.", scanContext.getContextName()); - remainingScanTime = remainingScanTime - (System.currentTimeMillis() - startTime); - } - - /** - * Wait for the results of the passive scan. Periodically checks the progress of - * the passive scan. - * - * @throws ClientApiException - */ - protected void passiveScan() throws ClientApiException { - LOG.info("For scan {}: Starting passive scan.", scanContext.getContextName()); - long startTime = System.currentTimeMillis(); - long maxDuration = scanDurationHelper.computePassiveScanMaxScanDuration(scanContext.isActiveScanEnabled(), scanContext.isAjaxSpiderEnabled(), - remainingScanTime); - - int numberOfRecords = Integer.parseInt(((ApiResponseElement) clientApi.pscan.recordsToScan()).getValue()); - - while (numberOfRecords > 0 || (System.currentTimeMillis() - startTime) > maxDuration) { - if (owaspZapEventHandler.isScanCancelled()) { - owaspZapEventHandler.cancelScan(scanContext.getContextName()); - } - waitForNextCheck(); - numberOfRecords = Integer.parseInt(((ApiResponseElement) clientApi.pscan.recordsToScan()).getValue()); - LOG.info("For scan {}: Passive scan number of records left for scanning: {}", scanContext.getContextName(), numberOfRecords); - } - LOG.info("For scan {}: Passive scan completed.", scanContext.getContextName()); - remainingScanTime = remainingScanTime - (System.currentTimeMillis() - startTime); - } - - /** - * Wait for the results of the active scan. Periodically checks the progress of - * the active scan. - * - * @param response - * @throws ClientApiException - */ - protected void waitForActiveScanResults(ApiResponse response) throws ClientApiException { - String scanId = ((ApiResponseElement) response).getValue(); - int progressActive = 0; - - long startTime = System.currentTimeMillis(); - long maxDuration = remainingScanTime; - boolean timeOut = false; - while (progressActive < 100 && !timeOut) { - if (owaspZapEventHandler.isScanCancelled()) { - clientApi.ascan.stop(scanId); - owaspZapEventHandler.cancelScan(scanContext.getContextName()); - } - waitForNextCheck(); - progressActive = Integer.parseInt(((ApiResponseElement) clientApi.ascan.status(scanId)).getValue()); - LOG.info("For scan {}: Active scan progress {}%", scanContext.getContextName(), progressActive); - - timeOut = (System.currentTimeMillis() - startTime) > maxDuration; - } - clientApi.ascan.stop(scanId); - LOG.info("For scan {}: Active scan completed.", scanContext.getContextName()); - } - - /** - * Generates the SARIF report for the current scan, identified using the context - * name. - * - * @throws ClientApiException - */ - protected void generateOwaspZapReport() throws ClientApiException { - LOG.info("For scan {}: Writing results to report...", scanContext.getContextName()); - Path reportFile = scanContext.getReportFile(); - - String title = scanContext.getContextName(); - String template = "sarif-json"; - String theme = null; - String description = null; - String contexts = scanContext.getContextName(); - String sites = null; - String sections = null; - String includedconfidences = null; - String includedrisks = null; - String reportfilename = reportFile.getFileName().toString(); - String reportfilenamepattern = null; - String reportdir = resolveParentDirectoryPath(reportFile); - String display = null; - /* @formatter:off */ - // we use the context name as report title - clientApi.reports.generate( - title, - template, - theme, - description, - contexts, - sites, - sections, - includedconfidences, - includedrisks, - reportfilename, - reportfilenamepattern, - reportdir, - display); - /* @formatter:on */ - - // rename is necessary if the file extension is not .json, because Owasp Zap - // adds the file extension .json since we create a json report. Might not be - // necessary anymore if we have the sarif support - renameReportFileIfFileExtensionIsNotJSON(); - - LOG.info("For scan {}: Report can be found at {}", scanContext.getContextName(), reportFile.toFile().getAbsolutePath()); - - } - - protected void cleanUp() { - // to ensure parts from previous scan are deleted - try { - LOG.info("Cleaning up by starting new and empty session...", scanContext.getContextName()); - clientApi.core.newSession("Cleaned after scan", "true"); - LOG.info("New and empty session inside Owasp Zap created."); - - // Replacer rules are persistent even after restarting OWASP ZAP - // This means we need to cleanUp after every scan. - LOG.info("Start cleaning up replacer rules."); - cleanUpReplacerRules(); - LOG.info("Cleanup successful."); - } catch (ClientApiException e) { - LOG.error("For scan: {}. An error occurred during the clean up, because: {}", scanContext.getContextName(), e.getMessage()); - } - } - - protected void setupBasicConfiguration() throws ClientApiException { - LOG.info("Creating new session inside the Owasp Zap"); - // to ensure parts from previous scan are deleted - clientApi.core.newSession(scanContext.getContextName(), "true"); - LOG.info("Setting default of how many alerts of the same rule will be inside the report to unlimited."); - // setting this value to zero means unlimited - clientApi.core.setOptionMaximumAlertInstances("0"); - - // enable all passive scanner rules by default - clientApi.pscan.enableAllScanners(); - // enable all passive scanner rules by default - // null specifies the default scan policy - clientApi.ascan.enableAllScanners(null); - - // use firefox in headless mode by default - clientApi.ajaxSpider.setOptionBrowserId("firefox-headless"); - } - - protected void setupAdditonalProxyConfiguration() throws ClientApiException { - ProxyInformation proxyInformation = scanContext.getProxyInformation(); - if (proxyInformation != null) { - String proxyHost = proxyInformation.getHost(); - int proxyPort = proxyInformation.getPort(); - LOG.info("Using proxy {}:{} to reach target.", proxyHost, proxyPort); - clientApi.network.setHttpProxy(proxyHost, "" + proxyPort, null, null, null); - clientApi.network.setHttpProxyEnabled("true"); - clientApi.network.setHttpProxyAuthEnabled("false"); - } else { - LOG.info("No proxy was set, continuing without proxy."); - clientApi.network.setHttpProxyEnabled("false"); - } - } - - protected void deactivateRules() throws ClientApiException { - OwaspZapFullRuleset fullRuleset = scanContext.getFullRuleset(); - DeactivatedRuleReferences deactivatedRuleReferences = scanContext.getDeactivatedRuleReferences(); - if (fullRuleset == null && deactivatedRuleReferences == null) { - return; - } - List rulesReferences = deactivatedRuleReferences.getDeactivatedRuleReferences(); - if (rulesReferences == null) { - return; - } - - for (RuleReference ruleRef : rulesReferences) { - Rule ruleToDeactivate = fullRuleset.findRuleByReference(ruleRef.getReference()); - if (isPassiveRule(ruleToDeactivate.getType())) { - clientApi.pscan.disableScanners(ruleToDeactivate.getId()); - } else if (isActiveRule(ruleToDeactivate.getType())) { - // null specifies the default scan policy - clientApi.ascan.disableScanners(ruleToDeactivate.getId(), null); - } - } - } - - protected void loadApiDefinitions() throws ClientApiException { - if (scanContext.getApiDefinitionFile() == null) { - LOG.info("For scan {}: No file with API definition found!", scanContext.getContextName()); - return; - } - Optional apiConfig = scanContext.getSecHubWebScanConfiguration().getApi(); - if (!apiConfig.isPresent()) { - throw new ZapWrapperRuntimeException("For scan :" + scanContext.getContextName() + " No API type was definied!", - ZapWrapperExitCode.API_DEFINITION_CONFIG_INVALID); - } - - switch (apiConfig.get().getType()) { - case OPEN_API: - clientApi.openapi.importFile(scanContext.getApiDefinitionFile().toString(), scanContext.getTargetUrlAsString(), contextId); - break; - default: - // should never happen since API type is an Enum - // Failure should happen before getting here - throw new ZapWrapperRuntimeException("For scan :" + scanContext.getContextName() + " Unknown API type was definied!", - ZapWrapperExitCode.API_DEFINITION_CONFIG_INVALID); - } - } - - /** - * This method checks if the sites tree is empty. The OWASP ZAP creates this - * sites tree while crawling and detecting pages. The method is necessary since - * the active scanner exits with an exception if the sites tree is empty, when - * starting an active scan. - * - * This can only happen in very few cases, but then we want to be able to inform - * the user and write a report which is empty or contains at least the passively - * detected results. - * - * @return - * @throws ClientApiException - */ - protected boolean atLeastOneURLDetected() throws ClientApiException { - ApiResponseList sitesList = (ApiResponseList) clientApi.core.sites(); - return sitesList.getItems().size() > 0; - } - - protected void addReplacerRulesForHeaders() throws ClientApiException { - if (scanContext.getSecHubWebScanConfiguration().getHeaders().isEmpty()) { - LOG.info("No headers were configured inside the sechub webscan configuration."); - return; - } - - // description specifies the rule name, which will be set later in this method - String description = null; - - String enabled = "true"; - // "REQ_HEADER" means the header entry will be added to the requests if not - // existing or replaced if already existing - String matchtype = "REQ_HEADER"; - String matchregex = "false"; - - // matchstring and replacement will be set to the header name and header value - String matchstring = null; - String replacement = null; - - // setting initiators to null means all initiators (ZAP components), - // this means spider, active scan, etc will send this rule for their requests. - String initiators = null; - // default URL is null which means the header would be send on any request to - // any URL - String url = null; - List httpHeaders = scanContext.getSecHubWebScanConfiguration().getHeaders().get(); - LOG.info("For scan {}: Applying header configuration.", scanContext.getContextName()); - for (HTTPHeaderConfiguration httpHeader : httpHeaders) { - matchstring = httpHeader.getName(); - replacement = httpHeader.getValue(); - - if (httpHeader.getOnlyForUrls().isEmpty()) { - // if there are no onlyForUrl patterns, there is only one rule for each header - description = httpHeader.getName(); - clientApi.replacer.addRule(description, enabled, matchtype, matchregex, matchstring, replacement, initiators, url); - } else { - for (String onlyForUrl : httpHeader.getOnlyForUrls().get()) { - // we need to create a rule for each onlyForUrl pattern on each header - description = onlyForUrl; - url = urlUtil.replaceWildCardsWithRegexInUrl(onlyForUrl); - clientApi.replacer.addRule(description, enabled, matchtype, matchregex, matchstring, replacement, initiators, url); - } - } - } - } - - private void writeUserMessagesWithScannedURLs(List spiderResults) { - for (ApiResponse result : spiderResults) { - String url = result.toString(); - if (url.contains("robots.txt") || url.contains("sitemap.xml")) { - continue; - } - scanContext.getOwaspZapProductMessageHelper().writeSingleProductMessage(new SecHubMessage(SecHubMessageType.INFO, "Detect url to scan: " + url)); - } - } - - private boolean isPassiveRule(String type) { - return "passive".equals(type.toLowerCase()); - } - - private boolean isActiveRule(String type) { - return "active".equals(type.toLowerCase()); - } - - private void scanUnsafe() throws ClientApiException { - /* OWASP ZAP setup on local machine */ - setupBasicConfiguration(); - deactivateRules(); - setupAdditonalProxyConfiguration(); - createContext(); - addReplacerRulesForHeaders(); - - /* OWASP ZAP setup with access to target */ - addIncludedAndExcludedUrlsToContext(); - loadApiDefinitions(); - - /* OWASP ZAP scan */ - if (scanContext.isAjaxSpiderEnabled()) { - runAjaxSpider(); - } - runSpider(); - passiveScan(); - if (scanContext.isActiveScanEnabled()) { - runActiveScan(); - } - - /* After scan */ - generateOwaspZapReport(); - cleanUp(); - } - - private void waitForNextCheck() { - try { - Thread.sleep(CHECK_SCAN_STATUS_TIME_IN_MILLISECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - - private boolean isAjaxSpiderStopped(String status) { - return "stopped".equals(status); - } - - private String resolveParentDirectoryPath(Path reportFile) { - if (reportFile == null) { - throw new ZapWrapperRuntimeException("For scan: " + scanContext.getContextName() + ". Report file not set.", - ZapWrapperExitCode.PDS_CONFIGURATION_ERROR); - } - if (Files.isDirectory(reportFile)) { - throw new ZapWrapperRuntimeException("For scan: " + scanContext.getContextName() + ". Report file must not be a directory!", - ZapWrapperExitCode.PDS_CONFIGURATION_ERROR); - } - - Path parent = reportFile.getParent(); - Path absolutePath = parent.toAbsolutePath(); - - return absolutePath.toString(); - } - - /** - * This method is used to rename the file back to the specified name in case the - * file did not end with .json. - * - * The reason for this method is that the Owasp Zap appends ".json" to the - * result file if we generate a report in json format. The PDS result.txt will - * then be called result.txt.json. Because of this behaviour the file will be - * renamed. - */ - private void renameReportFileIfFileExtensionIsNotJSON() { - String specifiedReportFile = scanContext.getReportFile().toAbsolutePath().toFile().getAbsolutePath(); - // If the Owasp Zap creates the file below, it will be renamed to the originally - // specified name - File owaspZapCreatedFile = new File(specifiedReportFile + ".json"); - if (owaspZapCreatedFile.exists()) { - try { - Path owaspzapReport = Paths.get(specifiedReportFile + ".json"); - Files.move(owaspzapReport, owaspzapReport.resolveSibling(scanContext.getReportFile().toAbsolutePath()), StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - throw new ZapWrapperRuntimeException("For scan: " + scanContext.getContextName() + ". An error occurred renaming the report file", e, - ZapWrapperExitCode.IO_ERROR); - } - } - } - - private void visitInclude(String url) { - try { - String followRedirects = "false"; - clientApi.core.accessUrl(url, followRedirects); - } catch (ClientApiException e) { - LOG.error("While trying to access URL {} got the error: {}", url, e.getMessage()); - } - } - - private void registerUrlsIncludedInContext() throws ClientApiException { - for (URL url : scanContext.getOwaspZapURLsIncludeList()) { - clientApi.context.includeInContext(scanContext.getContextName(), url + ".*"); - visitInclude(url.toString()); - } - } - - private void registerUrlsExcludedFromContext() throws ClientApiException { - for (URL url : scanContext.getOwaspZapURLsExcludeList()) { - clientApi.context.excludeFromContext(scanContext.getContextName(), url + ".*"); - } - } - - private void cleanUpReplacerRules() throws ClientApiException { - if (scanContext.getSecHubWebScanConfiguration().getHeaders().isEmpty()) { - return; - } - - List httpHeaders = scanContext.getSecHubWebScanConfiguration().getHeaders().get(); - for (HTTPHeaderConfiguration httpHeader : httpHeaders) { - if (httpHeader.getOnlyForUrls().isEmpty()) { - String description = httpHeader.getName(); - clientApi.replacer.removeRule(description); - } else { - for (String onlyForUrl : httpHeader.getOnlyForUrls().get()) { - String description = onlyForUrl; - clientApi.replacer.removeRule(description); - } - } - } - } - - /** - * Runs classical spider (suitable for web applications) - just parsing.... - * creates tree - * - * @throws ClientApiException - */ - protected abstract void runSpider() throws ClientApiException; - - /** - * Runs web driver oriented spider (suitable for single page applications)- just - * clicking.... creates tree - * - * @throws ClientApiException - */ - protected abstract void runAjaxSpider() throws ClientApiException; - - /** - * Attacks the target - * - * @throws ClientApiException - */ - protected abstract void runActiveScan() throws ClientApiException; - -} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/scan/OwaspZapScan.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/scan/OwaspZapScan.java deleted file mode 100644 index fe2a668467..0000000000 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/scan/OwaspZapScan.java +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.scan; - -public interface OwaspZapScan { - - void scan(); - -} \ No newline at end of file diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/scan/UnauthenticatedScan.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/scan/UnauthenticatedScan.java deleted file mode 100644 index e609185654..0000000000 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/scan/UnauthenticatedScan.java +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.scan; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.zaproxy.clientapi.core.ApiResponse; -import org.zaproxy.clientapi.core.ClientApi; -import org.zaproxy.clientapi.core.ClientApiException; - -import com.mercedesbenz.sechub.commons.model.SecHubMessage; -import com.mercedesbenz.sechub.commons.model.SecHubMessageType; -import com.mercedesbenz.sechub.owaspzapwrapper.config.OwaspZapScanContext; - -public class UnauthenticatedScan extends AbstractScan { - - private static final Logger LOG = LoggerFactory.getLogger(UnauthenticatedScan.class); - - public UnauthenticatedScan(ClientApi clientApi, OwaspZapScanContext scanContext) { - super(clientApi, scanContext); - } - - @Override - protected void runSpider() throws ClientApiException { - String contextName = scanContext.getContextName(); - String subTreeOnly = "true"; - String recurse = "true"; - String maxChildren = null; - String targetUrlAsString = scanContext.getTargetUrlAsString(); - LOG.info("For scan {}: Starting Spider.", contextName); - /* @formatter:off */ - ApiResponse responseSpider = clientApi.spider.scan( - targetUrlAsString, - maxChildren, - recurse, - contextName, - subTreeOnly); - /* @formatter:on */ - waitForSpiderResults(responseSpider); - } - - @Override - protected void runAjaxSpider() throws ClientApiException { - String inScope = "true"; - String subTreeOnly = "true"; - String contextName = scanContext.getContextName(); - String targetUrlAsString = scanContext.getTargetUrlAsString(); - LOG.info("For scan {}: Starting AjaxSpider.", scanContext.getContextName()); - /* @formatter:off */ - clientApi.ajaxSpider.scan( - targetUrlAsString, - inScope, - contextName, - subTreeOnly); - /* @formatter:on */ - waitForAjaxSpiderResults(); - } - - @Override - protected void runActiveScan() throws ClientApiException { - // Necessary otherwise the active scanner exits with an exception, - // if no URLs to scan where detected by the spider/ajaxSpider before - if (!atLeastOneURLDetected()) { - LOG.warn("For {} skipping active scan, since no URLs where detected by spider or ajaxSpider!", scanContext.getContextName()); - scanContext.getOwaspZapProductMessageHelper().writeSingleProductMessage( - new SecHubMessage(SecHubMessageType.WARNING, "Skipped the active scan, because no URLs were detected by the crawler! " - + "Please check if the URL you specified or any of the includes are accessible.")); - return; - } - String targetUrlAsString = scanContext.getTargetUrlAsString(); - String inScopeOnly = "true"; - String recurse = "true"; - String scanPolicyName = null; - String method = null; - String postData = null; - LOG.info("For scan {}: Starting ActiveScan.", scanContext.getContextName()); - /* @formatter:off */ - ApiResponse responseActive = clientApi.ascan.scan( - targetUrlAsString, - recurse, - inScopeOnly, - scanPolicyName, - method, - postData); - /* @formatter:on */ - waitForActiveScanResults(responseActive); - } -} \ No newline at end of file diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/scan/auth/AbstractAuthScan.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/scan/auth/AbstractAuthScan.java deleted file mode 100644 index b23cd16ea2..0000000000 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/scan/auth/AbstractAuthScan.java +++ /dev/null @@ -1,143 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.scan.auth; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.zaproxy.clientapi.core.ApiResponse; -import org.zaproxy.clientapi.core.ClientApi; -import org.zaproxy.clientapi.core.ClientApiException; - -import com.mercedesbenz.sechub.commons.model.SecHubMessage; -import com.mercedesbenz.sechub.commons.model.SecHubMessageType; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperExitCode; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; -import com.mercedesbenz.sechub.owaspzapwrapper.config.OwaspZapScanContext; -import com.mercedesbenz.sechub.owaspzapwrapper.scan.AbstractScan; - -public abstract class AbstractAuthScan extends AbstractScan implements AuthScan { - private static final Logger LOG = LoggerFactory.getLogger(AbstractAuthScan.class); - - protected String userId; - protected String username; - - public AbstractAuthScan(ClientApi clientApi, OwaspZapScanContext scanContext) { - super(clientApi, scanContext); - } - - @Override - public void scan() { - try { - scanUnsafe(); - } catch (ClientApiException e) { - LOG.error("For scan {}: An error occured while scanning! Reason: {}", scanContext.getContextName(), e.getMessage(), e); - throw new ZapWrapperRuntimeException("An error occurred during the scan execution", e, ZapWrapperExitCode.PRODUCT_EXECUTION_ERROR); - } - } - - @Override - protected void runSpider() throws ClientApiException { - String url = scanContext.getTargetUrlAsString(); - String maxchildren = null; - String recurse = "true"; - String subtreeonly = "true"; - LOG.info("For scan {}: Starting authenticated Spider.", scanContext.getContextName()); - /* @formatter:off */ - ApiResponse responseSpider = clientApi.spider.scanAsUser( - contextId, - userId, - url, - maxchildren, - recurse, - subtreeonly); - /* @formatter:on */ - waitForSpiderResults(responseSpider); - } - - @Override - protected void runAjaxSpider() throws ClientApiException { - String contextname = scanContext.getContextName(); - String url = scanContext.getTargetUrlAsString(); - String subtreeonly = "true"; - LOG.info("For scan {}: Starting authenticated Ajax Spider.", scanContext.getContextName()); - /* @formatter:off */ - clientApi.ajaxSpider.scanAsUser( - contextname, - username, - url, - subtreeonly); - /* @formatter:on */ - - waitForAjaxSpiderResults(); - } - - @Override - protected void runActiveScan() throws ClientApiException { - // Necessary otherwise the active scanner exits with an exception, - // if no URLs to scan where detected by the spider/ajaxSpider before - if (!atLeastOneURLDetected()) { - LOG.warn("For {} skipping active scan, since no URLs where detected by spider or ajaxSpider!", scanContext.getContextName()); - scanContext.getOwaspZapProductMessageHelper().writeSingleProductMessage( - new SecHubMessage(SecHubMessageType.WARNING, "Skipped the active scan, because no URLs were detected by the crawler! " - + "Please check if the URL you specified or any of the includes are accessible.")); - return; - } - String url = scanContext.getTargetUrlAsString(); - String recurse = "true"; - String scanpolicyname = null; - String method = null; - String postdata = null; - LOG.info("For scan {}: Starting authenticated ActiveScan.", scanContext.getContextName()); - /* @formatter:off */ - ApiResponse responseActive = clientApi.ascan.scanAsUser( - url, - contextId, - userId, - recurse, - scanpolicyname, - method, - postdata); - /* @formatter:on */ - waitForActiveScanResults(responseActive); - } - - protected String urlEncodeUTF8(String stringToEncode) { - try { - return URLEncoder.encode(stringToEncode, StandardCharsets.UTF_8.toString()); - } catch (UnsupportedEncodingException e) { - throw new IllegalStateException("This should not happen because we always use UTF-8: " + e); - } - } - - private void scanUnsafe() throws ClientApiException { - /* OWASP ZAP setup on local machine */ - setupBasicConfiguration(); - deactivateRules(); - setupAdditonalProxyConfiguration(); - createContext(); - addReplacerRulesForHeaders(); - - /* OWASP ZAP setup with access to target */ - addIncludedAndExcludedUrlsToContext(); - init(); - loadApiDefinitions(); - - /* OWASP ZAP scan */ - if (scanContext.isAjaxSpiderEnabled()) { - runAjaxSpider(); - } - runSpider(); - passiveScan(); - if (scanContext.isActiveScanEnabled()) { - runActiveScan(); - } - - /* After scan */ - generateOwaspZapReport(); - cleanUp(); - } - -} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/scan/auth/AuthScan.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/scan/auth/AuthScan.java deleted file mode 100644 index 1474c93d49..0000000000 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/scan/auth/AuthScan.java +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.scan.auth; - -import org.zaproxy.clientapi.core.ClientApiException; - -public interface AuthScan { - - public void init() throws ClientApiException; - -} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/scan/auth/HTTPBasicAuthScan.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/scan/auth/HTTPBasicAuthScan.java deleted file mode 100644 index 98b3d21015..0000000000 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/scan/auth/HTTPBasicAuthScan.java +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.scan.auth; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.zaproxy.clientapi.core.ApiResponse; -import org.zaproxy.clientapi.core.ClientApi; -import org.zaproxy.clientapi.core.ClientApiException; - -import com.mercedesbenz.sechub.commons.model.login.BasicLoginConfiguration; -import com.mercedesbenz.sechub.owaspzapwrapper.config.OwaspZapScanContext; -import com.mercedesbenz.sechub.owaspzapwrapper.config.auth.SessionManagementType; - -public class HTTPBasicAuthScan extends AbstractAuthScan { - - private BasicLoginConfiguration basicLoginConfiguration; - - private static final Logger LOG = LoggerFactory.getLogger(HTTPBasicAuthScan.class); - - public HTTPBasicAuthScan(ClientApi clientApi, OwaspZapScanContext scanContext) { - super(clientApi, scanContext); - } - - @Override - public void init() throws ClientApiException { - this.basicLoginConfiguration = this.scanContext.getSecHubWebScanConfiguration().getLogin().get().getBasic().get(); - initAuthenticationMethod(); - initScanUser(); - - } - - private void initAuthenticationMethod() throws ClientApiException { - String realm = ""; - if (basicLoginConfiguration.getRealm().isPresent()) { - realm = basicLoginConfiguration.getRealm().get(); - } - String port = Integer.toString(scanContext.getTargetUrl().getPort()); - /* @formatter:off */ - StringBuilder authMethodConfigParams = new StringBuilder(); - authMethodConfigParams.append("hostname=").append(urlEncodeUTF8(scanContext.getTargetUrl().getHost())) - .append("&realm=").append(urlEncodeUTF8(realm)) - .append("&port=").append(urlEncodeUTF8(port)); - /* @formatter:on */ - LOG.info("For scan {}: Setting authentication.", scanContext.getContextName()); - String authMethodName = scanContext.getAuthenticationType().getOwaspZapAuthenticationMethod(); - clientApi.authentication.setAuthenticationMethod(contextId, authMethodName, authMethodConfigParams.toString()); - - String methodName = SessionManagementType.HTTP_AUTH_SESSION_MANAGEMENT.getOwaspZapSessionManagementMethod(); - - // methodconfigparams in case of http basic auth is null, because it is - // configured automatically - String methodconfigparams = null; - clientApi.sessionManagement.setSessionManagementMethod(contextId, methodName, methodconfigparams); - } - - private void initScanUser() throws ClientApiException { - username = new String(basicLoginConfiguration.getUser()); - String password = new String(basicLoginConfiguration.getPassword()); - - ApiResponse creatUserResponse = clientApi.users.newUser(contextId, username); - userId = apiResponseHelper.getIdOfApiRepsonse(creatUserResponse); - - /* @formatter:off */ - StringBuilder authCredentialsConfigParams = new StringBuilder(); - authCredentialsConfigParams.append("username=").append(urlEncodeUTF8(username)) - .append("&password=").append(urlEncodeUTF8(password)); - /* @formatter:on */ - - LOG.info("For scan {}: Setting up user.", scanContext.getContextName()); - clientApi.users.setAuthenticationCredentials(contextId, userId, authCredentialsConfigParams.toString()); - String enabled = "true"; - clientApi.users.setUserEnabled(contextId, userId, enabled); - - clientApi.forcedUser.setForcedUser(contextId, userId); - clientApi.forcedUser.setForcedUserModeEnabled(true); - } -} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/CommandLineSettings.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/cli/CommandLineSettings.java similarity index 73% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/CommandLineSettings.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/cli/CommandLineSettings.java index 05522a922b..99624d951c 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/CommandLineSettings.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/cli/CommandLineSettings.java @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.cli; +package com.mercedesbenz.sechub.zapwrapper.cli; import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import com.beust.jcommander.Parameter; -import com.mercedesbenz.sechub.owaspzapwrapper.util.EnvironmentVariableConstants; -import com.mercedesbenz.sechub.owaspzapwrapper.util.FileUtilities; +import com.mercedesbenz.sechub.zapwrapper.util.EnvironmentVariableConstants; +import com.mercedesbenz.sechub.zapwrapper.util.FileUtilities; public class CommandLineSettings { @Parameter(names = { "--help" }, description = "Shows help and provides information on how to use the wrapper.", help = true) @@ -32,8 +32,7 @@ public Path getReportFile() { return reportFileAsPath.toAbsolutePath(); } - @Parameter(names = { - "--jobUUID" }, description = "The Job-UUID, which will be used as internal identifier for the Owasp Zap scan context.", required = false) + @Parameter(names = { "--jobUUID" }, description = "The Job-UUID, which will be used as internal identifier for the Zap scan context.", required = false) private String jobUUID; public String getJobUUID() { @@ -47,21 +46,21 @@ public File getSecHubConfigFile() { return FileUtilities.stringToFile(sechubConfigFile); } - @Parameter(names = { "--ajaxSpider" }, description = "Set this option to enable Owasp Zap ajaxSpider.", required = false) + @Parameter(names = { "--ajaxSpider" }, description = "Set this option to enable Zap ajaxSpider.", required = false) private boolean ajaxSpiderEnabled; public boolean isAjaxSpiderEnabled() { return ajaxSpiderEnabled; } - @Parameter(names = { "--activeScan" }, description = "Set this option to enable Owasp Zap active scan.", required = false) + @Parameter(names = { "--activeScan" }, description = "Set this option to enable Zap active scan.", required = false) private boolean activeScanEnabled; public boolean isActiveScanEnabled() { return activeScanEnabled; } - @Parameter(names = { "--zapHost" }, description = "Specifies the Owasp Zap host address. You can also set the environment variable " + @Parameter(names = { "--zapHost" }, description = "Specifies the Zap host address. You can also set the environment variable " + EnvironmentVariableConstants.ZAP_HOST_ENV_VARIABLE_NAME + ", instead of using this parameter.", required = false) private String zapHost; @@ -69,7 +68,7 @@ public String getZapHost() { return zapHost; } - @Parameter(names = { "--zapPort" }, description = "Specifies the Owasp Zap host port. You can also set the environment variable " + @Parameter(names = { "--zapPort" }, description = "Specifies the Zap host port. You can also set the environment variable " + EnvironmentVariableConstants.ZAP_PORT_ENV_VARIABLE_NAME + ", instead of using this parameter.", required = false) private int zapPort; @@ -77,7 +76,7 @@ public int getZapPort() { return zapPort; } - @Parameter(names = { "--zapApiKey" }, description = "Specifies the Owasp Zap host api key. You can also set the environment variable " + @Parameter(names = { "--zapApiKey" }, description = "Specifies the Zap host api key. You can also set the environment variable " + EnvironmentVariableConstants.ZAP_API_KEY_ENV_VARIABLE_NAME + ", instead of using this parameter.", required = false) private String zapApiKey; @@ -108,22 +107,21 @@ public int getProxyPort() { return proxyPort; } - @Parameter(names = { "--fullRulesetfile" }, description = "Specify a file with all rules installed for the Owasp Zap.", required = true) + @Parameter(names = { "--fullRulesetfile" }, description = "Specify a file with all rules installed for the Zap.", required = true) private String fullRulesetFile; public File getFullRulesetFile() { return FileUtilities.stringToFile(fullRulesetFile); } - @Parameter(names = { - "--rulesDeactivationfile" }, description = "Specify a file with rules to deactivate during the scan inside the Owasp Zap.", required = false) + @Parameter(names = { "--rulesDeactivationfile" }, description = "Specify a file with rules to deactivate during the scan inside the Zap.", required = false) private String rulesDeactvationFile; public File getRulesDeactvationFile() { return FileUtilities.stringToFile(rulesDeactvationFile); } - @Parameter(names = { "--deactivateRules" }, description = "Specify references of rules you want to deactivate during the scan inside the Owasp Zap. " + @Parameter(names = { "--deactivateRules" }, description = "Specify references of rules you want to deactivate during the scan inside the Zap. " + "If you specifiy multiple rules use comma separated values like: rule1,rule,rule3", required = false) private String deactivatedRuleReferences; @@ -157,4 +155,24 @@ public int getRetryWaittimeInMilliseconds() { } return retryWaittimeInMilliseconds; } + + @Parameter(names = { + "--pdsUserMessageFolder" }, description = "Folder where the user messages are written to. When using with SecHub+PDS solution this is not needed since the PDS provides the env variable: " + + EnvironmentVariableConstants.PDS_JOB_USER_MESSAGES_FOLDER + + ". This env variable is automatically used if this command line parameter is not set.", required = false) + private String pdsUserMessageFolder; + + public String getPDSUserMessageFolder() { + return pdsUserMessageFolder; + } + + @Parameter(names = { + "--pdsEventFolder" }, description = "Folder where the ZAP wrapper listens for events of the PDS, like cancel requests for the current job. When using with SecHub+PDS solution this is not needed since the PDS provides the env variable: " + + EnvironmentVariableConstants.PDS_JOB_EVENTS_FOLDER + + ". This env variable is automatically used if this command line parameter is not set.", required = false) + private String pdsEventFolder; + + public String getPDSEventFolder() { + return pdsEventFolder; + } } diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/cli/ZapScanExecutor.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/cli/ZapScanExecutor.java new file mode 100644 index 0000000000..076eac6fe0 --- /dev/null +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/cli/ZapScanExecutor.java @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.zapwrapper.cli; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.mercedesbenz.sechub.zapwrapper.config.ZapScanContext; +import com.mercedesbenz.sechub.zapwrapper.config.ZapScannerFactory; +import com.mercedesbenz.sechub.zapwrapper.scan.ZapScanner; +import com.mercedesbenz.sechub.zapwrapper.util.TargetConnectionChecker; + +public class ZapScanExecutor { + private static final Logger LOG = LoggerFactory.getLogger(ZapScanExecutor.class); + + ZapScannerFactory zapScannerFactory; + + TargetConnectionChecker connectionChecker; + + public ZapScanExecutor() { + zapScannerFactory = new ZapScannerFactory(); + connectionChecker = new TargetConnectionChecker(); + } + + public void execute(ZapScanContext scanContext) throws ZapWrapperRuntimeException { + if (scanContext.connectionCheckEnabled()) { + connectionChecker.assertApplicationIsReachable(scanContext); + } + + ZapScanner zapScanner = zapScannerFactory.create(scanContext); + + LOG.info("Starting Zap scan."); + zapScanner.scan(); + } +} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/OwaspZapWrapperCLI.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/cli/ZapWrapperCLI.java similarity index 54% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/OwaspZapWrapperCLI.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/cli/ZapWrapperCLI.java index 6e680b4554..40cdd9804c 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/OwaspZapWrapperCLI.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/cli/ZapWrapperCLI.java @@ -1,23 +1,23 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.cli; +package com.mercedesbenz.sechub.zapwrapper.cli; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.OwaspZapWrapperCommandLineParser.OwaspZapWrapperCommandLineParserException; -import com.mercedesbenz.sechub.owaspzapwrapper.config.OwaspZapScanContext; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperCommandLineParser.ZapWrapperCommandLineParserException; +import com.mercedesbenz.sechub.zapwrapper.config.ZapScanContext; -public class OwaspZapWrapperCLI { - private static final Logger LOG = LoggerFactory.getLogger(OwaspZapWrapperCLI.class); +public class ZapWrapperCLI { + private static final Logger LOG = LoggerFactory.getLogger(ZapWrapperCLI.class); public static void main(String[] args) throws IOException { - new OwaspZapWrapperCLI().start(args); + new ZapWrapperCLI().start(args); } private void start(String[] args) throws IOException { - OwaspZapScanContext scanContext = null; + ZapScanContext scanContext = null; try { LOG.info("Building the scan configuration."); scanContext = resolveScanContext(args); @@ -30,22 +30,22 @@ private void start(String[] args) throws IOException { } catch (ZapWrapperRuntimeException e) { LOG.error("An error occurred during the scan: {}.", e.getMessage(), e); - scanContext.getOwaspZapProductMessageHelper().writeProductError(e); + scanContext.getZapProductMessageHelper().writeProductError(e); System.exit(e.getExitCode().getExitCode()); - } catch (OwaspZapWrapperCommandLineParserException e) { + } catch (ZapWrapperCommandLineParserException e) { LOG.error("An error occurred while parsing the command line arguments: {}", e.getMessage(), e); System.exit(ZapWrapperExitCode.UNSUPPORTED_CONFIGURATION.getExitCode()); } } - private OwaspZapScanContext resolveScanContext(String[] args) throws OwaspZapWrapperCommandLineParserException { - OwaspZapWrapperCommandLineParser parser = new OwaspZapWrapperCommandLineParser(); + private ZapScanContext resolveScanContext(String[] args) throws ZapWrapperCommandLineParserException { + ZapWrapperCommandLineParser parser = new ZapWrapperCommandLineParser(); return parser.parse(args); } - private void startExecution(OwaspZapScanContext scanContext) { - OwaspZapScanExecutor scanExecutor = new OwaspZapScanExecutor(); + private void startExecution(ZapScanContext scanContext) { + ZapScanExecutor scanExecutor = new ZapScanExecutor(); scanExecutor.execute(scanContext); } } \ No newline at end of file diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/OwaspZapWrapperCommandLineParser.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/cli/ZapWrapperCommandLineParser.java similarity index 57% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/OwaspZapWrapperCommandLineParser.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/cli/ZapWrapperCommandLineParser.java index 3449bdf87c..11682fb983 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/OwaspZapWrapperCommandLineParser.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/cli/ZapWrapperCommandLineParser.java @@ -1,19 +1,19 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.cli; +package com.mercedesbenz.sechub.zapwrapper.cli; import com.beust.jcommander.JCommander; import com.beust.jcommander.ParameterException; -import com.mercedesbenz.sechub.owaspzapwrapper.config.OwaspZapScanContext; -import com.mercedesbenz.sechub.owaspzapwrapper.config.OwaspZapScanContextFactory; +import com.mercedesbenz.sechub.zapwrapper.config.ZapScanContext; +import com.mercedesbenz.sechub.zapwrapper.config.ZapScanContextFactory; -public class OwaspZapWrapperCommandLineParser { +public class ZapWrapperCommandLineParser { private JCommander commander; - public class OwaspZapWrapperCommandLineParserException extends Exception { + public class ZapWrapperCommandLineParserException extends Exception { private static final long serialVersionUID = 1L; - public OwaspZapWrapperCommandLineParserException(String message, Exception e) { + public ZapWrapperCommandLineParserException(String message, Exception e) { super(message, e); } } @@ -23,9 +23,9 @@ public OwaspZapWrapperCommandLineParserException(String message, Exception e) { * * @param args * @return configuration or null when only help wanted - * @throws OwaspZapWrapperCommandLineParserException + * @throws ZapWrapperCommandLineParserException */ - public OwaspZapScanContext parse(String... args) throws OwaspZapWrapperCommandLineParserException { + public ZapScanContext parse(String... args) throws ZapWrapperCommandLineParserException { CommandLineSettings settings = parseCommandLineParameters(args); if (settings.isHelpRequired()) { @@ -33,16 +33,16 @@ public OwaspZapScanContext parse(String... args) throws OwaspZapWrapperCommandLi return null; } - OwaspZapScanContextFactory configFactory = new OwaspZapScanContextFactory(); + ZapScanContextFactory configFactory = new ZapScanContextFactory(); return configFactory.create(settings); } - private CommandLineSettings parseCommandLineParameters(String... args) throws OwaspZapWrapperCommandLineParserException { + private CommandLineSettings parseCommandLineParameters(String... args) throws ZapWrapperCommandLineParserException { CommandLineSettings settings = new CommandLineSettings(); /* @formatter:off */ commander = JCommander.newBuilder() - .programName("OwaspZapWrapper") + .programName("ZapWrapper") .addObject(settings) .acceptUnknownOptions(false) .build(); @@ -51,7 +51,7 @@ private CommandLineSettings parseCommandLineParameters(String... args) throws Ow commander.parse(args); return settings; } catch (ParameterException e) { - throw new OwaspZapWrapperCommandLineParserException("Parsing command line parameters failed!", e); + throw new ZapWrapperCommandLineParserException("Parsing command line parameters failed!", e); } } diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/ZapWrapperExitCode.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/cli/ZapWrapperExitCode.java similarity index 92% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/ZapWrapperExitCode.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/cli/ZapWrapperExitCode.java index 36c339819e..029130e14d 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/ZapWrapperExitCode.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/cli/ZapWrapperExitCode.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.cli; +package com.mercedesbenz.sechub.zapwrapper.cli; /** * diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/ZapWrapperRuntimeException.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/cli/ZapWrapperRuntimeException.java similarity index 91% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/ZapWrapperRuntimeException.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/cli/ZapWrapperRuntimeException.java index 276c57ed40..1dea710e81 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/ZapWrapperRuntimeException.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/cli/ZapWrapperRuntimeException.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.cli; +package com.mercedesbenz.sechub.zapwrapper.cli; public class ZapWrapperRuntimeException extends RuntimeException { diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/ApiDefinitionFileProvider.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/ApiDefinitionFileProvider.java new file mode 100644 index 0000000000..9614678131 --- /dev/null +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/ApiDefinitionFileProvider.java @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.zapwrapper.config; + +import java.io.File; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.mercedesbenz.sechub.commons.model.SecHubScanConfiguration; +import com.mercedesbenz.sechub.commons.model.SecHubSourceDataConfiguration; +import com.mercedesbenz.sechub.commons.model.SecHubWebScanApiConfiguration; +import com.mercedesbenz.sechub.commons.model.SecHubWebScanConfiguration; + +public class ApiDefinitionFileProvider { + private static final Logger LOG = LoggerFactory.getLogger(ApiDefinitionFileProvider.class); + + /** + * + * This method takes the extracted sources folder path and the SecHub scan + * configuration (both usually provided by SecHub) and fetches all API + * definitions files uploaded for the current scan. + * + * @param extractedSourcesFolderPath + * @param sechubConfig + * @return Unmodifiable list of API definition files or an unmodifiable empty + * list no API definition files where found. + */ + public List fetchApiDefinitionFiles(String extractedSourcesFolderPath, SecHubScanConfiguration sechubConfig) { + + if (extractedSourcesFolderPath == null) { + LOG.info("Extracted sources folder path env variable was not set."); + return Collections.emptyList(); + } + if (!isValidWebScanConfigWithDataSection(sechubConfig)) { + return Collections.emptyList(); + } + + SecHubWebScanConfiguration secHubWebScanConfiguration = sechubConfig.getWebScan().get(); + if (secHubWebScanConfiguration.getApi().isEmpty()) { + LOG.info("No API definition was configured for the webscan. Continuing without API definition"); + return Collections.emptyList(); + } + + SecHubWebScanApiConfiguration secHubWebScanApiConfiguration = secHubWebScanConfiguration.getApi().get(); + + Set namesOfUsedDataConfigurationObjects = secHubWebScanApiConfiguration.getNamesOfUsedDataConfigurationObjects(); + List sourceData = sechubConfig.getData().get().getSources(); + + List apiFiles = new LinkedList<>(); + LOG.info("Collecting all {} definitions files.", secHubWebScanApiConfiguration.getType().name()); + for (String use : namesOfUsedDataConfigurationObjects) { + if (use == null) { + continue; + } + for (SecHubSourceDataConfiguration dataConfig : sourceData) { + // Continue if this is NOT the correct data section + if (!use.equals(dataConfig.getUniqueName())) { + continue; + } + + if (dataConfig.getFileSystem().isEmpty()) { + continue; + } + List files = dataConfig.getFileSystem().get().getFiles(); + for (String file : files) { + // Add all files to the list of API definition files + apiFiles.add(new File(extractedSourcesFolderPath, file)); + } + } + } + return Collections.unmodifiableList(apiFiles); + } + + private boolean isValidWebScanConfigWithDataSection(SecHubScanConfiguration sechubConfig) { + if (sechubConfig == null) { + LOG.info("SecHub scan configuration was not set."); + return false; + } + if (sechubConfig.getWebScan().isEmpty()) { + LOG.info("Cannot read API definition, because no webscan was configured."); + return false; + } + if (sechubConfig.getData().isEmpty()) { + LOG.info("No data section was found. Continuing without API definition."); + return false; + } + return true; + } + +} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/BrowserId.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/BrowserId.java new file mode 100644 index 0000000000..4df1ff7439 --- /dev/null +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/BrowserId.java @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.zapwrapper.config; + +public enum BrowserId { + + FIREFOX_HEADLESS("firefox-headless"), + + ; + + private String browserId; + + private BrowserId(String browserId) { + this.browserId = browserId; + } + + public String getBrowserId() { + return browserId; + } + +} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/ProxyInformation.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/ProxyInformation.java similarity index 73% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/ProxyInformation.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/ProxyInformation.java index b5f8acb88f..3bb5385675 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/ProxyInformation.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/ProxyInformation.java @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config; +package com.mercedesbenz.sechub.zapwrapper.config; public class ProxyInformation { private String host; private int port; - ProxyInformation(String host, int port) { + public ProxyInformation(String host, int port) { this.host = host; this.port = port; } diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/RuleProvider.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/RuleProvider.java similarity index 70% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/RuleProvider.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/RuleProvider.java index 8d67a8c482..4dc48c8b3f 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/RuleProvider.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/RuleProvider.java @@ -1,14 +1,14 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config; +package com.mercedesbenz.sechub.zapwrapper.config; import java.io.File; import java.io.IOException; import com.mercedesbenz.sechub.commons.TextFileReader; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperExitCode; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; -import com.mercedesbenz.sechub.owaspzapwrapper.config.data.DeactivatedRuleReferences; -import com.mercedesbenz.sechub.owaspzapwrapper.config.data.OwaspZapFullRuleset; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperExitCode; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.config.data.DeactivatedRuleReferences; +import com.mercedesbenz.sechub.zapwrapper.config.data.ZapFullRuleset; public class RuleProvider { @@ -17,11 +17,11 @@ public class RuleProvider { /** * * @param fullRulesetFile - * @return OwaspZapFullRuleset specified by file or new empty - * OwaspZapFullRuleset if file is null or does not exist + * @return ZapFullRuleset specified by file or new empty ZapFullRuleset if file + * is null or does not exist */ - public OwaspZapFullRuleset fetchFullRuleset(File fullRulesetFile) { - OwaspZapFullRuleset fullRuleset = new OwaspZapFullRuleset(); + public ZapFullRuleset fetchFullRuleset(File fullRulesetFile) { + ZapFullRuleset fullRuleset = new ZapFullRuleset(); if (fullRulesetFile == null) { return fullRuleset; } diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/SecHubScanConfigProvider.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/SecHubScanConfigProvider.java similarity index 82% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/SecHubScanConfigProvider.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/SecHubScanConfigProvider.java index 1aae1b9ed1..9c483f3959 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/SecHubScanConfigProvider.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/SecHubScanConfigProvider.java @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config; +package com.mercedesbenz.sechub.zapwrapper.config; import java.io.File; import java.io.IOException; import com.mercedesbenz.sechub.commons.TextFileReader; import com.mercedesbenz.sechub.commons.model.SecHubScanConfiguration; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperExitCode; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperExitCode; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; public class SecHubScanConfigProvider { public SecHubScanConfiguration getSecHubWebConfiguration(File secHubConfigFile) { diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/ZapScanContext.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/ZapScanContext.java new file mode 100644 index 0000000000..1717e5c4aa --- /dev/null +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/ZapScanContext.java @@ -0,0 +1,354 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.zapwrapper.config; + +import java.io.File; +import java.net.URL; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import com.mercedesbenz.sechub.commons.model.SecHubWebScanConfiguration; +import com.mercedesbenz.sechub.zapwrapper.config.auth.AuthenticationType; +import com.mercedesbenz.sechub.zapwrapper.config.data.DeactivatedRuleReferences; +import com.mercedesbenz.sechub.zapwrapper.config.data.ZapFullRuleset; +import com.mercedesbenz.sechub.zapwrapper.helper.ZapPDSEventHandler; +import com.mercedesbenz.sechub.zapwrapper.helper.ZapProductMessageHelper; + +public class ZapScanContext { + private ZapServerConfiguration serverConfig; + private boolean verboseOutput = false; + + private boolean ajaxSpiderEnabled; + private boolean activeScanEnabled; + + private Path reportFile; + + private String contextName; + + private URL targetUrl; + + private AuthenticationType authenticationType; + + private long maxScanDurationInMilliSeconds; + + private SecHubWebScanConfiguration secHubWebScanConfiguration; + + private ProxyInformation proxyInformation; + + private ZapFullRuleset fullRuleset; + + private DeactivatedRuleReferences deactivatedRuleReferences; + + private List apiDefinitionFiles = new ArrayList<>(); + + // Using Set here to avoid duplicates + private Set zapURLsIncludeSet = new HashSet<>(); + private Set zapURLsExcludeSet = new HashSet<>(); + + private boolean connectionCheckEnabled; + + private int maxNumberOfConnectionRetries; + private int retryWaittimeInMilliseconds; + + private ZapProductMessageHelper zapProductMessageHelper; + private ZapPDSEventHandler zapPDSEventHandler; + + private ZapScanContext() { + } + + public ZapServerConfiguration getServerConfig() { + return serverConfig; + } + + public boolean isVerboseOutput() { + return verboseOutput; + } + + public boolean isAjaxSpiderEnabled() { + return ajaxSpiderEnabled; + } + + public boolean isActiveScanEnabled() { + return activeScanEnabled; + } + + public Path getReportFile() { + return reportFile; + } + + public String getContextName() { + return contextName; + } + + public String getTargetUrlAsString() { + return getTargetUrl().toString(); + } + + public URL getTargetUrl() { + return targetUrl; + } + + public AuthenticationType getAuthenticationType() { + return authenticationType; + } + + public long getMaxScanDurationInMilliSeconds() { + return maxScanDurationInMilliSeconds; + } + + public SecHubWebScanConfiguration getSecHubWebScanConfiguration() { + return secHubWebScanConfiguration; + } + + /** + * Resolves proxy information if available + * + * @return proxy information or null when no proxy information + * available + */ + public ProxyInformation getProxyInformation() { + return proxyInformation; + } + + public ZapFullRuleset getFullRuleset() { + return fullRuleset; + } + + public DeactivatedRuleReferences getDeactivatedRuleReferences() { + return deactivatedRuleReferences; + } + + public List getApiDefinitionFiles() { + if (apiDefinitionFiles == null) { + return Collections.emptyList(); + } + return apiDefinitionFiles; + } + + public Set getZapURLsIncludeSet() { + if (zapURLsIncludeSet == null) { + return Collections.emptySet(); + } + return zapURLsIncludeSet; + } + + public Set getZapURLsExcludeSet() { + if (zapURLsExcludeSet == null) { + return Collections.emptySet(); + } + return zapURLsExcludeSet; + } + + public boolean connectionCheckEnabled() { + return connectionCheckEnabled; + } + + public int getMaxNumberOfConnectionRetries() { + return maxNumberOfConnectionRetries; + } + + public int getRetryWaittimeInMilliseconds() { + return retryWaittimeInMilliseconds; + } + + public ZapProductMessageHelper getZapProductMessageHelper() { + return zapProductMessageHelper; + } + + public ZapPDSEventHandler getZapPDSEventHandler() { + return zapPDSEventHandler; + } + + public static ZapBasicScanContextBuilder builder() { + return new ZapBasicScanContextBuilder(); + } + + public static class ZapBasicScanContextBuilder { + private ZapServerConfiguration serverConfig; + + private boolean verboseOutput = false; + + private boolean ajaxSpiderEnabled; + private boolean activeScanEnabled; + + private Path reportFile; + + private String contextName; + + private URL targetUrl; + + private AuthenticationType authenticationType; + + private long maxScanDurationInMilliSeconds; + + private SecHubWebScanConfiguration secHubWebScanConfiguration; + + private ProxyInformation proxyInformation; + + private ZapFullRuleset fullRuleset; + + private DeactivatedRuleReferences deactivatedRuleReferences; + + private List apiDefinitionFiles = new LinkedList<>(); + + // Using Set here to avoid duplicates + private Set zapURLsIncludeSet = new HashSet<>(); + private Set zapURLsExcludeSet = new HashSet<>(); + + private boolean connectionCheckEnabled; + + private int maxNumberOfConnectionRetries; + private int setRetryWaittimeInMilliseconds; + + private ZapProductMessageHelper zapProductMessageHelper; + + private ZapPDSEventHandler zapPDSEventHandler; + + public ZapBasicScanContextBuilder setServerConfig(ZapServerConfiguration serverConfig) { + this.serverConfig = serverConfig; + return this; + } + + public ZapBasicScanContextBuilder setVerboseOutput(boolean verboseOutput) { + this.verboseOutput = verboseOutput; + return this; + } + + public ZapBasicScanContextBuilder setAjaxSpiderEnabled(boolean ajaxSpiderEnabled) { + this.ajaxSpiderEnabled = ajaxSpiderEnabled; + return this; + } + + public ZapBasicScanContextBuilder setActiveScanEnabled(boolean activeScanEnabled) { + this.activeScanEnabled = activeScanEnabled; + return this; + } + + public ZapBasicScanContextBuilder setReportFile(Path reportFile) { + this.reportFile = reportFile; + return this; + } + + public ZapBasicScanContextBuilder setContextName(String contextName) { + this.contextName = contextName; + return this; + } + + public ZapBasicScanContextBuilder setTargetUrl(URL targetUrl) { + this.targetUrl = targetUrl; + return this; + } + + public ZapBasicScanContextBuilder setAuthenticationType(AuthenticationType authenticationType) { + this.authenticationType = authenticationType; + return this; + } + + public ZapBasicScanContextBuilder setMaxScanDurationInMilliSeconds(long maxScanDurationInMilliSeconds) { + this.maxScanDurationInMilliSeconds = maxScanDurationInMilliSeconds; + return this; + } + + public ZapBasicScanContextBuilder setSecHubWebScanConfiguration(SecHubWebScanConfiguration secHubWebScanConfiguration) { + this.secHubWebScanConfiguration = secHubWebScanConfiguration; + return this; + } + + public ZapBasicScanContextBuilder setProxyInformation(ProxyInformation proxyInformation) { + this.proxyInformation = proxyInformation; + return this; + } + + public ZapBasicScanContextBuilder setFullRuleset(ZapFullRuleset fullRuleset) { + this.fullRuleset = fullRuleset; + return this; + } + + public ZapBasicScanContextBuilder setDeactivatedRuleReferences(DeactivatedRuleReferences deactivatedRuleReferences) { + this.deactivatedRuleReferences = deactivatedRuleReferences; + return this; + } + + public ZapBasicScanContextBuilder addApiDefinitionFiles(List apiDefinitionFiles) { + this.apiDefinitionFiles.addAll(apiDefinitionFiles); + return this; + } + + public ZapBasicScanContextBuilder addZapURLsIncludeSet(Set zapURLsIncludeList) { + this.zapURLsIncludeSet.addAll(zapURLsIncludeList); + return this; + } + + public ZapBasicScanContextBuilder addZapURLsExcludeSet(Set zapURLsExcludeList) { + this.zapURLsExcludeSet.addAll(zapURLsExcludeList); + return this; + } + + public ZapBasicScanContextBuilder setConnectionCheckEnabled(boolean connectionCheckEnabled) { + this.connectionCheckEnabled = connectionCheckEnabled; + return this; + } + + public ZapBasicScanContextBuilder setMaxNumberOfConnectionRetries(int maxNumberOfConnectionRetries) { + this.maxNumberOfConnectionRetries = maxNumberOfConnectionRetries; + return this; + } + + public ZapBasicScanContextBuilder setRetryWaittimeInMilliseconds(int retryWaittimeInMilliseconds) { + this.setRetryWaittimeInMilliseconds = retryWaittimeInMilliseconds; + return this; + } + + public ZapBasicScanContextBuilder setZapProductMessageHelper(ZapProductMessageHelper zapProductMessageHelper) { + this.zapProductMessageHelper = zapProductMessageHelper; + return this; + } + + public ZapBasicScanContextBuilder setZapPDSEventHandler(ZapPDSEventHandler zapPDSEventHandler) { + this.zapPDSEventHandler = zapPDSEventHandler; + return this; + } + + public ZapScanContext build() { + ZapScanContext zapBasicScanConfiguration = new ZapScanContext(); + zapBasicScanConfiguration.serverConfig = this.serverConfig; + zapBasicScanConfiguration.verboseOutput = this.verboseOutput; + zapBasicScanConfiguration.ajaxSpiderEnabled = this.ajaxSpiderEnabled; + zapBasicScanConfiguration.activeScanEnabled = this.activeScanEnabled; + zapBasicScanConfiguration.reportFile = this.reportFile; + zapBasicScanConfiguration.contextName = this.contextName; + zapBasicScanConfiguration.targetUrl = this.targetUrl; + zapBasicScanConfiguration.authenticationType = this.authenticationType; + + zapBasicScanConfiguration.maxScanDurationInMilliSeconds = this.maxScanDurationInMilliSeconds; + + zapBasicScanConfiguration.secHubWebScanConfiguration = this.secHubWebScanConfiguration; + + zapBasicScanConfiguration.proxyInformation = this.proxyInformation; + + zapBasicScanConfiguration.fullRuleset = this.fullRuleset; + zapBasicScanConfiguration.deactivatedRuleReferences = this.deactivatedRuleReferences; + + zapBasicScanConfiguration.apiDefinitionFiles = this.apiDefinitionFiles; + + zapBasicScanConfiguration.zapURLsIncludeSet.addAll(this.zapURLsIncludeSet); + zapBasicScanConfiguration.zapURLsExcludeSet.addAll(this.zapURLsExcludeSet); + + zapBasicScanConfiguration.connectionCheckEnabled = this.connectionCheckEnabled; + + zapBasicScanConfiguration.maxNumberOfConnectionRetries = this.maxNumberOfConnectionRetries; + zapBasicScanConfiguration.retryWaittimeInMilliseconds = this.setRetryWaittimeInMilliseconds; + + zapBasicScanConfiguration.zapProductMessageHelper = this.zapProductMessageHelper; + + zapBasicScanConfiguration.zapPDSEventHandler = this.zapPDSEventHandler; + + return zapBasicScanConfiguration; + } + + } +} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/OwaspZapScanContextFactory.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/ZapScanContextFactory.java similarity index 64% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/OwaspZapScanContextFactory.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/ZapScanContextFactory.java index 4f15c0ef45..cf2a8c7234 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/OwaspZapScanContextFactory.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/ZapScanContextFactory.java @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config; +package com.mercedesbenz.sechub.zapwrapper.config; +import java.io.File; import java.net.URL; -import java.nio.file.Path; import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -15,23 +15,24 @@ import com.mercedesbenz.sechub.commons.model.SecHubMessage; import com.mercedesbenz.sechub.commons.model.SecHubScanConfiguration; import com.mercedesbenz.sechub.commons.model.SecHubWebScanConfiguration; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.CommandLineSettings; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperExitCode; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; -import com.mercedesbenz.sechub.owaspzapwrapper.config.auth.AuthenticationType; -import com.mercedesbenz.sechub.owaspzapwrapper.config.data.DeactivatedRuleReferences; -import com.mercedesbenz.sechub.owaspzapwrapper.config.data.OwaspZapFullRuleset; -import com.mercedesbenz.sechub.owaspzapwrapper.config.data.RuleReference; -import com.mercedesbenz.sechub.owaspzapwrapper.helper.BaseTargetUriFactory; -import com.mercedesbenz.sechub.owaspzapwrapper.helper.IncludeExcludeToOwaspZapURLHelper; -import com.mercedesbenz.sechub.owaspzapwrapper.helper.OwaspZapProductMessageHelper; -import com.mercedesbenz.sechub.owaspzapwrapper.helper.OwaspZapURLType; -import com.mercedesbenz.sechub.owaspzapwrapper.helper.SecHubWebScanConfigurationHelper; -import com.mercedesbenz.sechub.owaspzapwrapper.util.EnvironmentVariableConstants; -import com.mercedesbenz.sechub.owaspzapwrapper.util.EnvironmentVariableReader; - -public class OwaspZapScanContextFactory { - private static final Logger LOG = LoggerFactory.getLogger(OwaspZapScanContextFactory.class); +import com.mercedesbenz.sechub.zapwrapper.cli.CommandLineSettings; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperExitCode; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.config.auth.AuthenticationType; +import com.mercedesbenz.sechub.zapwrapper.config.data.DeactivatedRuleReferences; +import com.mercedesbenz.sechub.zapwrapper.config.data.RuleReference; +import com.mercedesbenz.sechub.zapwrapper.config.data.ZapFullRuleset; +import com.mercedesbenz.sechub.zapwrapper.helper.BaseTargetUriFactory; +import com.mercedesbenz.sechub.zapwrapper.helper.IncludeExcludeToZapURLHelper; +import com.mercedesbenz.sechub.zapwrapper.helper.SecHubWebScanConfigurationHelper; +import com.mercedesbenz.sechub.zapwrapper.helper.ZapPDSEventHandler; +import com.mercedesbenz.sechub.zapwrapper.helper.ZapProductMessageHelper; +import com.mercedesbenz.sechub.zapwrapper.helper.ZapURLType; +import com.mercedesbenz.sechub.zapwrapper.util.EnvironmentVariableConstants; +import com.mercedesbenz.sechub.zapwrapper.util.EnvironmentVariableReader; + +public class ZapScanContextFactory { + private static final Logger LOG = LoggerFactory.getLogger(ZapScanContextFactory.class); SecHubWebScanConfigurationHelper sechubWebConfigHelper; EnvironmentVariableReader environmentVariableReader; @@ -39,24 +40,24 @@ public class OwaspZapScanContextFactory { RuleProvider ruleProvider; ApiDefinitionFileProvider apiDefinitionFileProvider; SecHubScanConfigProvider secHubScanConfigProvider; - IncludeExcludeToOwaspZapURLHelper includeExcludeToOwaspZapURLHelper; + IncludeExcludeToZapURLHelper includeExcludeToZapURLHelper; - public OwaspZapScanContextFactory() { + public ZapScanContextFactory() { sechubWebConfigHelper = new SecHubWebScanConfigurationHelper(); environmentVariableReader = new EnvironmentVariableReader(); targetUriFactory = new BaseTargetUriFactory(); ruleProvider = new RuleProvider(); apiDefinitionFileProvider = new ApiDefinitionFileProvider(); secHubScanConfigProvider = new SecHubScanConfigProvider(); - includeExcludeToOwaspZapURLHelper = new IncludeExcludeToOwaspZapURLHelper(); + includeExcludeToZapURLHelper = new IncludeExcludeToZapURLHelper(); } - public OwaspZapScanContext create(CommandLineSettings settings) { + public ZapScanContext create(CommandLineSettings settings) { if (settings == null) { throw new ZapWrapperRuntimeException("Command line settings must not be null!", ZapWrapperExitCode.UNSUPPORTED_CONFIGURATION); } - /* Owasp Zap rule setup */ - OwaspZapFullRuleset fullRuleset = ruleProvider.fetchFullRuleset(settings.getFullRulesetFile()); + /* Zap rule setup */ + ZapFullRuleset fullRuleset = ruleProvider.fetchFullRuleset(settings.getFullRulesetFile()); DeactivatedRuleReferences deactivatedRuleReferences = createDeactivatedRuleReferencesFromSettingsOrEnv(settings); DeactivatedRuleReferences ruleReferencesFromFile = ruleProvider.fetchDeactivatedRuleReferences(settings.getRulesDeactvationFile()); @@ -65,7 +66,7 @@ public OwaspZapScanContext create(CommandLineSettings settings) { } /* Wrapper settings */ - OwaspZapServerConfiguration serverConfig = createOwaspZapServerConfig(settings); + ZapServerConfiguration serverConfig = createZapServerConfig(settings); ProxyInformation proxyInformation = createProxyInformation(settings); /* SecHub settings */ @@ -77,9 +78,9 @@ public OwaspZapScanContext create(CommandLineSettings settings) { AuthenticationType authType = sechubWebConfigHelper.determineAuthenticationType(sechubWebConfig); - Path apiDefinitionFile = createPathToApiDefinitionFileOrNull(sechubScanConfig); + List apiDefinitionFiles = fetchApiDefinitionFiles(sechubScanConfig); - /* we always use the SecHub job UUID as OWASP Zap context name */ + /* we always use the SecHub job UUID as Zap context name */ String contextName = settings.getJobUUID(); if (contextName == null) { contextName = UUID.randomUUID().toString(); @@ -90,16 +91,13 @@ public OwaspZapScanContext create(CommandLineSettings settings) { Set includeSet = createUrlsIncludedInContext(targetUrl, sechubWebConfig, userMessages); Set excludeSet = createUrlsExcludedFromContext(targetUrl, sechubWebConfig, userMessages); - String userMessagesFolder = environmentVariableReader.readAsString(EnvironmentVariableConstants.PDS_JOB_USER_MESSAGES_FOLDER); - if (userMessagesFolder == null) { - throw new IllegalStateException( - "PDS configuration invalid. Cannot send user messages, because environment variable PDS_JOB_USER_MESSAGES_FOLDER is not set."); - } - OwaspZapProductMessageHelper productMessagehelper = new OwaspZapProductMessageHelper(userMessagesFolder); + ZapProductMessageHelper productMessagehelper = createZapProductMessageHelper(settings); + ZapPDSEventHandler zapEventHandler = createZapEventhandler(settings); + checkForIncludeExcludeErrors(userMessages, productMessagehelper); /* @formatter:off */ - OwaspZapScanContext scanContext = OwaspZapScanContext.builder() + ZapScanContext scanContext = ZapScanContext.builder() .setTargetUrl(targetUrl) .setVerboseOutput(settings.isVerboseEnabled()) .setReportFile(settings.getReportFile()) @@ -108,18 +106,19 @@ public OwaspZapScanContext create(CommandLineSettings settings) { .setActiveScanEnabled(settings.isActiveScanEnabled()) .setServerConfig(serverConfig) .setAuthenticationType(authType) - .setMaxScanDurationInMillis(maxScanDurationInMillis) + .setMaxScanDurationInMilliSeconds(maxScanDurationInMillis) .setSecHubWebScanConfiguration(sechubWebConfig) .setProxyInformation(proxyInformation) .setFullRuleset(fullRuleset) .setDeactivatedRuleReferences(deactivatedRuleReferences) - .setApiDefinitionFile(apiDefinitionFile) - .setOwaspZapURLsIncludeSet(includeSet) - .setOwaspZapURLsExcludeSet(excludeSet) + .addApiDefinitionFiles(apiDefinitionFiles) + .addZapURLsIncludeSet(includeSet) + .addZapURLsExcludeSet(excludeSet) .setConnectionCheckEnabled(settings.isConnectionCheckEnabled()) .setMaxNumberOfConnectionRetries(settings.getMaxNumberOfConnectionRetries()) .setRetryWaittimeInMilliseconds(settings.getRetryWaittimeInMilliseconds()) - .setOwaspZapProductMessageHelper(productMessagehelper) + .setZapProductMessageHelper(productMessagehelper) + .setZapPDSEventHandler(zapEventHandler) .build(); /* @formatter:on */ return scanContext; @@ -155,7 +154,7 @@ private DeactivatedRuleReferences createDeactivatedRuleReferencesFromSettingsOrE return deactivatedRuleReferences; } - private OwaspZapServerConfiguration createOwaspZapServerConfig(CommandLineSettings settings) { + private ZapServerConfiguration createZapServerConfig(CommandLineSettings settings) { String zapHost = settings.getZapHost(); int zapPort = settings.getZapPort(); String zapApiKey = settings.getZapApiKey(); @@ -171,19 +170,19 @@ private OwaspZapServerConfiguration createOwaspZapServerConfig(CommandLineSettin } if (zapHost == null) { - throw new ZapWrapperRuntimeException("Owasp Zap host is null. Please set the Owasp Zap host to the host use by the Owasp Zap.", + throw new ZapWrapperRuntimeException("Zap host is null. Please set the Zap host to the host use by the Zap.", ZapWrapperExitCode.PDS_CONFIGURATION_ERROR); } if (zapPort <= 0) { - throw new ZapWrapperRuntimeException("Owasp Zap Port was set to " + zapPort + ". Please set the Owasp Zap port to the port used by the Owasp Zap.", + throw new ZapWrapperRuntimeException("Zap Port was set to " + zapPort + ". Please set the Zap port to the port used by the Zap.", ZapWrapperExitCode.PDS_CONFIGURATION_ERROR); } if (zapApiKey == null) { - throw new ZapWrapperRuntimeException("Owasp Zap API-Key is null. Please set the Owasp Zap API-key to the same value set inside your Owasp Zap.", + throw new ZapWrapperRuntimeException("Zap API-Key is null. Please set the Zap API-key to the same value set inside your Zap.", ZapWrapperExitCode.PDS_CONFIGURATION_ERROR); } - return new OwaspZapServerConfiguration(zapHost, zapPort, zapApiKey); + return new ZapServerConfiguration(zapHost, zapPort, zapApiKey); } private ProxyInformation createProxyInformation(CommandLineSettings settings) { @@ -211,19 +210,18 @@ private SecHubWebScanConfiguration getSecHubWebConfiguration(SecHubScanConfigura return sechubConfig.getWebScan().get(); } - private Path createPathToApiDefinitionFileOrNull(SecHubScanConfiguration sechubScanConfig) { + private List fetchApiDefinitionFiles(SecHubScanConfiguration sechubScanConfig) { // use the extracted sources folder path, where all text files are uploaded and // extracted String extractedSourcesFolderPath = environmentVariableReader.readAsString(EnvironmentVariableConstants.PDS_JOB_EXTRACTED_SOURCES_FOLDER); - return apiDefinitionFileProvider.fetchApiDefinitionFile(extractedSourcesFolderPath, sechubScanConfig); + return apiDefinitionFileProvider.fetchApiDefinitionFiles(extractedSourcesFolderPath, sechubScanConfig); } private Set createUrlsIncludedInContext(URL targetUrl, SecHubWebScanConfiguration sechubWebConfig, List userMessages) { Set includeSet = new HashSet<>(); includeSet.add(targetUrl); if (sechubWebConfig.getIncludes().isPresent()) { - includeSet.addAll( - includeExcludeToOwaspZapURLHelper.createListOfUrls(OwaspZapURLType.INCLUDE, targetUrl, sechubWebConfig.getIncludes().get(), userMessages)); + includeSet.addAll(includeExcludeToZapURLHelper.createListOfUrls(ZapURLType.INCLUDE, targetUrl, sechubWebConfig.getIncludes().get(), userMessages)); } return includeSet; } @@ -231,13 +229,37 @@ private Set createUrlsIncludedInContext(URL targetUrl, SecHubWebScanConfigu private Set createUrlsExcludedFromContext(URL targetUrl, SecHubWebScanConfiguration sechubWebConfig, List userMessages) { Set excludeSet = new HashSet<>(); if (sechubWebConfig.getExcludes().isPresent()) { - excludeSet.addAll( - includeExcludeToOwaspZapURLHelper.createListOfUrls(OwaspZapURLType.EXCLUDE, targetUrl, sechubWebConfig.getExcludes().get(), userMessages)); + excludeSet.addAll(includeExcludeToZapURLHelper.createListOfUrls(ZapURLType.EXCLUDE, targetUrl, sechubWebConfig.getExcludes().get(), userMessages)); } return excludeSet; } - private void checkForIncludeExcludeErrors(List userMessages, OwaspZapProductMessageHelper productMessageHelper) { + private ZapProductMessageHelper createZapProductMessageHelper(CommandLineSettings settings) { + String userMessagesFolder = settings.getPDSUserMessageFolder(); + if (userMessagesFolder == null) { + userMessagesFolder = environmentVariableReader.readAsString(EnvironmentVariableConstants.PDS_JOB_USER_MESSAGES_FOLDER); + } + if (userMessagesFolder == null) { + throw new ZapWrapperRuntimeException("PDS configuration invalid. Cannot send user messages, because environment variable " + + EnvironmentVariableConstants.PDS_JOB_USER_MESSAGES_FOLDER + " is not set.", ZapWrapperExitCode.PDS_CONFIGURATION_ERROR); + } + return new ZapProductMessageHelper(userMessagesFolder); + } + + private ZapPDSEventHandler createZapEventhandler(CommandLineSettings settings) { + String pdsJobEventsFolder = settings.getPDSEventFolder(); + if (pdsJobEventsFolder == null) { + pdsJobEventsFolder = environmentVariableReader.readAsString(EnvironmentVariableConstants.PDS_JOB_EVENTS_FOLDER); + } + + if (pdsJobEventsFolder == null) { + throw new ZapWrapperRuntimeException("PDS configuration invalid. Cannot send check for job events, because environment variable " + + EnvironmentVariableConstants.PDS_JOB_EVENTS_FOLDER + " is not set.", ZapWrapperExitCode.PDS_CONFIGURATION_ERROR); + } + return new ZapPDSEventHandler(pdsJobEventsFolder); + } + + private void checkForIncludeExcludeErrors(List userMessages, ZapProductMessageHelper productMessageHelper) { if (userMessages == null) { return; } diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/ZapScannerFactory.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/ZapScannerFactory.java new file mode 100644 index 0000000000..568f0ac176 --- /dev/null +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/ZapScannerFactory.java @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.zapwrapper.config; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.zaproxy.clientapi.core.ClientApi; + +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperExitCode; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.internal.scan.ClientApiFacade; +import com.mercedesbenz.sechub.zapwrapper.scan.ZapScanner; + +public class ZapScannerFactory { + private static final Logger LOG = LoggerFactory.getLogger(ZapScannerFactory.class); + + public ZapScanner create(ZapScanContext scanContext) { + if (scanContext == null) { + throw new ZapWrapperRuntimeException("Zap scan configuration may not be null!", ZapWrapperExitCode.UNSUPPORTED_CONFIGURATION); + } + + LOG.info("Creating Zap ClientApi."); + ZapServerConfiguration serverConfig = scanContext.getServerConfig(); + assertValidServerConfig(serverConfig); + String zaproxyHost = serverConfig.getZaproxyHost(); + int zaproxyPort = serverConfig.getZaproxyPort(); + String zaproxyApiKey = serverConfig.getZaproxyApiKey(); + + ClientApi clientApi = new ClientApi(zaproxyHost, zaproxyPort, zaproxyApiKey); + ClientApiFacade clientApiFacade = new ClientApiFacade(clientApi); + + return ZapScanner.from(clientApiFacade, scanContext); + } + + private void assertValidServerConfig(ZapServerConfiguration serverConfig) { + if (serverConfig == null) { + throw new ZapWrapperRuntimeException("Zap server configuration may not be null!", ZapWrapperExitCode.PDS_CONFIGURATION_ERROR); + } + if (serverConfig.getZaproxyHost() == null) { + throw new ZapWrapperRuntimeException("Zap host configuration may not be null!", ZapWrapperExitCode.PDS_CONFIGURATION_ERROR); + } + if (serverConfig.getZaproxyPort() <= 0) { + throw new ZapWrapperRuntimeException("Zap host configuration ahs to be a valid port number!", ZapWrapperExitCode.PDS_CONFIGURATION_ERROR); + } + if (serverConfig.getZaproxyApiKey() == null) { + throw new ZapWrapperRuntimeException("Zap api-key configuration may not be null!", ZapWrapperExitCode.PDS_CONFIGURATION_ERROR); + } + } +} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/OwaspZapServerConfiguration.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/ZapServerConfiguration.java similarity index 71% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/OwaspZapServerConfiguration.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/ZapServerConfiguration.java index ea8539c2b7..fd4d27bf23 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/OwaspZapServerConfiguration.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/ZapServerConfiguration.java @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config; +package com.mercedesbenz.sechub.zapwrapper.config; -public class OwaspZapServerConfiguration { +public class ZapServerConfiguration { private String zaproxyAddress; private int zaproxyPort; private String zaproxyApiKey; - OwaspZapServerConfiguration(String zaproxyAddress, int zaproxyPort, String zaproxyApiKey) { + ZapServerConfiguration(String zaproxyAddress, int zaproxyPort, String zaproxyApiKey) { this.zaproxyAddress = zaproxyAddress; this.zaproxyPort = zaproxyPort; this.zaproxyApiKey = zaproxyApiKey; diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/auth/AuthenticationType.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/auth/AuthenticationType.java similarity index 65% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/auth/AuthenticationType.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/auth/AuthenticationType.java index 1180836b9f..1cede08ea5 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/auth/AuthenticationType.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/auth/AuthenticationType.java @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config.auth; +package com.mercedesbenz.sechub.zapwrapper.config.auth; /** - * Representing the different authentication types available to Owasp Zap. Makes - * the Owasp Zap API easier to use. + * Representing the different authentication types available to Zap. Makes the + * Zap API easier to use. * */ public enum AuthenticationType { @@ -20,10 +20,10 @@ public enum AuthenticationType { ; - private String owaspZapAuthenticationMethod; + private String zapAuthenticationMethod; private AuthenticationType(String methodName) { - this.owaspZapAuthenticationMethod = methodName; + this.zapAuthenticationMethod = methodName; } /** @@ -31,7 +31,7 @@ private AuthenticationType(String methodName) { * @return authentication method name or null in case of * {@link #UNAUTHENTICATED} */ - public String getOwaspZapAuthenticationMethod() { - return owaspZapAuthenticationMethod; + public String getZapAuthenticationMethod() { + return zapAuthenticationMethod; } } diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/auth/SessionManagementType.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/auth/SessionManagementType.java new file mode 100644 index 0000000000..e5f11ae28e --- /dev/null +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/auth/SessionManagementType.java @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.zapwrapper.config.auth; + +/** + * Representing the different session management types available to Zap. Makes + * the ZAP API easier to use. + * + */ +public enum SessionManagementType { + + HTTP_AUTH_SESSION_MANAGEMENT("httpAuthSessionManagement"), + + COOKIE_BASED_SESSION_MANAGEMENT("cookieBasedSessionManagement"), + + SCRIPT_BASED_SESSION_MANAGEMENT("scriptBasedSessionManagement"), + + ; + + private String zapSessionManagementMethod; + + private SessionManagementType(String zapSessionManagementMethod) { + this.zapSessionManagementMethod = zapSessionManagementMethod; + } + + public String getZapSessionManagementMethod() { + return zapSessionManagementMethod; + } +} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/data/DeactivatedRuleReferences.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/data/DeactivatedRuleReferences.java similarity index 94% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/data/DeactivatedRuleReferences.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/data/DeactivatedRuleReferences.java index 75ab40b209..27fbaea855 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/data/DeactivatedRuleReferences.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/data/DeactivatedRuleReferences.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config.data; +package com.mercedesbenz.sechub.zapwrapper.config.data; import java.util.Collections; import java.util.LinkedList; diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/data/Rule.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/data/Rule.java similarity index 91% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/data/Rule.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/data/Rule.java index b6a57958ed..6c35739639 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/data/Rule.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/data/Rule.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config.data; +package com.mercedesbenz.sechub.zapwrapper.config.data; public class Rule { diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/data/RuleReference.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/data/RuleReference.java similarity index 90% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/data/RuleReference.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/data/RuleReference.java index 4719dbd661..8aeccb5531 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/data/RuleReference.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/data/RuleReference.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config.data; +package com.mercedesbenz.sechub.zapwrapper.config.data; public class RuleReference { diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/data/OwaspZapFullRuleset.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/data/ZapFullRuleset.java similarity index 84% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/data/OwaspZapFullRuleset.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/data/ZapFullRuleset.java index 1c1791b415..6920f5c2d4 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/config/data/OwaspZapFullRuleset.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/config/data/ZapFullRuleset.java @@ -1,21 +1,21 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config.data; +package com.mercedesbenz.sechub.zapwrapper.config.data; import java.util.Collections; import java.util.HashMap; import java.util.Map; import com.mercedesbenz.sechub.commons.model.JSONable; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperExitCode; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperExitCode; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; -public class OwaspZapFullRuleset implements JSONable { +public class ZapFullRuleset implements JSONable { private String timestamp; private String origin; private Map rules; - public OwaspZapFullRuleset() { + public ZapFullRuleset() { this.rules = new HashMap<>(); } @@ -73,8 +73,8 @@ public Rule findRuleByReference(String reference) { } @Override - public Class getJSONTargetClass() { - return OwaspZapFullRuleset.class; + public Class getJSONTargetClass() { + return ZapFullRuleset.class; } } diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/BaseTargetUriFactory.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/BaseTargetUriFactory.java similarity index 92% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/BaseTargetUriFactory.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/BaseTargetUriFactory.java index bd8f69917e..be0b9151ff 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/BaseTargetUriFactory.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/BaseTargetUriFactory.java @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.helper; +package com.mercedesbenz.sechub.zapwrapper.helper; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperExitCode; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperExitCode; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; public class BaseTargetUriFactory { diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/IncludeExcludeToOwaspZapURLHelper.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/IncludeExcludeToZapURLHelper.java similarity index 56% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/IncludeExcludeToOwaspZapURLHelper.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/IncludeExcludeToZapURLHelper.java index 9b3435eef8..8f9e6dcaef 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/IncludeExcludeToOwaspZapURLHelper.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/IncludeExcludeToZapURLHelper.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.helper; +package com.mercedesbenz.sechub.zapwrapper.helper; import java.net.MalformedURLException; import java.net.URL; @@ -9,17 +9,36 @@ import com.mercedesbenz.sechub.commons.model.SecHubMessage; import com.mercedesbenz.sechub.commons.model.SecHubMessageType; -public class IncludeExcludeToOwaspZapURLHelper { +public class IncludeExcludeToZapURLHelper { - public List createListOfUrls(OwaspZapURLType urlType, URL targetUrl, List subSites, List userMessages) { + /** + * Combine the targetUrl with all list of subSites.
+ *
+ * E.g. for the targetUrl http://localhost:8000 and the sub sites ["/api/v1/", + * "admin/profile"], results in ["http://localhost:8000/api/v1", + * "http://localhost:8000/admin/profile"]. + * + * @param urlType + * @param targetUrl + * @param subSites + * @param userMessages + * @return a list of full URLs + */ + public List createListOfUrls(ZapURLType urlType, URL targetUrl, List subSites, List userMessages) { if (subSites == null) { return new LinkedList(); } + String targetUrlAsString = targetUrl.toString(); List listOfUrls = new LinkedList<>(); for (String subSite : subSites) { StringBuilder urlBuilder = new StringBuilder(); - urlBuilder.append(targetUrl); + + if (targetUrlAsString.endsWith("/")) { + urlBuilder.append(targetUrlAsString.substring(0, targetUrlAsString.length() - 1)); + } else { + urlBuilder.append(targetUrlAsString); + } if (!subSite.startsWith("/")) { urlBuilder.append("/"); diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/ScanDurationHelper.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/ScanDurationHelper.java similarity index 79% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/ScanDurationHelper.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/ScanDurationHelper.java index f22dc5cedd..0c9c7dbe8a 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/ScanDurationHelper.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/ScanDurationHelper.java @@ -1,14 +1,14 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.helper; +package com.mercedesbenz.sechub.zapwrapper.helper; -import static com.mercedesbenz.sechub.owaspzapwrapper.helper.ScanPercentageConstants.*; +import static com.mercedesbenz.sechub.zapwrapper.helper.ScanPercentageConstants.*; public class ScanDurationHelper { /** * - * Computes the max duration for the Owasp Zap spider. The computed time depends - * on how many of the other modules are enabled. + * Computes the max duration for the Zap spider. The computed time depends on + * how many of the other modules are enabled. * * @param isActiveScanEnabled * @param isAjaxSpiderEnabled @@ -29,8 +29,8 @@ public long computeSpiderMaxScanDuration(boolean isActiveScanEnabled, boolean is } /** - * Computes the max duration for the Owasp Zap spider. The computed time depends - * on how many of the other modules are enabled. + * Computes the max duration for the Zap spider. The computed time depends on + * how many of the other modules are enabled. * * @param isActiveScanEnabled * @param maxScanDurationInMinutes @@ -48,8 +48,8 @@ public long computeAjaxSpiderMaxScanDuration(boolean isActiveScanEnabled, long m } /** - * Computes the max duration for the Owasp Zap spider. The computed time depends - * on how many of the other modules are enabled. + * Computes the max duration for the Zap spider. The computed time depends on + * how many of the other modules are enabled. * * @param isActiveScanEnabled * @param isAjaxSpiderEnabled diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/ScanPercentageConstants.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/ScanPercentageConstants.java similarity index 96% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/ScanPercentageConstants.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/ScanPercentageConstants.java index 21be5ed46c..9f24480662 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/ScanPercentageConstants.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/ScanPercentageConstants.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.helper; +package com.mercedesbenz.sechub.zapwrapper.helper; public class ScanPercentageConstants { diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/SecHubWebScanConfigurationHelper.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/SecHubWebScanConfigurationHelper.java similarity index 94% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/SecHubWebScanConfigurationHelper.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/SecHubWebScanConfigurationHelper.java index bad4e48bbe..b976c6d4ec 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/SecHubWebScanConfigurationHelper.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/SecHubWebScanConfigurationHelper.java @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.helper; +package com.mercedesbenz.sechub.zapwrapper.helper; import com.mercedesbenz.sechub.commons.model.SecHubTimeUnit; import com.mercedesbenz.sechub.commons.model.SecHubWebScanConfiguration; import com.mercedesbenz.sechub.commons.model.login.WebLoginConfiguration; -import com.mercedesbenz.sechub.owaspzapwrapper.config.auth.AuthenticationType; +import com.mercedesbenz.sechub.zapwrapper.config.auth.AuthenticationType; public class SecHubWebScanConfigurationHelper { private static final int SECONDS_IN_MS = 1000; diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/ZapPDSEventHandler.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/ZapPDSEventHandler.java new file mode 100644 index 0000000000..f772ffebe5 --- /dev/null +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/ZapPDSEventHandler.java @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.zapwrapper.helper; + +import java.io.File; + +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperExitCode; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; + +public class ZapPDSEventHandler { + File cancelEventFile; + + public ZapPDSEventHandler(String pdsJobEventsFolder) { + this.cancelEventFile = new File(pdsJobEventsFolder, "cancel_requested.json"); + } + + public boolean isScanCancelled() { + return cancelEventFile.exists(); + } + + public void cancelScan(String scanContextName) { + if (isScanCancelled()) { + throw new ZapWrapperRuntimeException("Scan job: " + scanContextName + " was cancelled!", ZapWrapperExitCode.SCAN_JOB_CANCELLED); + } + } +} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapProductMessageHelper.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/ZapProductMessageHelper.java similarity index 77% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapProductMessageHelper.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/ZapProductMessageHelper.java index f43d7c1e7d..00d6da2d4f 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapProductMessageHelper.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/ZapProductMessageHelper.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.helper; +package com.mercedesbenz.sechub.zapwrapper.helper; import java.io.IOException; import java.util.List; @@ -11,15 +11,15 @@ import com.mercedesbenz.sechub.commons.model.SecHubMessage; import com.mercedesbenz.sechub.commons.model.SecHubMessageType; import com.mercedesbenz.sechub.commons.pds.PDSUserMessageSupport; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperExitCode; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperExitCode; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; -public class OwaspZapProductMessageHelper { - private static final Logger LOG = LoggerFactory.getLogger(OwaspZapProductMessageHelper.class); +public class ZapProductMessageHelper { + private static final Logger LOG = LoggerFactory.getLogger(ZapProductMessageHelper.class); private PDSUserMessageSupport productMessageSupport; - public OwaspZapProductMessageHelper(String userMessagesFolder) { + public ZapProductMessageHelper(String userMessagesFolder) { productMessageSupport = new PDSUserMessageSupport(userMessagesFolder, new TextFileWriter()); } @@ -58,6 +58,17 @@ public void writeProductError(ZapWrapperRuntimeException zapWrapperRuntimeExcept } } + public void writeUserMessagesWithScannedURLs(List urls) { + for (String url : urls) { + // robots.txt and sitemap.xml always appear inside the sites tree even if they + // are not available. Because of this it is skipped here. + if (url.contains("robots.txt") || url.contains("sitemap.xml")) { + continue; + } + writeSingleProductMessage(new SecHubMessage(SecHubMessageType.INFO, "Detect url to scan: " + url)); + } + } + private void writeProductErrorForExitCode(ZapWrapperExitCode exitCode) throws IOException { if (exitCode == null) { return; @@ -77,8 +88,7 @@ private void writeProductErrorForExitCode(ZapWrapperExitCode exitCode) throws IO "Target URL invalid. The target URL, specified inside SecHub configuration, is not a valid URL.")); break; case PRODUCT_EXECUTION_ERROR: - productMessageSupport - .writeMessage(new SecHubMessage(SecHubMessageType.ERROR, "Product error. The DAST scanner OWASP ZAP ended with a product error.")); + productMessageSupport.writeMessage(new SecHubMessage(SecHubMessageType.ERROR, "Product error. The DAST scanner ZAP ended with a product error.")); break; case INVALID_INCLUDE_OR_EXCLUDE_URLS: productMessageSupport.writeMessage(new SecHubMessage(SecHubMessageType.ERROR, diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapURLType.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/ZapURLType.java similarity index 60% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapURLType.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/ZapURLType.java index 7f8def6b9c..c083eb21f9 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapURLType.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/helper/ZapURLType.java @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.helper; +package com.mercedesbenz.sechub.zapwrapper.helper; -public enum OwaspZapURLType { +public enum ZapURLType { INCLUDE("include"), EXCLUDE("exclude"), @@ -10,7 +10,7 @@ public enum OwaspZapURLType { private String id; - private OwaspZapURLType(String id) { + private ZapURLType(String id) { this.id = id; } diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/internal/scan/ClientApiFacade.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/internal/scan/ClientApiFacade.java new file mode 100644 index 0000000000..4208482aa0 --- /dev/null +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/internal/scan/ClientApiFacade.java @@ -0,0 +1,580 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.zapwrapper.internal.scan; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.zaproxy.clientapi.core.ApiResponse; +import org.zaproxy.clientapi.core.ApiResponseElement; +import org.zaproxy.clientapi.core.ApiResponseList; +import org.zaproxy.clientapi.core.ClientApi; +import org.zaproxy.clientapi.core.ClientApiException; + +public class ClientApiFacade { + + private static final Logger LOG = LoggerFactory.getLogger(ClientApiFacade.class); + + private ClientApi clientApi; + + public ClientApiFacade(ClientApi clientApi) { + this.clientApi = clientApi; + } + + /** + * Create new context inside the ZAP with the given name. + * + * @param contextName + * @return contextId returned by ZAP + * @throws ClientApiException + */ + public String createNewContext(String contextName) throws ClientApiException { + ApiResponseElement createContextResponse = ((ApiResponseElement) clientApi.context.newContext(contextName)); + return getIdOfApiResponseElement(createContextResponse); + } + + /** + * Create a new session inside the ZAP. Overwriting files if the parameter is + * set. + * + * @param contextName + * @param overwrite + * @return + * @throws ClientApiException + */ + public ApiResponse createNewSession(String contextName, String overwrite) throws ClientApiException { + return clientApi.core.newSession(contextName, overwrite); + } + + /** + * Set maximum alerts for rule. + * + * @param maximum + * @return + * @throws ClientApiException + */ + public ApiResponse configureMaximumAlertsForEachRule(String maximum) throws ClientApiException { + return clientApi.core.setOptionMaximumAlertInstances(maximum); + } + + /** + * Enables all passive rules. + * + * @return + * @throws ClientApiException + */ + public ApiResponse enableAllPassiveScannerRules() throws ClientApiException { + return clientApi.pscan.enableAllScanners(); + } + + /** + * Enable all active rules for the given policy. + * + * @param policy + * @return + * @throws ClientApiException + */ + public ApiResponse enableAllActiveScannerRulesForPolicy(String policy) throws ClientApiException { + return clientApi.ascan.enableAllScanners(null); + } + + /** + * Set the Browser used by the AjaxSpider. + * + * @param browserId + * @return + * @throws ClientApiException + */ + public ApiResponse configureAjaxSpiderBrowserId(String browserId) throws ClientApiException { + return clientApi.ajaxSpider.setOptionBrowserId(browserId); + } + + /** + * + * @param ruleId + * @return + * @throws ClientApiException + */ + public ApiResponse disablePassiveScannerRule(String ruleId) throws ClientApiException { + return clientApi.pscan.disableScanners(ruleId); + } + + /** + * Disable the given rule by ID inside the given policy. + * + * @param ruleId + * @param policy + * @return + * @throws ClientApiException + */ + public ApiResponse disableActiveScannerRuleForPolicy(String ruleId, String policy) throws ClientApiException { + return clientApi.ascan.disableScanners(ruleId, null); + } + + /** + * Set HTTP proxy with the given parameters. + * + * @param host + * @param port + * @param realm + * @param username + * @param password + * @return + * @throws ClientApiException + */ + public ApiResponse configureHttpProxy(String host, String port, String realm, String username, String password) throws ClientApiException { + return clientApi.network.setHttpProxy(host, port, realm, username, password); + } + + /** + * Set usage of a HTTP proxy. + * + * @param enabled + * @return + * @throws ClientApiException + */ + public ApiResponse setHttpProxyEnabled(String enabled) throws ClientApiException { + return clientApi.network.setHttpProxyEnabled(enabled); + } + + /** + * Set usage of HTTP proxy authentication. + * + * @param enabled + * @return + * @throws ClientApiException + */ + public ApiResponse setHttpProxyAuthEnabled(String enabled) throws ClientApiException { + return clientApi.network.setHttpProxyAuthEnabled(enabled); + } + + /** + * Add replacer rule. If a entry already exists from the last scan it is + * replaced. + * + * @param description + * @param enabled + * @param matchtype + * @param matchregex + * @param matchstring + * @param replacement + * @param initiators + * @param url + * @return + * @throws ClientApiException + */ + public ApiResponse addReplacerRule(String description, String enabled, String matchtype, String matchregex, String matchstring, String replacement, + String initiators, String url) throws ClientApiException { + try { + return clientApi.replacer.addRule(description, enabled, matchtype, matchregex, matchstring, replacement, initiators, url); + } catch (ClientApiException e) { + String message = e.getMessage(); + if ("already exists".equalsIgnoreCase(message)) { + clientApi.replacer.removeRule(description); + } + return clientApi.replacer.addRule(description, enabled, matchtype, matchregex, matchstring, replacement, initiators, url); + } + } + + /** + * Include URL pattern to the given context. + * + * @param contextName + * @param urlPattern + * @return + * @throws ClientApiException + */ + public ApiResponse addIncludeUrlPatternToContext(String contextName, String urlPattern) throws ClientApiException { + return clientApi.context.includeInContext(contextName, urlPattern); + } + + /** + * Exclude URL pattern from the given context. + * + * @param contextName + * @param urlPattern + * @return + * @throws ClientApiException + */ + public ApiResponse addExcludeUrlPatternToContext(String contextName, String urlPattern) throws ClientApiException { + return clientApi.context.excludeFromContext(contextName, urlPattern); + } + + /** + * Access an URL through the ZAP. Successfully accessing the site will add it to + * the site tree. + * + * @param url + * @param followRedirects + * @return ApiResponse of ZAP or null when URL was not accessible. + */ + public ApiResponse accessUrlViaZap(String url, String followRedirects) { + ApiResponse response = null; + try { + response = clientApi.core.accessUrl(url, followRedirects); + } catch (ClientApiException e) { + LOG.error("While trying to access URL {} got the error: {}", url, e.getMessage()); + } + return response; + } + + /** + * Import the given openApi file in the context with the given ID. While + * importing the file the ZAP tries to access all API endpoints via the given + * URL and adds them to the sites tree if they could be accessed. + * + * @param openApiFile + * @param url + * @param contextId + * @return + * @throws ClientApiException + */ + public ApiResponse importOpenApiFile(String openApiFile, String url, String contextId) throws ClientApiException { + return clientApi.openapi.importFile(openApiFile, url, contextId); + } + + /** + * This method checks if the site tree is empty. The ZAP creates the site tree + * while crawling and detecting pages. The method is necessary since the active + * scanner exits with an exception if the site tree is empty, when starting an + * active scan. + * + * This can only happen in very few cases, but then we want to be able to inform + * the user and write a report which is empty or contains at least the passively + * detected results. + * + * @return + * @throws ClientApiException + */ + public boolean atLeastOneURLDetected() throws ClientApiException { + ApiResponseList sitesList = (ApiResponseList) clientApi.core.sites(); + return sitesList.getItems().size() > 0; + } + + /** + * Removes a replacer rule by the given description. (Description is the ID for + * the replacer rule) + * + * @param description + * @return + * @throws ClientApiException + */ + public ApiResponse removeReplacerRule(String description) throws ClientApiException { + return clientApi.replacer.removeRule(description); + } + + /** + * Generate a report for the given parameters. + * + * @param title + * @param template + * @param theme + * @param description + * @param contexts + * @param sites + * @param sections + * @param includedconfidences + * @param includedrisks + * @param reportfilename + * @param reportfilenamepattern + * @param reportdir + * @param display + * @return + * @throws ClientApiException + */ + public ApiResponse generateReport(String title, String template, String theme, String description, String contexts, String sites, String sections, + String includedconfidences, String includedrisks, String reportfilename, String reportfilenamepattern, String reportdir, String display) + throws ClientApiException { + return clientApi.reports.generate(title, template, theme, description, contexts, sites, sections, includedconfidences, includedrisks, reportfilename, + reportfilenamepattern, reportdir, display); + } + + /** + * Check the status of the ajax spider scan. + * + * @return The status as string after the ajax spider scan is started it is + * either "running" or "stopped". + * @throws ClientApiException + */ + public String getAjaxSpiderStatus() throws ClientApiException { + return ((ApiResponseElement) clientApi.ajaxSpider.status()).getValue(); + } + + /** + * Stop the ajax spider. + * + * @return + * @throws ClientApiException + */ + public ApiResponse stopAjaxSpider() throws ClientApiException { + return clientApi.ajaxSpider.stop(); + } + + /** + * Stop the spider for the given scan ID. + * + * @param scanId + * @return + * @throws ClientApiException + */ + public ApiResponse stopSpiderScan(String scanId) throws ClientApiException { + return clientApi.spider.stop(scanId); + } + + /** + * Get a list of all URLs detected by the spider scan. + * + * @return + * @throws ClientApiException + */ + public List getAllSpiderUrls() throws ClientApiException { + List results = ((ApiResponseList) clientApi.spider.allUrls()).getItems(); + List urls = new ArrayList<>(); + for (ApiResponse response : results) { + urls.add(response.toString()); + } + return urls; + } + + /** + * Get the status of the spider scan with a specific scan ID. + * + * @param scanId + * @return The status as a number between 0 and 100. (percentage of scan + * completion) + * @throws ClientApiException + */ + public int getSpiderStatusForScan(String scanId) throws ClientApiException { + ApiResponseElement status = (ApiResponseElement) clientApi.spider.status(scanId); + return Integer.parseInt(status.getValue()); + } + + /** + * Get the number of records left to scan for the passive scan. + * + * @param scanId + * @return + * @throws ClientApiException + */ + public int getNumberOfPassiveScannerRecordsToScan() throws ClientApiException { + ApiResponseElement recordsToScan = (ApiResponseElement) clientApi.pscan.recordsToScan(); + return Integer.parseInt(recordsToScan.getValue()); + } + + /** + * Stop the active scanner for the given scan ID. + * + * @param scanId + * @return + * @throws ClientApiException + */ + public ApiResponse stopActiveScan(String scanId) throws ClientApiException { + return clientApi.ascan.stop(scanId); + } + + /** + * Get the status of the active scan with a specific scan ID. + * + * @param scanId + * @return The status as a number between 0 and 100. (percentage of scan + * completion) + * @throws ClientApiException + */ + public int getActiveScannerStatusForScan(String scanId) throws ClientApiException { + ApiResponseElement status = (ApiResponseElement) clientApi.ascan.status(scanId); + return Integer.parseInt(status.getValue()); + } + + /** + * Start the spider with the given parameters. + * + * @param targetUrlAsString + * @param maxChildren + * @param recurse + * @param contextName + * @param subTreeOnly + * @return the ID of the started spider scan + * @throws ClientApiException + */ + public String startSpiderScan(String targetUrlAsString, String maxChildren, String recurse, String contextName, String subTreeOnly) + throws ClientApiException { + ApiResponse response = clientApi.spider.scan(targetUrlAsString, maxChildren, recurse, contextName, subTreeOnly); + return getIdOfApiResponseElement((ApiResponseElement) response); + } + + /** + * Start the ajax spider with the given parameters. + * + * @param targetUrlAsString + * @param inScope + * @param contextName + * @param subTreeOnly + * @return the response of the ZAP API call + * @throws ClientApiException + */ + public ApiResponse startAjaxSpiderScan(String targetUrlAsString, String inScope, String contextName, String subTreeOnly) throws ClientApiException { + return clientApi.ajaxSpider.scan(targetUrlAsString, inScope, contextName, subTreeOnly); + } + + /** + * Start the active scanner with the given parameters. + * + * @param targetUrlAsString + * @param recurse + * @param inScopeOnly + * @param scanPolicyName + * @param method + * @param postData + * @return the ID of the started active scan + * @throws ClientApiException + */ + public String startActiveScan(String targetUrlAsString, String recurse, String inScopeOnly, String scanPolicyName, String method, String postData) + throws ClientApiException { + ApiResponse response = clientApi.ascan.scan(targetUrlAsString, recurse, inScopeOnly, scanPolicyName, method, postData); + return getIdOfApiResponseElement((ApiResponseElement) response); + } + + /** + * Start the spider with the given parameters as the given user. + * + * @param contextId + * @param userId + * @param url + * @param maxchildren + * @param recurse + * @param subtreeonly + * @return the ID of the started spider scan + * @throws ClientApiException + */ + public String startSpiderScanAsUser(String contextId, String userId, String url, String maxchildren, String recurse, String subtreeonly) + throws ClientApiException { + ApiResponse response = clientApi.spider.scanAsUser(contextId, userId, url, maxchildren, recurse, subtreeonly); + return getIdOfApiResponseElement((ApiResponseElement) response); + } + + /** + * Start the ajax spider with the given parameters as the given user. + * + * @param contextname + * @param username + * @param url + * @param subtreeonly + * @return the response of the ZAP API call + * @throws ClientApiException + */ + public ApiResponse startAjaxSpiderScanAsUser(String contextname, String username, String url, String subtreeonly) throws ClientApiException { + return clientApi.ajaxSpider.scanAsUser(contextname, username, url, subtreeonly); + } + + /** + * Start the active scanner with the given parameters as the given user. + * + * @param url + * @param contextId + * @param userId + * @param recurse + * @param scanpolicyname + * @param method + * @param postdata + * @return the ID of the started active scan + * @throws ClientApiException + */ + public String startActiveScanAsUser(String url, String contextId, String userId, String recurse, String scanpolicyname, String method, String postdata) + throws ClientApiException { + ApiResponse response = clientApi.ascan.scanAsUser(url, contextId, userId, recurse, scanpolicyname, method, postdata); + return getIdOfApiResponseElement((ApiResponseElement) response); + } + + /** + * Configure the given authentication method for the given context. + * + * @param contextId + * @param authMethodName + * @param authMethodConfigParams + * @return + * @throws ClientApiException + */ + public ApiResponse configureAuthenticationMethod(String contextId, String authMethodName, String authMethodConfigParams) throws ClientApiException { + return clientApi.authentication.setAuthenticationMethod(contextId, authMethodName, authMethodConfigParams); + } + + /** + * Set session management method for the given context. + * + * @param contextId + * @param methodName + * @param methodconfigparams + * @return + * @throws ClientApiException + */ + public ApiResponse setSessionManagementMethod(String contextId, String methodName, String methodconfigparams) throws ClientApiException { + return clientApi.sessionManagement.setSessionManagementMethod(contextId, methodName, methodconfigparams); + } + + /** + * Create a new user inside the given context. + * + * @param contextId + * @param username + * @return + * @throws ClientApiException + */ + public String createNewUser(String contextId, String username) throws ClientApiException { + ApiResponseElement creatUserResponse = ((ApiResponseElement) clientApi.users.newUser(contextId, username)); + return getIdOfApiResponseElement(creatUserResponse); + } + + /** + * Set authentication credentials for the given user inside the given context. + * + * @param contextId + * @param userId + * @param authCredentialsConfigParams + * @return + * @throws ClientApiException + */ + public ApiResponse configureAuthenticationCredentials(String contextId, String userId, String authCredentialsConfigParams) throws ClientApiException { + return clientApi.users.setAuthenticationCredentials(contextId, userId, authCredentialsConfigParams); + } + + /** + * Sets whether or not the user, should be enabled inside the given context. + * + * @param contextId + * @param userId + * @param enabled + * @return + * @throws ClientApiException + */ + public ApiResponse setUserEnabled(String contextId, String userId, String enabled) throws ClientApiException { + return clientApi.users.setUserEnabled(contextId, userId, enabled); + } + + /** + * Set the user that will be used in forced user mode for the given context. + * + * @param contextId + * @param userId + * @return + * @throws ClientApiException + */ + public ApiResponse setForcedUser(String contextId, String userId) throws ClientApiException { + return clientApi.forcedUser.setForcedUser(contextId, userId); + } + + /** + * Set if the forced user mode should be enabled or not. + * + * @param enabled + * @return + * @throws ClientApiException + */ + public ApiResponse setForcedUserModeEnabled(boolean enabled) throws ClientApiException { + return clientApi.forcedUser.setForcedUserModeEnabled(enabled); + } + + private String getIdOfApiResponseElement(ApiResponseElement apiResponseElement) { + return apiResponseElement.getValue(); + } +} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/scan/ZapScan.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/scan/ZapScan.java new file mode 100644 index 0000000000..9e774f4599 --- /dev/null +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/scan/ZapScan.java @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.zapwrapper.scan; + +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; + +public interface ZapScan { + + void scan() throws ZapWrapperRuntimeException; + +} \ No newline at end of file diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/scan/ZapScanner.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/scan/ZapScanner.java new file mode 100644 index 0000000000..d162e9bcb3 --- /dev/null +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/scan/ZapScanner.java @@ -0,0 +1,772 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.zapwrapper.scan; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.List; +import java.util.Optional; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.zaproxy.clientapi.core.ClientApiException; + +import com.mercedesbenz.sechub.commons.model.HTTPHeaderConfiguration; +import com.mercedesbenz.sechub.commons.model.SecHubMessage; +import com.mercedesbenz.sechub.commons.model.SecHubMessageType; +import com.mercedesbenz.sechub.commons.model.SecHubWebScanApiConfiguration; +import com.mercedesbenz.sechub.commons.model.login.BasicLoginConfiguration; +import com.mercedesbenz.sechub.commons.model.login.WebLoginConfiguration; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperExitCode; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.config.BrowserId; +import com.mercedesbenz.sechub.zapwrapper.config.ProxyInformation; +import com.mercedesbenz.sechub.zapwrapper.config.ZapScanContext; +import com.mercedesbenz.sechub.zapwrapper.config.auth.SessionManagementType; +import com.mercedesbenz.sechub.zapwrapper.config.data.DeactivatedRuleReferences; +import com.mercedesbenz.sechub.zapwrapper.config.data.Rule; +import com.mercedesbenz.sechub.zapwrapper.config.data.RuleReference; +import com.mercedesbenz.sechub.zapwrapper.config.data.ZapFullRuleset; +import com.mercedesbenz.sechub.zapwrapper.helper.ScanDurationHelper; +import com.mercedesbenz.sechub.zapwrapper.helper.ZapPDSEventHandler; +import com.mercedesbenz.sechub.zapwrapper.internal.scan.ClientApiFacade; +import com.mercedesbenz.sechub.zapwrapper.util.SystemUtil; +import com.mercedesbenz.sechub.zapwrapper.util.UrlUtil; + +public class ZapScanner implements ZapScan { + private static final Logger LOG = LoggerFactory.getLogger(ZapScanner.class); + static final int CHECK_SCAN_STATUS_TIME_IN_MILLISECONDS = 5000; + + ClientApiFacade clientApiFacade; + ZapScanContext scanContext; + + ScanDurationHelper scanDurationHelper; + UrlUtil urlUtil; + SystemUtil systemUtil; + + long remainingScanTime; + + public static ZapScanner from(ClientApiFacade clientApiFacade, ZapScanContext scanContext) { + if (clientApiFacade == null) { + throw new ZapWrapperRuntimeException("Cannot create Zap Scanner because ClientApiFacade is null!", ZapWrapperExitCode.UNSUPPORTED_CONFIGURATION); + } + + if (scanContext == null) { + throw new ZapWrapperRuntimeException("Cannot create Zap Scanner because ZapScanContext is null!", ZapWrapperExitCode.UNSUPPORTED_CONFIGURATION); + } + + ScanDurationHelper scanDurationHelper = new ScanDurationHelper(); + UrlUtil urlUtil = new UrlUtil(); + SystemUtil systemUtil = new SystemUtil(); + + return new ZapScanner(clientApiFacade, scanContext, scanDurationHelper, urlUtil, systemUtil); + } + + private ZapScanner(ClientApiFacade clientApiFacade, ZapScanContext scanContext, ScanDurationHelper scanDurationHelper, UrlUtil urlUtil, + SystemUtil systemUtil) { + this.clientApiFacade = clientApiFacade; + this.scanContext = scanContext; + + this.scanDurationHelper = scanDurationHelper; + this.urlUtil = urlUtil; + this.systemUtil = systemUtil; + + this.remainingScanTime = scanContext.getMaxScanDurationInMilliSeconds(); + } + + @Override + public void scan() throws ZapWrapperRuntimeException { + try { + /* ZAP setup on local machine */ + setupStandardConfiguration(); + deactivateRules(scanContext.getFullRuleset(), scanContext.getDeactivatedRuleReferences()); + setupAdditonalProxyConfiguration(scanContext.getProxyInformation()); + String zapContextId = createContext(); + addReplacerRulesForHeaders(); + + /* ZAP setup with access to target */ + addIncludedAndExcludedUrlsToContext(); + loadApiDefinitions(zapContextId); + + /* ZAP scan */ + executeScan(zapContextId); + + /* After scan */ + generateZapReport(); + cleanUp(); + } catch (ClientApiException e) { + cleanUp(); + throw new ZapWrapperRuntimeException("For scan: " + scanContext.getContextName() + ". An error occured while scanning!", e, + ZapWrapperExitCode.PRODUCT_EXECUTION_ERROR); + } + } + + void setupStandardConfiguration() throws ClientApiException { + LOG.info("Creating new session inside the Zap"); + // to ensure parts from previous scan are deleted + clientApiFacade.createNewSession(scanContext.getContextName(), "true"); + + LOG.info("Setting default maximum number of alerts for each rule."); + // setting this value to zero means unlimited + clientApiFacade.configureMaximumAlertsForEachRule("0"); + + LOG.info("Enable all passive scan rules before configuration begins."); + // enable all passive scanner rules by default + clientApiFacade.enableAllPassiveScannerRules(); + + LOG.info("Enable all active scan rules before configuration begins."); + // enable all passive scanner rules by default + // null specifies the default scan policy + clientApiFacade.enableAllActiveScannerRulesForPolicy(null); + + LOG.info("Set browser for ajaxSpider."); + // use firefox in headless mode by default + clientApiFacade.configureAjaxSpiderBrowserId(BrowserId.FIREFOX_HEADLESS.getBrowserId()); + } + + void deactivateRules(ZapFullRuleset fullRuleset, DeactivatedRuleReferences deactivatedRuleReferences) throws ClientApiException { + if (fullRuleset == null || deactivatedRuleReferences == null) { + return; + } + List rulesReferences = deactivatedRuleReferences.getDeactivatedRuleReferences(); + if (rulesReferences == null) { + return; + } + + for (RuleReference ruleRef : rulesReferences) { + Rule ruleToDeactivate = fullRuleset.findRuleByReference(ruleRef.getReference()); + if (isPassiveRule(ruleToDeactivate.getType())) { + LOG.info("Deactivate passive scanner rule: {} ", ruleRef.getReference()); + clientApiFacade.disablePassiveScannerRule(ruleToDeactivate.getId()); + } else if (isActiveRule(ruleToDeactivate.getType())) { + LOG.info("Deactivate active scanner rule: {} ", ruleRef.getReference()); + // null specifies the default scan policy + clientApiFacade.disableActiveScannerRuleForPolicy(ruleToDeactivate.getId(), null); + } + } + } + + void setupAdditonalProxyConfiguration(ProxyInformation proxyInformation) throws ClientApiException { + if (proxyInformation != null) { + String proxyHost = proxyInformation.getHost(); + int proxyPort = proxyInformation.getPort(); + LOG.info("Using proxy {}:{} to reach target.", proxyHost, proxyPort); + clientApiFacade.configureHttpProxy(proxyHost, "" + proxyPort, null, null, null); + clientApiFacade.setHttpProxyEnabled("true"); + clientApiFacade.setHttpProxyAuthEnabled("false"); + } else { + LOG.info("No proxy was set, continuing without proxy."); + clientApiFacade.setHttpProxyEnabled("false"); + } + } + + /** + * Creates new context in the current ZAP session. + * + * @return the context id returned by the ZAP API + * @throws ClientApiException + */ + String createContext() throws ClientApiException { + LOG.info("Creating context: {}", scanContext.getContextName()); + return clientApiFacade.createNewContext(scanContext.getContextName()); + } + + void addReplacerRulesForHeaders() throws ClientApiException { + if (scanContext.getSecHubWebScanConfiguration().getHeaders().isEmpty()) { + LOG.info("No headers were configured inside the sechub webscan configuration."); + return; + } + + // description specifies the rule name, which will be set later in this method + String description = null; + + String enabled = "true"; + // "REQ_HEADER" means the header entry will be added to the requests if not + // existing or replaced if already existing + String matchtype = "REQ_HEADER"; + String matchregex = "false"; + + // matchstring and replacement will be set to the header name and header value + String matchstring = null; + String replacement = null; + + // setting initiators to null means all initiators (ZAP components), + // this means spider, active scan, etc will send this rule for their requests. + String initiators = null; + // default URL is null which means the header would be send on any request to + // any URL + String url = null; + List httpHeaders = scanContext.getSecHubWebScanConfiguration().getHeaders().get(); + LOG.info("For scan {}: Applying header configuration.", scanContext.getContextName()); + for (HTTPHeaderConfiguration httpHeader : httpHeaders) { + matchstring = httpHeader.getName(); + replacement = httpHeader.getValue(); + + if (httpHeader.getOnlyForUrls().isEmpty()) { + // if there are no onlyForUrl patterns, there is only one rule for each header + description = httpHeader.getName(); + clientApiFacade.addReplacerRule(description, enabled, matchtype, matchregex, matchstring, replacement, initiators, url); + } else { + for (String onlyForUrl : httpHeader.getOnlyForUrls().get()) { + // we need to create a rule for each onlyForUrl pattern on each header + description = onlyForUrl; + url = urlUtil.replaceWildCardsWithRegexInUrl(onlyForUrl); + clientApiFacade.addReplacerRule(description, enabled, matchtype, matchregex, matchstring, replacement, initiators, url); + } + } + } + } + + /** + * Adds all included and excluded URLs into scan context. + * + * @throws ClientApiException + */ + void addIncludedAndExcludedUrlsToContext() throws ClientApiException { + LOG.info("For scan {}: Adding include parts.", scanContext.getContextName()); + for (URL url : scanContext.getZapURLsIncludeSet()) { + clientApiFacade.addIncludeUrlPatternToContext(scanContext.getContextName(), url + ".*"); + String followRedirects = "false"; + clientApiFacade.accessUrlViaZap(url.toString(), followRedirects); + } + + LOG.info("For scan {}: Adding exclude parts.", scanContext.getContextName()); + for (URL url : scanContext.getZapURLsExcludeSet()) { + clientApiFacade.addExcludeUrlPatternToContext(scanContext.getContextName(), url + ".*"); + } + } + + void loadApiDefinitions(String zapContextId) throws ClientApiException { + if (scanContext.getApiDefinitionFiles().isEmpty()) { + LOG.info("For scan {}: No file with API definition found!", scanContext.getContextName()); + return; + } + Optional apiConfig = scanContext.getSecHubWebScanConfiguration().getApi(); + if (!apiConfig.isPresent()) { + LOG.info("For scan {}: No API definition was found!", scanContext.getContextName()); + return; + } + + switch (apiConfig.get().getType()) { + case OPEN_API: + for (File apiFile : scanContext.getApiDefinitionFiles()) { + LOG.info("For scan {}: Loading openAPI file: {}", scanContext.getContextName(), apiFile.toString()); + clientApiFacade.importOpenApiFile(apiFile.toString(), scanContext.getTargetUrlAsString(), zapContextId); + } + break; + default: + // should never happen since API type is an Enum + // Failure should happen before getting here + throw new ZapWrapperRuntimeException("For scan :" + scanContext.getContextName() + ". Unknown API type was definied!", + ZapWrapperExitCode.API_DEFINITION_CONFIG_INVALID); + } + } + + void executeScan(String zapContextId) throws ClientApiException { + UserInformation userInfo = configureLoginInsideZapContext(zapContextId); + if (userInfo != null) { + if (scanContext.isAjaxSpiderEnabled()) { + runAjaxSpiderAsUser(userInfo.userName); + } + runSpiderAsUser(zapContextId, userInfo.zapuserId); + passiveScan(); + if (scanContext.isActiveScanEnabled()) { + runActiveScanAsUser(zapContextId, userInfo.zapuserId); + } + } else { + if (scanContext.isAjaxSpiderEnabled()) { + runAjaxSpider(); + } + runSpider(); + passiveScan(); + if (scanContext.isActiveScanEnabled()) { + runActiveScan(); + } + } + } + + /** + * Configure login according to the sechub webscan config. + * + * @param zapContextId + * @return UserInformation containing userName and zapUserId or + * null if nothing could be configured. + * @throws ClientApiException + */ + UserInformation configureLoginInsideZapContext(String zapContextId) throws ClientApiException { + if (scanContext.getSecHubWebScanConfiguration().getLogin().isEmpty()) { + LOG.info("For scan {}: No login section detected.", scanContext.getContextName()); + return null; + } + + WebLoginConfiguration webLoginConfiguration = scanContext.getSecHubWebScanConfiguration().getLogin().get(); + if (webLoginConfiguration.getBasic().isPresent()) { + LOG.info("For scan {}: Applying basic authentication config.", scanContext.getContextName()); + return initBasicAuthentication(zapContextId, webLoginConfiguration.getBasic().get()); + } + + return null; + } + + /** + * Generates the SARIF report for the current scan, identified using the context + * name. + * + * @throws ClientApiException + */ + void generateZapReport() throws ClientApiException { + LOG.info("For scan {}: Writing results to report...", scanContext.getContextName()); + Path reportFile = scanContext.getReportFile(); + + String title = scanContext.getContextName(); + String template = "sarif-json"; + String theme = null; + String description = null; + String contexts = scanContext.getContextName(); + String sites = null; + String sections = null; + String includedconfidences = null; + String includedrisks = null; + String reportfilename = reportFile.getFileName().toString(); + String reportfilenamepattern = null; + String reportdir = resolveParentDirectoryPath(reportFile); + String display = null; + /* @formatter:off */ + // we use the context name as report title + clientApiFacade.generateReport( + title, + template, + theme, + description, + contexts, + sites, + sections, + includedconfidences, + includedrisks, + reportfilename, + reportfilenamepattern, + reportdir, + display + ); + /* @formatter:on */ + + // rename is necessary if the file extension is not .json, because Zap + // adds the file extension .json since we create a json report. Might not be + // necessary anymore if we have the sarif support + renameReportFileToOriginalNameIfNecessary(); + + LOG.info("For scan {}: Report can be found at {}", scanContext.getContextName(), reportFile.toFile().getAbsolutePath()); + } + + void cleanUp() { + // to ensure parts from previous scan are deleted + try { + LOG.info("Cleaning up by starting new and empty session...", scanContext.getContextName()); + clientApiFacade.createNewSession("Cleaned after scan", "true"); + LOG.info("New and empty session inside Zap created."); + + // Replacer rules are persistent even after restarting ZAP + // This means we need to cleanUp after every scan. + LOG.info("Start cleaning up replacer rules."); + cleanUpReplacerRules(); + LOG.info("Cleanup successful."); + } catch (ClientApiException e) { + LOG.error("For scan: {}. An error occurred during the clean up, because: {}", scanContext.getContextName(), e.getMessage()); + } + } + + void runSpider() throws ClientApiException { + String contextName = scanContext.getContextName(); + String subTreeOnly = "true"; + String recurse = "true"; + String maxChildren = null; + String targetUrlAsString = scanContext.getTargetUrlAsString(); + LOG.info("For scan {}: Starting Spider.", contextName); + /* @formatter:off */ + String scanId = + clientApiFacade.startSpiderScan( + targetUrlAsString, + maxChildren, + recurse, + contextName, + subTreeOnly); + /* @formatter:on */ + waitForSpiderResults(scanId); + } + + void runAjaxSpider() throws ClientApiException { + String inScope = "true"; + String subTreeOnly = "true"; + String contextName = scanContext.getContextName(); + String targetUrlAsString = scanContext.getTargetUrlAsString(); + LOG.info("For scan {}: Starting AjaxSpider.", scanContext.getContextName()); + /* @formatter:off */ + clientApiFacade.startAjaxSpiderScan( + targetUrlAsString, + inScope, + contextName, + subTreeOnly); + /* @formatter:on */ + waitForAjaxSpiderResults(); + } + + void runActiveScan() throws ClientApiException { + // Necessary otherwise the active scanner exits with an exception, + // if no URLs to scan where detected by the spider/ajaxSpider before + if (!clientApiFacade.atLeastOneURLDetected()) { + LOG.warn("For {} skipping active scan, since no URLs where detected by spider or ajaxSpider!", scanContext.getContextName()); + scanContext.getZapProductMessageHelper().writeSingleProductMessage( + new SecHubMessage(SecHubMessageType.WARNING, "Skipped the active scan, because no URLs were detected by the crawler! " + + "Please check if the URL you specified or any of the includes are accessible.")); + return; + } + String targetUrlAsString = scanContext.getTargetUrlAsString(); + String inScopeOnly = "true"; + String recurse = "true"; + String scanPolicyName = null; + String method = null; + String postData = null; + LOG.info("For scan {}: Starting ActiveScan.", scanContext.getContextName()); + /* @formatter:off */ + String scanId = + clientApiFacade.startActiveScan( + targetUrlAsString, + recurse, + inScopeOnly, + scanPolicyName, + method, + postData); + /* @formatter:on */ + waitForActiveScanResults(scanId); + } + + void runSpiderAsUser(String contextId, String userId) throws ClientApiException { + String url = scanContext.getTargetUrlAsString(); + String maxchildren = null; + String recurse = "true"; + String subtreeonly = "true"; + LOG.info("For scan {}: Starting authenticated Spider.", scanContext.getContextName()); + /* @formatter:off */ + String scanId = + clientApiFacade.startSpiderScanAsUser( + contextId, + userId, + url, + maxchildren, + recurse, + subtreeonly); + /* @formatter:on */ + waitForSpiderResults(scanId); + } + + void runAjaxSpiderAsUser(String username) throws ClientApiException { + String contextname = scanContext.getContextName(); + String url = scanContext.getTargetUrlAsString(); + String subtreeonly = "true"; + LOG.info("For scan {}: Starting authenticated Ajax Spider.", scanContext.getContextName()); + /* @formatter:off */ + clientApiFacade.startAjaxSpiderScanAsUser( + contextname, + username, + url, + subtreeonly); + /* @formatter:on */ + waitForAjaxSpiderResults(); + } + + void runActiveScanAsUser(String contextId, String userId) throws ClientApiException { + // Necessary otherwise the active scanner exits with an exception, + // if no URLs to scan where detected by the spider/ajaxSpider before + if (!clientApiFacade.atLeastOneURLDetected()) { + LOG.warn("For {} skipping active scan, since no URLs where detected by spider or ajaxSpider!", scanContext.getContextName()); + scanContext.getZapProductMessageHelper().writeSingleProductMessage( + new SecHubMessage(SecHubMessageType.WARNING, "Skipped the active scan, because no URLs were detected by the crawler! " + + "Please check if the URL you specified or any of the includes are accessible.")); + return; + } + String url = scanContext.getTargetUrlAsString(); + String recurse = "true"; + String scanpolicyname = null; + String method = null; + String postdata = null; + LOG.info("For scan {}: Starting authenticated ActiveScan.", scanContext.getContextName()); + /* @formatter:off */ + String scanId = + clientApiFacade.startActiveScanAsUser( + url, + contextId, + userId, + recurse, + scanpolicyname, + method, + postdata); + /* @formatter:on */ + waitForActiveScanResults(scanId); + } + + /** + * Wait for the results of the ajax spider. Periodically checks the progress of + * the ajax spider. + * + * @throws ClientApiException + */ + void waitForAjaxSpiderResults() throws ClientApiException { + String ajaxSpiderStatus = null; + + long startTime = systemUtil.getCurrentTimeInMilliseconds(); + long maxDuration = scanDurationHelper.computeAjaxSpiderMaxScanDuration(scanContext.isActiveScanEnabled(), remainingScanTime); + + boolean timeOut = false; + + ZapPDSEventHandler zapPDSEventHandler = scanContext.getZapPDSEventHandler(); + + while (!isAjaxSpiderStopped(ajaxSpiderStatus) && !timeOut) { + if (zapPDSEventHandler.isScanCancelled()) { + clientApiFacade.stopAjaxSpider(); + zapPDSEventHandler.cancelScan(scanContext.getContextName()); + } + systemUtil.waitForMilliseconds(CHECK_SCAN_STATUS_TIME_IN_MILLISECONDS); + ajaxSpiderStatus = clientApiFacade.getAjaxSpiderStatus(); + LOG.info("For scan {}: AjaxSpider status {}", scanContext.getContextName(), ajaxSpiderStatus); + timeOut = (systemUtil.getCurrentTimeInMilliseconds() - startTime) > maxDuration; + } + /* stop spider - otherwise running in background */ + clientApiFacade.stopAjaxSpider(); + LOG.info("For scan {}: AjaxSpider completed.", scanContext.getContextName()); + remainingScanTime = remainingScanTime - (systemUtil.getCurrentTimeInMilliseconds() - startTime); + } + + /** + * Wait for the results of the spider. Periodically checks the progress of the + * spider. + * + * @param response + * @throws ClientApiException + */ + void waitForSpiderResults(String scanId) throws ClientApiException { + int progressSpider = 0; + + long startTime = systemUtil.getCurrentTimeInMilliseconds(); + long maxDuration = scanDurationHelper.computeSpiderMaxScanDuration(scanContext.isActiveScanEnabled(), scanContext.isAjaxSpiderEnabled(), + remainingScanTime); + + boolean timeOut = false; + ZapPDSEventHandler zapPDSEventHandler = scanContext.getZapPDSEventHandler(); + + while (progressSpider < 100 && !timeOut) { + if (zapPDSEventHandler.isScanCancelled()) { + clientApiFacade.stopSpiderScan(scanId); + zapPDSEventHandler.cancelScan(scanContext.getContextName()); + } + systemUtil.waitForMilliseconds(CHECK_SCAN_STATUS_TIME_IN_MILLISECONDS); + progressSpider = clientApiFacade.getSpiderStatusForScan(scanId); + LOG.info("For scan {}: Spider progress {}%", scanContext.getContextName(), progressSpider); + timeOut = systemUtil.getCurrentTimeInMilliseconds() - startTime > maxDuration; + } + /* stop spider - otherwise running in background */ + clientApiFacade.stopSpiderScan(scanId); + + scanContext.getZapProductMessageHelper().writeUserMessagesWithScannedURLs(clientApiFacade.getAllSpiderUrls()); + LOG.info("For scan {}: Spider completed.", scanContext.getContextName()); + remainingScanTime = remainingScanTime - (systemUtil.getCurrentTimeInMilliseconds() - startTime); + } + + /** + * Wait for the results of the passive scan. Periodically checks the progress of + * the passive scan. + * + * @throws ClientApiException + */ + void passiveScan() throws ClientApiException { + LOG.info("For scan {}: Starting passive scan.", scanContext.getContextName()); + long startTime = systemUtil.getCurrentTimeInMilliseconds(); + long maxDuration = scanDurationHelper.computePassiveScanMaxScanDuration(scanContext.isActiveScanEnabled(), scanContext.isAjaxSpiderEnabled(), + remainingScanTime); + + int numberOfRecords = clientApiFacade.getNumberOfPassiveScannerRecordsToScan(); + boolean timeOut = false; + ZapPDSEventHandler zapPDSEventHandler = scanContext.getZapPDSEventHandler(); + + while (numberOfRecords > 0 && !timeOut) { + if (zapPDSEventHandler.isScanCancelled()) { + zapPDSEventHandler.cancelScan(scanContext.getContextName()); + } + systemUtil.waitForMilliseconds(CHECK_SCAN_STATUS_TIME_IN_MILLISECONDS); + numberOfRecords = clientApiFacade.getNumberOfPassiveScannerRecordsToScan(); + LOG.info("For scan {}: Passive scan number of records left for scanning: {}", scanContext.getContextName(), numberOfRecords); + timeOut = systemUtil.getCurrentTimeInMilliseconds() - startTime > maxDuration; + } + LOG.info("For scan {}: Passive scan completed.", scanContext.getContextName()); + remainingScanTime = remainingScanTime - (systemUtil.getCurrentTimeInMilliseconds() - startTime); + } + + /** + * Wait for the results of the active scan. Periodically checks the progress of + * the active scan. + * + * @param response + * @throws ClientApiException + */ + void waitForActiveScanResults(String scanId) throws ClientApiException { + int progressActive = 0; + + long startTime = systemUtil.getCurrentTimeInMilliseconds(); + long maxDuration = remainingScanTime; + boolean timeOut = false; + + ZapPDSEventHandler zapPDSEventHandler = scanContext.getZapPDSEventHandler(); + + while (progressActive < 100 && !timeOut) { + if (zapPDSEventHandler.isScanCancelled()) { + clientApiFacade.stopActiveScan(scanId); + zapPDSEventHandler.cancelScan(scanContext.getContextName()); + } + systemUtil.waitForMilliseconds(CHECK_SCAN_STATUS_TIME_IN_MILLISECONDS); + progressActive = clientApiFacade.getActiveScannerStatusForScan(scanId); + LOG.info("For scan {}: Active scan progress {}%", scanContext.getContextName(), progressActive); + + timeOut = (systemUtil.getCurrentTimeInMilliseconds() - startTime) > maxDuration; + } + clientApiFacade.stopActiveScan(scanId); + LOG.info("For scan {}: Active scan completed.", scanContext.getContextName()); + } + + private boolean isPassiveRule(String type) { + return "passive".equals(type.toLowerCase()); + } + + private boolean isActiveRule(String type) { + return "active".equals(type.toLowerCase()); + } + + private UserInformation initBasicAuthentication(String zapContextId, BasicLoginConfiguration basicLoginConfiguration) throws ClientApiException { + String realm = ""; + if (basicLoginConfiguration.getRealm().isPresent()) { + realm = basicLoginConfiguration.getRealm().get(); + } + String port = "" + scanContext.getTargetUrl().getPort(); + /* @formatter:off */ + StringBuilder authMethodConfigParams = new StringBuilder(); + authMethodConfigParams.append("hostname=").append(urlEncodeUTF8(scanContext.getTargetUrl().getHost())) + .append("&realm=").append(urlEncodeUTF8(realm)) + .append("&port=").append(urlEncodeUTF8(port)); + /* @formatter:on */ + LOG.info("For scan {}: Setting basic authentication.", scanContext.getContextName()); + String authMethodName = scanContext.getAuthenticationType().getZapAuthenticationMethod(); + clientApiFacade.configureAuthenticationMethod(zapContextId, authMethodName, authMethodConfigParams.toString()); + + String methodName = SessionManagementType.HTTP_AUTH_SESSION_MANAGEMENT.getZapSessionManagementMethod(); + + // methodconfigparams in case of http basic auth is null, because it is + // configured automatically + String methodconfigparams = null; + clientApiFacade.setSessionManagementMethod(zapContextId, methodName, methodconfigparams); + + return initBasicAuthScanUser(zapContextId, basicLoginConfiguration); + } + + private UserInformation initBasicAuthScanUser(String zapContextId, BasicLoginConfiguration basicLoginConfiguration) throws ClientApiException { + String username = new String(basicLoginConfiguration.getUser()); + String password = new String(basicLoginConfiguration.getPassword()); + + String userId = clientApiFacade.createNewUser(zapContextId, username); + + /* @formatter:off */ + StringBuilder authCredentialsConfigParams = new StringBuilder(); + authCredentialsConfigParams.append("username=").append(urlEncodeUTF8(username)) + .append("&password=").append(urlEncodeUTF8(password)); + /* @formatter:on */ + + LOG.info("For scan {}: Setting up user.", scanContext.getContextName()); + clientApiFacade.configureAuthenticationCredentials(zapContextId, userId, authCredentialsConfigParams.toString()); + String enabled = "true"; + clientApiFacade.setUserEnabled(zapContextId, userId, enabled); + + clientApiFacade.setForcedUser(zapContextId, userId); + clientApiFacade.setForcedUserModeEnabled(true); + + UserInformation userInfo = new UserInformation(username, userId); + return userInfo; + } + + private boolean isAjaxSpiderStopped(String status) { + return "stopped".equals(status); + } + + private String resolveParentDirectoryPath(Path reportFile) { + if (reportFile == null) { + throw new ZapWrapperRuntimeException("For scan: " + scanContext.getContextName() + ". Report file not set.", + ZapWrapperExitCode.PDS_CONFIGURATION_ERROR); + } + if (Files.isDirectory(reportFile)) { + throw new ZapWrapperRuntimeException("For scan: " + scanContext.getContextName() + ". Report file cannot be a directory!", + ZapWrapperExitCode.PDS_CONFIGURATION_ERROR); + } + + Path parent = reportFile.getParent(); + Path absolutePath = parent.toAbsolutePath(); + + return absolutePath.toString(); + } + + /** + * This method is used to rename the file back to the specified name in case the + * file did not end with .json. + * + * The reason for this method is that the Zap appends ".json" to the result file + * if we generate a report in json format. The PDS result.txt will then be + * called result.txt.json. Because of this behaviour the file will be renamed. + */ + private void renameReportFileToOriginalNameIfNecessary() { + String specifiedReportFile = scanContext.getReportFile().toAbsolutePath().toFile().getAbsolutePath(); + // If the Zap creates the file below, it will be renamed to the originally + // specified name + File zapCreatedFile = new File(specifiedReportFile + ".json"); + if (zapCreatedFile.exists()) { + try { + Path zapReport = Paths.get(specifiedReportFile + ".json"); + Files.move(zapReport, zapReport.resolveSibling(scanContext.getReportFile().toAbsolutePath()), StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + throw new ZapWrapperRuntimeException("For scan: " + scanContext.getContextName() + ". An error occurred renaming the report file", e, + ZapWrapperExitCode.IO_ERROR); + } + } + } + + private void cleanUpReplacerRules() throws ClientApiException { + if (scanContext.getSecHubWebScanConfiguration().getHeaders().isEmpty()) { + return; + } + + List httpHeaders = scanContext.getSecHubWebScanConfiguration().getHeaders().get(); + for (HTTPHeaderConfiguration httpHeader : httpHeaders) { + if (httpHeader.getOnlyForUrls().isEmpty()) { + String description = httpHeader.getName(); + clientApiFacade.removeReplacerRule(description); + } else { + for (String onlyForUrl : httpHeader.getOnlyForUrls().get()) { + String description = onlyForUrl; + clientApiFacade.removeReplacerRule(description); + } + } + } + } + + private String urlEncodeUTF8(String stringToEncode) { + try { + return URLEncoder.encode(stringToEncode, StandardCharsets.UTF_8.toString()); + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException("This should not happen because we always use UTF-8: " + e); + } + } + + record UserInformation(String userName, String zapuserId) { + } +} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/util/EnvironmentVariableConstants.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/util/EnvironmentVariableConstants.java similarity index 93% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/util/EnvironmentVariableConstants.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/util/EnvironmentVariableConstants.java index f7dd50462e..3db406a115 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/util/EnvironmentVariableConstants.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/util/EnvironmentVariableConstants.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.util; +package com.mercedesbenz.sechub.zapwrapper.util; public class EnvironmentVariableConstants { diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/util/EnvironmentVariableReader.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/util/EnvironmentVariableReader.java similarity index 96% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/util/EnvironmentVariableReader.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/util/EnvironmentVariableReader.java index a9ceec1a8c..dfac1d2beb 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/util/EnvironmentVariableReader.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/util/EnvironmentVariableReader.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.util; +package com.mercedesbenz.sechub.zapwrapper.util; public class EnvironmentVariableReader { diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/util/FileUtilities.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/util/FileUtilities.java similarity index 71% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/util/FileUtilities.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/util/FileUtilities.java index a56f9e75c5..08684b940f 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/util/FileUtilities.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/util/FileUtilities.java @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.util; +package com.mercedesbenz.sechub.zapwrapper.util; import java.io.File; import java.io.IOException; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperExitCode; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperExitCode; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; public class FileUtilities { diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/util/SystemUtil.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/util/SystemUtil.java new file mode 100644 index 0000000000..480335657d --- /dev/null +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/util/SystemUtil.java @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.zapwrapper.util; + +public class SystemUtil { + + /** + * Use Thread.sleep(milliseconds) to wait for the specified amount of + * milliseconds. + * + * @param milliseconds + */ + public void waitForMilliseconds(int milliseconds) { + try { + Thread.sleep(milliseconds); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + public long getCurrentTimeInMilliseconds() { + return System.currentTimeMillis(); + } +} diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/util/TargetConnectionChecker.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/util/TargetConnectionChecker.java similarity index 88% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/util/TargetConnectionChecker.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/util/TargetConnectionChecker.java index af8611de29..6bc270a096 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/util/TargetConnectionChecker.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/util/TargetConnectionChecker.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.util; +package com.mercedesbenz.sechub.zapwrapper.util; import java.io.IOException; import java.net.HttpURLConnection; @@ -24,10 +24,10 @@ import com.mercedesbenz.sechub.commons.model.SecHubMessage; import com.mercedesbenz.sechub.commons.model.SecHubMessageType; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperExitCode; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; -import com.mercedesbenz.sechub.owaspzapwrapper.config.OwaspZapScanContext; -import com.mercedesbenz.sechub.owaspzapwrapper.config.ProxyInformation; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperExitCode; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.config.ProxyInformation; +import com.mercedesbenz.sechub.zapwrapper.config.ZapScanContext; /** * This class is used to test if a target URI is reachable. This way we can stop @@ -38,9 +38,9 @@ public class TargetConnectionChecker { private static final Logger LOG = LoggerFactory.getLogger(TargetConnectionChecker.class); private static final String TLS = "TLS"; - public void assertApplicationIsReachable(OwaspZapScanContext scanContext) { + public void assertApplicationIsReachable(ZapScanContext scanContext) { boolean isReachable = false; - Iterator iterator = scanContext.getOwaspZapURLsIncludeList().iterator(); + Iterator iterator = scanContext.getZapURLsIncludeSet().iterator(); while (iterator.hasNext() && isReachable == false) { // trying to reach the target URL and all includes until the first reachable // URL is found. @@ -58,7 +58,7 @@ boolean isReponseCodeValid(int responseCode) { return responseCode < 500 && responseCode != 404; } - private boolean isSiteCurrentlyReachable(OwaspZapScanContext scanContext, URL url, int maxNumberOfConnectionRetries, int retryWaittimeInMilliseconds) { + private boolean isSiteCurrentlyReachable(ZapScanContext scanContext, URL url, int maxNumberOfConnectionRetries, int retryWaittimeInMilliseconds) { if (isTargetReachable(url, scanContext.getProxyInformation())) { return true; } @@ -70,7 +70,7 @@ private boolean isSiteCurrentlyReachable(OwaspZapScanContext scanContext, URL ur } } // write message to the user for each URL that was not reachable - scanContext.getOwaspZapProductMessageHelper().writeSingleProductMessage(new SecHubMessage(SecHubMessageType.WARNING, + scanContext.getZapProductMessageHelper().writeSingleProductMessage(new SecHubMessage(SecHubMessageType.WARNING, "The URL " + url + " was not reachable after trying " + maxNumberOfConnectionRetries + 1 + " times. It might cannot be scanned.")); return false; } @@ -123,7 +123,7 @@ private void wait(int waittimeInMilliseconds) { } } - private String createErrorMessage(OwaspZapScanContext scanContext) { + private String createErrorMessage(ZapScanContext scanContext) { ProxyInformation proxyInformation = scanContext.getProxyInformation(); String errorMessage = "Target url: " + scanContext.getTargetUrl() + " is not reachable"; diff --git a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/util/UrlUtil.java b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/util/UrlUtil.java similarity index 94% rename from sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/util/UrlUtil.java rename to sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/util/UrlUtil.java index 187ab84f5e..683ce8f43a 100644 --- a/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/owaspzapwrapper/util/UrlUtil.java +++ b/sechub-wrapper-owasp-zap/src/main/java/com/mercedesbenz/sechub/zapwrapper/util/UrlUtil.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.util; +package com.mercedesbenz.sechub.zapwrapper.util; import java.util.regex.Pattern; diff --git a/sechub-wrapper-owasp-zap/src/main/resources/full-rulesets/owasp-zap-full-ruleset-all-release-status.json b/sechub-wrapper-owasp-zap/src/main/resources/full-rulesets/zap-full-ruleset-all-release-status.json similarity index 100% rename from sechub-wrapper-owasp-zap/src/main/resources/full-rulesets/owasp-zap-full-ruleset-all-release-status.json rename to sechub-wrapper-owasp-zap/src/main/resources/full-rulesets/zap-full-ruleset-all-release-status.json diff --git a/sechub-wrapper-owasp-zap/src/main/resources/owaspzap-ruleset-helper/requirements.txt b/sechub-wrapper-owasp-zap/src/main/resources/zap-ruleset-helper/requirements.txt similarity index 100% rename from sechub-wrapper-owasp-zap/src/main/resources/owaspzap-ruleset-helper/requirements.txt rename to sechub-wrapper-owasp-zap/src/main/resources/zap-ruleset-helper/requirements.txt diff --git a/sechub-wrapper-owasp-zap/src/main/resources/owaspzap-ruleset-helper/owaspzap_ruleset_helper.py b/sechub-wrapper-owasp-zap/src/main/resources/zap-ruleset-helper/zap_ruleset_helper.py similarity index 100% rename from sechub-wrapper-owasp-zap/src/main/resources/owaspzap-ruleset-helper/owaspzap_ruleset_helper.py rename to sechub-wrapper-owasp-zap/src/main/resources/zap-ruleset-helper/zap_ruleset_helper.py diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/OwaspZapScanExecutorTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/OwaspZapScanExecutorTest.java deleted file mode 100644 index e2b50d1c78..0000000000 --- a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/OwaspZapScanExecutorTest.java +++ /dev/null @@ -1,114 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.cli; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.net.URL; -import java.util.HashSet; -import java.util.Set; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.zaproxy.clientapi.core.ClientApi; - -import com.mercedesbenz.sechub.owaspzapwrapper.config.OwaspZapClientApiFactory; -import com.mercedesbenz.sechub.owaspzapwrapper.config.OwaspZapScanContext; -import com.mercedesbenz.sechub.owaspzapwrapper.helper.OwaspZapProductMessageHelper; -import com.mercedesbenz.sechub.owaspzapwrapper.scan.OwaspZapScan; -import com.mercedesbenz.sechub.owaspzapwrapper.util.TargetConnectionChecker; - -class OwaspZapScanExecutorTest { - - private OwaspZapScanExecutor executorToTest; - - private OwaspZapClientApiFactory clientApiFactory; - private OwaspZapScanResolver resolver; - private TargetConnectionChecker connectionChecker; - - @BeforeEach - void beforeEach() { - executorToTest = new OwaspZapScanExecutor(); - - clientApiFactory = mock(OwaspZapClientApiFactory.class); - resolver = mock(OwaspZapScanResolver.class); - connectionChecker = mock(TargetConnectionChecker.class); - - executorToTest.clientApiFactory = clientApiFactory; - executorToTest.resolver = resolver; - executorToTest.connectionChecker = connectionChecker; - } - - @Test - void the_result_from_resolver_returned_is_executed() throws Exception { - /* prepare */ - OwaspZapScanContext scanContext = mock(OwaspZapScanContext.class); - ClientApi clientApi = mock(ClientApi.class); - - URL targetUrl = new URL("http://www.example.com"); - Set includeList = new HashSet<>(); - includeList.add(targetUrl); - - when(scanContext.getTargetUrl()).thenReturn(targetUrl); - when(scanContext.getOwaspZapURLsIncludeList()).thenReturn(includeList); - when(scanContext.getMaxNumberOfConnectionRetries()).thenReturn(1); - when(scanContext.getRetryWaittimeInMilliseconds()).thenReturn(0); - when(scanContext.connectionCheckEnabled()).thenReturn(false); - - OwaspZapScan scan = mock(OwaspZapScan.class); - when(resolver.resolveScanImplementation(eq(scanContext), any())).thenReturn(scan); - when(clientApiFactory.create(scanContext.getServerConfig())).thenReturn(clientApi); - doNothing().when(connectionChecker).assertApplicationIsReachable(scanContext); - - /* execute */ - executorToTest.execute(scanContext); - - /* test */ - verify(connectionChecker, never()).assertApplicationIsReachable(scanContext); - verify(clientApiFactory).create(scanContext.getServerConfig()); - verify(resolver).resolveScanImplementation(scanContext, clientApi); - verify(scan).scan(); - - } - - @Test - void target_is_not_reachable_throws_mustexitruntimeexception() throws Exception { - /* prepare */ - OwaspZapScanContext scanContext = mock(OwaspZapScanContext.class); - OwaspZapProductMessageHelper productMessageHelper = mock(OwaspZapProductMessageHelper.class); - - ClientApi clientApi = mock(ClientApi.class); - - URL targetUrl = new URL("http://www.my-url.com"); - - Set includeList = new HashSet<>(); - includeList.add(targetUrl); - when(scanContext.getOwaspZapURLsIncludeList()).thenReturn(includeList); - when(scanContext.getMaxNumberOfConnectionRetries()).thenReturn(1); - when(scanContext.getRetryWaittimeInMilliseconds()).thenReturn(0); - when(scanContext.getOwaspZapProductMessageHelper()).thenReturn(productMessageHelper); - when(scanContext.connectionCheckEnabled()).thenReturn(true); - doNothing().when(productMessageHelper).writeSingleProductMessage(any()); - - OwaspZapScan scan = mock(OwaspZapScan.class); - when(resolver.resolveScanImplementation(eq(scanContext), any())).thenReturn(scan); - when(clientApiFactory.create(scanContext.getServerConfig())).thenReturn(clientApi); - doThrow(new ZapWrapperRuntimeException(null, null)).when(connectionChecker).assertApplicationIsReachable(eq(scanContext)); - - /* execute + test */ - assertThrows(ZapWrapperRuntimeException.class, () -> executorToTest.execute(scanContext)); - - verify(connectionChecker).assertApplicationIsReachable(scanContext); - verify(scan, never()).scan(); - verify(clientApiFactory, never()).create(scanContext.getServerConfig()); - verify(resolver, never()).resolveScanImplementation(scanContext, clientApi); - - } -} diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/OwaspZapScanResolverTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/OwaspZapScanResolverTest.java deleted file mode 100644 index 6fe977a2cc..0000000000 --- a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/cli/OwaspZapScanResolverTest.java +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.cli; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.EnumSource; -import org.zaproxy.clientapi.core.ClientApi; - -import com.mercedesbenz.sechub.owaspzapwrapper.config.OwaspZapScanContext; -import com.mercedesbenz.sechub.owaspzapwrapper.config.auth.AuthenticationType; -import com.mercedesbenz.sechub.owaspzapwrapper.scan.OwaspZapScan; -import com.mercedesbenz.sechub.owaspzapwrapper.scan.UnauthenticatedScan; -import com.mercedesbenz.sechub.owaspzapwrapper.scan.auth.HTTPBasicAuthScan; - -class OwaspZapScanResolverTest { - - private OwaspZapScanResolver resolverToTest; - - @BeforeEach - void beforeEach() { - resolverToTest = new OwaspZapScanResolver(); - } - - @Test - void unauthenticated_scan_is_resolved_correctly() { - /* prepare */ - OwaspZapScanContext scanContext = mock(OwaspZapScanContext.class); - when(scanContext.getAuthenticationType()).thenReturn(AuthenticationType.UNAUTHENTICATED); - ClientApi clientApi = mock(ClientApi.class); - - /* execute */ - OwaspZapScan scan = resolverToTest.resolveScanImplementation(scanContext, clientApi); - - /* test */ - assertTrue(scan instanceof UnauthenticatedScan); - } - - @Test - void http_basic_authentication_scan_is_resolved_correctly() { - /* prepare */ - OwaspZapScanContext scanContext = mock(OwaspZapScanContext.class); - when(scanContext.getAuthenticationType()).thenReturn(AuthenticationType.HTTP_BASIC_AUTHENTICATION); - ClientApi clientApi = mock(ClientApi.class); - - /* execute */ - OwaspZapScan scan = resolverToTest.resolveScanImplementation(scanContext, clientApi); - - /* test */ - assertTrue(scan instanceof HTTPBasicAuthScan); - } - - @Test - void authenticationtype_null_is_throwing_mustexitruntimeexception() { - /* prepare */ - OwaspZapScanContext scanContext = mock(OwaspZapScanContext.class); - when(scanContext.getAuthenticationType()).thenReturn(null); - ClientApi clientApi = mock(ClientApi.class); - - /* execute + test */ - assertThrows(ZapWrapperRuntimeException.class, () -> resolverToTest.resolveScanImplementation(scanContext, clientApi)); - } - - @ParameterizedTest - @EnumSource(value = AuthenticationType.class, names = { "FORM_BASED_AUTHENTICATION", "SCRIPT_BASED_AUTHENTICATION", "JSON_BASED_AUTHENTICATION" }) - void not_yet_supported_authenticationtype_is_throwing_mustexitruntimeexception(AuthenticationType authType) { - /* prepare */ - OwaspZapScanContext scanContext = mock(OwaspZapScanContext.class); - when(scanContext.getAuthenticationType()).thenReturn(authType); - ClientApi clientApi = mock(ClientApi.class); - - /* execute + test */ - assertThrows(ZapWrapperRuntimeException.class, () -> resolverToTest.resolveScanImplementation(scanContext, clientApi)); - } - -} diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/config/ApiDefinitionFileProviderTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/config/ApiDefinitionFileProviderTest.java deleted file mode 100644 index 3b431c8b8a..0000000000 --- a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/config/ApiDefinitionFileProviderTest.java +++ /dev/null @@ -1,141 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import java.nio.file.Path; -import java.util.stream.Stream; - -import org.junit.jupiter.api.Named; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import com.mercedesbenz.sechub.commons.model.SecHubScanConfiguration; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperExitCode; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; - -class ApiDefinitionFileProviderTest { - - private ApiDefinitionFileProvider providerToTest = new ApiDefinitionFileProvider();; - - @Test - void sources_folder_is_null_results_in_null_as_api_file_path() { - /* execute */ - Path result = providerToTest.fetchApiDefinitionFile(null, new SecHubScanConfiguration()); - - /* test */ - assertEquals(null, result); - } - - @Test - void sechub_scan_config_is_null_results_in_null_as_api_file_path() { - /* execute */ - Path result = providerToTest.fetchApiDefinitionFile("/example/path/to/extracted/sources", null); - - /* test */ - assertEquals(null, result); - } - - @Test - void missing_data_section_part_results_in_null_as_api_file_path() { - /* prepare */ - String sechubScanConfigJSON = "{\"apiVersion\":\"1.0\"," - + "\"webScan\":{\"uri\":\"https://localhost:8443\",\"api\":{\"type\":\"openApi\",\"use\":[\"open-api-file-reference\"]}}}"; - SecHubScanConfiguration sechubScanConfiguration = SecHubScanConfiguration.createFromJSON(sechubScanConfigJSON); - - /* execute */ - Path result = providerToTest.fetchApiDefinitionFile("/example/path/to/extracted/sources", sechubScanConfiguration); - - /* test */ - assertEquals(null, result); - } - - @ParameterizedTest - @MethodSource("sourcesPartSizeTestNamedArguments") - void sources_part_with_size_other_than_exactly_one_results_in_zap_wrapper_runtime_exception(String sechubScanConfigJSON) { - /* prepare */ - SecHubScanConfiguration sechubScanConfiguration = SecHubScanConfiguration.createFromJSON(sechubScanConfigJSON); - - /* execute + test */ - ZapWrapperRuntimeException exception = assertThrows(ZapWrapperRuntimeException.class, - () -> providerToTest.fetchApiDefinitionFile("/example/path/to/extracted/sources", sechubScanConfiguration)); - - assertEquals("Sources must contain exactly 1 entry.", exception.getMessage()); - assertEquals(ZapWrapperExitCode.API_DEFINITION_CONFIG_INVALID, exception.getExitCode()); - } - - @Test - void missing_filesystem_part_results_in_zap_wrapper_runtime_exception() { - /* prepare */ - String sechubScanConfigJSON = "{\"apiVersion\":\"1.0\",\"data\":{\"sources\":[{\"name\":\"open-api-file-reference\"}]}," - + "\"webScan\":{\"uri\":\"https://localhost:8443\",\"api\":{\"type\":\"openApi\",\"use\":[\"open-api-file-reference\"]}}}"; - SecHubScanConfiguration sechubScanConfiguration = SecHubScanConfiguration.createFromJSON(sechubScanConfigJSON); - - /* execute + test */ - ZapWrapperRuntimeException exception = assertThrows(ZapWrapperRuntimeException.class, - () -> providerToTest.fetchApiDefinitionFile("/example/path/to/extracted/sources", sechubScanConfiguration)); - - assertEquals("Sources filesystem part must be set at this stage.", exception.getMessage()); - assertEquals(ZapWrapperExitCode.API_DEFINITION_CONFIG_INVALID, exception.getExitCode()); - - } - - @ParameterizedTest - @MethodSource("filesystemPartSizeTestNamedArguments") - void filesystem_part_with_size_other_than_exactly_one_results_in_zap_wrapper_runtime_exception(String sechubScanConfigJSON) { - /* prepare */ - SecHubScanConfiguration sechubScanConfiguration = SecHubScanConfiguration.createFromJSON(sechubScanConfigJSON); - - /* execute + test */ - ZapWrapperRuntimeException exception = assertThrows(ZapWrapperRuntimeException.class, - () -> providerToTest.fetchApiDefinitionFile("/example/path/to/extracted/sources", sechubScanConfiguration)); - - assertEquals("Sources filesystem files part must contain exactly 1 entry.", exception.getMessage()); - assertEquals(ZapWrapperExitCode.API_DEFINITION_CONFIG_INVALID, exception.getExitCode()); - } - - @Test - void provider_returns_correct_path_for_valid_sechub_scan_config_with_openapi_definition_file() { - /* prepare */ - String sechubScanConfigJSON = "{\"apiVersion\":\"1.0\",\"data\":{\"sources\":[{\"name\":\"open-api-file-reference\",\"fileSystem\":{\"files\":[\"openapi3.json\"]}}]}," - + "\"webScan\":{\"uri\":\"https://localhost:8443\",\"api\":{\"type\":\"openApi\",\"use\":[\"open-api-file-reference\"]}}}"; - SecHubScanConfiguration sechubScanConfiguration = SecHubScanConfiguration.createFromJSON(sechubScanConfigJSON); - - /* execute */ - Path path = providerToTest.fetchApiDefinitionFile("test/path", sechubScanConfiguration); - - /* test */ - assertEquals(path.toString(), "test/path/openapi3.json"); - } - - static Stream sourcesPartSizeTestNamedArguments() { - /* @formatter:off */ - return Stream.of( - Arguments.of( - Named.of("Sources part empty", - "{\"apiVersion\":\"1.0\",\"data\":{\"sources\":[]},\"webScan\":{\"uri\":\"https://localhost:8443\",\"api\":{\"type\":\"openApi\",\"use\":[\"open-api-file-reference\"]}}}")), - Arguments.of( - Named.of("Sources part more than one file", - "{\"apiVersion\":\"1.0\",\"data\":{\"sources\":[{\"name\":\"open-api-file-reference\",\"fileSystem\":{\"files\":[\"openapi3.json\"]}},{\"name\":\"second-reference\",\"fileSystem\":{\"files\":[\"second-openapi-file.json\"]}}]},\"webScan\":{\"uri\":\"https://localhost:8443\",\"api\":{\"type\":\"openApi\",\"use\":[\"open-api-file-reference\",\"second-reference\"]}}}")), - Arguments.of( - Named.of("Binaries part used instead of sources", - "{\"apiVersion\":\"1.0\",\"data\":{\"binaries\":[{\"name\":\"open-api-file-reference\"}]},\"webScan\":{\"uri\":\"https://localhost:8443\",\"api\":{\"type\":\"openApi\",\"use\":[\"open-api-file-reference\"]}}}"))); - /* @formatter:on */ - } - - static Stream filesystemPartSizeTestNamedArguments() { - /* @formatter:off */ - return Stream.of( - Arguments.of( - Named.of("Filesystem part empty", - "{\"apiVersion\":\"1.0\",\"data\":{\"sources\":[{\"name\":\"open-api-file-reference\",\"fileSystem\":{}}]},\"webScan\":{\"uri\":\"https://localhost:8443\",\"api\":{\"type\":\"openApi\",\"use\":[\"open-api-file-reference\"]}}}")), - Arguments.of( - Named.of("Filesystem part more than one file", - "{\"apiVersion\":\"1.0\",\"data\":{\"sources\":[{\"name\":\"open-api-file-reference\",\"fileSystem\":{\"files\":[\"openapi3.json\", \"second-file.json\"]}}]},\"webScan\":{\"uri\":\"https://localhost:8443\",\"api\":{\"type\":\"openApi\",\"use\":[\"open-api-file-reference\"]}}}"))); - /* @formatter:on */ - } - -} diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapApiResponseHelperTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapApiResponseHelperTest.java deleted file mode 100644 index e999dbfd0d..0000000000 --- a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapApiResponseHelperTest.java +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.helper; - -import static org.junit.jupiter.api.Assertions.*; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.zaproxy.clientapi.core.ApiResponse; -import org.zaproxy.clientapi.core.ApiResponseElement; -import org.zaproxy.clientapi.core.ApiResponseList; - -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; - -class OwaspZapApiResponseHelperTest { - - private OwaspZapApiResponseHelper helperToTest; - - @BeforeEach - void beforeEach() { - helperToTest = new OwaspZapApiResponseHelper(); - } - - @Test - void invalid_type_helper_throws_mustexitruntimeexception() { - /* prepare */ - ApiResponse response = new ApiResponseList("example"); - - /* execute + test */ - assertThrows(ZapWrapperRuntimeException.class, () -> helperToTest.getIdOfApiRepsonse(response)); - } - - @Test - void valid_type_results_in_correct_id() { - /* prepare */ - ApiResponse response = new ApiResponseElement("example", "10"); - - /* execute */ - String id = helperToTest.getIdOfApiRepsonse(response); - - /* test */ - assertEquals("10", id); - } -} diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/config/ApiDefinitionFileProviderTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/config/ApiDefinitionFileProviderTest.java new file mode 100644 index 0000000000..994198267e --- /dev/null +++ b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/config/ApiDefinitionFileProviderTest.java @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.zapwrapper.config; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; +import java.util.List; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Named; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import com.mercedesbenz.sechub.commons.model.SecHubScanConfiguration; + +class ApiDefinitionFileProviderTest { + + private ApiDefinitionFileProvider providerToTest = new ApiDefinitionFileProvider();; + + @Test + void sources_folder_is_null_results_in_empty_list() { + /* execute */ + List result = providerToTest.fetchApiDefinitionFiles(null, new SecHubScanConfiguration()); + + /* test */ + assertTrue(result.isEmpty()); + } + + @Test + void sechub_scan_config_is_null_results_in_empty_list() { + /* execute */ + List result = providerToTest.fetchApiDefinitionFiles("/example/path/to/extracted/sources", null); + + /* test */ + assertTrue(result.isEmpty()); + } + + @Test + void missing_data_section_part_results_in_empty_list() { + /* prepare */ + String sechubScanConfigJSON = """ + {"apiVersion":"1.0","webScan":{"url":"https://localhost:8443","api":{"type":"openApi","use":["open-api-file-reference"]}}}"""; + SecHubScanConfiguration sechubScanConfiguration = SecHubScanConfiguration.createFromJSON(sechubScanConfigJSON); + + /* execute */ + List result = providerToTest.fetchApiDefinitionFiles("/example/path/to/extracted/sources", sechubScanConfiguration); + + /* test */ + assertTrue(result.isEmpty()); + } + + @Test + void empty_sources_section_in_sechub_configuration_results_in_empty_list() { + /* prepare */ + String sechubScanConfigJSON = """ + {"apiVersion":"1.0","data":{"sources":[]}, + "webScan":{"url":"https://localhost:8443","api":{"type":"openApi","use":["open-api-file-reference"]}}}"""; + SecHubScanConfiguration sechubScanConfiguration = SecHubScanConfiguration.createFromJSON(sechubScanConfigJSON); + + /* execute */ + List result = providerToTest.fetchApiDefinitionFiles("/example/path/to/extracted/sources", sechubScanConfiguration); + + /* test */ + assertTrue(result.isEmpty()); + } + + @Test + void missing_filesystem_part_in_sechub_configuration_results_in_empty_openapi_files_list() { + /* prepare */ + String sechubScanConfigJSON = """ + {"apiVersion":"1.0","data":{"sources":[{"name":"open-api-file-reference"}]}, + "webScan":{"url":"https://localhost:8443","api":{"type":"openApi","use":["open-api-file-reference"]}}}"""; + SecHubScanConfiguration sechubScanConfiguration = SecHubScanConfiguration.createFromJSON(sechubScanConfigJSON); + + /* execute */ + List result = providerToTest.fetchApiDefinitionFiles("/example/path/to/extracted/sources", sechubScanConfiguration); + + /* test */ + assertTrue(result.isEmpty()); + } + + @Test + void empty_filesystem_part_in_sechub_configuration_results_in_empty_list() { + /* prepare */ + String sechubScanConfigJSON = """ + {"apiVersion":"1.0","data":{"sources":[{"name":"open-api-file-reference","fileSystem":{}}]}, + "webScan":{"url":"https://localhost:8443","api":{"type":"openApi","use":["open-api-file-reference"]}}}"""; + SecHubScanConfiguration sechubScanConfiguration = SecHubScanConfiguration.createFromJSON(sechubScanConfigJSON); + + /* execute */ + List result = providerToTest.fetchApiDefinitionFiles("/example/path/to/extracted/sources", sechubScanConfiguration); + + /* test */ + assertTrue(result.isEmpty()); + } + + @Test + void binaries_instead_of_sources_results_in_empty_list() { + /* prepare */ + String sechubScanConfigJSON = """ + {"apiVersion":"1.0","data":{"binaries":[{"name":"open-api-file-reference"}]}, + "webScan":{"url":"https://localhost:8443","api":{"type":"openApi","use":["open-api-file-reference"]}}}"""; + SecHubScanConfiguration sechubScanConfiguration = SecHubScanConfiguration.createFromJSON(sechubScanConfigJSON); + + /* execute */ + List result = providerToTest.fetchApiDefinitionFiles("/example/path/to/extracted/sources", sechubScanConfiguration); + + /* test */ + assertTrue(result.isEmpty()); + } + + @Test + void folders_instead_of_files_inside_filesystem_results_in_empty_list() { + /* prepare */ + String sechubScanConfigJSON = """ + {"apiVersion":"1.0","data":{"sources":[{"name":"open-api-file-reference","fileSystem":{"folders":["openapifolder/"]}}]}, + "webScan":{"url":"https://localhost:8443","api":{"type":"openApi","use":["open-api-file-reference"]}}}"""; + SecHubScanConfiguration sechubScanConfiguration = SecHubScanConfiguration.createFromJSON(sechubScanConfigJSON); + + /* execute */ + List result = providerToTest.fetchApiDefinitionFiles("test/path", sechubScanConfiguration); + + /* test */ + assertTrue(result.isEmpty()); + } + + @Test + void data_section_name_differs_from_use_part_inside_openapi_definition_results_in_empty_list() { + /* prepare */ + String sechubScanConfigJSON = """ + {"apiVersion":"1.0","data":{"sources":[{"name":"open-api-file-reference","fileSystem":{"files":["openapi3.json"]}}]}, + "webScan":{"url":"https://localhost:8443","api":{"type":"openApi","use":["no-existing-reference"]}}}"""; + SecHubScanConfiguration sechubScanConfiguration = SecHubScanConfiguration.createFromJSON(sechubScanConfigJSON); + + /* execute */ + List result = providerToTest.fetchApiDefinitionFiles("test/path", sechubScanConfiguration); + + /* test */ + assertTrue(result.isEmpty()); + } + + @Test + void valid_sechub_scan_config_with_openapi_definition_file_results_in_list_with_one_file() { + /* prepare */ + String sechubScanConfigJSON = """ + {"apiVersion":"1.0","data":{"sources":[{"name":"open-api-file-reference","fileSystem":{"files":["openapi3.json"]}}]}, + "webScan":{"url":"https://localhost:8443","api":{"type":"openApi","use":["open-api-file-reference"]}}}"""; + SecHubScanConfiguration sechubScanConfiguration = SecHubScanConfiguration.createFromJSON(sechubScanConfigJSON); + + /* execute */ + List result = providerToTest.fetchApiDefinitionFiles("test/path", sechubScanConfiguration); + + /* test */ + assertEquals(1, result.size()); + } + + @ParameterizedTest + @MethodSource("multipleFilesTestNamedArguments") + void mutliple_files_result_in_correct_list_of_files(String sechubScanConfigJSON) { + /* prepare */ + SecHubScanConfiguration sechubScanConfiguration = SecHubScanConfiguration.createFromJSON(sechubScanConfigJSON); + + /* execute */ + List result = providerToTest.fetchApiDefinitionFiles("test/path", sechubScanConfiguration); + + /* test */ + assertEquals(2, result.size()); + } + + static Stream multipleFilesTestNamedArguments() { + /* @formatter:off */ + String moreThanOneDataSectionName = "Sources part more than one file in 2 data sections"; + String sechubConfigWithmoreThanOneDataSection = """ + {"apiVersion":"1.0","data":{"sources":[{"name":"open-api-file-reference","fileSystem":{"files":["openapi3.json"]}}, + {"name":"second-reference","fileSystem":{"files":["second-openapi-file.json"]}}]}, + "webScan":{"url":"https://localhost:8443","api":{"type":"openApi","use":["open-api-file-reference","second-reference"]}}}"""; + + String filesystemPartHasMoreThanOneFileName = "Filesystem files part more than one file"; + String sechubConfigWithfilesystemPartHasMoreThanOneFile = """ + {"apiVersion":"1.0","data":{"sources":[{"name":"open-api-file-reference","fileSystem":{"files":["openapi3.json", "second-file.json"]}}]}, + "webScan":{"url":"https://localhost:8443","api":{"type":"openApi","use":["open-api-file-reference"]}}}"""; + + return Stream.of( + Arguments.of( + Named.of(moreThanOneDataSectionName, + sechubConfigWithmoreThanOneDataSection)), + Arguments.of( + Named.of(filesystemPartHasMoreThanOneFileName, + sechubConfigWithfilesystemPartHasMoreThanOneFile))); + /* @formatter:on */ + } + +} diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/config/RuleProviderTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/config/RuleProviderTest.java similarity index 79% rename from sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/config/RuleProviderTest.java rename to sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/config/RuleProviderTest.java index 6c2fa3fec3..9bb12204d3 100644 --- a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/config/RuleProviderTest.java +++ b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/config/RuleProviderTest.java @@ -1,7 +1,9 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config; +package com.mercedesbenz.sechub.zapwrapper.config; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; import java.util.stream.Stream; @@ -11,8 +13,8 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import com.mercedesbenz.sechub.owaspzapwrapper.config.data.DeactivatedRuleReferences; -import com.mercedesbenz.sechub.owaspzapwrapper.config.data.OwaspZapFullRuleset; +import com.mercedesbenz.sechub.zapwrapper.config.data.DeactivatedRuleReferences; +import com.mercedesbenz.sechub.zapwrapper.config.data.ZapFullRuleset; class RuleProviderTest { @@ -27,7 +29,7 @@ void beforeEach() { @MethodSource("invalidParams") void null_as_files_returns_new_empty_objects(File file) { /* execute */ - OwaspZapFullRuleset fullRuleset = rulesProvider.fetchFullRuleset(file); + ZapFullRuleset fullRuleset = rulesProvider.fetchFullRuleset(file); DeactivatedRuleReferences deactivatedRuleReferences = rulesProvider.fetchDeactivatedRuleReferences(file); /* test */ @@ -45,10 +47,10 @@ void null_as_files_returns_new_empty_objects(File file) { @Test void valid_fullruleset_file_returns_valid_object() { /* prepare */ - File testFile = new File("src/test/resources/zap-available-rules/owaspzap-full-ruleset.json"); + File testFile = new File("src/test/resources/zap-available-rules/zap-full-ruleset.json"); /* execute */ - OwaspZapFullRuleset fullRuleset = rulesProvider.fetchFullRuleset(testFile); + ZapFullRuleset fullRuleset = rulesProvider.fetchFullRuleset(testFile); /* test */ assertNotNull(fullRuleset); @@ -61,7 +63,7 @@ void valid_fullruleset_file_returns_valid_object() { @Test void valid_deactivatedrulereferences_file_returns_valid_object() { /* prepare */ - File testFile = new File("src/test/resources/wrapper-deactivated-rule-examples/owaspzap-rules-to-deactivate.json"); + File testFile = new File("src/test/resources/wrapper-deactivated-rule-examples/zap-rules-to-deactivate.json"); /* execute */ DeactivatedRuleReferences deactivatedRuleReferences = rulesProvider.fetchDeactivatedRuleReferences(testFile); diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/config/SecHubScanConfigProviderTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/config/SecHubScanConfigProviderTest.java similarity index 94% rename from sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/config/SecHubScanConfigProviderTest.java rename to sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/config/SecHubScanConfigProviderTest.java index c0fbee0ecc..d3fea5ff4f 100644 --- a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/config/SecHubScanConfigProviderTest.java +++ b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/config/SecHubScanConfigProviderTest.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config; +package com.mercedesbenz.sechub.zapwrapper.config; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -13,7 +13,7 @@ import com.mercedesbenz.sechub.commons.model.SecHubWebScanConfiguration; import com.mercedesbenz.sechub.commons.model.login.BasicLoginConfiguration; import com.mercedesbenz.sechub.commons.model.login.WebLoginConfiguration; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; class SecHubScanConfigProviderTest { diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/config/OwaspZapScanContextFactoryTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/config/ZapScanContextFactoryTest.java similarity index 84% rename from sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/config/OwaspZapScanContextFactoryTest.java rename to sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/config/ZapScanContextFactoryTest.java index c94bd36da7..ecbfec0dbf 100644 --- a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/config/OwaspZapScanContextFactoryTest.java +++ b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/config/ZapScanContextFactoryTest.java @@ -1,14 +1,15 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config; - -import static com.mercedesbenz.sechub.owaspzapwrapper.util.EnvironmentVariableConstants.PDS_JOB_EXTRACTED_SOURCES_FOLDER; -import static com.mercedesbenz.sechub.owaspzapwrapper.util.EnvironmentVariableConstants.PDS_JOB_USER_MESSAGES_FOLDER; -import static com.mercedesbenz.sechub.owaspzapwrapper.util.EnvironmentVariableConstants.PROXY_HOST_ENV_VARIABLE_NAME; -import static com.mercedesbenz.sechub.owaspzapwrapper.util.EnvironmentVariableConstants.PROXY_PORT_ENV_VARIABLE_NAME; -import static com.mercedesbenz.sechub.owaspzapwrapper.util.EnvironmentVariableConstants.ZAP_API_KEY_ENV_VARIABLE_NAME; -import static com.mercedesbenz.sechub.owaspzapwrapper.util.EnvironmentVariableConstants.ZAP_DEACTIVATED_RULE_REFERENCES; -import static com.mercedesbenz.sechub.owaspzapwrapper.util.EnvironmentVariableConstants.ZAP_HOST_ENV_VARIABLE_NAME; -import static com.mercedesbenz.sechub.owaspzapwrapper.util.EnvironmentVariableConstants.ZAP_PORT_ENV_VARIABLE_NAME; +package com.mercedesbenz.sechub.zapwrapper.config; + +import static com.mercedesbenz.sechub.zapwrapper.util.EnvironmentVariableConstants.PDS_JOB_EVENTS_FOLDER; +import static com.mercedesbenz.sechub.zapwrapper.util.EnvironmentVariableConstants.PDS_JOB_EXTRACTED_SOURCES_FOLDER; +import static com.mercedesbenz.sechub.zapwrapper.util.EnvironmentVariableConstants.PDS_JOB_USER_MESSAGES_FOLDER; +import static com.mercedesbenz.sechub.zapwrapper.util.EnvironmentVariableConstants.PROXY_HOST_ENV_VARIABLE_NAME; +import static com.mercedesbenz.sechub.zapwrapper.util.EnvironmentVariableConstants.PROXY_PORT_ENV_VARIABLE_NAME; +import static com.mercedesbenz.sechub.zapwrapper.util.EnvironmentVariableConstants.ZAP_API_KEY_ENV_VARIABLE_NAME; +import static com.mercedesbenz.sechub.zapwrapper.util.EnvironmentVariableConstants.ZAP_DEACTIVATED_RULE_REFERENCES; +import static com.mercedesbenz.sechub.zapwrapper.util.EnvironmentVariableConstants.ZAP_HOST_ENV_VARIABLE_NAME; +import static com.mercedesbenz.sechub.zapwrapper.util.EnvironmentVariableConstants.ZAP_PORT_ENV_VARIABLE_NAME; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -33,17 +34,17 @@ import org.junit.jupiter.params.provider.NullSource; import org.junit.jupiter.params.provider.ValueSource; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.CommandLineSettings; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; -import com.mercedesbenz.sechub.owaspzapwrapper.config.auth.AuthenticationType; -import com.mercedesbenz.sechub.owaspzapwrapper.config.data.DeactivatedRuleReferences; -import com.mercedesbenz.sechub.owaspzapwrapper.config.data.OwaspZapFullRuleset; -import com.mercedesbenz.sechub.owaspzapwrapper.helper.SecHubWebScanConfigurationHelper; -import com.mercedesbenz.sechub.owaspzapwrapper.util.EnvironmentVariableReader; +import com.mercedesbenz.sechub.zapwrapper.cli.CommandLineSettings; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.config.auth.AuthenticationType; +import com.mercedesbenz.sechub.zapwrapper.config.data.DeactivatedRuleReferences; +import com.mercedesbenz.sechub.zapwrapper.config.data.ZapFullRuleset; +import com.mercedesbenz.sechub.zapwrapper.helper.SecHubWebScanConfigurationHelper; +import com.mercedesbenz.sechub.zapwrapper.util.EnvironmentVariableReader; -class OwaspZapScanContextFactoryTest { +class ZapScanContextFactoryTest { - private OwaspZapScanContextFactory factoryToTest; + private ZapScanContextFactory factoryToTest; private SecHubWebScanConfigurationHelper sechubWebConfigHelper; private EnvironmentVariableReader environmentVariableReader; @@ -60,7 +61,7 @@ class OwaspZapScanContextFactoryTest { void beforeEach() { // create object to test - factoryToTest = new OwaspZapScanContextFactory(); + factoryToTest = new ZapScanContextFactory(); // create mocks sechubWebConfigHelper = mock(SecHubWebScanConfigurationHelper.class); @@ -73,10 +74,11 @@ void beforeEach() { factoryToTest.ruleProvider = ruleProvider; // create test data - fullRulesetFile = new File("src/test/resources/zap-available-rules/owaspzap-full-ruleset.json"); - deactivationFile = new File("src/test/resources/wrapper-deactivated-rule-examples/owaspzap-rules-to-deactivate.json"); + fullRulesetFile = new File("src/test/resources/zap-available-rules/zap-full-ruleset.json"); + deactivationFile = new File("src/test/resources/wrapper-deactivated-rule-examples/zap-rules-to-deactivate.json"); when(environmentVariableReader.readAsString(PDS_JOB_USER_MESSAGES_FOLDER)).thenReturn(tempDir.getAbsolutePath()); + when(environmentVariableReader.readAsString(PDS_JOB_EVENTS_FOLDER)).thenReturn(""); } @Test @@ -94,10 +96,10 @@ void created_configuration_has_max_scan_duration_from_sechub_webconfig() { when(ruleProvider.fetchDeactivatedRuleReferences(any())).thenReturn(new DeactivatedRuleReferences()); /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); /* test */ - assertEquals(result.getMaxScanDurationInMillis(), maxScanDuration); + assertEquals(result.getMaxScanDurationInMilliSeconds(), maxScanDuration); } @@ -111,7 +113,7 @@ void context_name_is_used_from_settings_when_defined() { when(ruleProvider.fetchDeactivatedRuleReferences(any())).thenReturn(new DeactivatedRuleReferences()); /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); /* test */ assertEquals(result.getContextName(), jobUUID); @@ -126,7 +128,7 @@ void context_name_is_created_as_UUID_when_not_defined() { when(ruleProvider.fetchDeactivatedRuleReferences(any())).thenReturn(new DeactivatedRuleReferences()); /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); /* test */ String contextName = result.getContextName(); @@ -148,10 +150,10 @@ void result_contains_server_config_with_arguments_from_command_line_settings_no_ when(ruleProvider.fetchDeactivatedRuleReferences(any())).thenReturn(new DeactivatedRuleReferences()); /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); /* test */ - OwaspZapServerConfiguration serverConfig = result.getServerConfig(); + ZapServerConfiguration serverConfig = result.getServerConfig(); assertNotNull(serverConfig); assertEquals(host, serverConfig.getZaproxyHost()); assertEquals(port, serverConfig.getZaproxyPort()); @@ -184,10 +186,10 @@ void result_contains_server_config_with_arguments_from_environment_when_command_ when(environmentVariableReader.readAsInt(PROXY_PORT_ENV_VARIABLE_NAME)).thenReturn(proxyPort); /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); /* test */ - OwaspZapServerConfiguration serverConfig = result.getServerConfig(); + ZapServerConfiguration serverConfig = result.getServerConfig(); assertNotNull(serverConfig); assertEquals(host, serverConfig.getZaproxyHost()); assertEquals(port, serverConfig.getZaproxyPort()); @@ -208,7 +210,7 @@ void proxy_set_or_not_is_valid_result_returned_contains_null_as_proxyinformation when(environmentVariableReader.readAsInt(PROXY_PORT_ENV_VARIABLE_NAME)).thenReturn(0); /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); /* test */ assertNotNull(result); @@ -249,7 +251,7 @@ void authentication_type_from_config_is_in_result() { when(ruleProvider.fetchDeactivatedRuleReferences(any())).thenReturn(new DeactivatedRuleReferences()); /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); /* test */ assertEquals(result.getAuthenticationType(), type); @@ -271,7 +273,7 @@ void targetURI_calculated_by_factory_is_in_result() { when(ruleProvider.fetchDeactivatedRuleReferences(any())).thenReturn(new DeactivatedRuleReferences()); /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); /* test */ assertEquals(result.getTargetUrl().toString(), createdUri.toString()); @@ -287,7 +289,7 @@ void verbose_from_settings_is_in_result(boolean verboseEnabled) { when(ruleProvider.fetchDeactivatedRuleReferences(any())).thenReturn(new DeactivatedRuleReferences()); /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); /* test */ assertEquals(result.isVerboseOutput(), verboseEnabled); @@ -303,7 +305,7 @@ void ajaxspider_enabled_from_settings_is_in_result(boolean enabled) { when(ruleProvider.fetchDeactivatedRuleReferences(any())).thenReturn(new DeactivatedRuleReferences()); /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); /* test */ assertEquals(result.isAjaxSpiderEnabled(), enabled); @@ -319,7 +321,7 @@ void active_scan_enabled_from_settings_is_in_result(boolean enabled) { when(ruleProvider.fetchDeactivatedRuleReferences(any())).thenReturn(new DeactivatedRuleReferences()); /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); /* test */ assertEquals(result.isActiveScanEnabled(), enabled); @@ -335,7 +337,7 @@ void report_file_from_setting_is_used_in_result() { when(ruleProvider.fetchDeactivatedRuleReferences(any())).thenReturn(new DeactivatedRuleReferences()); /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); /* test */ assertEquals(result.getReportFile(), path); @@ -352,13 +354,13 @@ void commandline_settings_null_throws_zap_wrapper_runtime_exception() { void fullruleset_returned_by_provider_is_in_result() { /* prepare */ CommandLineSettings settings = createSettingsMockWithNecessaryParts(); - when(ruleProvider.fetchFullRuleset(fullRulesetFile)).thenReturn(createOwaspZapFullRuleset()); + when(ruleProvider.fetchFullRuleset(fullRulesetFile)).thenReturn(createZapFullRuleset()); when(ruleProvider.fetchDeactivatedRuleReferences(any())).thenReturn(new DeactivatedRuleReferences()); /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); - OwaspZapFullRuleset fullRuleset = result.getFullRuleset(); + ZapFullRuleset fullRuleset = result.getFullRuleset(); /* test */ verify(ruleProvider, times(1)).fetchFullRuleset(any()); @@ -376,7 +378,7 @@ void rules_to_deactivate_returned_by_provider_is_inside_result() { when(ruleProvider.fetchDeactivatedRuleReferences(deactivationFile)).thenReturn(createDeactivatedRuleReferences()); /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); DeactivatedRuleReferences deactivatedRuleReferences = result.getDeactivatedRuleReferences(); /* test */ @@ -403,7 +405,7 @@ void rules_to_deactivate_returned_by_env_variable_is_inside_result(String value) } /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); DeactivatedRuleReferences deactivatedRuleReferences = result.getDeactivatedRuleReferences(); /* test */ @@ -427,7 +429,7 @@ void rules_to_deactivate_returned_by_command_line_parameter_is_inside_result(Str } /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); DeactivatedRuleReferences deactivatedRuleReferences = result.getDeactivatedRuleReferences(); /* test */ @@ -464,14 +466,12 @@ void api_definition_file_from_sechub_scan_config_is_inside_result() { when(settings.getSecHubConfigFile()).thenReturn(sechubScanConfigFile); when(environmentVariableReader.readAsString(PDS_JOB_EXTRACTED_SOURCES_FOLDER)).thenReturn(extractedSourcesPath); - Path expectedPathToApiDefinitionFile = new File(extractedSourcesPath, "openapi3.json").toPath(); - /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); /* test */ verify(environmentVariableReader, times(1)).readAsString(PDS_JOB_EXTRACTED_SOURCES_FOLDER); - assertEquals(expectedPathToApiDefinitionFile, result.getApiDefinitionFile()); + assertEquals(1, result.getApiDefinitionFiles().size()); } @Test @@ -484,11 +484,11 @@ void includes_and_excludes_from_sechub_json_are_inside_result() { when(settings.getSecHubConfigFile()).thenReturn(sechubScanConfigFile); /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); /* test */ - assertEquals(3, result.getOwaspZapURLsIncludeList().size()); - assertEquals(2, result.getOwaspZapURLsExcludeList().size()); + assertEquals(3, result.getZapURLsIncludeSet().size()); + assertEquals(2, result.getZapURLsExcludeSet().size()); } @ParameterizedTest @@ -500,7 +500,7 @@ void connection_check_from_settings_is_in_result(boolean enabled) { when(ruleProvider.fetchDeactivatedRuleReferences(any())).thenReturn(new DeactivatedRuleReferences()); /* execute */ - OwaspZapScanContext result = factoryToTest.create(settings); + ZapScanContext result = factoryToTest.create(settings); /* test */ assertEquals(result.connectionCheckEnabled(), enabled); @@ -529,11 +529,13 @@ private CommandLineSettings createSettingsMockWithNecessaryPartsWithoutRuleFiles when(settings.getFullRulesetFile()).thenReturn(null); when(settings.getRulesDeactvationFile()).thenReturn(null); + when(settings.getPDSUserMessageFolder()).thenReturn(""); + when(settings.getPDSEventFolder()).thenReturn(""); return settings; } - private OwaspZapFullRuleset createOwaspZapFullRuleset() { + private ZapFullRuleset createZapFullRuleset() { RuleProvider provider = new RuleProvider(); return provider.fetchFullRuleset(fullRulesetFile); } diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/config/OwaspZapClientApiFactoryTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/config/ZapScannerFactoryTest.java similarity index 51% rename from sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/config/OwaspZapClientApiFactoryTest.java rename to sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/config/ZapScannerFactoryTest.java index 022a494699..3cbfc889c4 100644 --- a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/config/OwaspZapClientApiFactoryTest.java +++ b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/config/ZapScannerFactoryTest.java @@ -1,24 +1,27 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config; +package com.mercedesbenz.sechub.zapwrapper.config; -import static org.junit.Assert.*; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import org.zaproxy.clientapi.core.ClientApi; import org.zaproxy.clientapi.core.ClientApiException; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.scan.ZapScanner; -class OwaspZapClientApiFactoryTest { +class ZapScannerFactoryTest { - private OwaspZapClientApiFactory factoryToTest; + private ZapScannerFactory factoryToTest; @BeforeEach void beforeEach() { - factoryToTest = new OwaspZapClientApiFactory(); + factoryToTest = new ZapScannerFactory(); } @Test @@ -30,13 +33,16 @@ void server_config_is_null_throws_mustexcitruntimeexception() throws ClientApiEx @Test void valid_configuration_returns_clientapi_object() throws ClientApiException { /* prepare */ - OwaspZapServerConfiguration serverConfig = new OwaspZapServerConfiguration("127.0.0.1", 8080, "secret-key"); + ZapServerConfiguration serverConfig = new ZapServerConfiguration("127.0.0.1", 8080, "secret-key"); + + ZapScanContext scanContext = mock(ZapScanContext.class); + when(scanContext.getServerConfig()).thenReturn(serverConfig); /* execute */ - ClientApi clientApi = factoryToTest.create(serverConfig); + ZapScanner zapScanner = factoryToTest.create(scanContext); /* test */ - assertNotNull(clientApi); + assertNotNull(zapScanner); } /* @formatter:off */ @@ -49,10 +55,13 @@ void valid_configuration_returns_clientapi_object() throws ClientApiException { /* @formatter:on */ void configuration_where_one_field_is_null_or_invalid_throws_mustexitruntimeexception(String host, int port, String apiKey) throws ClientApiException { /* prepare */ - OwaspZapServerConfiguration serverConfig = new OwaspZapServerConfiguration(host, port, apiKey); + ZapServerConfiguration serverConfig = new ZapServerConfiguration(host, port, apiKey); + + ZapScanContext scanContext = mock(ZapScanContext.class); + when(scanContext.getServerConfig()).thenReturn(serverConfig); /* execute + test */ - assertThrows(ZapWrapperRuntimeException.class, () -> factoryToTest.create(serverConfig)); + assertThrows(ZapWrapperRuntimeException.class, () -> factoryToTest.create(scanContext)); } } diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/config/data/DeactivatedRuleReferencesTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/config/data/DeactivatedRuleReferencesTest.java similarity index 95% rename from sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/config/data/DeactivatedRuleReferencesTest.java rename to sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/config/data/DeactivatedRuleReferencesTest.java index 1e959087b4..760c5cf265 100644 --- a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/config/data/DeactivatedRuleReferencesTest.java +++ b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/config/data/DeactivatedRuleReferencesTest.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.config.data; +package com.mercedesbenz.sechub.zapwrapper.config.data; import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/BaseTargetUriFactoryTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/helper/BaseTargetUriFactoryTest.java similarity index 95% rename from sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/BaseTargetUriFactoryTest.java rename to sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/helper/BaseTargetUriFactoryTest.java index 1206ae8c7d..6371247c32 100644 --- a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/BaseTargetUriFactoryTest.java +++ b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/helper/BaseTargetUriFactoryTest.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.helper; +package com.mercedesbenz.sechub.zapwrapper.helper; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -12,7 +12,7 @@ import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.NullSource; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; class BaseTargetUriFactoryTest { diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/IncludeExcludeToOwaspZapURIHelperTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/helper/IncludeExcludeToZapURLHelperTest.java similarity index 64% rename from sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/IncludeExcludeToOwaspZapURIHelperTest.java rename to sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/helper/IncludeExcludeToZapURLHelperTest.java index d43ff3a664..a86e84c45f 100644 --- a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/IncludeExcludeToOwaspZapURIHelperTest.java +++ b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/helper/IncludeExcludeToZapURLHelperTest.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.helper; +package com.mercedesbenz.sechub.zapwrapper.helper; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -11,29 +11,31 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import com.mercedesbenz.sechub.commons.model.SecHubMessage; -class IncludeExcludeToOwaspZapURIHelperTest { +class IncludeExcludeToZapURLHelperTest { - private IncludeExcludeToOwaspZapURLHelper helperToTest; + private IncludeExcludeToZapURLHelper helperToTest; private List userMessages; @BeforeEach void beforeEach() { - helperToTest = new IncludeExcludeToOwaspZapURLHelper(); + helperToTest = new IncludeExcludeToZapURLHelper(); userMessages = new LinkedList<>(); } @Test - void returns_empty_list_if_list_of_subSites_is_null() throws MalformedURLException { + void list_of_subSites_is_null_returns_empty_list() throws MalformedURLException { /* prepare */ URL targetUrl = new URL("https://127.0.0.1:8080"); List sites = null; /* execute */ - List urls = helperToTest.createListOfUrls(OwaspZapURLType.INCLUDE, targetUrl, sites, userMessages); + List urls = helperToTest.createListOfUrls(ZapURLType.INCLUDE, targetUrl, sites, userMessages); /* test */ assertTrue(urls.isEmpty()); @@ -41,27 +43,28 @@ void returns_empty_list_if_list_of_subSites_is_null() throws MalformedURLExcepti } @Test - void returns_empty_list_if_list_of_subSites_is_empty() throws MalformedURLException { + void list_of_subSites_is_empty_returns_empty_list() throws MalformedURLException { /* prepare */ URL targetUrl = new URL("https://127.0.0.1:8080"); List sites = new ArrayList<>(); /* execute */ - List urls = helperToTest.createListOfUrls(OwaspZapURLType.INCLUDE, targetUrl, sites, userMessages); + List urls = helperToTest.createListOfUrls(ZapURLType.INCLUDE, targetUrl, sites, userMessages); /* test */ assertTrue(urls.isEmpty()); assertTrue(userMessages.isEmpty()); } - @Test - void returns_list_of_url_conform_for_owasp_zap_includes_or_excludes() throws MalformedURLException { + @ParameterizedTest + @ValueSource(strings = { "https://127.0.0.1:8080", "https://127.0.0.1:8080/" }) + void list_of_subsites_and_target_url_returns_list_of_combined_urls(String url) throws MalformedURLException { /* prepare */ - URL targetUrl = new URL("https://127.0.0.1:8080"); + URL targetUrl = new URL(url); List sites = createExampleListOfSites(); /* execute */ - List urls = helperToTest.createListOfUrls(OwaspZapURLType.EXCLUDE, targetUrl, sites, userMessages); + List urls = helperToTest.createListOfUrls(ZapURLType.EXCLUDE, targetUrl, sites, userMessages); /* test */ assertTrue(urls.contains(new URL("https://127.0.0.1:8080/sub"))); diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/ScanDurationHelperTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/helper/ScanDurationHelperTest.java similarity index 97% rename from sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/ScanDurationHelperTest.java rename to sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/helper/ScanDurationHelperTest.java index 95ec1462aa..d00297004f 100644 --- a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/ScanDurationHelperTest.java +++ b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/helper/ScanDurationHelperTest.java @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.helper; +package com.mercedesbenz.sechub.zapwrapper.helper; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/SecHubWebScanConfigurationHelperTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/helper/SecHubWebScanConfigurationHelperTest.java similarity index 90% rename from sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/SecHubWebScanConfigurationHelperTest.java rename to sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/helper/SecHubWebScanConfigurationHelperTest.java index 599e65087e..2a95c6c398 100644 --- a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/SecHubWebScanConfigurationHelperTest.java +++ b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/helper/SecHubWebScanConfigurationHelperTest.java @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.helper; +package com.mercedesbenz.sechub.zapwrapper.helper; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.File; @@ -9,8 +9,8 @@ import com.mercedesbenz.sechub.commons.model.SecHubScanConfiguration; import com.mercedesbenz.sechub.commons.model.SecHubWebScanConfiguration; -import com.mercedesbenz.sechub.owaspzapwrapper.config.auth.AuthenticationType; import com.mercedesbenz.sechub.test.TestFileReader; +import com.mercedesbenz.sechub.zapwrapper.config.auth.AuthenticationType; class SecHubWebScanConfigurationHelperTest { diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapEventHandlerTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/helper/ZapPDSEventHandlerTest.java similarity index 59% rename from sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapEventHandlerTest.java rename to sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/helper/ZapPDSEventHandlerTest.java index ee6adcd0c2..0002a37e9d 100644 --- a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapEventHandlerTest.java +++ b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/helper/ZapPDSEventHandlerTest.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.helper; +package com.mercedesbenz.sechub.zapwrapper.helper; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -14,15 +14,15 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; -class OwaspZapEventHandlerTest { +class ZapPDSEventHandlerTest { - private OwaspZapEventHandler owaspZapEventHandler; + private ZapPDSEventHandler zapPDSEventHandler; @BeforeEach void beforeEach() { - owaspZapEventHandler = new OwaspZapEventHandler(); + zapPDSEventHandler = new ZapPDSEventHandler(""); } @Test @@ -31,19 +31,19 @@ void file_does_not_exist_and_so_no_scan_is_cancelled() throws IOException { String scanContextName = UUID.randomUUID().toString(); /* execute + test */ - assertFalse(owaspZapEventHandler.isScanCancelled()); - assertDoesNotThrow(() -> owaspZapEventHandler.cancelScan(scanContextName)); + assertFalse(zapPDSEventHandler.isScanCancelled()); + assertDoesNotThrow(() -> zapPDSEventHandler.cancelScan(scanContextName)); } @Test void file_does_exist_and_so_scan_is_cancelled(@TempDir File tempDir) throws IOException { /* prepare */ - owaspZapEventHandler.cancelEventFile = tempDir; + zapPDSEventHandler.cancelEventFile = tempDir; String scanContextName = UUID.randomUUID().toString(); /* execute + test */ - assertTrue(owaspZapEventHandler.isScanCancelled()); - assertThrows(ZapWrapperRuntimeException.class, () -> owaspZapEventHandler.cancelScan(scanContextName)); + assertTrue(zapPDSEventHandler.isScanCancelled()); + assertThrows(ZapWrapperRuntimeException.class, () -> zapPDSEventHandler.cancelScan(scanContextName)); } } diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapProductMessageHelperTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/helper/ZapProductMessageHelperTest.java similarity index 90% rename from sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapProductMessageHelperTest.java rename to sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/helper/ZapProductMessageHelperTest.java index 2e0b3e2bab..bc7a9e5387 100644 --- a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/helper/OwaspZapProductMessageHelperTest.java +++ b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/helper/ZapProductMessageHelperTest.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.helper; +package com.mercedesbenz.sechub.zapwrapper.helper; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; @@ -21,19 +21,19 @@ import com.mercedesbenz.sechub.commons.model.SecHubMessage; import com.mercedesbenz.sechub.commons.model.SecHubMessageType; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperExitCode; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperExitCode; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; -class OwaspZapProductMessageHelperTest { +class ZapProductMessageHelperTest { private TemporaryFolder testFolder; - private OwaspZapProductMessageHelper helperToTest; + private ZapProductMessageHelper helperToTest; @BeforeEach void beforeEach() throws IOException { testFolder = new TemporaryFolder(); testFolder.create(); - helperToTest = new OwaspZapProductMessageHelper(testFolder.getRoot().getAbsolutePath()); + helperToTest = new ZapProductMessageHelper(testFolder.getRoot().getAbsolutePath()); } @AfterEach @@ -123,7 +123,7 @@ private void verifyMessageFileContent(File file, ZapWrapperExitCode exitCode) th assertEquals("Target URL invalid. The target URL, specified inside SecHub configuration, is not a valid URL.", messageContent, errorMessage); break; case PRODUCT_EXECUTION_ERROR: - assertEquals("Product error. The DAST scanner OWASP ZAP ended with a product error.", messageContent, errorMessage); + assertEquals("Product error. The DAST scanner ZAP ended with a product error.", messageContent, errorMessage); break; default: fail("Unsupported ZapWrapperExitCode, this should never occur!"); diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/scan/ZapScannerTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/scan/ZapScannerTest.java new file mode 100644 index 0000000000..a09382e223 --- /dev/null +++ b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/scan/ZapScannerTest.java @@ -0,0 +1,772 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.zapwrapper.scan; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Named; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; +import org.zaproxy.clientapi.core.ApiResponse; +import org.zaproxy.clientapi.core.ClientApiException; + +import com.mercedesbenz.sechub.commons.model.HTTPHeaderConfiguration; +import com.mercedesbenz.sechub.commons.model.SecHubScanConfiguration; +import com.mercedesbenz.sechub.commons.model.SecHubWebScanConfiguration; +import com.mercedesbenz.sechub.commons.model.login.BasicLoginConfiguration; +import com.mercedesbenz.sechub.test.TestFileReader; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperExitCode; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.config.ProxyInformation; +import com.mercedesbenz.sechub.zapwrapper.config.ZapScanContext; +import com.mercedesbenz.sechub.zapwrapper.config.auth.AuthenticationType; +import com.mercedesbenz.sechub.zapwrapper.config.auth.SessionManagementType; +import com.mercedesbenz.sechub.zapwrapper.config.data.DeactivatedRuleReferences; +import com.mercedesbenz.sechub.zapwrapper.config.data.RuleReference; +import com.mercedesbenz.sechub.zapwrapper.config.data.ZapFullRuleset; +import com.mercedesbenz.sechub.zapwrapper.helper.IncludeExcludeToZapURLHelper; +import com.mercedesbenz.sechub.zapwrapper.helper.ZapPDSEventHandler; +import com.mercedesbenz.sechub.zapwrapper.helper.ZapProductMessageHelper; +import com.mercedesbenz.sechub.zapwrapper.helper.ZapURLType; +import com.mercedesbenz.sechub.zapwrapper.internal.scan.ClientApiFacade; +import com.mercedesbenz.sechub.zapwrapper.scan.ZapScanner.UserInformation; +import com.mercedesbenz.sechub.zapwrapper.util.SystemUtil; + +class ZapScannerTest { + + private ZapScanner scannerToTest; + + private ClientApiFacade clientApiFacade; + private ZapScanContext scanContext; + private ZapPDSEventHandler zapPDSEventHandler; + private SystemUtil systemUtil; + + private ZapProductMessageHelper helper; + private String contextName = "context-name"; + + @BeforeEach + void beforeEach() { + // create mocks + clientApiFacade = mock(ClientApiFacade.class); + scanContext = mock(ZapScanContext.class); + systemUtil = mock(SystemUtil.class); + helper = mock(ZapProductMessageHelper.class); + + zapPDSEventHandler = mock(ZapPDSEventHandler.class); + + // assign mocks + scannerToTest = ZapScanner.from(clientApiFacade, scanContext); + scannerToTest.systemUtil = systemUtil; + + // set global behavior + when(scanContext.getContextName()).thenReturn(contextName); + when(scanContext.getZapProductMessageHelper()).thenReturn(helper); + when(scanContext.getZapPDSEventHandler()).thenReturn(zapPDSEventHandler); + + doNothing().when(helper).writeProductError(any()); + doNothing().when(helper).writeProductMessages(any()); + doNothing().when(helper).writeSingleProductMessage(any()); + doNothing().when(helper).writeUserMessagesWithScannedURLs(any()); + + doNothing().when(systemUtil).waitForMilliseconds(ZapScanner.CHECK_SCAN_STATUS_TIME_IN_MILLISECONDS); + when(systemUtil.getCurrentTimeInMilliseconds()).thenCallRealMethod(); + } + + @Test + void setup_standard_configuration_results_in_expected_calls() throws ClientApiException { + /* prepare */ + when(clientApiFacade.createNewSession(scanContext.getContextName(), "true")).thenReturn(null); + when(clientApiFacade.configureMaximumAlertsForEachRule("0")).thenReturn(null); + when(clientApiFacade.enableAllPassiveScannerRules()).thenReturn(null); + when(clientApiFacade.enableAllActiveScannerRulesForPolicy(null)).thenReturn(null); + when(clientApiFacade.configureAjaxSpiderBrowserId("firefox-headless")).thenReturn(null); + + /* execute */ + scannerToTest.setupStandardConfiguration(); + + /* test */ + verify(clientApiFacade, times(1)).createNewSession(scanContext.getContextName(), "true"); + verify(clientApiFacade, times(1)).configureMaximumAlertsForEachRule("0"); + verify(clientApiFacade, times(1)).enableAllPassiveScannerRules(); + verify(clientApiFacade, times(1)).enableAllActiveScannerRulesForPolicy(null); + verify(clientApiFacade, times(1)).configureAjaxSpiderBrowserId("firefox-headless"); + } + + @Test + void deactivate_rules_ruleset_or_rules_to_deactivate_null_results_in_nothing_is_configured() throws ClientApiException { + /* prepare */ + DeactivatedRuleReferences deactivatedReferences = mock(DeactivatedRuleReferences.class); + when(deactivatedReferences.getDeactivatedRuleReferences()).thenReturn(null); + + /* execute */ + scannerToTest.deactivateRules(null, null); + scannerToTest.deactivateRules(new ZapFullRuleset(), null); + scannerToTest.deactivateRules(null, new DeactivatedRuleReferences()); + scannerToTest.deactivateRules(new ZapFullRuleset(), deactivatedReferences); + + /* test */ + verify(clientApiFacade, never()).disablePassiveScannerRule(any()); + verify(clientApiFacade, never()).disableActiveScannerRuleForPolicy(any(), any()); + } + + @Test + void deactivate_rules_results_in_rules_are_deactivated() throws ClientApiException { + /* prepare */ + DeactivatedRuleReferences deactivatedReferences = new DeactivatedRuleReferences(); + // passive rules to deactivate + deactivatedReferences.addRuleReference(new RuleReference("Timestamp-Disclosure-10096", "first-info")); + // active rules to deactivate + deactivatedReferences.addRuleReference(new RuleReference("Cross-Site-Scripting-(Reflected)-40012", "second-info")); + deactivatedReferences.addRuleReference(new RuleReference("Path-Traversal-6", "third-info")); + + String json = TestFileReader.loadTextFile("src/test/resources/zap-available-rules/zap-full-ruleset.json"); + ZapFullRuleset ruleSet = new ZapFullRuleset().fromJSON(json); + + when(clientApiFacade.disablePassiveScannerRule(any())).thenReturn(null); + when(clientApiFacade.disableActiveScannerRuleForPolicy(any(), any())).thenReturn(null); + + /* execute */ + scannerToTest.deactivateRules(ruleSet, deactivatedReferences); + + /* test */ + verify(clientApiFacade, times(1)).disablePassiveScannerRule(any()); + verify(clientApiFacade, times(2)).disableActiveScannerRuleForPolicy(any(), any()); + } + + @Test + void setup_addtional_proxy_information_with_proxy_information_null_results_in_proxy_disabled() + throws ClientApiException { + /* prepare */ + when(clientApiFacade.setHttpProxyEnabled("false")).thenReturn(null); + + /* execute */ + scannerToTest.setupAdditonalProxyConfiguration(null); + + /* test */ + verify(clientApiFacade, times(1)).setHttpProxyEnabled("false"); + } + + @Test + void setup_addtional_proxy_information_results_in_proxy_enabled() throws ClientApiException { + /* prepare */ + String host = "127.0.0.1"; + int port = 8000; + var portAsString = String.valueOf(port); + ProxyInformation proxyInformation = new ProxyInformation(host, port); + + when(clientApiFacade.configureHttpProxy(host, portAsString, null, null, null)).thenReturn(null); + when(clientApiFacade.setHttpProxyEnabled("true")).thenReturn(null); + when(clientApiFacade.setHttpProxyAuthEnabled("false")).thenReturn(null); + + /* execute */ + scannerToTest.setupAdditonalProxyConfiguration(proxyInformation); + + /* test */ + verify(clientApiFacade, times(1)).configureHttpProxy(host, portAsString, null, null, null); + verify(clientApiFacade, times(1)).setHttpProxyEnabled("true"); + verify(clientApiFacade, times(1)).setHttpProxyAuthEnabled("false"); + } + + @Test + void create_context_results_in_expected_calls() throws ClientApiException { + /* prepare */ + String expectedContextId = "random-id"; + when(clientApiFacade.createNewContext(contextName)).thenReturn(expectedContextId); + + /* execute */ + String contextId = scannerToTest.createContext(); + + /* test */ + assertEquals(expectedContextId, contextId); + verify(scanContext, times(2)).getContextName(); + verify(clientApiFacade, times(1)).createNewContext(contextName); + } + + @Test + void add_replacer_rules_for_headers_with_no_headers_results_add_replacer_rule_is_never_called() throws ClientApiException { + /* prepare */ + SecHubWebScanConfiguration sechubwebScanConfig = new SecHubWebScanConfiguration(); + when(scanContext.getSecHubWebScanConfiguration()).thenReturn(sechubwebScanConfig); + + ApiResponse response = mock(ApiResponse.class); + when(clientApiFacade.addReplacerRule(any(), any(), any(), any(), any(), any(), any(), any())).thenReturn(response); + + /* execute */ + scannerToTest.addReplacerRulesForHeaders(); + + /* test */ + verify(clientApiFacade, never()).addReplacerRule(any(), any(), any(), any(), any(), any(), any(), any()); + } + + @ParameterizedTest + @MethodSource("headerPartWithoutOnlyForUrlsTestNamedArguments") + void add_replacer_rules_for_headers_with_no_onlyForUrls_results_add_replacer_rule_is_called_once_for_each_header(String sechubScanConfigJSON) + throws ClientApiException { + /* prepare */ + SecHubWebScanConfiguration sechubWebScanConfig = SecHubScanConfiguration.createFromJSON(sechubScanConfigJSON).getWebScan().get(); + when(scanContext.getSecHubWebScanConfiguration()).thenReturn(sechubWebScanConfig); + + ApiResponse response = mock(ApiResponse.class); + when(clientApiFacade.addReplacerRule(any(), any(), any(), any(), any(), any(), any(), any())).thenReturn(response); + + /* execute */ + scannerToTest.addReplacerRulesForHeaders(); + + /* test */ + int times = sechubWebScanConfig.getHeaders().get().size(); + verify(clientApiFacade, times(times)).addReplacerRule(any(), any(), any(), any(), any(), any(), any(), any()); + } + + @ParameterizedTest + @MethodSource("headerPartWithOnlyForUrlsTestNamedArguments") + void add_replacer_rules_for_headers_with_onlyForUrls_results_add_replacer_rule_is_called_once_for_each_onylForUrl(String sechubScanConfigJSON) + throws ClientApiException { + /* prepare */ + SecHubWebScanConfiguration sechubWebScanConfig = SecHubScanConfiguration.createFromJSON(sechubScanConfigJSON).getWebScan().get(); + when(scanContext.getSecHubWebScanConfiguration()).thenReturn(sechubWebScanConfig); + + ApiResponse response = mock(ApiResponse.class); + when(clientApiFacade.addReplacerRule(any(), any(), any(), any(), any(), any(), any(), any())).thenReturn(response); + + /* execute */ + scannerToTest.addReplacerRulesForHeaders(); + + /* test */ + int times = sechubWebScanConfig.getHeaders().get().size(); + for (HTTPHeaderConfiguration header : sechubWebScanConfig.getHeaders().get()) { + if (header.getOnlyForUrls().isPresent()) { + // minus 1 because the method will called for any header at least once + times += header.getOnlyForUrls().get().size() - 1; + } + } + verify(clientApiFacade, times(times)).addReplacerRule(any(), any(), any(), any(), any(), any(), any(), any()); + } + + @ParameterizedTest + @ValueSource(strings = { "src/test/resources/sechub-config-examples/no-auth-include-exclude.json" }) + void set_includes_and_excludes_api_facade_is_called_once_for_each_include_and_once_for_exclude(String sechubConfigFile) + throws ClientApiException, MalformedURLException { + /* prepare */ + String json = TestFileReader.loadTextFile(sechubConfigFile); + + SecHubWebScanConfiguration sechubWebScanConfig = SecHubScanConfiguration.createFromJSON(json).getWebScan().get(); + IncludeExcludeToZapURLHelper helper = new IncludeExcludeToZapURLHelper(); + + URL targetUrl = sechubWebScanConfig.getUrl().toURL(); + List includesList = sechubWebScanConfig.getIncludes().get(); + Set includes = new HashSet<>(helper.createListOfUrls(ZapURLType.INCLUDE, targetUrl, includesList, new ArrayList<>())); + when(scanContext.getZapURLsIncludeSet()).thenReturn(includes); + + List excludesList = sechubWebScanConfig.getExcludes().get(); + Set excludes = new HashSet<>(helper.createListOfUrls(ZapURLType.EXCLUDE, targetUrl, excludesList, new ArrayList<>())); + when(scanContext.getZapURLsExcludeSet()).thenReturn(excludes); + + ApiResponse response = mock(ApiResponse.class); + when(clientApiFacade.addIncludeUrlPatternToContext(any(), any())).thenReturn(response); + when(clientApiFacade.accessUrlViaZap(any(), any())).thenReturn(response); + when(clientApiFacade.addExcludeUrlPatternToContext(any(), any())).thenReturn(response); + + /* execute */ + scannerToTest.addIncludedAndExcludedUrlsToContext(); + + /* test */ + verify(clientApiFacade, times(includes.size())).addIncludeUrlPatternToContext(any(), any()); + verify(clientApiFacade, times(includes.size())).accessUrlViaZap(any(), any()); + verify(clientApiFacade, times(excludes.size())).addExcludeUrlPatternToContext(any(), any()); + } + + @Test + void import_openapi_file_but_api_file_is_null_api_facade_is_never_called() throws ClientApiException { + /* prepare */ + String contextId = "context-id"; + when(scanContext.getApiDefinitionFiles()).thenReturn(Collections.emptyList()); + + ApiResponse response = mock(ApiResponse.class); + when(clientApiFacade.importOpenApiFile(any(), any(), any())).thenReturn(response); + + /* execute */ + scannerToTest.loadApiDefinitions(contextId); + + /* test */ + verify(clientApiFacade, never()).importOpenApiFile(any(), any(), any()); + } + + @ParameterizedTest + @ValueSource(strings = { "src/test/resources/sechub-config-examples/no-auth-with-openapi-file.json" }) + void import_openapi_file_api_facade_is_called_once(String sechubConfigFile) throws ClientApiException { + /* prepare */ + String contextId = "context-id"; + String json = TestFileReader.loadTextFile(sechubConfigFile); + SecHubWebScanConfiguration sechubWebScanConfig = SecHubScanConfiguration.createFromJSON(json).getWebScan().get(); + + List apiFiles = new ArrayList<>(); + apiFiles.add(new File("examplefile.json")); + + when(scanContext.getApiDefinitionFiles()).thenReturn(apiFiles); + when(scanContext.getSecHubWebScanConfiguration()).thenReturn(sechubWebScanConfig); + + ApiResponse response = mock(ApiResponse.class); + when(clientApiFacade.importOpenApiFile(any(), any(), any())).thenReturn(response); + + /* execute */ + scannerToTest.loadApiDefinitions(contextId); + + /* test */ + verify(clientApiFacade, times(1)).importOpenApiFile(any(), any(), any()); + } + + @ParameterizedTest + @ValueSource(strings = { "src/test/resources/sechub-config-examples/no-auth-with-openapi-file.json", + "src/test/resources/sechub-config-examples/form-based-auth.json" }) + void configure_login_inside_zap_using_no_auth_and_unsupported_auth_return_null(String sechubConfigFile) throws ClientApiException { + /* prepare */ + String contextId = "context-id"; + String json = TestFileReader.loadTextFile(sechubConfigFile); + SecHubWebScanConfiguration sechubWebScanConfig = SecHubScanConfiguration.createFromJSON(json).getWebScan().get(); + + when(scanContext.getSecHubWebScanConfiguration()).thenReturn(sechubWebScanConfig); + + /* execute */ + UserInformation userInformation = scannerToTest.configureLoginInsideZapContext(contextId); + + /* test */ + assertEquals(null, userInformation); + } + + @Test + void configure_login_inside_zap_using_basic_auth_results_in_expected_calls() throws ClientApiException, MalformedURLException { + /* prepare */ + String contextId = "context-id"; + String userId = "user-id"; + URL targetUrl = URI.create("https:127.0.0.1:8000").toURL(); + String json = TestFileReader.loadTextFile("src/test/resources/sechub-config-examples/basic-auth.json"); + SecHubWebScanConfiguration sechubWebScanConfig = SecHubScanConfiguration.createFromJSON(json).getWebScan().get(); + BasicLoginConfiguration basicLoginConfiguration = sechubWebScanConfig.getLogin().get().getBasic().get(); + String userName = new String(basicLoginConfiguration.getUser()); + + ApiResponse response = mock(ApiResponse.class); + + when(scanContext.getTargetUrl()).thenReturn(targetUrl); + when(scanContext.getAuthenticationType()).thenReturn(AuthenticationType.HTTP_BASIC_AUTHENTICATION); + when(scanContext.getSecHubWebScanConfiguration()).thenReturn(sechubWebScanConfig); + + when(clientApiFacade.configureAuthenticationMethod(eq(contextId), eq(AuthenticationType.HTTP_BASIC_AUTHENTICATION.getZapAuthenticationMethod()), any())) + .thenReturn(response); + when(clientApiFacade.setSessionManagementMethod(eq(contextId), eq(SessionManagementType.HTTP_AUTH_SESSION_MANAGEMENT.getZapSessionManagementMethod()), + any())).thenReturn(response); + when(clientApiFacade.createNewUser(contextId, userName)).thenReturn(userId); + when(clientApiFacade.configureAuthenticationCredentials(eq(contextId), eq(userId), any())).thenReturn(response); + when(clientApiFacade.setForcedUser(contextId, userId)).thenReturn(response); + when(clientApiFacade.setForcedUserModeEnabled(true)).thenReturn(response); + + /* execute */ + UserInformation userInformation = scannerToTest.configureLoginInsideZapContext(contextId); + + /* test */ + assertEquals(userName, userInformation.userName()); + assertEquals(userId, userInformation.zapuserId()); + + verify(scanContext, times(2)).getTargetUrl(); + verify(scanContext, times(1)).getAuthenticationType(); + + verify(clientApiFacade, times(1)).configureAuthenticationMethod(eq(contextId), + eq(AuthenticationType.HTTP_BASIC_AUTHENTICATION.getZapAuthenticationMethod()), any()); + verify(clientApiFacade, times(1)).setSessionManagementMethod(eq(contextId), + eq(SessionManagementType.HTTP_AUTH_SESSION_MANAGEMENT.getZapSessionManagementMethod()), any()); + verify(clientApiFacade, times(1)).createNewUser(contextId, userName); + verify(clientApiFacade, times(1)).configureAuthenticationCredentials(eq(contextId), eq(userId), any()); + verify(clientApiFacade, times(1)).setForcedUser(contextId, userId); + verify(clientApiFacade, times(1)).setForcedUserModeEnabled(true); + } + + @Test + void generate_report_calls_api_facade_once() throws ClientApiException { + /* prepare */ + when(scanContext.getReportFile()) + .thenReturn(Paths.get("src/test/resources/sechub-config-examples/no-auth-with-openapi-file.json")); + ApiResponse response = mock(ApiResponse.class); + when(clientApiFacade.generateReport(any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), + any(), any())).thenReturn(response); + + /* execute */ + scannerToTest.generateZapReport(); + + /* test */ + verify(clientApiFacade, times(1)).generateReport(any(), any(), any(), any(), any(), any(), any(), any(), any(), + any(), any(), any(), any()); + } + + @Test + void cleanup_after_scan() throws ClientApiException { + /* prepare */ + SecHubWebScanConfiguration sechubwebScanConfig = new SecHubWebScanConfiguration(); + when(scanContext.getSecHubWebScanConfiguration()).thenReturn(sechubwebScanConfig); + + ApiResponse response = mock(ApiResponse.class); + when(clientApiFacade.removeReplacerRule(any())).thenReturn(response); + + /* execute */ + scannerToTest.cleanUp(); + + /* test */ + verify(clientApiFacade, never()).removeReplacerRule(any()); + } + + @ParameterizedTest + @MethodSource("headerPartWithoutOnlyForUrlsTestNamedArguments") + void cleanup_after_scan_without_onylForUrls_headers_set_cleans_up_all_replacer_rules(String sechubScanConfigJSON) throws ClientApiException { + /* prepare */ + SecHubWebScanConfiguration sechubWebScanConfig = SecHubScanConfiguration.createFromJSON(sechubScanConfigJSON).getWebScan().get(); + when(scanContext.getSecHubWebScanConfiguration()).thenReturn(sechubWebScanConfig); + + ApiResponse response = mock(ApiResponse.class); + when(clientApiFacade.removeReplacerRule(any())).thenReturn(response); + + /* execute */ + scannerToTest.cleanUp(); + + /* test */ + int times = sechubWebScanConfig.getHeaders().get().size(); + verify(clientApiFacade, times(times)).removeReplacerRule(any()); + } + + @ParameterizedTest + @MethodSource("headerPartWithOnlyForUrlsTestNamedArguments") + void cleanup_after_scan_with_onylForUrls_headers_set_cleans_up_all_replacer_rules(String sechubScanConfigJSON) throws ClientApiException { + /* prepare */ + SecHubWebScanConfiguration sechubWebScanConfig = SecHubScanConfiguration.createFromJSON(sechubScanConfigJSON).getWebScan().get(); + when(scanContext.getSecHubWebScanConfiguration()).thenReturn(sechubWebScanConfig); + + ApiResponse response = mock(ApiResponse.class); + when(clientApiFacade.removeReplacerRule(any())).thenReturn(response); + + /* execute */ + scannerToTest.cleanUp(); + + /* test */ + int times = sechubWebScanConfig.getHeaders().get().size(); + for (HTTPHeaderConfiguration header : sechubWebScanConfig.getHeaders().get()) { + if (header.getOnlyForUrls().isPresent()) { + // minus 1 because the method will called for any header at least once + times += header.getOnlyForUrls().get().size() - 1; + } + } + verify(clientApiFacade, times(times)).removeReplacerRule(any()); + } + + @Test + void wait_for_ajaxSpider_scan_is_cancelled_results_in_exception_with_dedicated_exit_code() throws ClientApiException { + /* prepare */ + when(zapPDSEventHandler.isScanCancelled()).thenReturn(true); + doCallRealMethod().when(zapPDSEventHandler).cancelScan(contextName); + + when(scanContext.getMaxScanDurationInMilliSeconds()).thenReturn(20000L); + when(scanContext.isActiveScanEnabled()).thenReturn(true); + + when(clientApiFacade.stopAjaxSpider()).thenReturn(null); + + /* execute */ + ZapWrapperRuntimeException exception = assertThrows(ZapWrapperRuntimeException.class, () -> { + scannerToTest.waitForAjaxSpiderResults(); + }); + + /* test */ + assertEquals(ZapWrapperExitCode.SCAN_JOB_CANCELLED, exception.getExitCode()); + verify(zapPDSEventHandler, times(2)).isScanCancelled(); + verify(scanContext, times(1)).getMaxScanDurationInMilliSeconds(); + verify(scanContext, times(1)).isActiveScanEnabled(); + verify(clientApiFacade, times(1)).stopAjaxSpider(); + } + + @Test + void wait_for_ajaxSpider_scan_ended_results_in_expected_calls() throws ClientApiException { + /* prepare */ + when(zapPDSEventHandler.isScanCancelled()).thenReturn(false); + + when(scanContext.getMaxScanDurationInMilliSeconds()).thenReturn(1000L); + when(scanContext.isActiveScanEnabled()).thenReturn(true); + + when(clientApiFacade.stopAjaxSpider()).thenReturn(null); + when(clientApiFacade.getAjaxSpiderStatus()).thenReturn("stopped"); + + /* execute */ + scannerToTest.waitForAjaxSpiderResults(); + + /* test */ + verify(scanContext, times(1)).getMaxScanDurationInMilliSeconds(); + verify(scanContext, times(1)).isActiveScanEnabled(); + verify(clientApiFacade, atLeast(1)).getAjaxSpiderStatus(); + verify(clientApiFacade, times(1)).stopAjaxSpider(); + } + + @Test + void wait_for_spider_scan_is_cancelled_results_in_exception_with_dedicated_exit_code() throws ClientApiException { + /* prepare */ + String scanId = "12345"; + + when(zapPDSEventHandler.isScanCancelled()).thenReturn(true); + doCallRealMethod().when(zapPDSEventHandler).cancelScan(contextName); + + when(scanContext.getMaxScanDurationInMilliSeconds()).thenReturn(20000L); + when(scanContext.isActiveScanEnabled()).thenReturn(true); + + when(clientApiFacade.stopSpiderScan(scanId)).thenReturn(null); + + /* execute */ + ZapWrapperRuntimeException exception = assertThrows(ZapWrapperRuntimeException.class, () -> { + scannerToTest.waitForSpiderResults(scanId); + }); + + /* test */ + assertEquals(ZapWrapperExitCode.SCAN_JOB_CANCELLED, exception.getExitCode()); + verify(zapPDSEventHandler, times(2)).isScanCancelled(); + verify(scanContext, times(1)).getMaxScanDurationInMilliSeconds(); + verify(scanContext, times(1)).isActiveScanEnabled(); + verify(clientApiFacade, times(1)).stopSpiderScan(scanId); + } + + @Test + void wait_for_spider_scan_ended_results_in_expected_calls() throws ClientApiException { + /* prepare */ + String scanId = "12345"; + + when(zapPDSEventHandler.isScanCancelled()).thenReturn(false); + + when(scanContext.getMaxScanDurationInMilliSeconds()).thenReturn(1000L); + when(scanContext.isActiveScanEnabled()).thenReturn(true); + ZapProductMessageHelper messageHelper = mock(ZapProductMessageHelper.class); + when(scanContext.getZapProductMessageHelper()).thenReturn(messageHelper); + doNothing().when(messageHelper).writeUserMessagesWithScannedURLs(any()); + + when(clientApiFacade.stopSpiderScan(scanId)).thenReturn(null); + when(clientApiFacade.getSpiderStatusForScan(scanId)).thenReturn(42); + when(clientApiFacade.getAllSpiderUrls()).thenReturn(null); + + /* execute */ + scannerToTest.waitForSpiderResults(scanId); + + /* test */ + verify(scanContext, times(1)).getMaxScanDurationInMilliSeconds(); + verify(scanContext, times(1)).isActiveScanEnabled(); + verify(scanContext, times(1)).getZapProductMessageHelper(); + verify(messageHelper, times(1)).writeUserMessagesWithScannedURLs(any()); + verify(clientApiFacade, atLeast(1)).getSpiderStatusForScan(scanId); + verify(clientApiFacade, times(1)).stopSpiderScan(scanId); + verify(clientApiFacade, times(1)).getAllSpiderUrls(); + } + + @Test + void wait_for_passiveScan_scan_is_cancelled_results_in_exception_with_dedicated_exit_code() throws ClientApiException { + /* prepare */ + when(zapPDSEventHandler.isScanCancelled()).thenReturn(true); + doCallRealMethod().when(zapPDSEventHandler).cancelScan(contextName); + + when(scanContext.getMaxScanDurationInMilliSeconds()).thenReturn(20000L); + when(scanContext.isActiveScanEnabled()).thenReturn(false); + when(scanContext.isAjaxSpiderEnabled()).thenReturn(false); + + when(clientApiFacade.getNumberOfPassiveScannerRecordsToScan()).thenReturn(12); + + /* execute */ + ZapWrapperRuntimeException exception = assertThrows(ZapWrapperRuntimeException.class, () -> { + scannerToTest.passiveScan(); + }); + + /* test */ + assertEquals(ZapWrapperExitCode.SCAN_JOB_CANCELLED, exception.getExitCode()); + verify(zapPDSEventHandler, times(2)).isScanCancelled(); + verify(scanContext, times(1)).getMaxScanDurationInMilliSeconds(); + verify(scanContext, times(1)).isActiveScanEnabled(); + verify(scanContext, times(1)).isAjaxSpiderEnabled(); + verify(clientApiFacade, atLeast(1)).getNumberOfPassiveScannerRecordsToScan(); + } + + @Test + void wait_for_passiveScan_scan_is_ended_results_in_expected_calls() throws ClientApiException { + /* prepare */ + when(zapPDSEventHandler.isScanCancelled()).thenReturn(false); + + when(scanContext.getMaxScanDurationInMilliSeconds()).thenReturn(20000L); + when(scanContext.isActiveScanEnabled()).thenReturn(false); + when(scanContext.isAjaxSpiderEnabled()).thenReturn(false); + + when(clientApiFacade.getNumberOfPassiveScannerRecordsToScan()).thenReturn(0); + + /* execute */ + scannerToTest.passiveScan(); + + /* test */ + verify(scanContext, times(1)).getMaxScanDurationInMilliSeconds(); + verify(scanContext, times(1)).isActiveScanEnabled(); + verify(scanContext, times(1)).isAjaxSpiderEnabled(); + verify(clientApiFacade, times(1)).getNumberOfPassiveScannerRecordsToScan(); + } + + @Test + void wait_for_activeScan_scan_is_cancelled_results_in_exception_with_dedicated_exit_code() throws ClientApiException { + /* prepare */ + String scanId = "12345"; + + when(zapPDSEventHandler.isScanCancelled()).thenReturn(true); + doCallRealMethod().when(zapPDSEventHandler).cancelScan(contextName); + + when(clientApiFacade.getActiveScannerStatusForScan(scanId)).thenReturn(42); + when(clientApiFacade.stopActiveScan(scanId)).thenReturn(null); + + /* execute */ + ZapWrapperRuntimeException exception = assertThrows(ZapWrapperRuntimeException.class, () -> { + scannerToTest.waitForActiveScanResults(scanId); + }); + + /* test */ + assertEquals(ZapWrapperExitCode.SCAN_JOB_CANCELLED, exception.getExitCode()); + verify(zapPDSEventHandler, times(2)).isScanCancelled(); + verify(clientApiFacade, never()).getActiveScannerStatusForScan(scanId); + verify(clientApiFacade, times(1)).stopActiveScan(scanId); + } + + @Test + void wait_for_activeScan_scan_is_ended_results_in_expected_calls() throws ClientApiException { + /* prepare */ + String scanId = "12345"; + + when(zapPDSEventHandler.isScanCancelled()).thenReturn(false); + + when(clientApiFacade.getActiveScannerStatusForScan(scanId)).thenReturn(100); + when(clientApiFacade.stopActiveScan(scanId)).thenReturn(null); + + /* execute */ + scannerToTest.waitForActiveScanResults(scanId); + + /* test */ + verify(clientApiFacade, atLeast(1)).getActiveScannerStatusForScan(scanId); + verify(clientApiFacade, times(1)).stopActiveScan(scanId); + } + + @Test + void run_ajaxSpider_scan_ended_results_in_expected_calls() throws ClientApiException { + /* prepare */ + when(zapPDSEventHandler.isScanCancelled()).thenReturn(false); + + when(scanContext.getMaxScanDurationInMilliSeconds()).thenReturn(1000L); + when(scanContext.isActiveScanEnabled()).thenReturn(true); + + when(clientApiFacade.stopAjaxSpider()).thenReturn(null); + when(clientApiFacade.getAjaxSpiderStatus()).thenReturn("stopped"); + + /* execute */ + scannerToTest.runAjaxSpider(); + + /* test */ + verify(scanContext, times(1)).getMaxScanDurationInMilliSeconds(); + verify(scanContext, times(1)).isActiveScanEnabled(); + verify(clientApiFacade, atLeast(1)).getAjaxSpiderStatus(); + verify(clientApiFacade, times(1)).stopAjaxSpider(); + } + + @Test + void run_spider_scan_ended_results_in_expected_calls() throws ClientApiException { + /* prepare */ + String scanId = "12345"; + + when(zapPDSEventHandler.isScanCancelled()).thenReturn(false); + + when(scanContext.getMaxScanDurationInMilliSeconds()).thenReturn(1000L); + when(scanContext.isActiveScanEnabled()).thenReturn(true); + ZapProductMessageHelper messageHelper = mock(ZapProductMessageHelper.class); + when(scanContext.getZapProductMessageHelper()).thenReturn(messageHelper); + doNothing().when(messageHelper).writeUserMessagesWithScannedURLs(any()); + + when(clientApiFacade.stopSpiderScan(scanId)).thenReturn(null); + when(clientApiFacade.getSpiderStatusForScan(scanId)).thenReturn(42); + when(clientApiFacade.getAllSpiderUrls()).thenReturn(null); + when(clientApiFacade.startSpiderScan(any(), any(), any(), any(), any())).thenReturn(scanId); + + /* execute */ + scannerToTest.runSpider(); + + /* test */ + verify(scanContext, times(1)).getMaxScanDurationInMilliSeconds(); + verify(scanContext, times(1)).isActiveScanEnabled(); + verify(scanContext, times(1)).getZapProductMessageHelper(); + verify(messageHelper, times(1)).writeUserMessagesWithScannedURLs(any()); + verify(clientApiFacade, atLeast(1)).getSpiderStatusForScan(scanId); + verify(clientApiFacade, times(1)).stopSpiderScan(scanId); + verify(clientApiFacade, times(1)).getAllSpiderUrls(); + verify(clientApiFacade, times(1)).startSpiderScan(any(), any(), any(), any(), any()); + } + + @Test + void run_activeScan_scan_is_ended_results_in_expected_calls() throws ClientApiException { + /* prepare */ + String scanId = "12345"; + + when(zapPDSEventHandler.isScanCancelled()).thenReturn(false); + + scannerToTest.remainingScanTime = 100L; + + when(clientApiFacade.getActiveScannerStatusForScan(scanId)).thenReturn(100); + when(clientApiFacade.stopActiveScan(scanId)).thenReturn(null); + when(clientApiFacade.startActiveScan(any(), any(), any(), any(), any(), any())).thenReturn(scanId); + when(clientApiFacade.atLeastOneURLDetected()).thenReturn(true); + + /* execute */ + scannerToTest.runActiveScan(); + + /* test */ + verify(clientApiFacade, atLeast(1)).getActiveScannerStatusForScan(scanId); + verify(clientApiFacade, times(1)).stopActiveScan(scanId); + verify(clientApiFacade, times(1)).startActiveScan(any(), any(), any(), any(), any(), any()); + } + + static Stream headerPartWithoutOnlyForUrlsTestNamedArguments() { + /* @formatter:off */ + return Stream.of( + Arguments.of( + Named.of("3 Headers without onlyForUrls", + "{\"apiVersion\":\"1.0\",\"webScan\":{\"url\":\"https://productfailure.demo.example.org\",\"headers\":[{\"name\":\"Authorization\",\"value\":\"{{.HEADER_VALUE}}\"},{\"name\":\"x-file-size\",\"value\":\"123456\"},{\"name\":\"custom-header\",\"value\":\"test-value\"}]}}")), + Arguments.of( + Named.of("2 Headers without onlyForUrls", + "{\"apiVersion\":\"1.0\",\"webScan\":{\"url\":\"https://productfailure.demo.example.org\",\"headers\":[{\"name\":\"x-file-size\",\"value\":\"123456\"},{\"name\":\"custom-header\",\"value\":\"test-value\"}]}}"))); + /* @formatter:on */ + } + + static Stream headerPartWithOnlyForUrlsTestNamedArguments() { + /* @formatter:off */ + return Stream.of( + Arguments.of( + Named.of("2 Headers 2nd with onlyForUrls", + "{\"apiVersion\":\"1.0\",\"webScan\":{\"url\":\"https://productfailure.demo.example.org\",\"headers\":[{\"name\":\"Authorization\",\"value\":\"{{.HEADER_VALUE}}\"},{\"name\":\"x-file-size\",\"value\":\"123456\",\"onlyForUrls\":[\"https://productfailure.demo.example.org/admin\",\"https://productfailure.demo.example.org/upload/<*>\",\"https://productfailure.demo.example.org/<*>/special/\"]}]}}")), + Arguments.of( + Named.of("3 Headers 2nd and 3rd with onlyForUrls", + "{\"apiVersion\":\"1.0\",\"webScan\":{\"url\":\"https://productfailure.demo.example.org\",\"headers\":[{\"name\":\"Authorization\",\"value\":\"{{.HEADER_VALUE}}\"},{\"name\":\"x-file-size\",\"value\":\"123456\",\"onlyForUrls\":[\"https://productfailure.demo.example.org/admin\",\"https://productfailure.demo.example.org/upload/<*>\",\"https://productfailure.demo.example.org/<*>/special/\"]},{\"name\":\"test-name\",\"value\":\"test-value\",\"onlyForUrls\":[\"https://productfailure.demo.example.org/profile\",\"https://productfailure.demo.example.org/upload\"]}]}}"))); + /* @formatter:on */ + } + +} diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/util/FileUtilitiesTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/util/FileUtilitiesTest.java similarity index 68% rename from sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/util/FileUtilitiesTest.java rename to sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/util/FileUtilitiesTest.java index 18d3cc8d06..d56274df02 100644 --- a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/util/FileUtilitiesTest.java +++ b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/util/FileUtilitiesTest.java @@ -1,13 +1,15 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.util; +package com.mercedesbenz.sechub.zapwrapper.util; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; import org.junit.jupiter.api.Test; -import com.mercedesbenz.sechub.owaspzapwrapper.cli.ZapWrapperRuntimeException; +import com.mercedesbenz.sechub.zapwrapper.cli.ZapWrapperRuntimeException; class FileUtilitiesTest { diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/util/TargetConnectionCheckerTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/util/TargetConnectionCheckerTest.java similarity index 83% rename from sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/util/TargetConnectionCheckerTest.java rename to sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/util/TargetConnectionCheckerTest.java index 0df27c89a0..cb05f10038 100644 --- a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/util/TargetConnectionCheckerTest.java +++ b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/util/TargetConnectionCheckerTest.java @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.util; +package com.mercedesbenz.sechub.zapwrapper.util; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; diff --git a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/util/UrlUtilTest.java b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/util/UrlUtilTest.java similarity index 93% rename from sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/util/UrlUtilTest.java rename to sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/util/UrlUtilTest.java index 29ab684f34..b258d37fc1 100644 --- a/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/owaspzapwrapper/util/UrlUtilTest.java +++ b/sechub-wrapper-owasp-zap/src/test/java/com/mercedesbenz/sechub/zapwrapper/util/UrlUtilTest.java @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.owaspzapwrapper.util; +package com.mercedesbenz.sechub.zapwrapper.util; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/sechub-wrapper-owasp-zap/src/test/resources/sechub-config-examples/form-based-auth.json b/sechub-wrapper-owasp-zap/src/test/resources/sechub-config-examples/form-based-auth.json new file mode 100644 index 0000000000..c58ee26e91 --- /dev/null +++ b/sechub-wrapper-owasp-zap/src/test/resources/sechub-config-examples/form-based-auth.json @@ -0,0 +1,41 @@ +{ + "apiVersion" : "1.0", + "webScan" : { + "url" : "https://productfailure.demo.example.org", + "login" : { + "url" : "https://productfailure.demo.example.org/login", + "form" : { + "script" : { + "pages" : [ { + "actions" : [ { + "type" : "username", + "selector" : "#example_login_userid", + "value" : "{{ .LOGIN_USER }}" + }, { + "type" : "password", + "selector" : "#example_login_pwd", + "value" : "{{ .LOGIN_PWD }}" + }, { + "type" : "click", + "selector" : "#next", + "description" : "Click to go to next page" + } ] + }, { + "actions" : [ { + "type" : "input", + "selector" : "#example_other_inputfield", + "value" : "{{ .OTHER_VALUE }}" + }, { + "type" : "wait", + "value" : "1", + "unit" : "second" + }, { + "type" : "click", + "selector" : "#doLogin" + } ] + } ] + } + } + } + } +} \ No newline at end of file diff --git a/sechub-wrapper-owasp-zap/src/test/resources/wrapper-deactivated-rule-examples/owaspzap-rules-to-deactivate.json b/sechub-wrapper-owasp-zap/src/test/resources/wrapper-deactivated-rule-examples/zap-rules-to-deactivate.json similarity index 100% rename from sechub-wrapper-owasp-zap/src/test/resources/wrapper-deactivated-rule-examples/owaspzap-rules-to-deactivate.json rename to sechub-wrapper-owasp-zap/src/test/resources/wrapper-deactivated-rule-examples/zap-rules-to-deactivate.json diff --git a/sechub-wrapper-owasp-zap/src/test/resources/zap-available-rules/owaspzap-full-ruleset.json b/sechub-wrapper-owasp-zap/src/test/resources/zap-available-rules/zap-full-ruleset.json similarity index 100% rename from sechub-wrapper-owasp-zap/src/test/resources/zap-available-rules/owaspzap-full-ruleset.json rename to sechub-wrapper-owasp-zap/src/test/resources/zap-available-rules/zap-full-ruleset.json