From 4f051e45cad1d6b37f02fc8e90c36e3a548f0fcf Mon Sep 17 00:00:00 2001 From: hamidonos Date: Fri, 17 Jan 2025 11:09:41 +0100 Subject: [PATCH] implement user self service api for user detail information #3723 | remove unused sechub-web-server module --- .github/workflows/release-web-server.yml | 265 ---------- gradle/projects.gradle | 6 +- .../AdministrationAPIConstants.java | 11 +- .../UserAdministrationRestController.java | 2 +- .../user/UserDetailInformation.java | 10 +- .../user/UserDetailInformationService.java | 42 +- .../user/UserRestController.java | 30 ++ .../ProjectChangeOwnerServiceTest.java | 2 +- ...rAdministrationRestControllerMockTest.java | 4 +- .../UserDetailInformationServiceTest.java | 129 +++++ .../user/UserRestControllerTest.java | 87 +++ sechub-developertools/build.gradle | 2 +- sechub-developertools/scripts/sdc.sh | 2 +- ...ministrationRestControllerRestDocTest.java | 2 +- .../UserRestControllerRestDocTest.java | 73 +++ .../sechub/api/DefaultSecHubClient.java | 9 +- .../mercedesbenz/sechub/api/SecHubClient.java | 2 +- .../src/main/resources/openapi.yaml | 27 +- .../sharedkernel/usecases/UseCaseGroup.java | 2 +- .../usecases/UseCaseIdentifier.java | 2 + ...eCaseUserFetchesUserDetailInformation.java | 27 + ...UseCaseUserClicksLinkToGetNewAPIToken.java | 2 +- .../sechub/test/SecHubTestURLBuilder.java | 7 +- .../01-start-single-docker-compose.sh | 21 - ...rt-single-sechub-network-docker-compose.sh | 17 - sechub-web-server-solution/10-create-image.sh | 75 --- sechub-web-server-solution/20-push-image.sh | 5 - sechub-web-server-solution/README.adoc | 5 - .../docker-compose_web_server.yaml | 27 - ...r-compose_web_server_external-network.yaml | 29 - sechub-web-server-solution/docker/.gitignore | 3 - .../docker/Web-Server-Debian.dockerfile | 166 ------ sechub-web-server-solution/docker/clone.sh | 28 - .../docker/copy/README.adoc | 4 - sechub-web-server-solution/docker/run.sh | 118 ----- sechub-web-server-solution/env | 12 - sechub-web-server-solution/env-web-server | 23 - sechub-web-server-solution/helm/.gitignore | 2 - .../helm/web-server/.helmignore | 23 - .../helm/web-server/Chart.yaml | 12 - .../helm/web-server/LICENSE | 21 - .../helm/web-server/README.md | 4 - .../helm/web-server/templates/deployment.yaml | 159 ------ .../web-server/templates/networkpolicy.yaml | 18 - .../helm/web-server/templates/service.yaml | 15 - .../helm/web-server/values.yaml | 91 ---- sechub-web-server/.gitignore | 2 - sechub-web-server/README.adoc | 41 -- sechub-web-server/README.md | 61 --- sechub-web-server/build.gradle | 95 ---- sechub-web-server/dev-base.sh | 28 - .../dev-create_localhost_certificate.sh | 10 - .../dev-ensure_localhost_certificate.sh | 9 - .../sechub/webserver/ApplicationProfiles.java | 18 - .../sechub/webserver/RequestConstants.java | 12 - .../webserver/SecHubWebServerApplication.java | 13 - .../credentials/NewApiTokenController.java | 38 -- .../credentials/NewApiTokenService.java | 47 -- .../encryption/AES256Encryption.java | 89 ---- .../encryption/AES256EncryptionException.java | 9 - .../AES256EncryptionProperties.java | 48 -- .../RequestParamLocaleContextResolver.java | 33 -- .../sechub/webserver/page/HomeController.java | 22 - .../webserver/page/LoginController.java | 40 -- .../webserver/sechubaccess/ClientCaller.java | 8 - .../webserver/sechubaccess/ErrorCallback.java | 6 - .../sechubaccess/SecHubAccessService.java | 111 ---- .../sechubaccess/SecHubClientExecutor.java | 89 ---- ...entIdAndSecretOAuth2AccessTokenClient.java | 124 ----- .../security/ClassicLoginSuccessHandler.java | 36 -- .../webserver/security/JwtCookieResolver.java | 81 --- .../webserver/security/JwtResponse.java | 91 ---- ...issingAuthenticationEntryPointHandler.java | 28 - .../security/OAuth2LoginSuccessHandler.java | 95 ---- .../webserver/security/OAuth2Properties.java | 83 --- .../security/OAuth2PropertiesConfig.java | 24 - .../webserver/security/PortAccessGuard.java | 40 -- .../security/UserInputSanitizer.java | 13 - .../WebServerSecurityConfiguration.java | 216 -------- .../server/ManagementServerProperties.java | 22 - .../webserver/server/ServerProperties.java | 22 - .../server/ServerPropertiesConfiguration.java | 11 - .../user/UserDetailInformationService.java | 17 - .../webserver/user/UserInfoService.java | 36 -- .../application-classic-auth-enabled.yml | 14 - .../application-integrationtest-data.yml | 6 - .../src/main/resources/application-local.yml | 10 - .../application-ssl-cert-provided.yml | 16 - .../application-ssl-cert-required.yml | 13 - .../src/main/resources/application.yml | 46 -- .../src/main/resources/banner.txt | 8 - .../certificates-untracked/.gitignore | 5 - .../certificates-untracked/README.md | 10 - .../main/resources/i18n/messages.properties | 11 - .../resources/i18n/messages_de.properties | 11 - .../src/main/resources/logback-spring.xml | 27 - .../src/main/resources/static/css/main.css | 166 ------ .../src/main/resources/static/sechub-logo.svg | 494 ------------------ .../resources/templates/fragments/banner.html | 13 - .../resources/templates/fragments/footer.html | 11 - .../resources/templates/fragments/header.html | 10 - .../resources/templates/fragments/navbar.html | 32 -- .../src/main/resources/templates/home.html | 47 -- .../src/main/resources/templates/login.html | 216 -------- .../resources/templates/new-apitoken.html | 20 - .../AES256EncryptionPropertiesTest.java | 63 --- .../encryption/AES256EncryptionTest.java | 76 --- .../webserver/page/HomeControllerTest.java | 60 --- ...LoginControllerClassicAuthEnabledTest.java | 55 -- ...rollerOAuth2AndClassicAuthEnabledTest.java | 58 -- .../LoginControllerOAuth2EnabledTest.java | 59 --- ...dAndSecretOAuth2AccessTokenClientTest.java | 187 ------- .../security/JwtCookieResolverTest.java | 130 ----- .../webserver/security/JwtResponseTest.java | 106 ---- .../security/OAuth2JwtPropertiesTest.java | 92 ---- .../OAuth2LoginSuccessHandlerTest.java | 106 ---- .../security/PortAccessGuardTest.java | 70 --- .../TestCookieRequestPostProcessor.java | 31 -- .../security/TestSecurityController.java | 63 --- .../TestWebServerSecurityConfiguration.java | 23 - .../WebServerSecurityConfigurationTest.java | 99 ---- .../src/test/resources/application-test.yml | 26 - .../src/test/resources/jwt-response.json | 7 - settings.gradle | 6 +- 124 files changed, 438 insertions(+), 5456 deletions(-) delete mode 100644 .github/workflows/release-web-server.yml create mode 100644 sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/user/UserRestController.java create mode 100644 sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/user/UserDetailInformationServiceTest.java create mode 100644 sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/user/UserRestControllerTest.java create mode 100644 sechub-doc/src/test/java/com/mercedesbenz/sechub/restdoc/UserRestControllerRestDocTest.java create mode 100644 sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/admin/user/UseCaseUserFetchesUserDetailInformation.java delete mode 100755 sechub-web-server-solution/01-start-single-docker-compose.sh delete mode 100755 sechub-web-server-solution/05-start-single-sechub-network-docker-compose.sh delete mode 100755 sechub-web-server-solution/10-create-image.sh delete mode 100755 sechub-web-server-solution/20-push-image.sh delete mode 100644 sechub-web-server-solution/README.adoc delete mode 100644 sechub-web-server-solution/docker-compose_web_server.yaml delete mode 100644 sechub-web-server-solution/docker-compose_web_server_external-network.yaml delete mode 100644 sechub-web-server-solution/docker/.gitignore delete mode 100644 sechub-web-server-solution/docker/Web-Server-Debian.dockerfile delete mode 100644 sechub-web-server-solution/docker/clone.sh delete mode 100644 sechub-web-server-solution/docker/copy/README.adoc delete mode 100755 sechub-web-server-solution/docker/run.sh delete mode 100644 sechub-web-server-solution/env delete mode 100644 sechub-web-server-solution/env-web-server delete mode 100644 sechub-web-server-solution/helm/.gitignore delete mode 100644 sechub-web-server-solution/helm/web-server/.helmignore delete mode 100644 sechub-web-server-solution/helm/web-server/Chart.yaml delete mode 100644 sechub-web-server-solution/helm/web-server/LICENSE delete mode 100644 sechub-web-server-solution/helm/web-server/README.md delete mode 100644 sechub-web-server-solution/helm/web-server/templates/deployment.yaml delete mode 100644 sechub-web-server-solution/helm/web-server/templates/networkpolicy.yaml delete mode 100644 sechub-web-server-solution/helm/web-server/templates/service.yaml delete mode 100644 sechub-web-server-solution/helm/web-server/values.yaml delete mode 100644 sechub-web-server/.gitignore delete mode 100644 sechub-web-server/README.adoc delete mode 100644 sechub-web-server/README.md delete mode 100644 sechub-web-server/build.gradle delete mode 100644 sechub-web-server/dev-base.sh delete mode 100755 sechub-web-server/dev-create_localhost_certificate.sh delete mode 100755 sechub-web-server/dev-ensure_localhost_certificate.sh delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/ApplicationProfiles.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/RequestConstants.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/SecHubWebServerApplication.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/credentials/NewApiTokenController.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/credentials/NewApiTokenService.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/encryption/AES256Encryption.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/encryption/AES256EncryptionException.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/encryption/AES256EncryptionProperties.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/i18n/RequestParamLocaleContextResolver.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/page/HomeController.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/page/LoginController.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/sechubaccess/ClientCaller.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/sechubaccess/ErrorCallback.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/sechubaccess/SecHubAccessService.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/sechubaccess/SecHubClientExecutor.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/Base64EncodedClientIdAndSecretOAuth2AccessTokenClient.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/ClassicLoginSuccessHandler.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/JwtCookieResolver.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/JwtResponse.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/MissingAuthenticationEntryPointHandler.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/OAuth2LoginSuccessHandler.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/OAuth2Properties.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/OAuth2PropertiesConfig.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/PortAccessGuard.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/UserInputSanitizer.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/WebServerSecurityConfiguration.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/server/ManagementServerProperties.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/server/ServerProperties.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/server/ServerPropertiesConfiguration.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/user/UserDetailInformationService.java delete mode 100644 sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/user/UserInfoService.java delete mode 100644 sechub-web-server/src/main/resources/application-classic-auth-enabled.yml delete mode 100644 sechub-web-server/src/main/resources/application-integrationtest-data.yml delete mode 100644 sechub-web-server/src/main/resources/application-local.yml delete mode 100644 sechub-web-server/src/main/resources/application-ssl-cert-provided.yml delete mode 100644 sechub-web-server/src/main/resources/application-ssl-cert-required.yml delete mode 100644 sechub-web-server/src/main/resources/application.yml delete mode 100644 sechub-web-server/src/main/resources/banner.txt delete mode 100644 sechub-web-server/src/main/resources/certificates-untracked/.gitignore delete mode 100644 sechub-web-server/src/main/resources/certificates-untracked/README.md delete mode 100644 sechub-web-server/src/main/resources/i18n/messages.properties delete mode 100644 sechub-web-server/src/main/resources/i18n/messages_de.properties delete mode 100644 sechub-web-server/src/main/resources/logback-spring.xml delete mode 100644 sechub-web-server/src/main/resources/static/css/main.css delete mode 100644 sechub-web-server/src/main/resources/static/sechub-logo.svg delete mode 100644 sechub-web-server/src/main/resources/templates/fragments/banner.html delete mode 100644 sechub-web-server/src/main/resources/templates/fragments/footer.html delete mode 100644 sechub-web-server/src/main/resources/templates/fragments/header.html delete mode 100644 sechub-web-server/src/main/resources/templates/fragments/navbar.html delete mode 100644 sechub-web-server/src/main/resources/templates/home.html delete mode 100644 sechub-web-server/src/main/resources/templates/login.html delete mode 100644 sechub-web-server/src/main/resources/templates/new-apitoken.html delete mode 100644 sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/encryption/AES256EncryptionPropertiesTest.java delete mode 100644 sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/encryption/AES256EncryptionTest.java delete mode 100644 sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/page/HomeControllerTest.java delete mode 100644 sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/page/LoginControllerClassicAuthEnabledTest.java delete mode 100644 sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/page/LoginControllerOAuth2AndClassicAuthEnabledTest.java delete mode 100644 sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/page/LoginControllerOAuth2EnabledTest.java delete mode 100644 sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/Base64EncodedClientIdAndSecretOAuth2AccessTokenClientTest.java delete mode 100644 sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/JwtCookieResolverTest.java delete mode 100644 sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/JwtResponseTest.java delete mode 100644 sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/OAuth2JwtPropertiesTest.java delete mode 100644 sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/OAuth2LoginSuccessHandlerTest.java delete mode 100644 sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/PortAccessGuardTest.java delete mode 100644 sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/TestCookieRequestPostProcessor.java delete mode 100644 sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/TestSecurityController.java delete mode 100644 sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/TestWebServerSecurityConfiguration.java delete mode 100644 sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/WebServerSecurityConfigurationTest.java delete mode 100644 sechub-web-server/src/test/resources/application-test.yml delete mode 100644 sechub-web-server/src/test/resources/jwt-response.json diff --git a/.github/workflows/release-web-server.yml b/.github/workflows/release-web-server.yml deleted file mode 100644 index b59607f25c..0000000000 --- a/.github/workflows/release-web-server.yml +++ /dev/null @@ -1,265 +0,0 @@ -# SPDX-License-Identifier: MIT -name: Release Web Server - -############################### -# D E P R E C A T E D ! ! -# -# web-server functionality will be integrated into SecHub server -############################### -on: - workflow_dispatch: - inputs: - actor-email: - description: Insert your email address here. It will be used in the generated pull requests - required: true - web-server-version: - description: Web Server Version (e.g. 0.1.0) - required: true - web-server-milestone-number: - description: Web Server Milestone number (e.g. 70) - required: true - -permissions: - contents: write - issues: write - packages: write - pull-requests: write - -env: - ACTIONS_BASE_IMAGE_ALPINE: alpine:3.20 - ACTIONS_BASE_IMAGE_DEBIAN: debian:12-slim - ACTIONS_SECHUB_REGISTRY: ghcr.io/mercedes-benz/sechub - ACTIONS_HELM_REGISTRY: "oci://ghcr.io/mercedes-benz/sechub/helm-charts" - -jobs: - release-version: - name: Create Web Server release - runs-on: ubuntu-latest - steps: - - - name: "Show Inputs" - run: | - echo "actor-email: '${{ inputs.actor-email }}'" - echo "Web Server '${{ inputs.web-server-version }}' - Milestone '${{ inputs.web-server-milestone-number }}'" - - # Check inputs: - - name: "Verify Input for Web Server release" - if: (inputs.web-server-version == '') || (inputs.web-server-milestone-number == '') - run: | - echo "For Web Server release, web-server-version and web-server-milestone-number must be provided!" - exit 1 - - - name: Checkout master - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - ref: master - - # Create temporary local tag, so we build for this tag... - # The final tag on git server side will be done automatically by the release when the draft is saved as "real" release - - name: "Temporary tag server version: v${{ inputs.web-server-version }}-web-server" - run: git tag v${{ inputs.web-server-version }}-web-server - - # ---------------------- - # Setup + Caching - # ---------------------- - - name: Set up JDK 17 - uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b - with: - java-version: 17 - distribution: temurin - - - name: Set up Gradle - uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 - with: - cache-read-only: false - - - name: Docker login to ghcr.io - uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - # ---------------------- - # Create pull request if license headers are missing - # ---------------------- - - name: run apply-headers.sh - id: apply-headers - run: | - git config user.name "$GITHUB_TRIGGERING_ACTOR (via github-actions)" - git config user.email "${{ inputs.actor-email }}" - ./apply-headers.sh - git commit -am "SPDX headers added by SecHub release job @github-actions" || true - COMMITS=`git log --oneline --branches --not --remotes` - echo "commits=$COMMITS" >> $GITHUB_OUTPUT - - - name: Create pull request for SPDX license headers - id: pr_spdx_headers - if: steps.apply-headers.outputs.commits != '' - uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f - with: - branch: release-spdx-headers - branch-suffix: short-commit-hash - delete-branch: true - title: '0 - Before web-server release: Add missing SPDX license headers [auto-generated]' - body: | - Auto-generated by Github Actions web-server release job. - - -> Please review and merge **before** publishing the web-server release. - - - name: Print PR infos - if: steps.apply-headers.outputs.commits != '' - run: | - echo "Pull Request Number - ${{ steps.pr_spdx_headers.outputs.pull-request-number }}" - echo "Pull Request URL - ${{ steps.pr_spdx_headers.outputs.pull-request-url }}" - - # ---------------------- - # Build SecHub Web Server - # ---------------------- - - name: Build Web Server jar files - run: ./gradlew ensureLocalhostCertificate :sechub-api-java:build :sechub-web-server:build -Dsechub.build.stage=api-necessary --console=plain - - # To identifiy parts not in git history - - name: Collect GIT status - if: always() - run: | - # restore reduced-openapi3.json - git restore sechub-api-java/src/main/resources/reduced-openapi3.json - mkdir -p build/reports - git status > build/reports/git-status.txt - echo "--- git tags:" >> build/reports/git-status.txt - git tag --points-at HEAD >> build/reports/git-status.txt - - - name: Archive GIT status - if: always() - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 - with: - name: git-status.txt - path: build/reports/git-status.txt - retention-days: 14 - - - name: Archive Web Server artifacts - if: always() - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 - with: - name: sechub-web-server - path: sechub-web-server/build/libs - retention-days: 14 - - # ----------------------------------------- - # Assert releaseable: Check for uncommitted changes - # ----------------------------------------- - - name: Assert releasable - run: | - git status - ./gradlew assertReleaseable - - - name: Create Web Server release - id: create_web-server_release - uses: actions/create-release@0cb9c9b65d5d1901c1f53e5e66eaf4afd303e70e - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token - with: - tag_name: v${{ inputs.web-server-version }}-web-server - commitish: master - release_name: web-server Version ${{ inputs.web-server-version }} - body: | - Changes in this Release - - Some minor changes on Web Server implementation - - For more details please look at [Milestone ${{inputs.web-server-milestone-number}}]( https://github.com/mercedes-benz/sechub/milestone/${{inputs.web-server-milestone-number}}?closed=1) - draft: true - prerelease: false - - - name: Create sha256 checksum file for Web Server jar - run: | - cd sechub-web-server/build/libs - sha256sum sechub-web-server-${{ inputs.web-server-version }}.jar > sechub-web-server-${{ inputs.web-server-version }}.jar.sha256sum - - - name: Upload Web Server release asset sechub-web-server-${{ inputs.web-server-version }}.jar - uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_web-server_release.outputs.upload_url }} - asset_path: sechub-web-server/build/libs/sechub-web-server-${{ inputs.web-server-version }}.jar - asset_name: sechub-web-server-${{ inputs.web-server-version }}.jar - asset_content_type: application/zip - - - name: Upload Web Server release asset sechub-web-server-${{ inputs.web-server-version }}.jar.sha256sum - uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_web-server_release.outputs.upload_url }} - asset_path: sechub-web-server/build/libs/sechub-web-server-${{ inputs.web-server-version }}.jar.sha256sum - asset_name: sechub-web-server-${{ inputs.web-server-version }}.jar.sha256sum - asset_content_type: text/plain - - # ----------------------------------------- - # Create release issue - # ----------------------------------------- - - name: Create SecHub Web Server ${{ inputs.web-server-version }} release issue - uses: dacbd/create-issue-action@main - with: - token: ${{ github.token }} - title: Release SecHub Web Server ${{ inputs.web-server-version }} - body: | - See [Milestone ${{inputs.web-server-milestone-number}}]( https://github.com/mercedes-benz/sechub/milestone/${{inputs.web-server-milestone-number}}?closed=1) for details. - - Please close this issue after the release. - milestone: ${{ inputs.web-server-milestone-number }} - - # Build SecHub Web Server container image + push to ghcr - - name: Build sechub-web-server ${{ inputs.web-server-version }} container image + push to ghcr - run: | - WEB_SERVER_VERSION="${{ inputs.web-server-version }}" - DOCKER_REGISTRY="$ACTIONS_SECHUB_REGISTRY/sechub-web-server" - VERSION_TAG="${WEB_SERVER_VERSION}" - cp sechub-web-server/build/libs/sechub-web-server-${WEB_SERVER_VERSION}.jar sechub-web-server-solution/docker/copy/ - cd sechub-web-server-solution - echo "# Building image $DOCKER_REGISTRY:$VERSION_TAG" - echo " from $ACTIONS_BASE_IMAGE_DEBIAN" - ./10-create-image.sh "$DOCKER_REGISTRY" "$VERSION_TAG" "WEB_SERVER_VERSION" "$ACTIONS_BASE_IMAGE_DEBIAN" copy - echo "# Pushing image $DOCKER_REGISTRY:$VERSION_TAG (latest)" - ./20-push-image.sh "$DOCKER_REGISTRY" "$VERSION_TAG" yes - - - name: Build sechub-web-server Helm chart + push to ghcr - shell: bash - run: | - cd sechub-web-server-solution/helm - echo "# Building Helm chart for SecHub Web Server" - helm package sechub-web-server - helm push sechub-web-server-*.tgz $ACTIONS_HELM_REGISTRY - - # ----------------------------------------- - # Create a pull request for merging back `master` into `develop` - # ----------------------------------------- - - name: pull-request master to develop - id: pr_master_to_develop - continue-on-error: true - uses: repo-sync/pull-request@7e79a9f5dc3ad0ce53138f01df2fad14a04831c5 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - source_branch: "master" - destination_branch: "develop" - pr_allow_empty: true # should allow an empty PR, but seems not to work - pr_title: '2 - After web-server release: Merge master back into develop [auto-generated]' - pr_body: | - After SecHub Web Server release - - Web Server '${{ inputs.web-server-version }}' - - Merge master branch back into develop - - -> Please merge **after** the release has been published. - - - name: Print PR infos if PR was created - if: steps.pr_master_to_develop.outcome == 'success' - run: | - echo "Pull Request Number - ${{ steps.pr_master_to_develop.outputs.pr_number }}" - echo "Pull Request URL - ${{ steps.pr_master_to_develop.outputs.pr_url }}" - - - name: Print info if no PR was created - if: steps.pr_master_to_develop.outcome != 'success' - run: | - echo "Nothing to merge - no pull request necessary." diff --git a/gradle/projects.gradle b/gradle/projects.gradle index 2955e328fb..9b76b660a5 100644 --- a/gradle/projects.gradle +++ b/gradle/projects.gradle @@ -106,12 +106,11 @@ projectType = [ project(':sechub-pds'), project(':sechub-wrapper-checkmarx'), project(':sechub-wrapper-prepare'), - project(':sechub-web-server'), project(':sechub-wrapper-secretvalidation'), ], springBootWebApplicationProjects:[ - project('sechub-web-server') + ], /* documentation projects */ @@ -128,8 +127,7 @@ projectType = [ project(':sechub-pds-solutions'), project(':sechub-solution'), project(':sechub-solutions-shared'), - project(':sechub-wrapper-xray'), - project(':sechub-web-server-solution'), + project(':sechub-wrapper-xray') ], asciiDoctorProjects: [ diff --git a/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/AdministrationAPIConstants.java b/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/AdministrationAPIConstants.java index ba3cdcaf21..0aca804ba7 100644 --- a/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/AdministrationAPIConstants.java +++ b/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/AdministrationAPIConstants.java @@ -64,7 +64,16 @@ private AdministrationAPIConstants() { public static final String API_LIST_USER_SIGNUPS = API_ADMINISTRATION + "signups"; /* +-----------------------------------------------------------------------+ */ - /* +............................ Users ....................................+ */ + /* +......................... Users (Self Service).........................+ */ + /* +-----------------------------------------------------------------------+ */ + + /** + * Fetch user detail information for authenticated user + */ + public static final String API_USER_DETAIL_INFO = API_MANAGEMENT + "user"; + + /* +-----------------------------------------------------------------------+ */ + /* +............................ Users (Admin) ............................+ */ /* +-----------------------------------------------------------------------+ */ /** * shows all users names diff --git a/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/user/UserAdministrationRestController.java b/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/user/UserAdministrationRestController.java index 6add06d122..387cd2f396 100644 --- a/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/user/UserAdministrationRestController.java +++ b/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/user/UserAdministrationRestController.java @@ -93,7 +93,7 @@ public List listAdministrators() { @RequestMapping(path = AdministrationAPIConstants.API_SHOW_USER_DETAILS, method = RequestMethod.GET, produces= {MediaType.APPLICATION_JSON_VALUE}) public UserDetailInformation showUserDetails(@PathVariable(name="userId") String userId) { /* @formatter:on */ - return detailsService.fetchDetails(userId); + return detailsService.fetchDetailsById(userId); } /* @formatter:off */ diff --git a/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/user/UserDetailInformation.java b/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/user/UserDetailInformation.java index 46fab0a603..6c32765149 100644 --- a/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/user/UserDetailInformation.java +++ b/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/user/UserDetailInformation.java @@ -20,15 +20,15 @@ public class UserDetailInformation { public static final String PROPERTY_OWNED_PROJECTS = "ownedProjects"; public static final String PROPERTY_SUPERADMIN = "superAdmin"; - private String userId; + private final String userId; - private String email; + private final String email; - private boolean superAdmin; + private final boolean superAdmin; - private List projects = new ArrayList<>(); + private final List projects = new ArrayList<>(); - private List ownedProjects = new ArrayList<>(); + private final List ownedProjects = new ArrayList<>(); public UserDetailInformation(User user) { this.userId = user.getName(); diff --git a/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/user/UserDetailInformationService.java b/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/user/UserDetailInformationService.java index 1d89bbac77..84da78d145 100644 --- a/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/user/UserDetailInformationService.java +++ b/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/user/UserDetailInformationService.java @@ -3,7 +3,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.mercedesbenz.sechub.sharedkernel.Step; @@ -12,27 +11,46 @@ import com.mercedesbenz.sechub.sharedkernel.security.UserContextService; import com.mercedesbenz.sechub.sharedkernel.usecases.admin.user.UseCaseAdminShowsUserDetails; import com.mercedesbenz.sechub.sharedkernel.usecases.admin.user.UseCaseAdminShowsUserDetailsForEmailAddress; +import com.mercedesbenz.sechub.sharedkernel.usecases.admin.user.UseCaseUserFetchesUserDetailInformation; import com.mercedesbenz.sechub.sharedkernel.validation.UserInputAssertion; import jakarta.annotation.security.RolesAllowed; @Service -@RolesAllowed(RoleConstants.ROLE_SUPERADMIN) public class UserDetailInformationService { private static final Logger LOG = LoggerFactory.getLogger(UserDetailInformationService.class); - @Autowired - UserContextService userContext; + private final UserContextService userContext; + private final UserRepository userRepository; + private final LogSanitizer logSanitizer; + private final UserInputAssertion assertion; + + public UserDetailInformationService(UserContextService userContext, UserRepository userRepository, LogSanitizer logSanitizer, + UserInputAssertion assertion) { + this.userContext = userContext; + this.userRepository = userRepository; + this.logSanitizer = logSanitizer; + this.assertion = assertion; + } - @Autowired - UserRepository userRepository; + /* @formatter:off */ + @UseCaseUserFetchesUserDetailInformation( + @Step( + number = 2, + name = "Service fetches user details for the authenticated user.", + description = "The service will fetch user details for the authenticated user")) + /* @formatter:on */ + @RolesAllowed(RoleConstants.ROLE_USER) + public UserDetailInformation fetchDetails() { + String userId = userContext.getUserId(); - @Autowired - LogSanitizer logSanitizer; + LOG.debug("User {} is fetching his user details", userId); - @Autowired - UserInputAssertion assertion; + User user = userRepository.findOrFailUser(userId); + + return new UserDetailInformation(user); + } /* @formatter:off */ @UseCaseAdminShowsUserDetails( @@ -41,7 +59,8 @@ public class UserDetailInformationService { name = "Service fetches user details.", description = "The service will fetch user details for given user id")) /* @formatter:on */ - public UserDetailInformation fetchDetails(String userId) { + @RolesAllowed(RoleConstants.ROLE_SUPERADMIN) + public UserDetailInformation fetchDetailsById(String userId) { LOG.debug("User {} is fetching user details for user: {}", userContext.getUserId(), logSanitizer.sanitize(userId, 30)); assertion.assertIsValidUserId(userId); @@ -58,6 +77,7 @@ public UserDetailInformation fetchDetails(String userId) { name = "Service fetches user details.", description = "The service will fetch user details for given user email address")) /* @formatter:on */ + @RolesAllowed(RoleConstants.ROLE_SUPERADMIN) public UserDetailInformation fetchDetailsByEmailAddress(String emailAddress) { LOG.debug("User {} is fetching user details for user email: {}", userContext.getUserId(), logSanitizer.sanitize(emailAddress, 30)); diff --git a/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/user/UserRestController.java b/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/user/UserRestController.java new file mode 100644 index 0000000000..99f0a15504 --- /dev/null +++ b/sechub-administration/src/main/java/com/mercedesbenz/sechub/domain/administration/user/UserRestController.java @@ -0,0 +1,30 @@ +package com.mercedesbenz.sechub.domain.administration.user; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.mercedesbenz.sechub.domain.administration.AdministrationAPIConstants; +import com.mercedesbenz.sechub.sharedkernel.Step; +import com.mercedesbenz.sechub.sharedkernel.security.RoleConstants; +import com.mercedesbenz.sechub.sharedkernel.usecases.admin.user.UseCaseUserFetchesUserDetailInformation; + +import jakarta.annotation.security.RolesAllowed; + +@RestController +@RolesAllowed(RoleConstants.ROLE_USER) +public class UserRestController { + + private final UserDetailInformationService userDetailInformationService; + + UserRestController(UserDetailInformationService userDetailInformationService) { + this.userDetailInformationService = userDetailInformationService; + } + + /* @formatter:off */ + @UseCaseUserFetchesUserDetailInformation(@Step(number=1,name="Rest call",description="Json response containing details about the authenticated user",needsRestDoc=true)) + @GetMapping(AdministrationAPIConstants.API_USER_DETAIL_INFO) + public UserDetailInformation fetchUserDetailInformation() { + /* @formatter:on */ + return userDetailInformationService.fetchDetails(); + } +} diff --git a/sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/project/ProjectChangeOwnerServiceTest.java b/sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/project/ProjectChangeOwnerServiceTest.java index 39dba6b20e..e0d075c773 100644 --- a/sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/project/ProjectChangeOwnerServiceTest.java +++ b/sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/project/ProjectChangeOwnerServiceTest.java @@ -65,7 +65,7 @@ public void assign_new_owner_to_project() { when(oldOwner.getName()).thenReturn("old"); when(newOwner.getName()).thenReturn("new"); when(userRepository.findOrFailUser("new")).thenReturn(newOwner); - when(newOwner.getProjects()).thenReturn(new HashSet()); + when(newOwner.getProjects()).thenReturn(new HashSet<>()); /* execute */ serviceToTest.changeProjectOwner(newOwner.getName(), project1.getId()); diff --git a/sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/user/UserAdministrationRestControllerMockTest.java b/sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/user/UserAdministrationRestControllerMockTest.java index b42a3f6744..bbb4a09b6d 100644 --- a/sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/user/UserAdministrationRestControllerMockTest.java +++ b/sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/user/UserAdministrationRestControllerMockTest.java @@ -107,7 +107,7 @@ public void show_user_details_returns_result_of_detail_service() throws Exceptio when(user.getProjects()).thenReturn(projects); UserDetailInformation info = new UserDetailInformation(user); - when(mockedUserDetailInformationService.fetchDetails("user1")).thenReturn(info); + when(mockedUserDetailInformationService.fetchDetailsById("user1")).thenReturn(info); /* execute + test @formatter:off */ this.mockMvc.perform( @@ -148,7 +148,7 @@ public void show_user_details_for_email_address_returns_result_of_detail_service andExpect(status().isOk()). andExpect(jsonPath("$.userId", equalTo(userId))). andExpect(jsonPath("$.email", equalTo(emailAddress))). - andExpect(jsonPath("$.projects", equalTo(Arrays.asList("project1"))) + andExpect(jsonPath("$.projects", equalTo(List.of("project1"))) ); /* @formatter:on */ diff --git a/sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/user/UserDetailInformationServiceTest.java b/sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/user/UserDetailInformationServiceTest.java new file mode 100644 index 0000000000..02c576b5fb --- /dev/null +++ b/sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/user/UserDetailInformationServiceTest.java @@ -0,0 +1,129 @@ +package com.mercedesbenz.sechub.domain.administration.user; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.util.ReflectionTestUtils.setField; + +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.mercedesbenz.sechub.domain.administration.project.Project; +import com.mercedesbenz.sechub.sharedkernel.logging.LogSanitizer; +import com.mercedesbenz.sechub.sharedkernel.security.UserContextService; +import com.mercedesbenz.sechub.sharedkernel.validation.UserInputAssertion; + +class UserDetailInformationServiceTest { + + private static final String USER_ID = UUID.randomUUID().toString(); + private static final String EMAIL_ADDRESS = "test-user@example.org"; + private static final Set PROJECTS = Set.of(createProject()); + private static final Set OWNED_PROJECTS = Set.of(createProject()); + private static final User USER = createUser(); + + private static final UserContextService userContextService = mock(); + private static final UserRepository userRepository = mock(); + private static final LogSanitizer logSanitizer = mock(); + private static final UserInputAssertion userInputAssertion = mock(); + private static final UserDetailInformationService serviceToTest = new UserDetailInformationService(userContextService, userRepository, logSanitizer, + userInputAssertion); + + @BeforeEach + void beforeEach() { + reset(userContextService, userRepository, logSanitizer, userInputAssertion); + when(userContextService.getUserId()).thenReturn(USER_ID); + when(userRepository.findOrFailUser(USER_ID)).thenReturn(USER); + } + + @Test + void fetchDetails__returns_user_details_for_the_authenticated_user() { + /* execute */ + UserDetailInformation userDetailInformation = serviceToTest.fetchDetails(); + + /* test */ + assertThat(userDetailInformation).isNotNull(); + assertThat(userDetailInformation.getUserId()).isEqualTo(USER_ID); + assertThat(userDetailInformation.getEmail()).isEqualTo(EMAIL_ADDRESS); + assertThat(userDetailInformation.getProjects()).isNotEmpty(); + assertThat(userDetailInformation.getProjects()).isEqualTo(getProjectIds(PROJECTS)); + assertThat(userDetailInformation.getOwnedProjects()).isNotEmpty(); + assertThat(userDetailInformation.getOwnedProjects()).isEqualTo(getProjectIds(OWNED_PROJECTS)); + assertThat(userDetailInformation.isSuperAdmin()).isTrue(); + verify(userContextService).getUserId(); + verify(userRepository).findOrFailUser(USER_ID); + } + + @Test + void fetchDetailsById__returns_user_details_for_given_user_id() { + /* execute */ + UserDetailInformation userDetailInformation = serviceToTest.fetchDetailsById(USER_ID); + + /* test */ + assertThat(userDetailInformation).isNotNull(); + assertThat(userDetailInformation.getUserId()).isEqualTo(USER_ID); + assertThat(userDetailInformation.getEmail()).isEqualTo(EMAIL_ADDRESS); + assertThat(userDetailInformation.getProjects()).isNotEmpty(); + assertThat(userDetailInformation.getProjects()).isEqualTo(getProjectIds(PROJECTS)); + assertThat(userDetailInformation.getOwnedProjects()).isNotEmpty(); + assertThat(userDetailInformation.getOwnedProjects()).isEqualTo(getProjectIds(OWNED_PROJECTS)); + assertThat(userDetailInformation.isSuperAdmin()).isTrue(); + verify(logSanitizer).sanitize(USER_ID, 30); + verify(userContextService).getUserId(); + verify(userInputAssertion).assertIsValidUserId(USER_ID); + verify(userRepository).findOrFailUser(USER_ID); + } + + @Test + void fetchDetailsByEmail__returns_user_details_for_given_email() { + /* prepare */ + when(userRepository.findOrFailUserByEmailAddress(EMAIL_ADDRESS)).thenReturn(USER); + + /* execute */ + UserDetailInformation userDetailInformation = serviceToTest.fetchDetailsByEmailAddress(EMAIL_ADDRESS); + + /* test */ + assertThat(userDetailInformation).isNotNull(); + assertThat(userDetailInformation.getUserId()).isEqualTo(USER_ID); + assertThat(userDetailInformation.getEmail()).isEqualTo(EMAIL_ADDRESS); + assertThat(userDetailInformation.getProjects()).isNotEmpty(); + assertThat(userDetailInformation.getProjects()).isEqualTo(getProjectIds(PROJECTS)); + assertThat(userDetailInformation.getOwnedProjects()).isNotEmpty(); + assertThat(userDetailInformation.getOwnedProjects()).isEqualTo(getProjectIds(OWNED_PROJECTS)); + assertThat(userDetailInformation.isSuperAdmin()).isTrue(); + verify(logSanitizer).sanitize(EMAIL_ADDRESS, 30); + verify(userContextService).getUserId(); + verify(userInputAssertion).assertIsValidEmailAddress(EMAIL_ADDRESS); + verify(userRepository).findOrFailUserByEmailAddress(EMAIL_ADDRESS); + } + + private static Project createProject() { + Project project = new Project(); + /* + * working around package private visibility of the id column by using + * reflections + */ + setField(project, "id", UUID.randomUUID().toString()); + return project; + } + + private static User createUser() { + User user = new User(); + user.name = UserDetailInformationServiceTest.USER_ID; + user.emailAddress = UserDetailInformationServiceTest.EMAIL_ADDRESS; + user.projects = UserDetailInformationServiceTest.PROJECTS; + user.ownedProjects = UserDetailInformationServiceTest.OWNED_PROJECTS; + user.superAdmin = true; + return user; + } + + private static List getProjectIds(Set projects) { + return projects.stream().map(Project::getId).toList(); + } + +} diff --git a/sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/user/UserRestControllerTest.java b/sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/user/UserRestControllerTest.java new file mode 100644 index 0000000000..aee0395367 --- /dev/null +++ b/sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/user/UserRestControllerTest.java @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.domain.administration.user; + +import static com.mercedesbenz.sechub.test.SecHubTestURLBuilder.https; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.Set; +import java.util.UUID; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import com.mercedesbenz.sechub.domain.administration.project.Project; +import com.mercedesbenz.sechub.sharedkernel.Profiles; +import com.mercedesbenz.sechub.sharedkernel.security.RoleConstants; +import com.mercedesbenz.sechub.test.TestPortProvider; + +@RunWith(SpringRunner.class) +@WebMvcTest +@ContextConfiguration(classes = { UserRestController.class }) +@ActiveProfiles({ Profiles.TEST }) +public class UserRestControllerTest { + + private static final int PORT_USED = TestPortProvider.DEFAULT_INSTANCE.getWebMVCTestHTTPSPort(); + + @Autowired + private MockMvc mockMvc; + + @MockBean + private UserDetailInformationService userDetailInformationService; + + @Test + @WithMockUser(roles = RoleConstants.ROLE_USER) + public void fetchUserDetailInformation__is_accessible_by_authenticated_user() throws Exception { + /* prepare */ + User user = createUser(); + String userId = user.getName(); + UserDetailInformation userDetailInformation = new UserDetailInformation(user); + when(userDetailInformationService.fetchDetails()).thenReturn(userDetailInformation); + + /* execute + test */ + /* @formatter:off */ + this.mockMvc.perform( + get(https(PORT_USED).buildFetchUserDetailInformationUrl())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.userId", equalTo(userId))) + .andExpect(jsonPath("$.email", equalTo(userDetailInformation.getEmail()))) + .andExpect(jsonPath("$.projects", equalTo(userDetailInformation.getProjects()))) + .andExpect(jsonPath("$.ownedProjects", equalTo(userDetailInformation.getOwnedProjects()))) + .andExpect(jsonPath("$.superAdmin", equalTo(userDetailInformation.isSuperAdmin()))); + /* @formatter:on */ + verify(userDetailInformationService).fetchDetails(); + } + + @Test + public void fetchUserDetailInformation__is_not_accessible_by_unauthenticated_user() throws Exception { + /* execute + test */ + /* @formatter:off */ + this.mockMvc.perform( + get(https(PORT_USED).buildFetchUserDetailInformationUrl())) + .andExpect(status().isUnauthorized()); + /* @formatter:on */ + } + + private static User createUser() { + User user = new User(); + user.name = UUID.randomUUID().toString(); + user.emailAddress = "test-user@example.org"; + user.projects = Set.of(new Project()); + user.ownedProjects = Set.of(new Project()); + user.superAdmin = true; + return user; + } +} diff --git a/sechub-developertools/build.gradle b/sechub-developertools/build.gradle index 4b132ec41d..69257b78c6 100644 --- a/sechub-developertools/build.gradle +++ b/sechub-developertools/build.gradle @@ -27,7 +27,7 @@ dependencies { task importEclipseProjectsNeedingOpenApiFile(type: Exec){ workingDir "$rootDir" - commandLine './gradlew', ':sechub-systemtest:cleanEclipse',':sechub-systemtest:eclipse', ':sechub-web-server:cleanEclipse',':sechub-web-server:eclipse', ':sechub-api-java:cleanEclipse',':sechub-api-java:eclipse', ':sechub-pds-tools:cleanEclipse',':sechub-pds-tools:eclipse',':sechub-examples:example-sechub-api-java:cleanEclipse',':sechub-examples:example-sechub-api-java:eclipse','-Dsechub.build.stage=all' + commandLine './gradlew', ':sechub-systemtest:cleanEclipse',':sechub-systemtest:eclipse', ':sechub-api-java:cleanEclipse',':sechub-api-java:eclipse', ':sechub-pds-tools:cleanEclipse',':sechub-pds-tools:eclipse',':sechub-examples:example-sechub-api-java:cleanEclipse',':sechub-examples:example-sechub-api-java:eclipse','-Dsechub.build.stage=all' } /* diff --git a/sechub-developertools/scripts/sdc.sh b/sechub-developertools/scripts/sdc.sh index f502bc9622..98383e6747 100755 --- a/sechub-developertools/scripts/sdc.sh +++ b/sechub-developertools/scripts/sdc.sh @@ -348,7 +348,7 @@ if [[ "$FULL_BUILD" = "YES" ]]; then ./gradlew ensureLocalhostCertificate build generateOpenapi -x :sechub-cli:build step "Generate and build Java projects related to SecHub Java API" - ./gradlew :sechub-api-java:build :sechub-systemtest:build :sechub-pds-tools:buildPDSToolsCLI :sechub-web-server:build -Dsechub.build.stage=api-necessary + ./gradlew :sechub-api-java:build :sechub-systemtest:build :sechub-pds-tools:buildPDSToolsCLI -Dsechub.build.stage=api-necessary step "Integration test" eval "${CMD_EXEC_ALL_INTEGRATIONTESTS}" diff --git a/sechub-doc/src/test/java/com/mercedesbenz/sechub/restdoc/UserAdministrationRestControllerRestDocTest.java b/sechub-doc/src/test/java/com/mercedesbenz/sechub/restdoc/UserAdministrationRestControllerRestDocTest.java index 15f074a33d..e2f20fce16 100644 --- a/sechub-doc/src/test/java/com/mercedesbenz/sechub/restdoc/UserAdministrationRestControllerRestDocTest.java +++ b/sechub-doc/src/test/java/com/mercedesbenz/sechub/restdoc/UserAdministrationRestControllerRestDocTest.java @@ -344,7 +344,7 @@ public void restdoc_show_user_details() throws Exception { when(user.getProjects()).thenReturn(projects); UserDetailInformation info = new UserDetailInformation(user); - when(userDetailService.fetchDetails("user1")).thenReturn(info); + when(userDetailService.fetchDetailsById("user1")).thenReturn(info); /* execute + test @formatter:off */ this.mockMvc.perform( diff --git a/sechub-doc/src/test/java/com/mercedesbenz/sechub/restdoc/UserRestControllerRestDocTest.java b/sechub-doc/src/test/java/com/mercedesbenz/sechub/restdoc/UserRestControllerRestDocTest.java new file mode 100644 index 0000000000..044317175d --- /dev/null +++ b/sechub-doc/src/test/java/com/mercedesbenz/sechub/restdoc/UserRestControllerRestDocTest.java @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.restdoc; + +import static com.mercedesbenz.sechub.restdoc.RestDocumentation.defineRestService; +import static com.mercedesbenz.sechub.test.SecHubTestURLBuilder.https; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.lang.annotation.Annotation; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import com.mercedesbenz.sechub.docgen.util.RestDocFactory; +import com.mercedesbenz.sechub.domain.administration.user.UserDetailInformationService; +import com.mercedesbenz.sechub.domain.administration.user.UserRestController; +import com.mercedesbenz.sechub.sharedkernel.Profiles; +import com.mercedesbenz.sechub.sharedkernel.security.RoleConstants; +import com.mercedesbenz.sechub.sharedkernel.usecases.UseCaseRestDoc; +import com.mercedesbenz.sechub.sharedkernel.usecases.admin.user.UseCaseUserFetchesUserDetailInformation; +import com.mercedesbenz.sechub.test.ExampleConstants; +import com.mercedesbenz.sechub.test.TestIsNecessaryForDocumentation; +import com.mercedesbenz.sechub.test.TestPortProvider; + +@RunWith(SpringRunner.class) +@WebMvcTest +@ContextConfiguration(classes = { UserRestController.class }) +@Import(TestRestDocSecurityConfiguration.class) +@WithMockUser(roles = RoleConstants.ROLE_USER) +@ActiveProfiles(Profiles.TEST) +@AutoConfigureRestDocs(uriScheme = "https", uriHost = ExampleConstants.URI_SECHUB_SERVER, uriPort = 443) +public class UserRestControllerRestDocTest implements TestIsNecessaryForDocumentation { + + private static final int PORT_USED = TestPortProvider.DEFAULT_INSTANCE.getRestDocTestPort(); + + @Autowired + private MockMvc mockMvc; + + @MockBean + private UserDetailInformationService userDetailInformationService; + + @Test + @UseCaseRestDoc(useCase = UseCaseUserFetchesUserDetailInformation.class) + public void restDoc__userFetchesUserDetailInformation() throws Exception { + /* prepare */ + String apiEndpoint = https(PORT_USED).buildFetchUserDetailInformationUrl(); + Class useCase = UseCaseUserFetchesUserDetailInformation.class; + + /* execute + test */ + /* @formatter:off */ + this.mockMvc.perform(get(apiEndpoint).header(AuthenticationHelper.HEADER_NAME, AuthenticationHelper.getHeaderValue())) + .andExpect(status().isOk()) + .andDo(defineRestService() + .with() + .useCaseData(useCase) + .tag(RestDocFactory.extractTag(apiEndpoint)) + .and() + .document()); + + /* @formatter:on */ + } + +} diff --git a/sechub-openapi-java-client/src/main/java/com/mercedesbenz/sechub/api/DefaultSecHubClient.java b/sechub-openapi-java-client/src/main/java/com/mercedesbenz/sechub/api/DefaultSecHubClient.java index 5c10d13497..9eeaf26fb6 100644 --- a/sechub-openapi-java-client/src/main/java/com/mercedesbenz/sechub/api/DefaultSecHubClient.java +++ b/sechub-openapi-java-client/src/main/java/com/mercedesbenz/sechub/api/DefaultSecHubClient.java @@ -11,7 +11,6 @@ import com.mercedesbenz.sechub.commons.core.security.CryptoAccess; import com.mercedesbenz.sechub.commons.model.JsonMapperFactory; import com.mercedesbenz.sechub.commons.model.SecHubConfigurationModel; -import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,7 +41,7 @@ public class DefaultSecHubClient extends AbstractSecHubClient { private final SystemApi systemApi; private final TestingApi testingApi; private final UserAdministrationApi userAdministrationApi; - private final UserProfileApi userProfileApi; + private final UserSelfServiceApi userSelfServiceApi; private final SecHubExecutionWorkaroundApi secHubExecutionWorkaroundApi; public static DefaultSecHubClientBuilder builder() { @@ -62,7 +61,7 @@ private DefaultSecHubClient(URI serverUri, String userId, String apiToken, boole systemApi = new SystemApi(apiClient); testingApi = new TestingApi(apiClient); userAdministrationApi = new UserAdministrationApi(apiClient); - userProfileApi = new UserProfileApi(apiClient); + userSelfServiceApi = new UserSelfServiceApi(apiClient); secHubExecutionWorkaroundApi = new SecHubExecutionWorkaroundApi(apiClient); } @@ -192,8 +191,8 @@ public UserAdministrationApi withUserAdministrationApi() { } @Override - public UserProfileApi withUserProfileApi() { - return userProfileApi; + public UserSelfServiceApi withUserSelfServiceApi() { + return userSelfServiceApi; } private void userUploadsBinaries(String projectId, UUID jobUUID, ArchiveSupport.ArchivesCreationResult createArchiveResult) throws ApiException { diff --git a/sechub-openapi-java-client/src/main/java/com/mercedesbenz/sechub/api/SecHubClient.java b/sechub-openapi-java-client/src/main/java/com/mercedesbenz/sechub/api/SecHubClient.java index 88af5807f3..c454d56b71 100644 --- a/sechub-openapi-java-client/src/main/java/com/mercedesbenz/sechub/api/SecHubClient.java +++ b/sechub-openapi-java-client/src/main/java/com/mercedesbenz/sechub/api/SecHubClient.java @@ -95,6 +95,6 @@ public interface SecHubClient { UserAdministrationApi withUserAdministrationApi(); - UserProfileApi withUserProfileApi(); + UserSelfServiceApi withUserSelfServiceApi(); } diff --git a/sechub-openapi-java/src/main/resources/openapi.yaml b/sechub-openapi-java/src/main/resources/openapi.yaml index 69d55763da..3e9917cf1b 100644 --- a/sechub-openapi-java/src/main/resources/openapi.yaml +++ b/sechub-openapi-java/src/main/resources/openapi.yaml @@ -18,8 +18,8 @@ tags: description: Operations relevant to user administration - name: Project Administration description: Operations relevant to project administration - - name: User Profile - description: Operations relevant to user profiles + - name: User Self Service + description: Operations relevant to the authenticated user - name: SecHub Execution description: Operations relevant to execution of SecHub - name: Sign Up @@ -2680,9 +2680,9 @@ paths: tags: - Project Administration - ################### - ## User Profile ## - ################### + ####################### + ## User Self Service ## + ####################### /api/anonymous/apitoken/{oneTimeToken}: get: @@ -2701,7 +2701,22 @@ paths: description: "Answer containing the new api token or error message if request could not be fulfilled" security: [ ] tags: - - User Profile + - User Self Service + + /api/management/user: + get: + summary: User fetches his user details + description: The authenticated user fetches his user details + operationId: userFetchUserDetailInformation + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/UserDetailInformation' + description: "200" + tags: + - User Self Service ###################### ## SecHub Execution ## diff --git a/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/UseCaseGroup.java b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/UseCaseGroup.java index b7fed0dc4d..c6ccf73629 100644 --- a/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/UseCaseGroup.java +++ b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/UseCaseGroup.java @@ -9,7 +9,7 @@ public enum UseCaseGroup { PROJECT_ADMINISTRATION("Project administration", "Usecases for project administration"), - USER_PROFILE("User profile", "User actions belonging to their profiles"), + USER_SELF_SERVICE("User self service", "User actions belonging to their user identity"), SECHUB_EXECUTION("Sechub execution", "Execution of SecHub -either by CLI or direct with REST api call"), diff --git a/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/UseCaseIdentifier.java b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/UseCaseIdentifier.java index de79c6097d..ef5391c2fc 100644 --- a/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/UseCaseIdentifier.java +++ b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/UseCaseIdentifier.java @@ -211,6 +211,8 @@ public enum UseCaseIdentifier { UC_USER_CANCELS_JOB(94), + UC_USER_FETCHES_USER_DETAIL_INFORMATION(95) + ; /* +-----------------------------------------------------------------------+ */ /* +............................ Helpers ................................+ */ diff --git a/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/admin/user/UseCaseUserFetchesUserDetailInformation.java b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/admin/user/UseCaseUserFetchesUserDetailInformation.java new file mode 100644 index 0000000000..043fc41466 --- /dev/null +++ b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/admin/user/UseCaseUserFetchesUserDetailInformation.java @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.sharedkernel.usecases.admin.user; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.mercedesbenz.sechub.sharedkernel.Step; +import com.mercedesbenz.sechub.sharedkernel.usecases.UseCaseDefinition; +import com.mercedesbenz.sechub.sharedkernel.usecases.UseCaseGroup; +import com.mercedesbenz.sechub.sharedkernel.usecases.UseCaseIdentifier; + +/* @formatter:off */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@UseCaseDefinition( + id=UseCaseIdentifier.UC_USER_FETCHES_USER_DETAIL_INFORMATION, + group=UseCaseGroup.USER_SELF_SERVICE, + apiName="userFetchUserDetailInformation", + title="User fetches his user details", + description="The authenticated user fetches his user details") +public @interface UseCaseUserFetchesUserDetailInformation { + + Step value(); +} +/* @formatter:on */ diff --git a/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/user/UseCaseUserClicksLinkToGetNewAPIToken.java b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/user/UseCaseUserClicksLinkToGetNewAPIToken.java index fc85b90f4a..4c6c6c00cb 100644 --- a/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/user/UseCaseUserClicksLinkToGetNewAPIToken.java +++ b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/user/UseCaseUserClicksLinkToGetNewAPIToken.java @@ -17,7 +17,7 @@ @Retention(RetentionPolicy.RUNTIME) @UseCaseDefinition( id=UC_USER_CLICKS_LINK_TO_GET_NEW_API_TOKEN, - group=UseCaseGroup.USER_PROFILE, + group=UseCaseGroup.USER_SELF_SERVICE, apiName="userClicksLinkToGetNewAPIToken", title="User clicks link to get new api token", description="user/clicks_link_to_get_new_api_token.adoc") diff --git a/sechub-testframework/src/main/java/com/mercedesbenz/sechub/test/SecHubTestURLBuilder.java b/sechub-testframework/src/main/java/com/mercedesbenz/sechub/test/SecHubTestURLBuilder.java index 3af5f15500..0ea5e46913 100644 --- a/sechub-testframework/src/main/java/com/mercedesbenz/sechub/test/SecHubTestURLBuilder.java +++ b/sechub-testframework/src/main/java/com/mercedesbenz/sechub/test/SecHubTestURLBuilder.java @@ -520,8 +520,13 @@ public String buildAdminFetchesEncryptionStatus() { } /* +-----------------------------------------------------------------------+ */ - /* +............................ user self service .....+ */ + /* +............................ user self service ........................+ */ /* +-----------------------------------------------------------------------+ */ + + public String buildFetchUserDetailInformationUrl() { + return buildUrl(API_MANAGEMENT + "/user"); + } + public String buildGetProjects() { return buildUrl(API_PROJECTS); } diff --git a/sechub-web-server-solution/01-start-single-docker-compose.sh b/sechub-web-server-solution/01-start-single-docker-compose.sh deleted file mode 100755 index bbd2fdcbef..0000000000 --- a/sechub-web-server-solution/01-start-single-docker-compose.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: MIT - -cd $(dirname "$0") -source "../sechub-solutions-shared/scripts/9999-env-file-helper.sh" - -# Only variables from .env can be used in the Docker-Compose file -# all other variables are only available in the container -setup_environment_file ".env" "env" -setup_environment_file ".env-web-server" "env-web-server" - -# Use Docker BuildKit -# nesessary for switching between build stages -export BUILDKIT_PROGRESS=plain -export DOCKER_BUILDKIT=1 - -echo "Copying install-java scripts into the docker directory" -cp --recursive --force ../sechub-solutions-shared/install-java/ docker/ - -echo "Starting single container." -docker compose --file docker-compose_web_server.yaml up --build --remove-orphans diff --git a/sechub-web-server-solution/05-start-single-sechub-network-docker-compose.sh b/sechub-web-server-solution/05-start-single-sechub-network-docker-compose.sh deleted file mode 100755 index bf2e6986bd..0000000000 --- a/sechub-web-server-solution/05-start-single-sechub-network-docker-compose.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: MIT - -cd $(dirname "$0") -source "../sechub-solutions-shared/scripts/9999-env-file-helper.sh" - -# Only variables from .env can be used in the Docker-Compose file -# all other variables are only available in the container -setup_environment_file ".env" "env" -setup_environment_file ".env-web-server" "env-web-server" - -# Use Docker BuildKit -export BUILDKIT_PROGRESS=plain -export DOCKER_BUILDKIT=1 - -echo "Starting single container." -docker compose --file docker-compose_web_server_external-network.yaml up --build --remove-orphans diff --git a/sechub-web-server-solution/10-create-image.sh b/sechub-web-server-solution/10-create-image.sh deleted file mode 100755 index c5b84dd612..0000000000 --- a/sechub-web-server-solution/10-create-image.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: MIT - -REGISTRY="$1" -VERSION="$2" -WEB_SERVER_VERSION="$3" -DEFAULT_BASE_IMAGE="debian:12-slim" -DEFAULT_BUILD_TYPE="download" - -cd `dirname $0` - -usage() { - cat - < - -Builds a docker image of SecHub Web Server for -with tag . - -Optional environment variables or options: -BASE_IMAGE - to build from ; defaults to $DEFAULT_BASE_IMAGE -BUILD_TYPE - (one of: build copy download) ; defaults to $DEFAULT_BUILD_TYPE -EOF -} - -FAILED=false -if [[ -z "$REGISTRY" ]] ; then - echo "Please provide a docker registry server as 1st parameter." - FAILED=true -fi - -if [[ -z "$VERSION" ]] ; then - echo "Please provide a version for the container as 2nd parameter." - FAILED=true -fi - -if [[ -z "$WEB_SERVER_VERSION" ]] ; then - echo "Please provide a SecHub Web Server release version as 3rd parameter." - FAILED=true -fi - -if $FAILED ; then - usage - exit 1 -fi - -if [[ -z "$BASE_IMAGE" ]]; then - BASE_IMAGE="$DEFAULT_BASE_IMAGE" -fi - -if [[ -z "$BUILD_TYPE" ]]; then - BUILD_TYPE="$DEFAULT_BUILD_TYPE" -fi - -BUILD_ARGS="--build-arg BASE_IMAGE=$BASE_IMAGE" -echo ">> Base image: $BASE_IMAGE" - -BUILD_ARGS+=" --build-arg BUILD_TYPE=$BUILD_TYPE" -echo ">> Build type: $BUILD_TYPE" - -BUILD_ARGS+=" --build-arg WEB_SERVER_VERSION=$WEB_SERVER_VERSION" -echo ">> SecHub Web Server release version: $WEB_SERVER_VERSION" - -echo "Copying install-java scripts into the docker directory" -cp --recursive --force ../sechub-solutions-shared/install-java/ docker/ - -# Use Docker BuildKit -# nesessary for switching between build stages -export BUILDKIT_PROGRESS=plain -export DOCKER_BUILDKIT=1 - -docker build --pull --no-cache $BUILD_ARGS \ - --tag "$REGISTRY:$VERSION" \ - --file docker/Web-Server-Debian.dockerfile docker/ -docker tag "$REGISTRY:$VERSION" "$REGISTRY:latest" diff --git a/sechub-web-server-solution/20-push-image.sh b/sechub-web-server-solution/20-push-image.sh deleted file mode 100755 index 76f6ba2f19..0000000000 --- a/sechub-web-server-solution/20-push-image.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: MIT - -cd `dirname $0` -../sechub-solutions-shared/scripts/20-push-image.sh "$1" "$2" "$3" diff --git a/sechub-web-server-solution/README.adoc b/sechub-web-server-solution/README.adoc deleted file mode 100644 index 1a5ee5bd29..0000000000 --- a/sechub-web-server-solution/README.adoc +++ /dev/null @@ -1,5 +0,0 @@ -// SPDX-License-Identifier: MIT - -== Web Server Image - -The files to create the Web Server container image. diff --git a/sechub-web-server-solution/docker-compose_web_server.yaml b/sechub-web-server-solution/docker-compose_web_server.yaml deleted file mode 100644 index 5c656505f3..0000000000 --- a/sechub-web-server-solution/docker-compose_web_server.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# SPDX-License-Identifier: MIT - -version: "3" -services: - web-server: - build: - args: - - BASE_IMAGE=${BASE_IMAGE} - - BUILD_TYPE=${BUILD_TYPE} - - WEB_SERVER_VERSION=${WEB_SERVER_VERSION} - - JAVA_VERSION=${JAVA_VERSION} - - TAG=${TAG} - - BRANCH=${BRANCH} - context: docker/ - dockerfile: Web-Server-Debian.dockerfile - container_name: web-server - env_file: - - .env - - .env-web-server - ports: - - "${HOST_NAME}:${WEB_SERVER_PORT}:4443" - - "${HOST_NAME}:${JAVA_DEBUG_PORT}:15025" - networks: - - "internal" - -networks: - internal: diff --git a/sechub-web-server-solution/docker-compose_web_server_external-network.yaml b/sechub-web-server-solution/docker-compose_web_server_external-network.yaml deleted file mode 100644 index 5ff79ebf02..0000000000 --- a/sechub-web-server-solution/docker-compose_web_server_external-network.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# SPDX-License-Identifier: MIT - -version: "3" -services: - web-server: - build: - args: - - BASE_IMAGE=${BASE_IMAGE} - - BUILD_TYPE=${BUILD_TYPE} - - WEB_SERVER_VERSION=${WEB_SERVER_VERSION} - - JAVA_VERSION=${JAVA_VERSION} - - TAG=${TAG} - - BRANCH=${BRANCH} - context: docker/ - dockerfile: Web-Server-Debian.dockerfile - container_name: web-server - env_file: - - .env - - .env-web-server - ports: - - "${HOST_NAME}:${WEB_SERVER_PORT}:4443" - - "${HOST_NAME}:${JAVA_DEBUG_PORT}:15025" - networks: - - "sechub" - -networks: - sechub: - external: true - name: "sechub" diff --git a/sechub-web-server-solution/docker/.gitignore b/sechub-web-server-solution/docker/.gitignore deleted file mode 100644 index 42044c3ae5..0000000000 --- a/sechub-web-server-solution/docker/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# install-java/ is copied by the build scripts from ../../sechub-solutions-shared/ -# so we exclude it here from git -install-java/ diff --git a/sechub-web-server-solution/docker/Web-Server-Debian.dockerfile b/sechub-web-server-solution/docker/Web-Server-Debian.dockerfile deleted file mode 100644 index 388fffdc97..0000000000 --- a/sechub-web-server-solution/docker/Web-Server-Debian.dockerfile +++ /dev/null @@ -1,166 +0,0 @@ -# SPDX-License-Identifier: MIT - -# The image argument needs to be placed on top -ARG BASE_IMAGE - -# Build args -ARG WEB_SERVER_VERSION -ARG BUILD_TYPE - -# possible values: temurin, openj9, openjdk -ARG JAVA_DISTRIBUTION="temurin" -# possible values: 17 -ARG JAVA_VERSION="17" - -# Artifact folder -ARG WEB_SERVER_ARTIFACT_FOLDER="/artifacts" - -#------------------- -# Builder Build -#------------------- - -FROM ${BASE_IMAGE} AS builder-build - -# Build args -ARG JAVA_DISTRIBUTION -ARG JAVA_VERSION -ARG TAG -ARG BRANCH -ARG WEB_SERVER_ARTIFACT_FOLDER - -ARG BUILD_FOLDER="/build" -ARG GIT_URL="https://github.com/mercedes-benz/sechub.git" - -ENV DOWNLOAD_FOLDER="/downloads" - -RUN mkdir --parent "$WEB_SERVER_ARTIFACT_FOLDER" "$DOWNLOAD_FOLDER" - -RUN export DEBIAN_FRONTEND=noninteractive && \ - apt-get update && \ - apt-get install --assume-yes --quiet git wget && \ - apt-get clean - -COPY --chmod=755 install-java/debian "$DOWNLOAD_FOLDER/install-java/" - -# Install Java -RUN cd "$DOWNLOAD_FOLDER/install-java/" && \ - ./install-java.sh "$JAVA_DISTRIBUTION" "$JAVA_VERSION" jdk - -# Copy clone script -COPY --chmod=755 clone.sh "$BUILD_FOLDER/clone.sh" - -# Clone SecHub repo and build sechub-web-server jar file -RUN mkdir --parent "$BUILD_FOLDER" && \ - cd "$BUILD_FOLDER" && \ - ./clone.sh "$GIT_URL" "$BRANCH" "$TAG" && \ - cd "sechub" && \ - ./gradlew ensureLocalhostCertificate :sechub-api-java:build :sechub-web-server:build -Dsechub.build.stage=api-necessary --console=plain && \ - cd sechub-web-server/build/libs/ && \ - rm -f *-javadoc.jar *-plain.jar *-sources.jar && \ - cp sechub-web-server-*.jar "$WEB_SERVER_ARTIFACT_FOLDER" - -#------------------- -# Builder Download -#------------------- - -FROM ${BASE_IMAGE} AS builder-download - -ARG WEB_SERVER_ARTIFACT_FOLDER -ARG WEB_SERVER_VERSION - -RUN mkdir --parent "$WEB_SERVER_ARTIFACT_FOLDER" - -RUN export DEBIAN_FRONTEND=noninteractive && \ - apt-get update && \ - apt-get install --assume-yes wget && \ - apt-get clean - -# Download the SecHub web-server jar file -RUN cd "$WEB_SERVER_ARTIFACT_FOLDER" && \ - wget --no-verbose "https://github.com/mercedes-benz/sechub/releases/download/v$WEB_SERVER_VERSION-web-server/sechub-web-server-$WEB_SERVER_VERSION.jar.sha256sum" && \ - wget --no-verbose "https://github.com/mercedes-benz/sechub/releases/download/v$WEB_SERVER_VERSION-web-server/sechub-web-server-$WEB_SERVER_VERSION.jar" && \ - sha256sum --check "sechub-web-server-$WEB_SERVER_VERSION.jar.sha256sum" - -#------------------- -# Builder Copy Jar -#------------------- - -FROM ${BASE_IMAGE} AS builder-copy - -ARG WEB_SERVER_ARTIFACT_FOLDER -ARG WEB_SERVER_VERSION - -RUN mkdir --parent "$WEB_SERVER_ARTIFACT_FOLDER" - -COPY copy/sechub-web-server-*.jar "$WEB_SERVER_ARTIFACT_FOLDER" - -#------------------- -# Builder -#------------------- - -FROM builder-${BUILD_TYPE} AS builder -RUN echo "build stage" - -#------------------- -# Web Server Image -#------------------- - -FROM ${BASE_IMAGE} AS web-server - -# Annotations according to the Open Containers Image Spec: -# https://github.com/opencontainers/image-spec/blob/main/annotations.md - -# Required by GitHub to link repository and image -LABEL org.opencontainers.image.source="https://github.com/mercedes-benz/sechub" -LABEL org.opencontainers.image.title="SecHub Web Server Image" -LABEL org.opencontainers.image.description="The SecHub Web Server image" -LABEL maintainer="SecHub FOSS Team" - -ARG WEB_SERVER_ARTIFACT_FOLDER -ARG JAVA_DISTRIBUTION -ARG JAVA_VERSION -ARG WEB_SERVER_VERSION - -# env vars in container -ENV USER="web-server" -ENV UID="4242" -ENV GID="${UID}" -ENV WEB_SERVER_VERSION="${WEB_SERVER_VERSION}" -ENV WEB_SERVER_FOLDER="/sechub-web-server" - -# non-root user -# using fixed group and user ids -RUN groupadd --gid "$GID" "$USER" && \ - useradd --uid "$UID" --gid "$GID" --no-log-init --create-home "$USER" - -# Create folders -RUN mkdir --parents "$WEB_SERVER_FOLDER" - -# Copy run script into the container -COPY run.sh /run.sh - -RUN export DEBIAN_FRONTEND=noninteractive && \ - apt-get update && \ - apt-get upgrade --assume-yes --quiet && \ - apt-get install --assume-yes --quiet bind9-host curl netcat-openbsd tree unzip vim-tiny && \ - apt-get clean - -# Install Java -COPY --chmod=755 install-java/debian "$DOWNLOAD_FOLDER/install-java/" -RUN cd "$DOWNLOAD_FOLDER/install-java/" && \ - ./install-java.sh "$JAVA_DISTRIBUTION" "$JAVA_VERSION" jre - -# Copy application .jar into the container -COPY --from=builder "$WEB_SERVER_ARTIFACT_FOLDER" "$WEB_SERVER_FOLDER" - -# Set permissions -RUN chown --recursive "$USER:$USER" "$WEB_SERVER_FOLDER" && \ - chmod +x /run.sh - -# Set workspace -WORKDIR "$WEB_SERVER_FOLDER" - -# Switch from root to non-root user -USER "$USER" - -CMD ["/run.sh"] diff --git a/sechub-web-server-solution/docker/clone.sh b/sechub-web-server-solution/docker/clone.sh deleted file mode 100644 index cf670bd2ac..0000000000 --- a/sechub-web-server-solution/docker/clone.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env sh -# SPDX-License-Identifier: MIT - -GIT_URL="$1" -BRANCH="$2" -TAG="$3" - -if [ -z "$GIT_URL" ] -then - echo "No Git url provided" 1>&2 - exit 1 -fi - -git_args="" - -if [ ! -z "$TAG" ] -then - echo "Tag: $TAG" - git_args="--branch $TAG" -elif [ ! -z "$BRANCH" ] -then - echo "Branch: $BRANCH" - git_args="--branch $BRANCH" -else - echo "Cloning default branch" -fi - -git clone --depth 1 $git_args "$GIT_URL" diff --git a/sechub-web-server-solution/docker/copy/README.adoc b/sechub-web-server-solution/docker/copy/README.adoc deleted file mode 100644 index 4d92ae86c3..0000000000 --- a/sechub-web-server-solution/docker/copy/README.adoc +++ /dev/null @@ -1,4 +0,0 @@ -// SPDX-License-Identifier: MIT -. Place a single WEB SERVER Jar into this folder. -. Name it `sechub-web-server-0.0.0.jar` -. Run `10-create-image.sh` to build the image diff --git a/sechub-web-server-solution/docker/run.sh b/sechub-web-server-solution/docker/run.sh deleted file mode 100755 index 8af696b9de..0000000000 --- a/sechub-web-server-solution/docker/run.sh +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/env sh -# SPDX-License-Identifier: MIT - -SLEEP_TIME_IN_WAIT_LOOP="2h" - -JAVA_DEBUG_OPTIONS="" -PID_JAVA_SERVER="" - -########################### -# Trap and process signals -trap trigger_shutdown INT QUIT TERM - -trigger_shutdown() -{ - if [ -n "$PID_JAVA_SERVER" ] ; then - echo "`basename $0`: Caught shutdown signal! Sending SIGTERM to Java server process $PID_JAVA_SERVER" - kill -TERM "$PID_JAVA_SERVER" - # Wait until Java server process has ended - wait "$PID_JAVA_SERVER" - fi - exit -} -########################### - -wait_loop() { - while true ; do - echo "wait_loop(): Sleeping for $SLEEP_TIME_IN_WAIT_LOOP." - sleep $SLEEP_TIME_IN_WAIT_LOOP - done -} - -setup_ssl() { - if [ -n "${SECHUB_WEB_SERVER_SSL_KEYSTORE_ALIAS}" -a "${SECHUB_WEB_SERVER_SSL_KEYSTORE_ALIAS}" != "undefined" ] ; then - # Create symlink to .p12 keystore file - ln -s "$WEB_SERVER_FOLDER/secrets/secret-ssl/keystore_file" ${SECHUB_WEB_SERVER_SSL_KEYSTORE_LOCATION} - cat - < -# SecHub Web Server - -This Helm chart enables one to deploy the [SecHub](https://github.com/mercedes-benz/sechub) Web Server Spring application into a Kubernetes environment. diff --git a/sechub-web-server-solution/helm/web-server/templates/deployment.yaml b/sechub-web-server-solution/helm/web-server/templates/deployment.yaml deleted file mode 100644 index 85e8822f2f..0000000000 --- a/sechub-web-server-solution/helm/web-server/templates/deployment.yaml +++ /dev/null @@ -1,159 +0,0 @@ -# SPDX-License-Identifier: MIT - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: web-server -spec: - replicas: {{ .Values.replicaCount }} - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 49% - selector: - matchLabels: - name: web-server - template: - metadata: - labels: - name: web-server -{{- if .Values.templateMetadataAnnotations }} - annotations: - {{ .Values.templateMetadataAnnotations | indent 8 | trim }} -{{- end }} - spec: - securityContext: - runAsUser: 4242 # uid of the application user. (should be same as in the Dockerfile) - runAsGroup: 4242 # gid of the application group. (should be same as in the Dockerfile) - fsGroup: 4242 # This gid has write access to the mounted volumes. - volumes: -{{- if ne .Values.web_server.ssl.keystoreAlias "undefined" }} - - name: secret-web-ui-ssl-volume - secret: - secretName: secret-web-ui-ssl -{{- end }} - containers: - # SecHub web-server container - - name: web-server - image: {{ .Values.image }} - imagePullPolicy: {{ .Values.imagePullPolicy }} - resources: - # min container memory - requests: - memory: "{{ .Values.resources.requests.memory }}" - # max container memory - limits: - memory: "{{ .Values.resources.limits.memory }}" - ports: - - name: web-server - containerPort: 4443 - # startupProbe: - # httpGet: - # scheme: HTTPS - # path: /api/anonymous/check/alive - # port: web-server - # failureThreshold: 24 - # periodSeconds: 5 - # successThreshold: 1 - # timeoutSeconds: 1 - # initialDelaySeconds: 5 - # livenessProbe: - # httpGet: - # scheme: HTTPS - # path: /api/anonymous/check/alive - # port: web-server - # failureThreshold: 3 - # periodSeconds: 10 - # successThreshold: 1 - # timeoutSeconds: 3 - volumeMounts: -{{- if ne .Values.web_server.ssl.keystoreAlias "undefined" }} - - mountPath: /sechub-web-server/secrets/secret-ssl - name: secret-web-ui-ssl-volume -{{- end }} - env: - # Server start mode - - name: WEB_SERVER_START_MODE - value: "{{ .Values.web_server.startMode }}" - # Spring profiles definition - - name: SPRING_PROFILES_ACTIVE - value: "{{ .Values.web_server.spring.profiles }}" - # Encryption key for access token - a string of 32 characters - - name: SECHUB_SECURITY_ENCRYPTION_SECRET_KEY - value: "{{ .Values.web_server.security.encryptionKey }}" -{{- if .Values.env }} - # ------------------------------------------------------------------------# - # Scope: Additional environment variables for the SecHub web-server container - # ----------------------------------------------------------------------- # - {{ .Values.env | indent 8 | trim }} -{{- end }} -{{- if .Values.deploymentComment }} - # Setting DEPLOYMENT_COMMENT to a different value every time forces k8s to spin up a new container. - # This way, you can force deployments e.g. when secrets have changed. - - name: DEPLOYMENT_COMMENT - value: "{{ .Values.deploymentComment }}" -{{- end }} -{{- if .Values.web_server.logging.type.enabled }} - - name: LOGGING_TYPE - value: "{{ .Values.web_server.logging.type.appenderName }}" -{{- end }} -# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -# + Connection to SecHub server -# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - name: SECHUB_SERVER_URL - value: "{{ .Values.web_server.sechubConnection.url }}" - - name: WEB_SERVER_SECHUB_TRUST_ALL_CERTIFICATES -{{- if .Values.web_server.sechubConnection.trustAllCertificates }} - value: "true" -{{- else }} - value: "false" -{{- end }} -# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -# + SSL certificate -# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - name: SECHUB_WEB_SERVER_SSL_KEYSTORE_TYPE - value: "PKCS12" - - name: SECHUB_WEB_SERVER_SSL_KEYSTORE_LOCATION - value: "/sechub-web-server/{{ .Values.web_server.ssl.keystoreAlias }}.p12" - - name: SECHUB_WEB_SERVER_SSL_KEYSTORE_ALIAS - value: "{{ .Values.web_server.ssl.keystoreAlias }}" - - name: SECHUB_WEB_SERVER_SSL_KEYSTORE_PASSWORD - valueFrom: - secretKeyRef: - name: secret-web-ui-ssl - key: keystore_password -{{- if .Values.web_server.spring.embeddedTomcat.logging.enabled }} -# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -# + Scope: embedded Tomcat -# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - # Logging to stdout: - - name: SERVER_TOMCAT_ACCESSLOG_ENABLED - value: "{{ .Values.web_server.spring.embeddedTomcat.logging.enabled }}" - - name: SERVER_TOMCAT_ACCESSLOG_DIRECTORY - value: "/dev" - - name: SERVER_TOMCAT_ACCESSLOG_PREFIX - value: "stdout" - - name: SERVER_TOMCAT_ACCESSLOG_BUFFERED - value: "false" - - name: SERVER_TOMCAT_ACCESSLOG_SUFFIX - value: "" - - name: SERVER_TOMCAT_ACCESSLOG_FILE_DATE_FORMAT - value: "" - - name: SERVER_TOMCAT_ACCESSLOG_PATTERN - value: "{{ .Values.web_server.spring.embeddedTomcat.logging.accessLogFormat }}" -{{- end }} -# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -# + Scope: development -# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - name: JAVA_ENABLE_DEBUG - value: "{{ .Values.web_server.development.javaDebug | toString }}" - - name: KEEP_CONTAINER_ALIVE_AFTER_CRASH - value: "{{ .Values.web_server.development.keepContainerAliveAfterApplicationCrash | toString }}" -# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -# + end of environment variables section -# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -{{- if .Values.imagePullSecrets }} - imagePullSecrets: - {{ .Values.imagePullSecrets | indent 8 | trim }} -{{- end }} diff --git a/sechub-web-server-solution/helm/web-server/templates/networkpolicy.yaml b/sechub-web-server-solution/helm/web-server/templates/networkpolicy.yaml deleted file mode 100644 index 61e2edfaa2..0000000000 --- a/sechub-web-server-solution/helm/web-server/templates/networkpolicy.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# SPDX-License-Identifier: MIT - -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: web-server-policy -spec: - podSelector: - matchLabels: - name: web-server - ingress: - - from: - - podSelector: - matchLabels: - name: web-ui # Allow SecHub Web-UI access - ports: - - protocol: TCP - port: 4443 diff --git a/sechub-web-server-solution/helm/web-server/templates/service.yaml b/sechub-web-server-solution/helm/web-server/templates/service.yaml deleted file mode 100644 index 80b66aaadd..0000000000 --- a/sechub-web-server-solution/helm/web-server/templates/service.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: MIT - -# Internal access via cluster IP (maybe obsolete when an api-gateway is in place) -apiVersion: v1 -kind: Service -metadata: - name: web-server -spec: - selector: - name: web-server - ports: - - protocol: TCP - port: 4443 - targetPort: 4443 - type: ClusterIP diff --git a/sechub-web-server-solution/helm/web-server/values.yaml b/sechub-web-server-solution/helm/web-server/values.yaml deleted file mode 100644 index 53d3e28886..0000000000 --- a/sechub-web-server-solution/helm/web-server/values.yaml +++ /dev/null @@ -1,91 +0,0 @@ -# SPDX-License-Identifier: MIT - -# This is a sample values file containing the defaults. - -image: "ghcr.io/mercedes-benz/sechub/web-server:latest" -# See https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy -imagePullPolicy: "IfNotPresent" -# Optional: If your image is in a private registry, you can specify pull secrets defined in k8s -# Docs: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ -# Example: -# imagePullSecrets: |- -# - name: sechub-pull-secret -# - name: sps2 - -# Number of instances to spin up -replicaCount: 1 - -resources: - requests: - # Initial container memory size - memory: 256Mi - limits: - # Maximum container memory size - memory: 1Gi - -web_server: - security: - # Encryption key for access token - a string of 32 characters - encryptionKey: "Change me. Change me. Change me." - sechubConnection: - # Connection url to SecHub server - url: "https://sechub-server-internal:8443" - # trustAllCertificates - 'true' if server uses a self-signed SSL certificate - trustAllCertificates: false - # Possible values: server, development - startMode: server - logging: - type: - enabled: false - appenderName: "LOGSTASH_JSON" - spring: - # Spring profiles (comma-separated list): - # - Server mode: - # - 'ssl-cert-provided' (use included self-signed SSL cert) or - # - 'ssl-cert-required' (use external SSL certificate; see keystoreAlias below) - # - SecHub connection: 'classic-auth-enabled' or leave empty for connect to configured SecHub server - profiles: "ssl-cert-provided" - # Configure Spring Boot's embedded Tomcat - embeddedTomcat: - logging: - enabled: false - accessLogFormat: "[ACCESS] %a %{org.apache.catalina.AccessLog.RemoteAddr}r %{X-Forwarded-For}i %{X-Forwarded-Host}i %l %t %D %F %B %S %u %r %s %b %{User-Agent}i" - ssl: - keystoreAlias: "undefined" - # Alias in .p12 keystore. - # - On `undefined`, a self-signed certificate will be used. - # - otherwise, k8s secret `secret-web-ui-ssl` must be defined containing - # - `keystore_file` (containing the ssl certificate chain) - # Inside the .p12 keystore, an alias with this name is expected - # pointing to the ssl certificate to use - # - `keystore_password` - # Development-only parameters: - development: - javaDebug: false - # Enables analysis after application exit - keepContainerAliveAfterApplicationCrash: false - -# deploymentComment (optional): -# When setting to a different value than before, it forces k8s to spin up a new container. -# This way, you can force deployments e.g. when only secrets have changed. -deploymentComment: "my deployment comment" - -# optional: Add annotations to template.metadata.annotations -# Can contain multiple lines. Example for Prometheus actuator: -# templateMetadataAnnotations: |- -# prometheus.io/scrape: "true" -# prometheus.io/probe: "true" -# prometheus.io/port: "10250" -# prometheus.io/path: "/actuator/prometheus" - -# ----------------------------------------------------------------------------------------------# -# Optional: Additional environment variables for the SecHub web-server container -# --------------------------------------------------------------------------------------------- # -# env: |- -# - name: SECHUB_EXAMPLE_VAR1 -# value: "value1" -# - name: SECHUB_EXAMPLE_VAR2 -# valueFrom: -# secretKeyRef: -# name: secret-web-server-example -# key: password diff --git a/sechub-web-server/.gitignore b/sechub-web-server/.gitignore deleted file mode 100644 index 0fc15402e5..0000000000 --- a/sechub-web-server/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -application-local.*.yaml -application-local.*.yml \ No newline at end of file diff --git a/sechub-web-server/README.adoc b/sechub-web-server/README.adoc deleted file mode 100644 index d5b9abe2df..0000000000 --- a/sechub-web-server/README.adoc +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT -= Web Server - -WARNING: Don't use this early Web Server in production. - -== Development - -=== Standalone with mocked SecHub server access -Activate the Spring Boot Dev Profile by -starting the application using the JVM argument: - ----- --Dspring.profiles.active=web-server_dev ----- - -The started application will - -- used mocked sechub access (with mocked data) -- start with self signed certificate -- Login credentials - - User: user - - Password: password -- Class auto reloading is activated - -==== Integration test with running SecHub server ----- --Dspring.profiles.active=web-server_integrationtest ----- - -The started application will - -- use running SecHub integration test server (port 8443) -- use predefined integrationtest sechub admin credentials -- trust generated inerationtest self signed certificate -- start with self signed certificate -- Login credentials - - User: user - - Password: password - -=== Access -The Web Server is accessible at: https://localhost:4443/ diff --git a/sechub-web-server/README.md b/sechub-web-server/README.md deleted file mode 100644 index 7efad5bcf3..0000000000 --- a/sechub-web-server/README.md +++ /dev/null @@ -1,61 +0,0 @@ - - -# SecHub Web Server - -## Overview - -SecHub Web Server is a web-based user interface for managing and interacting with the SecHub application. - -## Profiles - -To start the application locally use the `web-server_local` profile. - -This will include the following profiles: - -- `ssl-cert-provided`: a default ssl certificate will be used by the Web Server server -- `classic-auth-enabled`: enable classic login (for now with preconfigured credentials) at `/login/classic`) -- `local`: includes any local configurations matching `application-local.${USER}.yml` - -If you want to provide local configurations, create a file named `application-local.${USER}.yml` in the `src/main/resources` directory. -Make sure that the ${USER} part matches your system username. - -This will enable configurations suitable for local development and testing. - -## Running the application in OAuth2 Mode - -To run the application in OAuth2 mode, include the `oauth2-enabled` profile. - -Note: The `web-server_prod` profile includes the `oauth2-enabled` profile. - -Make sure that you either provide a valid `application-oauth2-enabled.yml` file in the `src/main/resources` directory or set the required environment variables. - -Example `application-oauth2-enabled.yml`: - -```yaml -sechub: - security: - oauth2: - client-id: example-client-id - client-secret: example-client-secret - provider: example-provider - redirect-uri: {baseUrl}/login/oauth2/code/{provider} - issuer-uri: https://sso.provider.example.org - authorization-uri: https://sso.provider.example.org/as/authorization.oauth2 - token-uri: https://sso.provider.example.org/as/token.oauth2 - user-info-uri: https://sso.provider.example.org/idp/userinfo.openid - jwk-set-uri: https://sso.provider.example.org/pf/JWKS -``` - -Alternatively, you can provide the following environment variables: - -```bash -SECHUB_SECURITY_OAUTH2_CLIENT_ID=example-client-id -SECHUB_SECURITY_OAUTH2_CLIENT_SECRET=example-client-secret -SECHUB_SECURITY_OAUTH2_PROVIDER=example-provider -SECHUB_SECURITY_OAUTH2_REDIRECT_URI={baseUrl}/login/oauth2/code/{provider} -SECHUB_SECURITY_OAUTH2_ISSUER_URI=https://sso.provider.example.org -SECHUB_SECURITY_OAUTH2_AUTHORIZATION_URI=https://sso.provider.example.org/as/authorization.oauth2 -SECHUB_SECURITY_OAUTH2_TOKEN_URI=https://sso.provider.example.org/as/token.oauth2 -SECHUB_SECURITY_OAUTH2_USER_INFO_URI=https://sso.provider.example.org/idp/userinfo.openid -SECHUB_SECURITY_OAUTH2_JWK_SET_URI=https://sso.provider.example.org/pf/JWKS -``` diff --git a/sechub-web-server/build.gradle b/sechub-web-server/build.gradle deleted file mode 100644 index 38c34fc1eb..0000000000 --- a/sechub-web-server/build.gradle +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: MIT - /*============================================================================ - * Build file for subproject - * - * Root build file: "${rootProject.projectDir}/build.gradle" - * ============================================================================ - */ - -plugins { - id 'org.springframework.boot' apply true -} - -dependencies { - implementation project(':sechub-commons-core') - implementation project(':sechub-api-java') - implementation library.springboot_starter_web - implementation library.springboot_starter_security - implementation library.springboot_starter_thymeleaf - implementation library.logstashLogbackEncoder - implementation library.thymeleaf_extras_springsecurity5 - implementation library.springboot_starter_oauth2_client - implementation library.springboot_starter_oauth2_resource_server - implementation library.springboot_starter_actuator - - testImplementation project(':sechub-testframework-spring') - testImplementation library.springboot_starter_test - testImplementation library.springframework_security_test - - developmentOnly library.springboot_devtoolssf -} - -/* make eclipse task depend on ensured local certificate*/ -tasks.eclipse.dependsOn 'ensureLocalhostCertificate' - -/** - * For integration tests, local develoment etc. we need a generated, private key - * which is different for each developer, not accidently committed to git, also - * valid on builds etc. - * - * This is done by dev-ensure_localhost_certificate.sh - for details refer to bash script - */ -task ensureLocalhostCertificate(type: Exec) { - group 'sechub' - description 'Calling this task, will ensure a localhost certificate exists. This is necessary for development and integration tests' - - workingDir "${projectDir}" - - if (OSUtil.isWindows()){ - commandLine 'cmd', '/c', 'bash', "${projectDir}/dev-ensure_localhost_certificate.sh" - }else{ - commandLine "${projectDir}/dev-ensure_localhost_certificate.sh" - } -} - -apply plugin: 'maven-publish' - -version = versionData.getWebServerVersion() - -publishing { - publications { - mavenJava(MavenPublication) { - - from components.java - - pom { - name = 'SecHub Web Server' - description = 'SecHub Web Server as a Spring Boot Jar. Ready to use.' - - scm { - url = 'https://github.com/mercedes-benz/sechub' - } - - licenses { - license { - name = 'MIT License' - url = 'https://github.com/mercedes-benz/sechub/blob/master/LICENSE' - } - } - } - } - } - - repositories { - maven { - url = project.hasProperty("mavenTargetRepoUrl") ? project.properties['mavenTargetRepoUrl'] : System.getProperty("user.home")+"/.m2/repository" - - if (project.hasProperty("mavenRepoUserName") && project.hasProperty("mavenRepoPassword")) { - credentials(PasswordCredentials) { - username project.properties['mavenRepoUserName'] - password project.properties['mavenRepoPassword'] - } - } - } - } -} \ No newline at end of file diff --git a/sechub-web-server/dev-base.sh b/sechub-web-server/dev-base.sh deleted file mode 100644 index 4f7ccb3026..0000000000 --- a/sechub-web-server/dev-base.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: MIT - -# For integration tests, local develoment etc. we need a generated, private key -# which is different for each developer, not accidently committed to git, also -# valid on builds etc. -# -# We support this by having a fixed target file path to a folder which is not tracked -# by git (except the README.md there). So even generated private keys are not accidently added -# to git... - -DEV_CERT_PATH="$(pwd)/src/main/resources/certificates-untracked" -DEV_CERT_FILE="$DEV_CERT_PATH/generated-dev-localhost-keystore.p12" - -PSEUDO_PWD="123456" - -function createLocalhostCertifcate(){ - - # - # PRECONDITION: We assume a JDK is installed and so keytool is accessible! - # - # see https://stackoverflow.com/questions/13578134/how-to-automate-keystore-generation-using-the-java-keystore-tool-w-o-user-inter - echo "Start creating localhost certificate" - keytool -genkey -alias tomcat -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore "$DEV_CERT_FILE" -validity 3650 -storepass $PSEUDO_PWD --dname "CN=localhost, OU=ID" - echo "Created file $DEV_CERT_FILE" - -} - diff --git a/sechub-web-server/dev-create_localhost_certificate.sh b/sechub-web-server/dev-create_localhost_certificate.sh deleted file mode 100755 index e8c0c2439b..0000000000 --- a/sechub-web-server/dev-create_localhost_certificate.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: MIT - -source dev-base.sh - -if [ -f "$DEV_CERT_FILE" ]; then - echo "Remove old localhost certificate" - rm "$DEV_CERT_FILE" -fi -createLocalhostCertifcate \ No newline at end of file diff --git a/sechub-web-server/dev-ensure_localhost_certificate.sh b/sechub-web-server/dev-ensure_localhost_certificate.sh deleted file mode 100755 index 60c650b531..0000000000 --- a/sechub-web-server/dev-ensure_localhost_certificate.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: MIT - -source dev-base.sh - -if [ -f "$DEV_CERT_FILE" ]; then - exit 0 -fi -createLocalhostCertifcate \ No newline at end of file diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/ApplicationProfiles.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/ApplicationProfiles.java deleted file mode 100644 index 79926433ac..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/ApplicationProfiles.java +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver; - -public final class ApplicationProfiles { - - public static final String BASIC_AUTH_MOCKED = "classic-auth-enabled"; - public static final String INTEGRATION_TEST_DATA = "integrationtest-data"; - public static final String LOCAL = "local"; - public static final String CLASSIC_AUTH_ENABLED = "classic-auth-enabled"; - public static final String OAUTH2_ENABLED = "oauth2-enabled"; - public static final String SSL_CERT_PROVIDED = "ssl-cert-provided"; - public static final String SSL_CERT_REQUIRED = "ssl-cert-required"; - public static final String TEST = "test"; - - private ApplicationProfiles() { - /* Prevent instantiation */ - } -} \ No newline at end of file diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/RequestConstants.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/RequestConstants.java deleted file mode 100644 index ff38893482..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/RequestConstants.java +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver; - -public final class RequestConstants { - - public static final String ROOT = "/"; - - public static final String LOGIN = "/login"; - public static final String HOME = "/home"; - - public static final String REQUEST_NEW_APITOKEN = "/request-new-apitoken"; -} diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/SecHubWebServerApplication.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/SecHubWebServerApplication.java deleted file mode 100644 index dbdcc6a5bb..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/SecHubWebServerApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class SecHubWebServerApplication { - - public static void main(String[] args) { - SpringApplication.run(SecHubWebServerApplication.class, args); - } -} diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/credentials/NewApiTokenController.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/credentials/NewApiTokenController.java deleted file mode 100644 index adbfa105ea..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/credentials/NewApiTokenController.java +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.credentials; - -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; - -import com.mercedesbenz.sechub.webserver.ApplicationProfiles; -import com.mercedesbenz.sechub.webserver.RequestConstants; -import com.mercedesbenz.sechub.webserver.sechubaccess.SecHubAccessService; -import com.mercedesbenz.sechub.webserver.user.UserInfoService; - -@Controller -@Profile(ApplicationProfiles.CLASSIC_AUTH_ENABLED) -class NewApiTokenController { - - private final NewApiTokenService newApiTokenService; - private final SecHubAccessService accessService; - private final UserInfoService userInfoService; - - NewApiTokenController(NewApiTokenService newApiTokenService, SecHubAccessService accessService, UserInfoService userInfoService) { - this.newApiTokenService = newApiTokenService; - this.accessService = accessService; - this.userInfoService = userInfoService; - } - - @GetMapping(RequestConstants.REQUEST_NEW_APITOKEN) - String requestNewApiToken(Model model) { - String emailAddress = userInfoService.getEmailAddress(); - - model.addAttribute("sechubServerUrl", accessService.getSecHubServerUri()); - model.addAttribute("successfullyRequestedToken", newApiTokenService.requestNewApiToken(emailAddress)); - model.addAttribute("userEmail", emailAddress); - - return "new-apitoken"; - } -} diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/credentials/NewApiTokenService.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/credentials/NewApiTokenService.java deleted file mode 100644 index bb800943c4..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/credentials/NewApiTokenService.java +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.credentials; - -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Service; - -import com.mercedesbenz.sechub.webserver.ApplicationProfiles; -import com.mercedesbenz.sechub.webserver.sechubaccess.SecHubAccessService; - -@Service -@Profile(ApplicationProfiles.CLASSIC_AUTH_ENABLED) -class NewApiTokenService { - - private final SecHubAccessService accessService; - - NewApiTokenService(SecHubAccessService accessService) { - this.accessService = accessService; - } - - /** - * Request new API token as described in documentation - * - *
-     *  curl
-     * 'https://sechub.example.com/api/anonymous/refresh/apitoken/emailAddress@test.
-     * com' -i -X POST -H 'Content-Type: application/json;charset=UTF-8'
-     * 
- */ - boolean requestNewApiToken(String emailAddress) { - /* @formatter:off */ - - Boolean result = accessService.createExecutorForResult(Boolean.class). - whenDoing("request a new api token"). - callAndReturn(client -> { - client.requestNewApiToken(emailAddress); - return Boolean.TRUE; - }). - onErrorReturn(exception -> Boolean.FALSE). - execute(); - - return Boolean.TRUE.equals(result); - - /* @formatter:on */ - } -} diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/encryption/AES256Encryption.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/encryption/AES256Encryption.java deleted file mode 100644 index cd7a5d4a85..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/encryption/AES256Encryption.java +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.encryption; - -import java.nio.charset.StandardCharsets; -import java.security.GeneralSecurityException; -import java.security.InvalidKeyException; - -import javax.crypto.Cipher; -import javax.crypto.SealedObject; -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; - -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.stereotype.Component; - -import com.mercedesbenz.sechub.commons.core.security.CryptoAccess; - -@Component -@EnableConfigurationProperties(AES256EncryptionProperties.class) -public class AES256Encryption { - - private static final String TRANSFORMATION = "AES"; - private static final CryptoAccess secretKeyCryptoAccess = new CryptoAccess<>(); - - private final Cipher encrypt; - private final Cipher decrypt; - private final SealedObject sealedSecretKey; - - AES256Encryption(AES256EncryptionProperties properties) throws GeneralSecurityException { - SecretKey secretKey = new SecretKeySpec(properties.getSecretKeyBytes(), TRANSFORMATION); - this.sealedSecretKey = secretKeyCryptoAccess.seal(secretKey); - - this.encrypt = Cipher.getInstance(TRANSFORMATION); - try { - initEncrypt(); - } catch (Exception e) { - throw new GeneralSecurityException(e); - } - - this.decrypt = Cipher.getInstance(TRANSFORMATION); - try { - initDecrypt(); - } catch (Exception e) { - throw new GeneralSecurityException(e); - } - } - - public byte[] encrypt(String plainText) { - byte[] encryptedBytes; - - try { - encryptedBytes = encrypt.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); - } catch (Exception e) { - initEncrypt(); - throw new AES256EncryptionException("Failed to encrypt text", e); - } - - return encryptedBytes; - } - - public String decrypt(byte[] encryptedBytes) { - byte[] decryptedBytes; - - try { - decryptedBytes = decrypt.doFinal(encryptedBytes); - } catch (Exception e) { - initDecrypt(); - throw new AES256EncryptionException("Failed to decrypt text", e); - } - - return new String(decryptedBytes, StandardCharsets.UTF_8); - } - - private void initEncrypt() { - try { - this.encrypt.init(Cipher.ENCRYPT_MODE, secretKeyCryptoAccess.unseal(sealedSecretKey)); - } catch (InvalidKeyException e) { - throw new AES256EncryptionException("Failed to init encryption cipher", e); - } - } - - private void initDecrypt() { - try { - this.decrypt.init(Cipher.DECRYPT_MODE, secretKeyCryptoAccess.unseal(sealedSecretKey)); - } catch (InvalidKeyException e) { - throw new AES256EncryptionException("Failed to init decryption cipher", e); - } - } -} diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/encryption/AES256EncryptionException.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/encryption/AES256EncryptionException.java deleted file mode 100644 index 800ec36cf6..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/encryption/AES256EncryptionException.java +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.encryption; - -public class AES256EncryptionException extends RuntimeException { - - public AES256EncryptionException(String errMsg, Exception e) { - super(errMsg, e); - } -} diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/encryption/AES256EncryptionProperties.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/encryption/AES256EncryptionProperties.java deleted file mode 100644 index cd2e241017..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/encryption/AES256EncryptionProperties.java +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.encryption; - -import static java.util.Objects.requireNonNull; - -import java.nio.charset.StandardCharsets; - -import javax.crypto.SealedObject; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.bind.ConstructorBinding; - -import com.mercedesbenz.sechub.commons.core.security.CryptoAccess; - -@ConfigurationProperties(prefix = AES256EncryptionProperties.PREFIX) -class AES256EncryptionProperties { - - static final String PREFIX = "sechub.security.encryption"; - private static final String ERR_MSG_FORMAT = "The property '%s.%s' must not be null"; - private static final int AES_256_SECRET_KEY_LENGTH = 32; - - private final SealedObject secretKeySealed; - - @ConstructorBinding - AES256EncryptionProperties(String secretKey) { - try { - requireNonNull(secretKey, ERR_MSG_FORMAT.formatted(PREFIX, "secret-key")); - this.secretKeySealed = CryptoAccess.CRYPTO_STRING.seal(secretKey); - if (!is256BitString(secretKey)) { - throw new IllegalArgumentException("The property %s.%s must be a 256-bit string".formatted(PREFIX, "secret-key")); - } - } finally { - /* Ensure that the secret key is cleared */ - secretKey = null; - } - } - - byte[] getSecretKeyBytes() { - return CryptoAccess.CRYPTO_STRING.unseal(secretKeySealed).getBytes(StandardCharsets.UTF_8); - } - - /* - * Checks if the secret key length is 32 characters (32 * 8 = 256 bits) - */ - private static boolean is256BitString(String secretKey) { - return secretKey.length() == AES_256_SECRET_KEY_LENGTH; - } -} diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/i18n/RequestParamLocaleContextResolver.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/i18n/RequestParamLocaleContextResolver.java deleted file mode 100644 index 963b9abdd7..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/i18n/RequestParamLocaleContextResolver.java +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.i18n; - -import java.util.List; -import java.util.Locale; - -import org.springframework.context.i18n.LocaleContext; -import org.springframework.context.i18n.SimpleLocaleContext; -import org.springframework.stereotype.Component; -import org.springframework.web.server.ServerWebExchange; -import org.springframework.web.server.adapter.WebHttpHandlerBuilder; -import org.springframework.web.server.i18n.LocaleContextResolver; - -@Component(WebHttpHandlerBuilder.LOCALE_CONTEXT_RESOLVER_BEAN_NAME) -public class RequestParamLocaleContextResolver implements LocaleContextResolver { - public LocaleContext resolveLocaleContext(ServerWebExchange exchange) { - List lang = exchange.getRequest().getQueryParams().get("lang"); - Locale targetLocale = null; - - if (lang != null && !lang.isEmpty()) { - targetLocale = Locale.forLanguageTag(lang.get(0)); - } - if (targetLocale == null) { - targetLocale = Locale.US; - } - return new SimpleLocaleContext(targetLocale); - } - - @Override - public void setLocaleContext(ServerWebExchange exchange, LocaleContext localeContext) { - throw new UnsupportedOperationException("Cannot change lang query parameter - use a different locale context resolution strategy"); - } -} diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/page/HomeController.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/page/HomeController.java deleted file mode 100644 index 8423fed050..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/page/HomeController.java +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.page; - -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.security.oauth2.core.oidc.user.OidcUser; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; - -import com.mercedesbenz.sechub.webserver.RequestConstants; - -@Controller -class HomeController { - - @GetMapping(RequestConstants.HOME) - public String home(@AuthenticationPrincipal OidcUser principal, Model model) { - if (principal != null) { - model.addAttribute("principal", principal.getAttribute("name")); - } - return "home"; - } -} diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/page/LoginController.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/page/LoginController.java deleted file mode 100644 index 45f5628d89..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/page/LoginController.java +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.page; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.env.Environment; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; - -import com.mercedesbenz.sechub.webserver.ApplicationProfiles; -import com.mercedesbenz.sechub.webserver.RequestConstants; -import com.mercedesbenz.sechub.webserver.security.OAuth2Properties; - -@Controller -class LoginController { - - private final OAuth2Properties oAuth2Properties; - private final boolean isOAuth2Enabled; - private final boolean isClassicAuthEnabled; - - LoginController(@Autowired(required = false) OAuth2Properties oAuth2Properties, Environment environment) { - this.oAuth2Properties = oAuth2Properties; - this.isOAuth2Enabled = environment.matchesProfiles(ApplicationProfiles.OAUTH2_ENABLED); - this.isClassicAuthEnabled = environment.matchesProfiles(ApplicationProfiles.CLASSIC_AUTH_ENABLED); - } - - @GetMapping({ RequestConstants.ROOT, RequestConstants.LOGIN }) - String login(Model model) { - model.addAttribute("isOAuth2Enabled", isOAuth2Enabled); - model.addAttribute("isClassicAuthEnabled", isClassicAuthEnabled); - - if (oAuth2Properties != null) { - String registrationId = oAuth2Properties.getProvider(); - model.addAttribute("registrationId", registrationId); - } - - return "login"; - } - -} \ No newline at end of file diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/sechubaccess/ClientCaller.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/sechubaccess/ClientCaller.java deleted file mode 100644 index d6ee6757e9..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/sechubaccess/ClientCaller.java +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.sechubaccess; - -import com.mercedesbenz.sechub.api.SecHubClient; - -public interface ClientCaller { - public R callAndReturn(SecHubClient client) throws Exception; -} \ No newline at end of file diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/sechubaccess/ErrorCallback.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/sechubaccess/ErrorCallback.java deleted file mode 100644 index 325b2da327..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/sechubaccess/ErrorCallback.java +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.sechubaccess; - -public interface ErrorCallback { - T handleExceptionAndReturnFallback(Exception e); -} \ No newline at end of file diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/sechubaccess/SecHubAccessService.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/sechubaccess/SecHubAccessService.java deleted file mode 100644 index 406b539f3d..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/sechubaccess/SecHubAccessService.java +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.sechubaccess; - -import java.net.URI; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Service; - -import com.mercedesbenz.sechub.api.MockedSecHubClient; -import com.mercedesbenz.sechub.api.OldDefaultSecHubClient; -import com.mercedesbenz.sechub.api.SecHubClient; -import com.mercedesbenz.sechub.api.SecHubClientException; -import com.mercedesbenz.sechub.webserver.ApplicationProfiles; - -import jakarta.annotation.PostConstruct; - -/** - * Main class for communication with SecHub server. The {@link SecHubClient} is - * not provided directly but via {@link #createExecutorForResult(Class)} and - * {@link #createExecutorWithoutResult()} methods which provide a fluent and - * secured access. - * - * - * @author Albert Tregnaghi - * - */ -@Service -@Profile(ApplicationProfiles.CLASSIC_AUTH_ENABLED) -public class SecHubAccessService { - - static final Logger LOG = LoggerFactory.getLogger(SecHubAccessService.class); - - @Value("${web-server.sechub.server-url}") - private String secHubServerUrl; - - @Value("${web-server.sechub.trust-all-certificates:false}") - private boolean trustAllCertificates; - - @Value("${web-server.client.mocked:false}") - private boolean useMockedClient; - - @Value("${web-server.sechub.userid}") - private String userId; - - @Value("${web-server.sechub.apitoken}") - private String apiToken; - - private SecHubClient client; - - @PostConstruct - void initSecHubClient() { - URI serverUri = URI.create(secHubServerUrl); - /* - * TODO Albert Tregnaghi, 2024-02-28: currently we have ONE client - maybe this - * is okay, but when we use real user credentials/are delegate for it etc. it - * could become necessary to have different clients ?! Means this is an open - * question - */ - /* @formatter:off */ - try { - if (useMockedClient) { - this.client = MockedSecHubClient.from(serverUri, userId, apiToken, trustAllCertificates); - } else { - - this.client = OldDefaultSecHubClient.builder(). - server(serverUri). - user(userId). - apiToken(apiToken). - trustAll(trustAllCertificates). - build(); - } - }finally { - // reset sensitive data - is now stored secure in client object - userId= null; - apiToken=null; - } - /* @formatter:on */ - } - - public boolean isSecHubServerAlive() { - try { - return client.isServerAlive(); - } catch (SecHubClientException e) { - return false; - } - } - - public String getServerVersion() { - try { - return client.getServerVersion(); - } catch (SecHubClientException e) { - return "invalid"; - } - } - - public URI getSecHubServerUri() { - return client.getServerUri(); - } - - public SecHubClientExecutor createExecutorForResult(Class clazz) { - return new SecHubClientExecutor<>(client, clazz); - } - - public SecHubClientExecutor createExecutorWithoutResult() { - return new SecHubClientExecutor<>(client, Void.class); - } - -} diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/sechubaccess/SecHubClientExecutor.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/sechubaccess/SecHubClientExecutor.java deleted file mode 100644 index b9851abd78..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/sechubaccess/SecHubClientExecutor.java +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.sechubaccess; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.mercedesbenz.sechub.api.SecHubClient; - -/** - * Provides a fluent api, automated logging and error handling. Also hides - * client object and client exceptions. - * - * @author Albert Tregnaghi - * - * @param - */ -public class SecHubClientExecutor { - - private static final Logger LOG = LoggerFactory.getLogger(SecHubClientExecutor.class); - - private SecHubClient client; - protected String info; - protected ClientCaller clientCaller; - protected ErrorCallback errorCallback; - protected Class resultClazz; - - private T fallbackResult; - private boolean onErrorReturnFallback; - - SecHubClientExecutor(SecHubClient client, Class resultClazz) { - this.client = client; - this.resultClazz = resultClazz; - } - - public SecHubClientExecutor whenDoing(String info) { - this.info = info; - return this; - } - - public SecHubClientExecutor callAndReturn(ClientCaller clientCaller) { - this.clientCaller = clientCaller; - return this; - } - - /** - * Within this method we can handle errors explicit via an error callback. - * - * @param errorCallback - * @return the object to return in case of an error - */ - public SecHubClientExecutor onErrorReturn(ErrorCallback errorCallback) { - this.onErrorReturnFallback = false; - this.errorCallback = errorCallback; - return this; - } - - public SecHubClientExecutor onErrorReturnAlways(T fallbackResult) { - this.onErrorReturnFallback = true; - this.fallbackResult = fallbackResult; - return this; - } - - public T execute() { - try { - if (clientCaller == null) { - throw new IllegalArgumentException("You did not define a client caller - please use call(..) method to define one!"); - } - return clientCaller.callAndReturn(client); - } catch (Exception e) { - - LOG.error("Client call failed: {}", info, e); - - if (onErrorReturnFallback) { - return fallbackResult; - } - - if (errorCallback == null) { - if (!resultClazz.isAssignableFrom(Void.class)) { - SecHubAccessService.LOG.warn( - "Error callback not set for '{}' - will return null for expected result of '{}' result! This is a bug in usage - please use onError(..) method or call allowNullResults() to define correct error result!", - info, resultClazz); - } - return null; - } - return errorCallback.handleExceptionAndReturnFallback(e); - } - } - -} \ No newline at end of file diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/Base64EncodedClientIdAndSecretOAuth2AccessTokenClient.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/Base64EncodedClientIdAndSecretOAuth2AccessTokenClient.java deleted file mode 100644 index 792083cda8..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/Base64EncodedClientIdAndSecretOAuth2AccessTokenClient.java +++ /dev/null @@ -1,124 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import java.util.Base64; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient; -import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest; -import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.security.oauth2.core.OAuth2AccessToken; -import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; -import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange; -import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.server.ResponseStatusException; - -/** - *

- * Custom implementation of {@link OAuth2AccessTokenResponseClient} for - * retrieving a JWT token response from a configured Identity Provider (IDP) - * after a successful OAuth2 authorization code grant request. - *

- *

- * This class handles the exchange of the authorization code for an access - * token, refresh token, and ID token by making a POST request to the token - * endpoint of the IDP. The client credentials (client ID and client secret) are - * encoded in Base64 and included in the Authorization header of the request. - *

- *

- * The response from the IDP is expected to be a {@link JwtResponse}, which - * includes the access token, refresh token, ID token, and the expiration time - * of the access token. - *

- * - * @see OAuth2AccessTokenResponseClient - * @see OAuth2AuthorizationCodeGrantRequest - * @see OAuth2AccessTokenResponse - * @see WebServerSecurityConfiguration - * @see JwtResponse - * - * @author hamidonos - */ -class Base64EncodedClientIdAndSecretOAuth2AccessTokenClient implements OAuth2AccessTokenResponseClient { - - private static final Logger LOG = LoggerFactory.getLogger(Base64EncodedClientIdAndSecretOAuth2AccessTokenClient.class); - private static final String GRANT_TYPE_VALUE = "authorization_code"; - private static final String BASIC_AUTHORIZATION_HEADER_VALUE_FORMAT = "Basic %s"; - private static final String CLIENT_ID_CLIENT_SECRET_FORMAT = "%s:%s"; - private static final String ID_TOKEN = "id_token"; - - private final RestTemplate restTemplate; - - Base64EncodedClientIdAndSecretOAuth2AccessTokenClient(RestTemplate restTemplate) { - this.restTemplate = restTemplate; - } - - @Override - public OAuth2AccessTokenResponse getTokenResponse(OAuth2AuthorizationCodeGrantRequest authorizationGrantRequest) { - ClientRegistration clientRegistration = authorizationGrantRequest.getClientRegistration(); - String tokenUri = clientRegistration.getProviderDetails().getTokenUri(); - String clientId = clientRegistration.getClientId(); - String clientSecret = clientRegistration.getClientSecret(); - - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); - headers.set(HttpHeaders.AUTHORIZATION, getBasicAuthHeaderValue(clientId, clientSecret)); - - HttpEntity> entity = getMultiValueMapHttpEntity(authorizationGrantRequest, headers); - - JwtResponse jwtResponse; - try { - jwtResponse = restTemplate.postForObject(tokenUri, entity, JwtResponse.class); - - if (jwtResponse == null) { - throw new RestClientException("JWT response is null"); - } - } catch (RestClientException e) { - String errMsg = "Failed to get JWT token response"; - LOG.error(errMsg, e); - throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, errMsg, e); - } - - Map additionalParameters = Map.of(ID_TOKEN, jwtResponse.getIdToken()); - - /* @formatter:off */ - return OAuth2AccessTokenResponse - .withToken(jwtResponse.getAccessToken()) - .tokenType(OAuth2AccessToken.TokenType.BEARER) - .expiresIn(jwtResponse.getExpiresIn()) - .refreshToken(jwtResponse.getRefreshToken()) - .additionalParameters(additionalParameters) - .build(); - /* @formatter:on */ - } - - private static HttpEntity> getMultiValueMapHttpEntity(OAuth2AuthorizationCodeGrantRequest authorizationGrantRequest, - HttpHeaders headers) { - MultiValueMap formParameters = new LinkedMultiValueMap<>(); - OAuth2AuthorizationExchange authorizationExchange = authorizationGrantRequest.getAuthorizationExchange(); - String code = authorizationExchange.getAuthorizationResponse().getCode(); - String redirectUri = authorizationExchange.getAuthorizationRequest().getRedirectUri(); - - formParameters.add(OAuth2ParameterNames.GRANT_TYPE, GRANT_TYPE_VALUE); - formParameters.add(OAuth2ParameterNames.CODE, code); - formParameters.add(OAuth2ParameterNames.REDIRECT_URI, redirectUri); - - return new HttpEntity<>(formParameters, headers); - } - - private static String getBasicAuthHeaderValue(String clientId, String clientSecret) { - String clientIdClientSecret = CLIENT_ID_CLIENT_SECRET_FORMAT.formatted(clientId, clientSecret); - String clientIdClientSecretB64Encoded = Base64.getEncoder().encodeToString(clientIdClientSecret.getBytes()); - return BASIC_AUTHORIZATION_HEADER_VALUE_FORMAT.formatted(clientIdClientSecretB64Encoded); - } -} \ No newline at end of file diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/ClassicLoginSuccessHandler.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/ClassicLoginSuccessHandler.java deleted file mode 100644 index f1d35f2cdf..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/ClassicLoginSuccessHandler.java +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import java.io.IOException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.core.Authentication; -import org.springframework.security.web.authentication.AuthenticationSuccessHandler; - -import com.mercedesbenz.sechub.webserver.RequestConstants; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -/** - * {@code ClassicLoginSuccessHandler} implements - * {@link AuthenticationSuccessHandler} to provide custom behavior upon - * successful authentication. This handler redirects the user to the /home page - * specified in {@link RequestConstants}. - * - * @see WebServerSecurityConfiguration - * @see RequestConstants - * - * @author hamidonos - */ -class ClassicLoginSuccessHandler implements AuthenticationSuccessHandler { - - private static final Logger LOG = LoggerFactory.getLogger(ClassicLoginSuccessHandler.class); - - @Override - public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { - LOG.debug("Redirecting to {}", RequestConstants.HOME); - response.sendRedirect(RequestConstants.HOME); - } -} \ No newline at end of file diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/JwtCookieResolver.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/JwtCookieResolver.java deleted file mode 100644 index 0a196524c1..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/JwtCookieResolver.java +++ /dev/null @@ -1,81 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import java.util.Arrays; -import java.util.Base64; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver; - -import com.mercedesbenz.sechub.webserver.encryption.AES256Encryption; - -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; - -/** - * {@code JwtCookieResolver} implements {@link BearerTokenResolver} to provide - * custom Bearer Token resolution. The encrypted JWT is read from the cookies - * and decrypted using {@link AES256Encryption}. Note that the JWT is expected - * in {@link Base64} encoded format. - * - * @see BearerTokenResolver - * @see AES256Encryption - * - * @author hamidonos - */ -class JwtCookieResolver implements BearerTokenResolver { - - private static final Logger LOG = LoggerFactory.getLogger(JwtCookieResolver.class); - private static final String MISSING_JWT_VALUE = "missing-jwt"; - private static final Base64.Decoder DECODER = Base64.getDecoder(); - - private final AES256Encryption aes256Encryption; - - JwtCookieResolver(AES256Encryption aes256Encryption) { - this.aes256Encryption = aes256Encryption; - } - - @Override - public String resolve(HttpServletRequest request) { - Cookie[] cookies = request.getCookies(); - - if (cookies == null) { - LOG.debug("No cookies found in the request"); - - /* - * If the JWT cookie is not found, we return a constant string to indicate that - * the JWT is missing. We do this because we want to pass exception handling - * further down the chain. Spring does not provide a way to wrap exceptions - * around custom BearerTokenResolver classes effectively. This is a good - * practice because it allows us to handle the missing JWT in a more controlled - * manner. - */ - return MISSING_JWT_VALUE; - } - - /* @formatter:off */ - String jwt = Arrays - .stream(cookies) - .filter(cookie -> WebServerSecurityConfiguration.ACCESS_TOKEN.equals(cookie.getName())) - .map(Cookie::getValue) - .findFirst() - .orElse(null); - /* @formatter:on */ - - if (jwt == null) { - LOG.debug("Request is missing the 'access_token' cookie"); - /* same here */ - return MISSING_JWT_VALUE; - } - - try { - byte[] jwtBytes = DECODER.decode(jwt); - return aes256Encryption.decrypt(jwtBytes); - } catch (Exception e) { - LOG.debug("Failed to decrypt JWT cookie", e); - /* same here */ - return MISSING_JWT_VALUE; - } - } -} diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/JwtResponse.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/JwtResponse.java deleted file mode 100644 index 97f5c1e1f6..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/JwtResponse.java +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import static java.util.Objects.requireNonNull; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Represents the response containing JWT-related tokens returned by an OAuth2 - * or OpenID Connect (OIDC) authentication flow. This class encapsulates the - * access token, token type, ID token, expiration time, and refresh token. It is - * primarily used for handling token-based authentication in secure API - * communication. - * - *

- * The {@code JwtResponse} object is constructed from JSON using Jackson, - * mapping the expected token fields from the authentication response. - *

- * - *

- * Fields: - *

    - *
  • {@code accessToken}: The access token used to authenticate subsequent - * requests to the API.
  • - *
  • {@code tokenType}: The type of the token (typically "Bearer").
  • - *
  • {@code idToken}: The ID token, which contains identity claims about the - * authenticated user.
  • - *
  • {@code expiresIn}: The duration in seconds until the access token - * expires.
  • - *
  • {@code refreshToken}: The token used to obtain a new access token without - * re-authenticating (optional).
  • - *
- *

- * - *

- * For more information on JSON Web Tokens (JWT), please refer to the - * official JWT documentation. - *

- * - * @author hamidonos - */ -class JwtResponse { - - private static final String JSON_PROPERTY_ACCESS_TOKEN = "access_token"; - private static final String JSON_PROPERTY_TOKEN_TYPE = "token_type"; - private static final String JSON_PROPERTY_ID_TOKEN = "id_token"; - private static final String JSON_PROPERTY_EXPIRES_IN = "expires_in"; - private static final String JSON_PROPERTY_REFRESH_TOKEN = "refresh_token"; - - private final String accessToken; - private final String tokenType; - private final String idToken; - private final Long expiresIn; - private final String refreshToken; - - /* @formatter:off */ - @JsonCreator - JwtResponse(@JsonProperty(JSON_PROPERTY_ACCESS_TOKEN) String accessToken, - @JsonProperty(JSON_PROPERTY_TOKEN_TYPE) String tokenType, - @JsonProperty(JSON_PROPERTY_ID_TOKEN) String idToken, - @JsonProperty(JSON_PROPERTY_EXPIRES_IN) Long expiresIn, - @JsonProperty(JSON_PROPERTY_REFRESH_TOKEN) String refreshToken) { - this.accessToken = requireNonNull(accessToken, JSON_PROPERTY_ACCESS_TOKEN + " must not be null"); - this.tokenType = requireNonNull(tokenType, JSON_PROPERTY_TOKEN_TYPE + " must not be null"); - this.idToken = requireNonNull(idToken, JSON_PROPERTY_ID_TOKEN + " must not be null"); - this.expiresIn = requireNonNull(expiresIn, JSON_PROPERTY_EXPIRES_IN + " must not be null"); - this.refreshToken = refreshToken; - } - /* @formatter:on */ - - String getAccessToken() { - return accessToken; - } - - String getTokenType() { - return tokenType; - } - - String getIdToken() { - return idToken; - } - - Long getExpiresIn() { - return expiresIn; - } - - String getRefreshToken() { - return refreshToken; - } -} diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/MissingAuthenticationEntryPointHandler.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/MissingAuthenticationEntryPointHandler.java deleted file mode 100644 index bccd85d875..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/MissingAuthenticationEntryPointHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import java.io.IOException; - -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.AuthenticationEntryPoint; - -import com.mercedesbenz.sechub.webserver.RequestConstants; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -/** - * {@code MissingAuthenticationEntryPointHandler} implements - * {@link AuthenticationEntryPoint} to provide custom behavior upon missing or - * invalid authentication. This class is used by Spring's - * oauth2ResourceServer configuration to redirect the user to the login - * page if the user is not authenticated. - * - * @author hamidonos - */ -class MissingAuthenticationEntryPointHandler implements AuthenticationEntryPoint { - @Override - public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { - response.sendRedirect(RequestConstants.LOGIN); - } -} diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/OAuth2LoginSuccessHandler.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/OAuth2LoginSuccessHandler.java deleted file mode 100644 index 29efdba404..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/OAuth2LoginSuccessHandler.java +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import static java.util.Objects.requireNonNull; -import static java.util.Objects.requireNonNullElseGet; - -import java.io.IOException; -import java.time.Instant; -import java.util.Base64; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.core.Authentication; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; -import org.springframework.security.oauth2.core.OAuth2AccessToken; -import org.springframework.security.web.authentication.AuthenticationSuccessHandler; - -import com.mercedesbenz.sechub.webserver.RequestConstants; -import com.mercedesbenz.sechub.webserver.encryption.AES256Encryption; - -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -/** - *

- * {@code OAuth2LoginSuccessHandler} implements - * {@link AuthenticationSuccessHandler} to provide custom behavior upon - * successful authentication. This handler redirects the user to the /home page - * specified in {@link RequestConstants}. - *

- * - *

- * This handler will also populate a secure HTTP-only cookie containing the JWT - * token which can be used in subsequent requests to authenticate the user. Note - * that the JWT is encrypted using {@link AES256Encryption} and encoded using - * {@link Base64}. - *

- * - * @see WebServerSecurityConfiguration - * @see RequestConstants - * @see OAuth2Properties - * @see OAuth2AuthorizedClientService - * - * @author hamidonos - */ -class OAuth2LoginSuccessHandler implements AuthenticationSuccessHandler { - - private static final Logger LOG = LoggerFactory.getLogger(OAuth2LoginSuccessHandler.class); - private static final Base64.Encoder ENCODER = Base64.getEncoder(); - private static final int DEFAULT_EXPIRY_SECONDS = 3600; - private static final String BASE_PATH = "/"; - - private final OAuth2Properties oAuth2Properties; - private final OAuth2AuthorizedClientService oAuth2AuthorizedClientService; - private final AES256Encryption aes256Encryption; - - public OAuth2LoginSuccessHandler(OAuth2Properties oAuth2Properties, OAuth2AuthorizedClientService oAuth2AuthorizedClientService, - AES256Encryption aes256Encryption) { - this.oAuth2Properties = requireNonNull(oAuth2Properties, "Property oAuthProperties must not be null"); - this.oAuth2AuthorizedClientService = requireNonNull(oAuth2AuthorizedClientService, "Property oAuth2AuthorizedClientService must not be null"); - this.aes256Encryption = requireNonNull(aes256Encryption, "Property aes256Encryption must not be null"); - } - - @Override - public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { - OAuth2AccessToken oAuth2AccessToken = getJwtFromAuthentication(authentication); - Instant issuedAt = requireNonNullElseGet(oAuth2AccessToken.getIssuedAt(), Instant::now); - /* Assume a default expiry of 1 hour if the expiry time is not set */ - Instant expiresAt = requireNonNullElseGet(oAuth2AccessToken.getExpiresAt(), () -> Instant.now().plusSeconds(DEFAULT_EXPIRY_SECONDS)); - long expirySeconds = expiresAt.getEpochSecond() - issuedAt.getEpochSecond(); - String jwt = oAuth2AccessToken.getTokenValue(); - byte[] encryptedJwtBytes = aes256Encryption.encrypt(jwt); - String encryptedJwtB64Encoded = ENCODER.encodeToString(encryptedJwtBytes); - response.addCookie(createJwtCookie(encryptedJwtB64Encoded, expirySeconds)); - LOG.debug("Redirecting to {}", RequestConstants.HOME); - response.sendRedirect(RequestConstants.HOME); - } - - private OAuth2AccessToken getJwtFromAuthentication(Authentication authentication) { - OAuth2AuthorizedClient oAuth2AuthorizedClient = oAuth2AuthorizedClientService.loadAuthorizedClient(oAuth2Properties.getProvider(), - authentication.getName()); - return oAuth2AuthorizedClient.getAccessToken(); - } - - private Cookie createJwtCookie(String jwt, long expirySeconds) { - Cookie cookie = new Cookie(WebServerSecurityConfiguration.ACCESS_TOKEN, jwt); - cookie.setMaxAge((int) expirySeconds); /* Casting this should be safe in all cases */ - cookie.setHttpOnly(true); /* Prevents client-side code (JavaScript) from accessing the cookie */ - cookie.setSecure(true); /* Send the cookie only over HTTPS */ - cookie.setPath(BASE_PATH); /* Cookie is available throughout the application */ - return cookie; - } -} \ No newline at end of file diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/OAuth2Properties.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/OAuth2Properties.java deleted file mode 100644 index d6cadee9dd..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/OAuth2Properties.java +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import static java.util.Objects.requireNonNull; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.bind.ConstructorBinding; - -@ConfigurationProperties(prefix = OAuth2Properties.PREFIX) -public final class OAuth2Properties { - - static final String PREFIX = "sechub.security.oauth2"; - private static final String ERR_MSG_FORMAT = "The property '%s.%s' must not be null"; - - private final String clientId; - private final String clientSecret; - private final String provider; - private final String redirectUri; - private final String issuerUri; - private final String authorizationUri; - private final String tokenUri; - private final String userInfoUri; - private final String jwkSetUri; - - /* @formatter:off */ - @ConstructorBinding - OAuth2Properties(String clientId, - String clientSecret, - String provider, - String redirectUri, - String issuerUri, - String authorizationUri, - String tokenUri, - String userInfoUri, - String jwkSetUri) { - this.clientId = requireNonNull(clientId, ERR_MSG_FORMAT.formatted(PREFIX, "client-id")); - this.clientSecret = requireNonNull(clientSecret, ERR_MSG_FORMAT.formatted(PREFIX, "client-secret"));; - this.provider = requireNonNull(provider, ERR_MSG_FORMAT.formatted(PREFIX, "provider")); - this.redirectUri = requireNonNull(redirectUri, ERR_MSG_FORMAT.formatted(PREFIX, "redirect-uri")); - this.issuerUri = requireNonNull(issuerUri, ERR_MSG_FORMAT.formatted(PREFIX, "issuer-uri")); - this.authorizationUri = requireNonNull(authorizationUri, ERR_MSG_FORMAT.formatted(PREFIX, "authorization-uri")); - this.tokenUri = requireNonNull(tokenUri, ERR_MSG_FORMAT.formatted(PREFIX, "token-uri")); - this.userInfoUri = requireNonNull(userInfoUri, ERR_MSG_FORMAT.formatted(PREFIX, "user-info-uri")); - this.jwkSetUri = requireNonNull(jwkSetUri, ERR_MSG_FORMAT.formatted(PREFIX, "jwk-set-uri")); - } - /* @formatter:on */ - - public String getClientId() { - return clientId; - } - - public String getClientSecret() { - return clientSecret; - } - - public String getProvider() { - return provider; - } - - public String getRedirectUri() { - return redirectUri; - } - - public String getIssuerUri() { - return issuerUri; - } - - public String getAuthorizationUri() { - return authorizationUri; - } - - public String getTokenUri() { - return tokenUri; - } - - public String getUserInfoUri() { - return userInfoUri; - } - - public String getJwkSetUri() { - return jwkSetUri; - } -} \ No newline at end of file diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/OAuth2PropertiesConfig.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/OAuth2PropertiesConfig.java deleted file mode 100644 index 10c966f282..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/OAuth2PropertiesConfig.java +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; - -import com.mercedesbenz.sechub.webserver.ApplicationProfiles; - -/** - * The - * {@link org.springframework.boot.context.properties.ConfigurationProperties} - * annotation does not support the {@link Profile} annotation. To ensure that - * the properties are only loaded when the - * {@link ApplicationProfiles#OAUTH2_ENABLED} profile is active, this separate - * configuration class is created with the {@link Profile} annotation. - * - * @author hamidonos - */ -@Configuration -@Profile(ApplicationProfiles.OAUTH2_ENABLED) -@EnableConfigurationProperties(OAuth2Properties.class) -class OAuth2PropertiesConfig { -} diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/PortAccessGuard.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/PortAccessGuard.java deleted file mode 100644 index d01591513f..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/PortAccessGuard.java +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import java.io.IOException; - -import org.springframework.web.filter.OncePerRequestFilter; - -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -/** - * Filter which checks if the request is targeting the allowed port. If not, it - * will return a 403 Forbidden response. - * - * @author hamidonos - */ -class PortAccessGuard extends OncePerRequestFilter { - - private final int allowedPort; - - public PortAccessGuard(int allowedPort) { - this.allowedPort = allowedPort; - } - - @Override - /* @formatter:off */ - protected void doFilterInternal(HttpServletRequest request, - @SuppressWarnings("NullableProblems") HttpServletResponse response, - @SuppressWarnings("NullableProblems") FilterChain filterChain) throws ServletException, IOException { - /* @formatter:on */ - int requestPort = request.getServerPort(); - if (allowedPort != requestPort) { - response.sendError(HttpServletResponse.SC_FORBIDDEN); - return; - } - filterChain.doFilter(request, response); - } -} diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/UserInputSanitizer.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/UserInputSanitizer.java deleted file mode 100644 index 9b1ae63732..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/UserInputSanitizer.java +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import org.springframework.stereotype.Component; - -@Component -public class UserInputSanitizer { - - public String sanitizeProjectId(String projectId) { - /* TODO Albert Tregnaghi, 2024-02-28:implement */ - return projectId; - } -} diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/WebServerSecurityConfiguration.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/WebServerSecurityConfiguration.java deleted file mode 100644 index deb12e3a23..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/security/WebServerSecurityConfiguration.java +++ /dev/null @@ -1,216 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import java.util.Arrays; - -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.core.annotation.Order; -import org.springframework.core.env.Environment; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; -import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; -import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; -import org.springframework.security.oauth2.core.AuthorizationGrantType; -import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver; -import org.springframework.security.web.AuthenticationEntryPoint; -import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.authentication.AuthenticationSuccessHandler; -import org.springframework.security.web.context.SecurityContextHolderFilter; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; -import org.springframework.security.web.util.matcher.NegatedRequestMatcher; -import org.springframework.security.web.util.matcher.OrRequestMatcher; -import org.springframework.security.web.util.matcher.RequestMatcher; -import org.springframework.web.client.RestTemplate; - -import com.mercedesbenz.sechub.webserver.ApplicationProfiles; -import com.mercedesbenz.sechub.webserver.RequestConstants; -import com.mercedesbenz.sechub.webserver.encryption.AES256Encryption; -import com.mercedesbenz.sechub.webserver.server.ManagementServerProperties; -import com.mercedesbenz.sechub.webserver.server.ServerProperties; - -@Configuration -@EnableWebSecurity -@EnableMethodSecurity -class WebServerSecurityConfiguration { - static final String ACCESS_TOKEN = "access_token"; - - private static final String ACTUATOR_PATH = "/actuator/**"; - /* @formatter:off */ - private static final String[] PUBLIC_PATHS = { - RequestConstants.LOGIN, - "/login/**", - "/css/**", - "/js/**", - "/images/**", - "/oauth2/**", - "/sechub-logo.svg" - }; - /* @formatter:on */ - private static final String SCOPE = "openid"; - private static final String USER_NAME_ATTRIBUTE_NAME = "sub"; - - private final Environment environment; - private final OAuth2Properties oAuth2Properties; - private final AES256Encryption aes256Encryption; - - /* @formatter:off */ - WebServerSecurityConfiguration(@Autowired Environment environment, - @Autowired(required = false) OAuth2Properties oAuth2Properties, - @Autowired AES256Encryption aes256Encryption) { - /* @formatter:on */ - this.environment = environment; - if (isOAuth2Enabled() && oAuth2Properties == null) { - throw new NoSuchBeanDefinitionException(OAuth2Properties.class); - } - if (!isOAuth2Enabled() && !isClassicAuthEnabled()) { - throw new IllegalStateException("At least one authentication method must be enabled"); - } - this.oAuth2Properties = oAuth2Properties; - this.aes256Encryption = aes256Encryption; - } - - @Bean - @Profile(ApplicationProfiles.OAUTH2_ENABLED) - ClientRegistrationRepository clientRegistrationRepository() { - /* @formatter:off */ - ClientRegistration clientRegistration = ClientRegistration - .withRegistrationId(oAuth2Properties.getProvider()) - .clientId(oAuth2Properties.getClientId()) - .clientSecret(oAuth2Properties.getClientSecret()) - .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) - .redirectUri(oAuth2Properties.getRedirectUri()) - .issuerUri(oAuth2Properties.getIssuerUri()).scope(SCOPE) - .authorizationUri(oAuth2Properties.getAuthorizationUri()) - .tokenUri(oAuth2Properties.getTokenUri()) - .userInfoUri(oAuth2Properties.getUserInfoUri()) - .jwkSetUri(oAuth2Properties.getJwkSetUri()) - .userNameAttributeName(USER_NAME_ATTRIBUTE_NAME) - .build(); - /* @formatter:on */ - - return new InMemoryClientRegistrationRepository(clientRegistration); - } - - @Bean - @Order(1) - /* @formatter:off */ - SecurityFilterChain securityFilterChainActuator(HttpSecurity httpSecurity, - ManagementServerProperties managementServerProperties) throws Exception { - PortAccessGuard portAccessGuard = new PortAccessGuard(managementServerProperties.getPort()); - - httpSecurity - .securityMatcher(ACTUATOR_PATH) - .authorizeHttpRequests(authorizeRequests -> authorizeRequests - .requestMatchers(ACTUATOR_PATH) - .permitAll()) - .addFilterBefore(portAccessGuard, SecurityContextHolderFilter.class); - /* @formatter:on */ - return httpSecurity.build(); - } - - @Bean - @Profile(ApplicationProfiles.OAUTH2_ENABLED) - @Order(2) - /* @formatter:off */ - SecurityFilterChain securityFilterChainProtectedPaths(HttpSecurity httpSecurity, - @Autowired(required = false) AuthenticationManager authenticationManager, - ServerProperties serverProperties) throws Exception { - AuthenticationEntryPoint authenticationEntryPoint = new MissingAuthenticationEntryPointHandler(); - BearerTokenResolver bearerTokenResolver = new JwtCookieResolver(aes256Encryption); - RequestMatcher publicPathsMatcher = new OrRequestMatcher( - Arrays.stream(PUBLIC_PATHS) - .map(AntPathRequestMatcher::new) - .toArray(AntPathRequestMatcher[]::new) - ); - RequestMatcher protectedPathsMatcher = new NegatedRequestMatcher(publicPathsMatcher); - PortAccessGuard portAccessGuard = new PortAccessGuard(serverProperties.getPort()); - - httpSecurity - .securityMatcher(protectedPathsMatcher) - .oauth2ResourceServer(oauth2ResourceServer -> oauth2ResourceServer - .authenticationEntryPoint(authenticationEntryPoint) - .bearerTokenResolver(bearerTokenResolver) - .jwt(jwt -> jwt.jwkSetUri(oAuth2Properties.getJwkSetUri())) - ); - /* @formatter:on */ - - if (authenticationManager != null) { - /* - * This is useful to mock authentication when no real authentication manager can - * be constructed (e.g. in tests) - */ - httpSecurity.authenticationManager(authenticationManager); - } - - httpSecurity.addFilterBefore(portAccessGuard, SecurityContextHolderFilter.class); - - return httpSecurity.build(); - } - - @Bean - @Order(3) - /* @formatter:on */ - SecurityFilterChain securityFilterChainPublicPaths(HttpSecurity httpSecurity, - @Autowired(required = false) OAuth2AuthorizedClientService oAuth2AuthorizedClientService, ServerProperties serverProperties) throws Exception { - - PortAccessGuard portAccessGuard = new PortAccessGuard(serverProperties.getPort()); - - httpSecurity.securityMatcher(PUBLIC_PATHS) - /* Disable CSRF */ - .csrf(AbstractHttpConfigurer::disable) - /* Make the application stateless */ - .sessionManagement(httpSecuritySessionManagementConfigurer -> httpSecuritySessionManagementConfigurer - .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); - - if (isOAuth2Enabled()) { - RestTemplate restTemplate = new RestTemplate(); - Base64EncodedClientIdAndSecretOAuth2AccessTokenClient base64EncodedClientIdAndSecretOAuth2AccessTokenClient = new Base64EncodedClientIdAndSecretOAuth2AccessTokenClient( - restTemplate); - if (oAuth2AuthorizedClientService == null) { - throw new NoSuchBeanDefinitionException( - "No qualifying bean of type 'OAuth2AuthorizedClientService' available: expected at least 1 bean which qualifies as autowire candidate."); - } - AuthenticationSuccessHandler authenticationSuccessHandler = new OAuth2LoginSuccessHandler(oAuth2Properties, oAuth2AuthorizedClientService, - aes256Encryption); - /* Enable OAuth2 */ - httpSecurity.oauth2Login(oauth2 -> oauth2.loginPage(RequestConstants.LOGIN) - .tokenEndpoint(token -> token.accessTokenResponseClient(base64EncodedClientIdAndSecretOAuth2AccessTokenClient)) - .successHandler(authenticationSuccessHandler)); - } - - if (isClassicAuthEnabled()) { - /* - * Enable Classic Authentication Note: This must be the last configuration in - * order to set the default 'loginPage' to oAuth2 because spring uses the - * 'loginPage' from the first authentication method configured - */ - AuthenticationSuccessHandler authenticationSuccessHandler = new ClassicLoginSuccessHandler(); - httpSecurity.formLogin(form -> form.loginPage(RequestConstants.LOGIN).successHandler(authenticationSuccessHandler)); - } - - /* @formatter:on */ - - httpSecurity.addFilterBefore(portAccessGuard, SecurityContextHolderFilter.class); - - return httpSecurity.build(); - } - - private boolean isOAuth2Enabled() { - return environment.matchesProfiles(ApplicationProfiles.OAUTH2_ENABLED); - } - - private boolean isClassicAuthEnabled() { - return environment.matchesProfiles(ApplicationProfiles.CLASSIC_AUTH_ENABLED); - } - -} diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/server/ManagementServerProperties.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/server/ManagementServerProperties.java deleted file mode 100644 index fe83077882..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/server/ManagementServerProperties.java +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.server; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.bind.ConstructorBinding; - -@ConfigurationProperties(prefix = ManagementServerProperties.PREFIX) -public final class ManagementServerProperties { - - static final String PREFIX = "management.server"; - - private final int port; - - @ConstructorBinding - ManagementServerProperties(int port) { - this.port = port; - } - - public int getPort() { - return port; - } -} \ No newline at end of file diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/server/ServerProperties.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/server/ServerProperties.java deleted file mode 100644 index 6e6a6e892f..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/server/ServerProperties.java +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.server; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.bind.ConstructorBinding; - -@ConfigurationProperties(prefix = ServerProperties.PREFIX) -public final class ServerProperties { - - static final String PREFIX = "server"; - - private final int port; - - @ConstructorBinding - ServerProperties(int port) { - this.port = port; - } - - public int getPort() { - return port; - } -} \ No newline at end of file diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/server/ServerPropertiesConfiguration.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/server/ServerPropertiesConfiguration.java deleted file mode 100644 index d283e7bd91..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/server/ServerPropertiesConfiguration.java +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.server; - -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Configuration -@EnableConfigurationProperties({ ServerProperties.class, ManagementServerProperties.class }) -public class ServerPropertiesConfiguration { - -} diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/user/UserDetailInformationService.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/user/UserDetailInformationService.java deleted file mode 100644 index bbfe5b294f..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/user/UserDetailInformationService.java +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.user; - -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.crypto.factory.PasswordEncoderFactories; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; - -@Service -public class UserDetailInformationService { - public UserDetails getUser() { - /* FIXME Albert Tregnaghi, 2024-02-28:implement real user management */ - PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); - return User.builder().passwordEncoder(encoder::encode).username("user").password("password").roles("USER").build(); - } -} \ No newline at end of file diff --git a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/user/UserInfoService.java b/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/user/UserInfoService.java deleted file mode 100644 index 2eee4f48e6..0000000000 --- a/sechub-web-server/src/main/java/com/mercedesbenz/sechub/webserver/user/UserInfoService.java +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.user; - -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.stereotype.Service; - -@Service -public class UserInfoService { - - public String getUserId() { - Authentication authentication = getAuthentication(); - if (authentication == null) { - return null; - } - return authentication.getName(); - } - - public String getEmailAddress() { - /* FIXME Albert Tregnaghi, 2024-02-28:implement */ - return getUserId() + "_calculated@example.org"; - } - - private Authentication getAuthentication() { - SecurityContext context = getContext(); - if (context == null) { - return null; - } - return getContext().getAuthentication(); - } - - private SecurityContext getContext() { - return SecurityContextHolder.getContext(); - } -} diff --git a/sechub-web-server/src/main/resources/application-classic-auth-enabled.yml b/sechub-web-server/src/main/resources/application-classic-auth-enabled.yml deleted file mode 100644 index bb475be945..0000000000 --- a/sechub-web-server/src/main/resources/application-classic-auth-enabled.yml +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: MIT -web-server: - client: - mocked: true - sechub: - ## Mocked sechub user (necessary for credentialinjection, we have no defaults...) - userid: "mocked-user" - apitoken: "mocked-apitoken" - -spring: - security: - user: - name: mock-user - password: mock-password \ No newline at end of file diff --git a/sechub-web-server/src/main/resources/application-integrationtest-data.yml b/sechub-web-server/src/main/resources/application-integrationtest-data.yml deleted file mode 100644 index 6d3e83fa71..0000000000 --- a/sechub-web-server/src/main/resources/application-integrationtest-data.yml +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: MIT -web-server: - sechub: - ## Setup integration test sechub user (currently admin, later other role) - userid: int-test_superadmin - apitoken: int-test_superadmin-pwd \ No newline at end of file diff --git a/sechub-web-server/src/main/resources/application-local.yml b/sechub-web-server/src/main/resources/application-local.yml deleted file mode 100644 index 1c01922465..0000000000 --- a/sechub-web-server/src/main/resources/application-local.yml +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: MIT -# Utility file to load user specific configuration for local development -# Define a profile for your local system user by creating a file named application-local.${USER}.yml (if needed) -# ${USER} is the value of your system username (e.g. application-local.JOHNDOE.yml) -# Note that all application-local.${USER}.yml files are ignored by git - -spring: - config: - import: - - optional:classpath:application-local.${USER}.yml \ No newline at end of file diff --git a/sechub-web-server/src/main/resources/application-ssl-cert-provided.yml b/sechub-web-server/src/main/resources/application-ssl-cert-provided.yml deleted file mode 100644 index 45a7810b64..0000000000 --- a/sechub-web-server/src/main/resources/application-ssl-cert-provided.yml +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: MIT -# This configuration is used for development and local testing. It uses a self-signed certificate provided by the build. - -server: - ssl: - key-store-type: 'PKCS12' - # we use a keystore location which is never tracked by git. - # see dev-create_localhost_certificate.sh and dev-ensure_localhost_certificate.sh - key-store: 'classpath:certificates-untracked/generated-dev-localhost-keystore.p12' - key-store-password: '123456' - key-alias: 'tomcat' - -web-server: - sechub: - server-url: "https://localhost:8443" - trust-all-certificates: true diff --git a/sechub-web-server/src/main/resources/application-ssl-cert-required.yml b/sechub-web-server/src/main/resources/application-ssl-cert-required.yml deleted file mode 100644 index f9c736423f..0000000000 --- a/sechub-web-server/src/main/resources/application-ssl-cert-required.yml +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: MIT -# This configuration is used for prod and int. It requires a valid certificate to be provided through the environment variables. - -server: - ssl: - keyStoreType: - ${SECHUB_WEB_SERVER_SSL_KEYSTORE_TYPE} - key-store: - ${SECHUB_WEB_SERVER_SSL_KEYSTORE_LOCATION} - key-store-password: - ${SECHUB_WEB_SERVER_SSL_KEYSTORE_PASSWORD} - key-alias: - ${SECHUB_WEB_SERVER_SSL_KEYSTORE_ALIAS} diff --git a/sechub-web-server/src/main/resources/application.yml b/sechub-web-server/src/main/resources/application.yml deleted file mode 100644 index 87ab18e370..0000000000 --- a/sechub-web-server/src/main/resources/application.yml +++ /dev/null @@ -1,46 +0,0 @@ -# SPDX-License-Identifier: MIT - -# Main settings -server: - port: - 4443 - ssl: - enabled: true # always enabled - protocol: TLS - enabled-protocols: TLSv1.2,TLSv1.3 - -spring: - messages: - basename: "i18n/messages" - profiles: - group: - web-server_prod: "ssl-cert-required,oauth2-enabled" - web-server_int: "ssl-cert-required,oauth2-enabled,classic-auth-enabled" - web-server_dev: "ssl-cert-provided,classic-auth-enabled" - web-server_local: "ssl-cert-provided,classic-auth-enabled,local" - web-server_test: "test" - web-server_integrationtest: "ssl-cert-provided,integrationtest-data" - web: - resources: - static-locations: classpath:/static - -# Spring Boot Actuators and Metrics -management: - server: - port: - 10250 - ssl: - enabled: false - endpoints: - web: - exposure: - include: "prometheus,health" - endpoint: - metrics: - enabled: true - prometheus: - enabled: true - prometheus: - metrics: - export: - enabled: true \ No newline at end of file diff --git a/sechub-web-server/src/main/resources/banner.txt b/sechub-web-server/src/main/resources/banner.txt deleted file mode 100644 index c071cd43f1..0000000000 --- a/sechub-web-server/src/main/resources/banner.txt +++ /dev/null @@ -1,8 +0,0 @@ - ____ _ _ _ __ __ _ ____ - / ___| ___ ___| | | |_ _| |__ \ \ / /__| |__/ ___| ___ _ ____ _____ _ __ - \___ \ / _ \/ __| |_| | | | | '_ \ \ \ /\ / / _ \ '_ \___ \ / _ \ '__\ \ / / _ \ '__| - ___) | __/ (__| _ | |_| | |_) | \ V V / __/ |_) |__) | __/ | \ V / __/ | - |____/ \___|\___|_| |_|\__,_|_.__/ \_/\_/ \___|_.__/____/ \___|_| \_/ \___|_| - -:: SecHub Web Server :: ${application.formatted-version} -:: Spring Boot :: ${spring-boot.formatted-version} \ No newline at end of file diff --git a/sechub-web-server/src/main/resources/certificates-untracked/.gitignore b/sechub-web-server/src/main/resources/certificates-untracked/.gitignore deleted file mode 100644 index a8df1b6f0c..0000000000 --- a/sechub-web-server/src/main/resources/certificates-untracked/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# accept nothing -* -# except the readme.md -!README.md -!.gitignore diff --git a/sechub-web-server/src/main/resources/certificates-untracked/README.md b/sechub-web-server/src/main/resources/certificates-untracked/README.md deleted file mode 100644 index 3172a4735d..0000000000 --- a/sechub-web-server/src/main/resources/certificates-untracked/README.md +++ /dev/null @@ -1,10 +0,0 @@ - - -# About p12 folder - -Here your p12 certificates have to be stored -- local development -- prod -- .. - -Inside this folder GIT does ignore anything except this `README.md`. \ No newline at end of file diff --git a/sechub-web-server/src/main/resources/i18n/messages.properties b/sechub-web-server/src/main/resources/i18n/messages.properties deleted file mode 100644 index 8a9f3d6b8d..0000000000 --- a/sechub-web-server/src/main/resources/i18n/messages.properties +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: MIT -common.projects=Projects -common.status=Status -common.loggout=Logout - -lang.switch-de=German -lang.switch-en=English - -newapitoken.request-new=Request new API Token - -scans.project-headline-prefix=Scanned \ No newline at end of file diff --git a/sechub-web-server/src/main/resources/i18n/messages_de.properties b/sechub-web-server/src/main/resources/i18n/messages_de.properties deleted file mode 100644 index e91330ba21..0000000000 --- a/sechub-web-server/src/main/resources/i18n/messages_de.properties +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: MIT -common.projects=Projekte -common.status=Status -common.loggout=Ausloggen - -lang.switch-de=Deutsch -lang.switch-en=Englisch - -newapitoken.request-new=Neues API Token anfordern - -scans.project-headline-prefix=Scans für \ No newline at end of file diff --git a/sechub-web-server/src/main/resources/logback-spring.xml b/sechub-web-server/src/main/resources/logback-spring.xml deleted file mode 100644 index 763b30380f..0000000000 --- a/sechub-web-server/src/main/resources/logback-spring.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sechub-web-server/src/main/resources/static/css/main.css b/sechub-web-server/src/main/resources/static/css/main.css deleted file mode 100644 index 9810deffeb..0000000000 --- a/sechub-web-server/src/main/resources/static/css/main.css +++ /dev/null @@ -1,166 +0,0 @@ -* { - margin: 0; - padding: 0; -} - -:root { - --color-dark: #100c08; - --color-light: #FDFDFD; - --color-grey: #696969; -} - -body { - font-family: sans-serif; - min-height: 100vh -} - -.placeholder { - color: var(--color-grey); -} - -.border-thin { - border-width: 0.2rem; - border-style: solid; -} - -.warning-border-dark-bg { - border-color: goldenrod; -} - -.warning-light-bg { - color: darkgoldenrod; -} - -.warning-dark-bg { - color: goldenrod; -} - -.container-flex { - display: flex; -} - -.flex-column { - flex-direction: column; -} - -.flex-row { - flex-direction: row; -} - -.flex-grow { - flex-grow: 1; -} - -.flex-shrink { - flex-shrink: 1; -} - -.text-align-center { - text-align: center; -} - -.padding-thin-all { - padding: 1em; -} - -.menu { - list-style: none; -} - -.menu > li { - display: inline; -} - -.item > a { - color: white; -} - -.item > a:hover { - color: gold; -} - -.item > a:visited { - color: white; -} - -.text-color-dark { - color: var(--color-dark); -} - -.text-color-light { - color: var(--color-light); -} - -.background-dark { - background: var(--color-dark); -} - -.background-light { - background: var(--color-light); -} - -.text-color-white { - color: white; -} - -.error { - color: darkred; -} - -/* ----------------- - * Info table - * ----------------- - */ - -.infoTable { - padding-bottom: 16px; - padding-top: 10px; - border-collapse: separate; - border: solid #cccccc 1px; - border-radius: 16px; - border-spacing: 0px; -} - -.infoTable th { - padding: 8px; - vertical-align: top; - text-align: left; -} - -.infoTable tr:nth-child(even) { - background: #f0f0f0; -} - -.infoTable tr:nth-child(odd) { - background: #fefefe; -} - -.infoTable td { - padding:8px; - - font-family: monospace; - vertical-align: top; - text-align: left; -} - -.infoTable td:nth-child(1) { - width: 150px; - padding-left: 10px; -} - -.infoTable td:nth-child(2) { - width: 300px; - padding-left: 10px; - border-left: 1px solid #cccccc; -} - -/* - * Logo - */ -.logo { - width: 80px; - height: 80px; -} - - - \ No newline at end of file diff --git a/sechub-web-server/src/main/resources/static/sechub-logo.svg b/sechub-web-server/src/main/resources/static/sechub-logo.svg deleted file mode 100644 index 39495203c3..0000000000 --- a/sechub-web-server/src/main/resources/static/sechub-logo.svg +++ /dev/null @@ -1,494 +0,0 @@ - - - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sechub-web-server/src/main/resources/templates/fragments/banner.html b/sechub-web-server/src/main/resources/templates/fragments/banner.html deleted file mode 100644 index 4e813969b2..0000000000 --- a/sechub-web-server/src/main/resources/templates/fragments/banner.html +++ /dev/null @@ -1,13 +0,0 @@ - - - -Banner - - -
-
-

Early WebUI draft - do not use this in production!

-
-
- - diff --git a/sechub-web-server/src/main/resources/templates/fragments/footer.html b/sechub-web-server/src/main/resources/templates/fragments/footer.html deleted file mode 100644 index dbf51cb428..0000000000 --- a/sechub-web-server/src/main/resources/templates/fragments/footer.html +++ /dev/null @@ -1,11 +0,0 @@ - - - -Footer - - -
- SecHub Server URL: None -
- - diff --git a/sechub-web-server/src/main/resources/templates/fragments/header.html b/sechub-web-server/src/main/resources/templates/fragments/header.html deleted file mode 100644 index 28f320d080..0000000000 --- a/sechub-web-server/src/main/resources/templates/fragments/header.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - SecHub - Header - - - - - - \ No newline at end of file diff --git a/sechub-web-server/src/main/resources/templates/fragments/navbar.html b/sechub-web-server/src/main/resources/templates/fragments/navbar.html deleted file mode 100644 index 9a7a936fdd..0000000000 --- a/sechub-web-server/src/main/resources/templates/fragments/navbar.html +++ /dev/null @@ -1,32 +0,0 @@ - - - -Navbar - - - - - \ No newline at end of file diff --git a/sechub-web-server/src/main/resources/templates/home.html b/sechub-web-server/src/main/resources/templates/home.html deleted file mode 100644 index d57369166d..0000000000 --- a/sechub-web-server/src/main/resources/templates/home.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - SecHub WebUI - - - - -
-

Welcome to the SecHub Web-UI UNDEFINED!

- SecHub Logo -

This site is under construction. Please check back later.

-
- - \ No newline at end of file diff --git a/sechub-web-server/src/main/resources/templates/login.html b/sechub-web-server/src/main/resources/templates/login.html deleted file mode 100644 index bc7af65886..0000000000 --- a/sechub-web-server/src/main/resources/templates/login.html +++ /dev/null @@ -1,216 +0,0 @@ - - - - - - SecHub Login - - - - -
- - -
- SecHub Logo -

SecHub

-

One central and easy way to use different security tools with one API/Client.

-
-
- - diff --git a/sechub-web-server/src/main/resources/templates/new-apitoken.html b/sechub-web-server/src/main/resources/templates/new-apitoken.html deleted file mode 100644 index d07d72e02d..0000000000 --- a/sechub-web-server/src/main/resources/templates/new-apitoken.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - Projects - - - -
- -
-

Requested new API token

-

New API token sent to: mail@example.org

-

Request for new API token failed!

-
-
- - - \ No newline at end of file diff --git a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/encryption/AES256EncryptionPropertiesTest.java b/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/encryption/AES256EncryptionPropertiesTest.java deleted file mode 100644 index 8fb707d986..0000000000 --- a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/encryption/AES256EncryptionPropertiesTest.java +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.encryption; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.nio.charset.StandardCharsets; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Configuration; -import org.springframework.test.context.TestPropertySource; - -import com.mercedesbenz.sechub.testframework.spring.YamlPropertyLoaderFactory; - -@SpringBootTest -@TestPropertySource(locations = "classpath:application-test.yml", factory = YamlPropertyLoaderFactory.class) -class AES256EncryptionPropertiesTest { - - private static final String VALID_AES_256_TEST_SECRET_KEY = "test-test-test-test-test-test-32"; - - private final AES256EncryptionProperties properties; - - @Autowired - AES256EncryptionPropertiesTest(AES256EncryptionProperties properties) { - this.properties = properties; - } - - @Test - void construct_aes256_encryption_properties_with_valid_properties_file_succeeds() { - assertThat(properties.getSecretKeyBytes()).isEqualTo(VALID_AES_256_TEST_SECRET_KEY.getBytes(StandardCharsets.UTF_8)); - } - - @Test - void construct_aes256encryption_properties_with_null_secret_key_fails() { - /* @formatter:off */ - /* execute & test */ - assertThatThrownBy(() -> new AES256EncryptionProperties(null)) - .isInstanceOf(NullPointerException.class) - .hasMessageContaining("The property 'sechub.security.encryption.secret-key' must not be null"); - /* @formatter:on */ - } - - @ParameterizedTest - @ValueSource(strings = { "", "1", "est-test-test-test-test-test-31", "-test-test-test-test-test-test-33" }) - void construct_aes256encryption_properties_with_non_256_bit_long_secret_key_fails(String secretKey) { - /* @formatter:off */ - /* execute & test */ - assertThatThrownBy(() -> new AES256EncryptionProperties(secretKey)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("The property sechub.security.encryption.secret-key must be a 256-bit string"); - /* @formatter:on */ - } - - @Configuration - @EnableConfigurationProperties(AES256EncryptionProperties.class) - static class TestConfig { - } -} diff --git a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/encryption/AES256EncryptionTest.java b/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/encryption/AES256EncryptionTest.java deleted file mode 100644 index b70e08da04..0000000000 --- a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/encryption/AES256EncryptionTest.java +++ /dev/null @@ -1,76 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.encryption; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.security.GeneralSecurityException; -import java.util.Base64; - -import org.junit.jupiter.api.Test; -import org.opentest4j.TestAbortedException; - -class AES256EncryptionTest { - - private static final String VALID_AES_256_TEST_SECRET_KEY = "test-test-test-test-test-test-32"; - private static final AES256EncryptionProperties aes256EncryptionProperties = new AES256EncryptionProperties(VALID_AES_256_TEST_SECRET_KEY); - private static final AES256Encryption aes256Encryption; - private static final Base64.Encoder ENCODER = Base64.getEncoder(); - - static { - try { - aes256Encryption = new AES256Encryption(aes256EncryptionProperties); - } catch (GeneralSecurityException e) { - throw new TestAbortedException("Failed to prepare AES256EncryptionTest", e); - } - } - - @Test - void encrypt_decrypt_returns_same_value() { - /* prepare */ - String plainText = "test"; - - /* execute */ - byte[] encryptedTextBytes = aes256Encryption.encrypt(plainText); - String decryptedText = aes256Encryption.decrypt(encryptedTextBytes); - - /* test */ - assertThat(decryptedText).isEqualTo(plainText); - } - - @Test - void encrypt_returns_correctly_encrypted_text() { - /* prepare */ - String plainText = "test"; - - /* execute */ - byte[] encryptedTextBytes = aes256Encryption.encrypt(plainText); - - /* test */ - String encryptedTextB64Encoded = ENCODER.encodeToString(encryptedTextBytes); - String expected = "SBRD1/R10NQuOFBdpC0S0g=="; - assertThat(encryptedTextB64Encoded).isEqualTo(expected); - } - - @Test - void encrypt_exceptions_are_handled_well() { - /* execute & test */ - - /* @formatter:off */ - assertThatThrownBy(() -> aes256Encryption.encrypt(null)) - .isInstanceOf(AES256EncryptionException.class) - .hasMessageContaining("Failed to encrypt text"); - /* @formatter:on */ - } - - @Test - void decrypt_exceptions_are_handled_well() { - /* execute & test */ - - /* @formatter:off */ - assertThatThrownBy(() -> aes256Encryption.decrypt(null)) - .isInstanceOf(AES256EncryptionException.class) - .hasMessageContaining("Failed to decrypt text"); - /* @formatter:on */ - } -} diff --git a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/page/HomeControllerTest.java b/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/page/HomeControllerTest.java deleted file mode 100644 index 0e1ab4f892..0000000000 --- a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/page/HomeControllerTest.java +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.page; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.RequestPostProcessor; - -import com.mercedesbenz.sechub.testframework.spring.WithMockJwtUser; -import com.mercedesbenz.sechub.testframework.spring.YamlPropertyLoaderFactory; -import com.mercedesbenz.sechub.webserver.security.TestWebServerSecurityConfiguration; -import com.mercedesbenz.sechub.webserver.server.ServerProperties; -import com.mercedesbenz.sechub.webserver.server.ServerPropertiesConfiguration; - -@WebMvcTest(HomeController.class) -@Import({ TestWebServerSecurityConfiguration.class, ServerPropertiesConfiguration.class }) -@TestPropertySource(locations = "classpath:application-test.yml", factory = YamlPropertyLoaderFactory.class) -@ActiveProfiles("oauth2-enabled") -class HomeControllerTest { - - private final MockMvc mockMvc; - private final RequestPostProcessor requestPostProcessor; - private final String homePageUrl; - - @Autowired - HomeControllerTest(MockMvc mockMvc, RequestPostProcessor requestPostProcessor, ServerProperties serverProperties) { - this.mockMvc = mockMvc; - this.requestPostProcessor = requestPostProcessor; - this.homePageUrl = "http://localhost:%d/home".formatted(serverProperties.getPort()); - } - - @Test - void home_page_is_not_accessible_anonymously() throws Exception { - /* @formatter:off */ - mockMvc - .perform(get(homePageUrl)) - .andExpect(status().is3xxRedirection()); - /* @formatter:on */ - } - - @Test - @WithMockJwtUser - void home_page_is_accessible_with_authenticated_user() throws Exception { - /* execute & test */ - - /* @formatter:off */ - mockMvc - .perform(get(homePageUrl).with(requestPostProcessor)) - .andExpect(status().isOk()) - .andReturn(); - /* @formatter:on */ - } -} diff --git a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/page/LoginControllerClassicAuthEnabledTest.java b/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/page/LoginControllerClassicAuthEnabledTest.java deleted file mode 100644 index d242c785c5..0000000000 --- a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/page/LoginControllerClassicAuthEnabledTest.java +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.page; - -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.not; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.web.servlet.MockMvc; - -import com.mercedesbenz.sechub.testframework.spring.YamlPropertyLoaderFactory; -import com.mercedesbenz.sechub.webserver.security.TestWebServerSecurityConfiguration; -import com.mercedesbenz.sechub.webserver.server.ServerProperties; -import com.mercedesbenz.sechub.webserver.server.ServerPropertiesConfiguration; - -@WebMvcTest(LoginController.class) -@Import({ TestWebServerSecurityConfiguration.class, ServerPropertiesConfiguration.class }) -@TestPropertySource(locations = "classpath:application-test.yml", factory = YamlPropertyLoaderFactory.class) -@ActiveProfiles("classic-auth-enabled") -class LoginControllerClassicAuthEnabledTest { - - private final MockMvc mockMvc; - private final ServerProperties serverProperties; - - @Autowired - LoginControllerClassicAuthEnabledTest(MockMvc mockMvc, ServerProperties serverProperties) { - this.mockMvc = mockMvc; - this.serverProperties = serverProperties; - } - - @Test - void login_page_is_accessible_anonymously() throws Exception { - /* @formatter:off */ - mockMvc - .perform(get("http://localhost:%d/login".formatted(serverProperties.getPort()))) - .andExpect(status().isOk()) - .andExpect(model().attributeExists("isOAuth2Enabled")) - .andExpect(model().attribute("isOAuth2Enabled", false)) - .andExpect(model().attributeExists("isClassicAuthEnabled")) - .andExpect(model().attribute("isClassicAuthEnabled", true)) - .andExpect(model().attributeDoesNotExist("registrationId")) - .andExpect(content().string(not(containsString("You will be redirected to your OAuth2 Provider for authentication.")))) - .andExpect(content().string(containsString("Login with your provided User ID & API Token."))) - .andExpect(content().string(containsString("Don't have an account? Register"))); - /* @formatter:on */ - } -} diff --git a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/page/LoginControllerOAuth2AndClassicAuthEnabledTest.java b/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/page/LoginControllerOAuth2AndClassicAuthEnabledTest.java deleted file mode 100644 index e1b2d74c78..0000000000 --- a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/page/LoginControllerOAuth2AndClassicAuthEnabledTest.java +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.page; - -import static org.hamcrest.Matchers.containsString; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.web.servlet.MockMvc; - -import com.mercedesbenz.sechub.testframework.spring.YamlPropertyLoaderFactory; -import com.mercedesbenz.sechub.webserver.security.OAuth2Properties; -import com.mercedesbenz.sechub.webserver.security.TestWebServerSecurityConfiguration; -import com.mercedesbenz.sechub.webserver.server.ServerProperties; -import com.mercedesbenz.sechub.webserver.server.ServerPropertiesConfiguration; - -@WebMvcTest(LoginController.class) -@Import({ TestWebServerSecurityConfiguration.class, ServerPropertiesConfiguration.class }) -@TestPropertySource(locations = "classpath:application-test.yml", factory = YamlPropertyLoaderFactory.class) -@ActiveProfiles({ "oauth2-enabled", "classic-auth-enabled" }) -class LoginControllerOAuth2AndClassicAuthEnabledTest { - - private final MockMvc mockMvc; - private final OAuth2Properties oAuth2Properties; - private final ServerProperties serverProperties; - - @Autowired - LoginControllerOAuth2AndClassicAuthEnabledTest(MockMvc mockMvc, OAuth2Properties oAuth2Properties, ServerProperties serverProperties) { - this.mockMvc = mockMvc; - this.oAuth2Properties = oAuth2Properties; - this.serverProperties = serverProperties; - } - - @Test - void login_page_is_accessible_anonymously() throws Exception { - /* @formatter:off */ - mockMvc - .perform(get("http://localhost:%d/login".formatted(serverProperties.getPort()))) - .andExpect(status().isOk()) - .andExpect(model().attributeExists("isOAuth2Enabled")) - .andExpect(model().attribute("isOAuth2Enabled", true)) - .andExpect(model().attributeExists("isClassicAuthEnabled")) - .andExpect(model().attribute("isClassicAuthEnabled", true)) - .andExpect(model().attributeExists("registrationId")) - .andExpect(model().attribute("registrationId", oAuth2Properties.getProvider())) - .andExpect(content().string(containsString("You will be redirected to your OAuth2 Provider for authentication."))) - .andExpect(content().string(containsString("Login with your provided User ID & API Token."))) - .andExpect(content().string(containsString("Don't have an account? Register"))); - /* @formatter:on */ - } -} diff --git a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/page/LoginControllerOAuth2EnabledTest.java b/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/page/LoginControllerOAuth2EnabledTest.java deleted file mode 100644 index ad6a13fb74..0000000000 --- a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/page/LoginControllerOAuth2EnabledTest.java +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.page; - -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.not; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.web.servlet.MockMvc; - -import com.mercedesbenz.sechub.testframework.spring.YamlPropertyLoaderFactory; -import com.mercedesbenz.sechub.webserver.security.OAuth2Properties; -import com.mercedesbenz.sechub.webserver.security.TestWebServerSecurityConfiguration; -import com.mercedesbenz.sechub.webserver.server.ServerProperties; -import com.mercedesbenz.sechub.webserver.server.ServerPropertiesConfiguration; - -@WebMvcTest(LoginController.class) -@Import({ TestWebServerSecurityConfiguration.class, ServerPropertiesConfiguration.class }) -@TestPropertySource(locations = "classpath:application-test.yml", factory = YamlPropertyLoaderFactory.class) -@ActiveProfiles("oauth2-enabled") -class LoginControllerOAuth2EnabledTest { - - private final MockMvc mockMvc; - private final OAuth2Properties oAuth2Properties; - private final ServerProperties serverProperties; - - @Autowired - LoginControllerOAuth2EnabledTest(MockMvc mockMvc, OAuth2Properties oAuth2Properties, ServerProperties serverProperties) { - this.mockMvc = mockMvc; - this.oAuth2Properties = oAuth2Properties; - this.serverProperties = serverProperties; - } - - @Test - void login_page_is_accessible_anonymously() throws Exception { - /* @formatter:off */ - mockMvc - .perform(get("http://localhost:%d/login".formatted(serverProperties.getPort()))) - .andExpect(status().isOk()) - .andExpect(model().attributeExists("isOAuth2Enabled")) - .andExpect(model().attribute("isOAuth2Enabled", true)) - .andExpect(model().attributeExists("isClassicAuthEnabled")) - .andExpect(model().attribute("isClassicAuthEnabled", false)) - .andExpect(model().attributeExists("registrationId")) - .andExpect(model().attribute("registrationId", oAuth2Properties.getProvider())) - .andExpect(content().string(containsString("You will be redirected to your OAuth2 Provider for authentication."))) - .andExpect(content().string(not(containsString("Login with your provided User ID & API Token.")))) - .andExpect(content().string(not(containsString("Don't have an account? Register")))); - /* @formatter:on */ - } -} diff --git a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/Base64EncodedClientIdAndSecretOAuth2AccessTokenClientTest.java b/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/Base64EncodedClientIdAndSecretOAuth2AccessTokenClientTest.java deleted file mode 100644 index 258ef2141e..0000000000 --- a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/Base64EncodedClientIdAndSecretOAuth2AccessTokenClientTest.java +++ /dev/null @@ -1,187 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; -import static org.springframework.test.web.client.match.MockRestRequestMatchers.content; -import static org.springframework.test.web.client.match.MockRestRequestMatchers.header; -import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; -import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; -import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.time.Instant; -import java.util.Base64; -import java.util.Set; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.opentest4j.TestAbortedException; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest; -import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.security.oauth2.core.AuthorizationGrantType; -import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; -import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange; -import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; -import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse; -import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; -import org.springframework.test.web.client.MockRestServiceServer; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.server.ResponseStatusException; - -import com.jayway.jsonpath.JsonPath; - -class Base64EncodedClientIdAndSecretOAuth2AccessTokenClientTest { - - /* @formatter:off */ - private static final RestTemplate restTemplate = new RestTemplate(); - private static final MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate); - private static final Base64EncodedClientIdAndSecretOAuth2AccessTokenClient client = new Base64EncodedClientIdAndSecretOAuth2AccessTokenClient(restTemplate); - private static final ClientRegistration clientRegistration = ClientRegistration.withRegistrationId(Constants.REGISTRATION_ID) - .clientId(Constants.CLIENT_ID) - .clientSecret(Constants.CLIENT_SECRET) - .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) - .redirectUri(Constants.REDIRECT_URI) - .tokenUri(Constants.TOKEN_URI) - .authorizationUri(Constants.AUTHORIZATION_URI) - .build(); - private static final OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest.authorizationCode() - .authorizationUri(Constants.AUTHORIZATION_URI) - .clientId(Constants.CLIENT_ID) - .redirectUri(Constants.REDIRECT_URI) - .scopes(Set.of(Constants.OPENID)) - .state(Constants.STATE) - .build(); - private static final OAuth2AuthorizationResponse authorizationResponse = OAuth2AuthorizationResponse.success(Constants.CODE) - .redirectUri(Constants.REDIRECT_URI) - .state(Constants.STATE) - .build(); - /* @formatter:on */ - private static final OAuth2AuthorizationExchange authorizationExchange = new OAuth2AuthorizationExchange(authorizationRequest, authorizationResponse); - private static final OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest = new OAuth2AuthorizationCodeGrantRequest(clientRegistration, - authorizationExchange); - private static final String jwtResponseJson; - - static { - try { - jwtResponseJson = Files.readString(Paths.get("src/test/resources/jwt-response.json")); - } catch (IOException e) { - throw new TestAbortedException("Failed to prepare test", e); - } - } - - @BeforeEach - void beforeEach() { - mockServer.reset(); - } - - @Test - void get_token_response_executes_correctly_formatted_http_request() { - /* prepare */ - String tokenUri = clientRegistration.getProviderDetails().getTokenUri(); - String authorizationHeaderValue = getBasicAuthHeaderValue(clientRegistration.getClientId(), clientRegistration.getClientSecret()); - /* @formatter:off */ - mockServer.expect(requestTo(tokenUri)) - .andExpect(method(HttpMethod.POST)) - .andExpect(header(HttpHeaders.CONTENT_TYPE, Constants.APPLICATION_FORM_URLENCODED_VALUE)) - .andExpect(header(HttpHeaders.AUTHORIZATION, authorizationHeaderValue)) - .andExpect(content().formData(getMultiValueMap(authorizationCodeGrantRequest))) - .andRespond(withSuccess(jwtResponseJson, MediaType.APPLICATION_JSON)); - /* @formatter:on */ - - /* execute */ - client.getTokenResponse(authorizationCodeGrantRequest); - - /* test */ - mockServer.verify(); - } - - @Test - void get_token_response_returns_o_auth_access_token_as_expected() { - /* prepare */ - String tokenUri = clientRegistration.getProviderDetails().getTokenUri(); - /* @formatter:off */ - mockServer.expect(requestTo(tokenUri)) - .andExpect(method(HttpMethod.POST)) - .andRespond(withSuccess(jwtResponseJson, MediaType.APPLICATION_JSON)); - /* @formatter:on */ - - /* execute */ - OAuth2AccessTokenResponse oAuth2AccessTokenResponse = client.getTokenResponse(authorizationCodeGrantRequest); - - /* test */ - mockServer.verify(); - assertThat(oAuth2AccessTokenResponse.getAccessToken().getTokenValue()).isEqualTo(JsonPath.read(jwtResponseJson, "$.access_token")); - assertThat(oAuth2AccessTokenResponse.getAccessToken().getTokenType().getValue()).isEqualTo(JsonPath.read(jwtResponseJson, "$.token_type")); - assertThat(oAuth2AccessTokenResponse.getAdditionalParameters().get(Constants.ID_TOKEN)).isEqualTo(JsonPath.read(jwtResponseJson, "$.id_token")); - assertThat(oAuth2AccessTokenResponse.getRefreshToken()).isNotNull(); - assertThat(oAuth2AccessTokenResponse.getRefreshToken().getTokenValue()).isEqualTo(JsonPath.read(jwtResponseJson, "$.refresh_token")); - int expiresIn = JsonPath.read(jwtResponseJson, "$.expires_in"); - long expiresInLong = Long.parseLong(String.valueOf(expiresIn)); - assertThat(oAuth2AccessTokenResponse.getAccessToken().getExpiresAt()) - .isAfterOrEqualTo(Instant.now().minus(expiresInLong, java.time.temporal.ChronoUnit.SECONDS)); - } - - @Test - void get_token_response_handles_rest_client_exception_well() { - /* prepare */ - String tokenUri = clientRegistration.getProviderDetails().getTokenUri(); - /* @formatter:off */ - mockServer.expect(requestTo(tokenUri)) - .andExpect(method(HttpMethod.POST)) - .andRespond(withSuccess("", MediaType.APPLICATION_JSON)); - - /* execute & test */ - - assertThatThrownBy(() -> client.getTokenResponse(authorizationCodeGrantRequest)) - .isExactlyInstanceOf(ResponseStatusException.class) - .hasMessageContaining("Failed to get JWT token response"); - /* @formatter:on */ - } - - private static MultiValueMap getMultiValueMap(OAuth2AuthorizationCodeGrantRequest authorizationGrantRequest) { - MultiValueMap formParameters = new LinkedMultiValueMap<>(); - OAuth2AuthorizationExchange authorizationExchange = authorizationGrantRequest.getAuthorizationExchange(); - String code = authorizationExchange.getAuthorizationResponse().getCode(); - String redirectUri = authorizationExchange.getAuthorizationRequest().getRedirectUri(); - - formParameters.add(OAuth2ParameterNames.GRANT_TYPE, Constants.GRANT_TYPE_VALUE); - formParameters.add(OAuth2ParameterNames.CODE, code); - formParameters.add(OAuth2ParameterNames.REDIRECT_URI, redirectUri); - - return formParameters; - } - - private static String getBasicAuthHeaderValue(String clientId, String clientSecret) { - String clientIdClientSecret = Constants.CLIENT_ID_CLIENT_SECRET_FORMAT.formatted(clientId, clientSecret); - String clientIdClientSecretB64Encoded = Base64.getEncoder().encodeToString(clientIdClientSecret.getBytes()); - return String.format(Constants.BASIC_AUTHORIZATION_HEADER_VALUE_FORMAT, clientIdClientSecretB64Encoded); - } - - private static final class Constants { - private static final String REGISTRATION_ID = "registration-id"; - private static final String CLIENT_ID = "client-id"; - private static final String CLIENT_SECRET = "client-secret"; - private static final String GRANT_TYPE_VALUE = "authorization_code"; - private static final String BASIC_AUTHORIZATION_HEADER_VALUE_FORMAT = "Basic %s"; - private static final String CLIENT_ID_CLIENT_SECRET_FORMAT = "%s:%s"; - private static final String APPLICATION_FORM_URLENCODED_VALUE = "%s;charset=%s".formatted(MediaType.APPLICATION_FORM_URLENCODED_VALUE, - StandardCharsets.UTF_8); - private static final String REDIRECT_URI = "http://localhost:8080/login/oauth2/code/registration-id"; - private static final String TOKEN_URI = "https://localhost:8080/oauth2/token"; - private static final String AUTHORIZATION_URI = "https://localhost:8080/oauth2/authorize"; - private static final String STATE = "state"; - private static final String CODE = "code"; - private static final String OPENID = "openid"; - private static final String ID_TOKEN = "id_token"; - - } -} \ No newline at end of file diff --git a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/JwtCookieResolverTest.java b/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/JwtCookieResolverTest.java deleted file mode 100644 index fe0ae83350..0000000000 --- a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/JwtCookieResolverTest.java +++ /dev/null @@ -1,130 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Base64; -import java.util.List; -import java.util.stream.Stream; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.ArgumentsProvider; -import org.junit.jupiter.params.provider.ArgumentsSource; -import org.mockito.Mockito; - -import com.mercedesbenz.sechub.webserver.encryption.AES256Encryption; - -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; - -class JwtCookieResolverTest { - - private static final String MISSING_JWT_VALUE = "missing-jwt"; - private static final String ACCESS_TOKEN = "access_token"; - private static final String JWT = "jwt"; - private static final String ENCRYPTED_JWT = "encrypted-jwt"; - private static final String ENCRYPTED_JWT_B64_ENCODED = Base64.getEncoder().encodeToString(ENCRYPTED_JWT.getBytes()); - private static final byte[] DECRYPTED_JWT_B64_DECODED = Base64.getDecoder().decode(ENCRYPTED_JWT_B64_ENCODED); - private static final String BASE_PATH = "/"; - - private static final AES256Encryption aes256Encryption = mock(); - private static final JwtCookieResolver jwtCookieResolver = new JwtCookieResolver(aes256Encryption); - private static final HttpServletRequest httpServletRequest = mock(); - - @BeforeEach - void beforeEach() { - Mockito.reset(aes256Encryption); - when(aes256Encryption.decrypt(any())).thenReturn(JWT); - } - - @Test - void resolve_reads_and_decrypts_jwt_from_cookies_successfully() { - /* prepare */ - Cookie jwtCookie = createJwtCookie(ACCESS_TOKEN, ENCRYPTED_JWT_B64_ENCODED); - Cookie someOtherCookie = createJwtCookie("some-other-cookie-name", "some-other-cookie-value"); - Cookie[] cookies = List.of(jwtCookie, someOtherCookie).toArray(new Cookie[0]); - when(httpServletRequest.getCookies()).thenReturn(cookies); - - /* execute */ - String jwt = jwtCookieResolver.resolve(httpServletRequest); - - /* test */ - assertThat(jwt).isEqualTo(JWT); - verify(aes256Encryption).decrypt(DECRYPTED_JWT_B64_DECODED); - } - - @ParameterizedTest - @ArgumentsSource(JwtCookieResolverTest.InvalidCookieListProvider.class) - void resolve_returns_missing_jwt_value_when_jwt_cookie_is_not_found(List cookies) { - /* prepare */ - Cookie[] array = cookies == null ? null : cookies.toArray(new Cookie[0]); - when(httpServletRequest.getCookies()).thenReturn(array); - - /* execute */ - String jwt = jwtCookieResolver.resolve(httpServletRequest); - - /* test */ - assertThat(jwt).isEqualTo(MISSING_JWT_VALUE); - } - - @Test - void resolve_returns_missing_jwt_value_when_access_token_decoding_fails() { - /* prepare */ - Cookie jwtCookie = createJwtCookie(ACCESS_TOKEN, ENCRYPTED_JWT_B64_ENCODED.concat("-invalid-b64")); - Cookie[] cookies = List.of(jwtCookie).toArray(new Cookie[0]); - when(httpServletRequest.getCookies()).thenReturn(cookies); - - /* execute & test */ - - String jwt = jwtCookieResolver.resolve(httpServletRequest); - - /* test */ - assertThat(jwt).isEqualTo(MISSING_JWT_VALUE); - } - - @Test - void resolve_returns_missing_jwt_value_when_access_token_decryption_fails() { - /* prepare */ - Cookie jwtCookie = createJwtCookie(ACCESS_TOKEN, ENCRYPTED_JWT_B64_ENCODED); - Cookie[] cookies = List.of(jwtCookie).toArray(new Cookie[0]); - when(httpServletRequest.getCookies()).thenReturn(cookies); - when(aes256Encryption.decrypt(any())).thenThrow(new RuntimeException()); - - /* execute & test */ - - String jwt = jwtCookieResolver.resolve(httpServletRequest); - - /* test */ - assertThat(jwt).isEqualTo(MISSING_JWT_VALUE); - } - - private static Cookie createJwtCookie(String name, String value) { - Cookie cookie = new Cookie(name, value); - cookie.setMaxAge(3600); - cookie.setHttpOnly(true); - cookie.setSecure(true); - cookie.setPath(BASE_PATH); - return cookie; - } - - static class InvalidCookieListProvider implements ArgumentsProvider { - @Override - public Stream provideArguments(ExtensionContext extensionContext) throws Exception { - /* @formatter:off */ - return Stream.of( - Arguments.of((Object) null), - Arguments.of(List.of()), - Arguments.of(List.of(createJwtCookie("invalid-cookie-name", ENCRYPTED_JWT_B64_ENCODED))) - ); - /* @formatter:on */ - } - } -} \ No newline at end of file diff --git a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/JwtResponseTest.java b/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/JwtResponseTest.java deleted file mode 100644 index 9507b96ab1..0000000000 --- a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/JwtResponseTest.java +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.stream.Stream; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.ArgumentsProvider; -import org.junit.jupiter.params.provider.ArgumentsSource; -import org.opentest4j.TestAbortedException; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.exc.ValueInstantiationException; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.jayway.jsonpath.JsonPath; - -class JwtResponseTest { - - private static final String jwtResponseJson; - private static final ObjectMapper objectMapper = new ObjectMapper(); - - static { - try { - jwtResponseJson = Files.readString(Paths.get("src/test/resources/jwt-response.json")); - } catch (IOException e) { - throw new TestAbortedException("Failed to prepare test", e); - } - } - - @Test - void construct_jwt_response_from_valid_json_is_successful() throws JsonProcessingException { - /* execute */ - JwtResponse jwtResponse = objectMapper.readValue(jwtResponseJson, JwtResponse.class); - - // assert - assertThat(jwtResponse).isNotNull(); - assertThat(jwtResponse.getAccessToken()).isEqualTo(JsonPath.read(jwtResponseJson, "$.access_token")); - assertThat(jwtResponse.getRefreshToken()).isEqualTo(JsonPath.read(jwtResponseJson, "$.refresh_token")); - assertThat(jwtResponse.getIdToken()).isEqualTo(JsonPath.read(jwtResponseJson, "$.id_token")); - int expiresIn = JsonPath.read(jwtResponseJson, "$.expires_in"); - long expiresInLong = Long.parseLong(String.valueOf(expiresIn)); - assertThat(jwtResponse.getExpiresIn()).isEqualTo(expiresInLong); - assertThat(jwtResponse.getTokenType()).isEqualTo(JsonPath.read(jwtResponseJson, "$.token_type")); - } - - @Test - void construct_jwt_response_from_valid_json_with_no_refresh_token_is_successful() throws JsonProcessingException { - /* prepare */ - String jwtResponseJsonWithoutRefreshToken = removeJsonKeyAndValue("refresh_token"); - - /* execute & test */ - - /* @formatter:off */ - assertDoesNotThrow(() -> { - JwtResponse jwtResponse = objectMapper.readValue(jwtResponseJsonWithoutRefreshToken, JwtResponse.class); - assertThat(jwtResponse.getRefreshToken()).isNull(); - }); - /* @formatter:on */ - } - - @ParameterizedTest - @ArgumentsSource(InvalidJwtResponseJsonProvider.class) - void construct_jwt_response_from_invalid_json_fails(String invalidJwtResponseJson, String expectedErrMsg) { - /* execute & test */ - - /* @formatter:off */ - assertThatThrownBy(() -> objectMapper.readValue(invalidJwtResponseJson, JwtResponse.class)) - .isInstanceOf(ValueInstantiationException.class) - .hasMessageContaining(expectedErrMsg); - /* @formatter:on */ - } - - private static String removeJsonKeyAndValue(String key) throws JsonProcessingException { - ObjectMapper objectMapper = new ObjectMapper(); - JsonNode rootNode = objectMapper.readTree(jwtResponseJson); - - if (rootNode instanceof ObjectNode) { - ((ObjectNode) rootNode).remove(key); - } else { - throw new IllegalArgumentException("Invalid JSON"); - } - - return objectMapper.writeValueAsString(rootNode); - } - - private static class InvalidJwtResponseJsonProvider implements ArgumentsProvider { - @Override - public Stream provideArguments(ExtensionContext extensionContext) throws Exception { - return Stream.of(Arguments.of(removeJsonKeyAndValue("access_token"), "access_token must not be null"), - Arguments.of(removeJsonKeyAndValue("token_type"), "token_type must not be null"), - Arguments.of(removeJsonKeyAndValue("id_token"), "id_token must not be null"), - Arguments.of(removeJsonKeyAndValue("expires_in"), "expires_in must not be null")); - } - } -} diff --git a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/OAuth2JwtPropertiesTest.java b/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/OAuth2JwtPropertiesTest.java deleted file mode 100644 index b40648b78a..0000000000 --- a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/OAuth2JwtPropertiesTest.java +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.util.stream.Stream; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.ArgumentsProvider; -import org.junit.jupiter.params.provider.ArgumentsSource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.TestPropertySource; - -import com.mercedesbenz.sechub.testframework.spring.YamlPropertyLoaderFactory; - -@SpringBootTest -@ActiveProfiles("oauth2-enabled") -@TestPropertySource(locations = "classpath:application-test.yml", factory = YamlPropertyLoaderFactory.class) -class OAuth2JwtPropertiesTest { - - private static final String ERR_MSG_FORMAT = "The property 'sechub.security.oauth2.%s' must not be null"; - - private final OAuth2Properties properties; - - @Autowired - OAuth2JwtPropertiesTest(OAuth2Properties properties) { - this.properties = properties; - } - - @Test - void construct_o_auth_2_properties_with_valid_properties_file_succeeds() { - assertThat(properties.getClientId()).isEqualTo("client-id"); - assertThat(properties.getClientSecret()).isEqualTo("client-secret"); - assertThat(properties.getProvider()).isEqualTo("provider"); - assertThat(properties.getRedirectUri()).isEqualTo("redirect-uri"); - assertThat(properties.getIssuerUri()).isEqualTo("issuer-uri"); - assertThat(properties.getAuthorizationUri()).isEqualTo("authorization-uri"); - assertThat(properties.getTokenUri()).isEqualTo("token-uri"); - assertThat(properties.getUserInfoUri()).isEqualTo("user-info-uri"); - assertThat(properties.getJwkSetUri()).isEqualTo("https://example.org/jwk-set-uri"); - } - - /* @formatter:off */ - @ParameterizedTest - @ArgumentsSource(InvalidOAuth2PropertiesProvider.class) - void construct_o_auth_2_properties_with_null_property_fails(String clientId, - String clientSecret, - String provider, - String redirectUri, - String issuerUri, - String authorizationUri, - String tokenUri, - String userInfoUri, - String jwkSetUri, - String errMsg) { - assertThatThrownBy(() -> new OAuth2Properties(clientId, clientSecret, provider, redirectUri, issuerUri, authorizationUri, tokenUri, userInfoUri, jwkSetUri)) - .isInstanceOf(NullPointerException.class) - .hasMessageContaining(errMsg); - } - /* @formatter:on */ - - @Configuration - @Import(OAuth2PropertiesConfig.class) - static class TestConfig { - } - - private static class InvalidOAuth2PropertiesProvider implements ArgumentsProvider { - @Override - public Stream provideArguments(ExtensionContext extensionContext) throws Exception { - /* @formatter:off */ - return Stream.of( - Arguments.of(null, "client-secret", "provider", "redirect-uri", "issuer-uri", "authorization-uri", "token-uri", "user-info-uri", "jwk-set-uri", ERR_MSG_FORMAT.formatted("client-id")), - Arguments.of("client-id", null, "provider", "redirect-uri", "issuer-uri", "authorization-uri", "token-uri", "user-info-uri", "jwk-set-uri", ERR_MSG_FORMAT.formatted("client-secret")), - Arguments.of("client-id", "client-secret", null, "redirect-uri", "issuer-uri", "authorization-uri", "token-uri", "user-info-uri", "jwk-set-uri", ERR_MSG_FORMAT.formatted("provider")), - Arguments.of("client-id", "client-secret", "provider", null, "issuer-uri", "authorization-uri", "token-uri", "user-info-uri", "jwk-set-uri", ERR_MSG_FORMAT.formatted("redirect-uri")), - Arguments.of("client-id", "client-secret", "provider", "redirect-uri", null, "authorization-uri", "token-uri", "user-info-uri", "jwk-set-uri", ERR_MSG_FORMAT.formatted("issuer-uri")), - Arguments.of("client-id", "client-secret", "provider", "redirect-uri", "issuer-uri", null, "token-uri", "user-info-uri", "jwk-set-uri", ERR_MSG_FORMAT.formatted("authorization-uri")), - Arguments.of("client-id", "client-secret", "provider", "redirect-uri", "issuer-uri", "authorization-uri", null, "user-info-uri", "jwk-set-uri", ERR_MSG_FORMAT.formatted("token-uri")), - Arguments.of("client-id", "client-secret", "provider", "redirect-uri", "issuer-uri", "authorization-uri", "token-uri", null, "jwk-set-uri", ERR_MSG_FORMAT.formatted("user-info-uri")), - Arguments.of("client-id", "client-secret", "provider", "redirect-uri", "issuer-uri", "authorization-uri", "token-uri", "user-info-uri", null, ERR_MSG_FORMAT.formatted("jwk-set-uri"))); - /* @formatter:on */ - } - } -} diff --git a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/OAuth2LoginSuccessHandlerTest.java b/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/OAuth2LoginSuccessHandlerTest.java deleted file mode 100644 index 3921bacddb..0000000000 --- a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/OAuth2LoginSuccessHandlerTest.java +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.time.Instant; -import java.util.Base64; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatcher; -import org.springframework.security.core.Authentication; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; -import org.springframework.security.oauth2.core.OAuth2AccessToken; - -import com.mercedesbenz.sechub.webserver.RequestConstants; -import com.mercedesbenz.sechub.webserver.encryption.AES256Encryption; - -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -class OAuth2LoginSuccessHandlerTest { - - private static final String ACCESS_TOKEN = "access_token"; - private static final String ENCRYPTED_JWT = "this-is-an-encrypted-jwt"; - private static final byte[] ENCRYPTED_JWT_BYTES = ENCRYPTED_JWT.getBytes(StandardCharsets.UTF_8); - private static final String ENCRYPTED_JWT_BASE64_ENCODED = Base64.getEncoder().encodeToString(ENCRYPTED_JWT_BYTES); - private static final String PROVIDER = "example-provider"; - private static final String PRINCIPAL = "example-principal"; - private static final String JWT = "this-is-a-plain-jwt"; - private static final int DEFAULT_EXPIRY_SECONDS = 3600; - private static final String BASE_PATH = "/"; - - private static final OAuth2Properties oAuth2Properties = mock(); - private static final OAuth2AuthorizedClientService oAuth2AuthorizedClientService = mock(); - private static final AES256Encryption aes256Encryption = mock(); - private static final HttpServletRequest httpServletRequest = mock(); - private static final HttpServletResponse httpServletResponse = mock(); - private static final Authentication authentication = mock(); - private static final OAuth2AuthorizedClient oauth2AuthorizedClient = mock(); - private static final OAuth2AccessToken oAuth2AccessToken = mock(); - private static final OAuth2LoginSuccessHandler oAuth2LoginSuccessHandler = new OAuth2LoginSuccessHandler(oAuth2Properties, oAuth2AuthorizedClientService, - aes256Encryption); - - @BeforeEach - void beforeEach() { - reset(aes256Encryption, httpServletResponse); - when(oAuth2Properties.getProvider()).thenReturn(PROVIDER); - when(aes256Encryption.encrypt(anyString())).thenReturn(ENCRYPTED_JWT_BYTES); - when(oAuth2AuthorizedClientService.loadAuthorizedClient(PROVIDER, PRINCIPAL)).thenReturn(oauth2AuthorizedClient); - when(authentication.getName()).thenReturn(PRINCIPAL); - when(oauth2AuthorizedClient.getAccessToken()).thenReturn(oAuth2AccessToken); - when(oAuth2AccessToken.getTokenValue()).thenReturn(JWT); - } - - @Test - void on_authentication_success_sends_a_valid_redirect_containing_the_encrypted_jwt_cookie() throws IOException { - /* prepare */ - Instant now = Instant.now(); - when(oAuth2AccessToken.getIssuedAt()).thenReturn(now); - when(oAuth2AccessToken.getExpiresAt()).thenReturn(now.plusSeconds(60)); - int expirySeconds = 60; - - /* execute */ - oAuth2LoginSuccessHandler.onAuthenticationSuccess(httpServletRequest, httpServletResponse, authentication); - - /* test */ - verify(aes256Encryption).encrypt(JWT); - verify(httpServletResponse).sendRedirect(RequestConstants.HOME); - ArgumentMatcher jwt = cookie -> { - /* @formatter:off */ - if (!ACCESS_TOKEN.equals(cookie.getName())) return false; - if (!ENCRYPTED_JWT_BASE64_ENCODED.equals(cookie.getValue())) return false; - if (cookie.getMaxAge() != expirySeconds) return false; - if (!cookie.isHttpOnly()) return false; - if (!cookie.getSecure()) return false; - return BASE_PATH.equals(cookie.getPath()); - /* @formatter:on */ - }; - verify(httpServletResponse).addCookie(argThat(jwt)); - } - - @Test - void on_authentication_success_assumes_default_expiry_when_expires_at_is_null() throws IOException { - /* prepare */ - Instant now = Instant.now(); - when(oAuth2AccessToken.getIssuedAt()).thenReturn(now); - when(oAuth2AccessToken.getExpiresAt()).thenReturn(null); - - /* execute */ - oAuth2LoginSuccessHandler.onAuthenticationSuccess(httpServletRequest, httpServletResponse, authentication); - - /* test */ - ArgumentMatcher jwt = cookie -> cookie.getMaxAge() == DEFAULT_EXPIRY_SECONDS; - verify(httpServletResponse).addCookie(argThat(jwt)); - } -} \ No newline at end of file diff --git a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/PortAccessGuardTest.java b/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/PortAccessGuardTest.java deleted file mode 100644 index 428d52ce64..0000000000 --- a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/PortAccessGuardTest.java +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; - -import java.io.IOException; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.mock.web.MockHttpServletRequest; - -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -class PortAccessGuardTest { - - private static final HttpServletResponse httpServletResponse = mock(); - private static final FilterChain filterChain = mock(); - - @BeforeEach - void beforeEach() { - reset(httpServletResponse, filterChain); - } - - @Test - void do_filter_internal_does_not_send_error_when_requested_port_is_allowed() throws ServletException, IOException { - /* prepare */ - int port = 8080; - PortAccessGuard guard = new PortAccessGuard(port); - HttpServletRequest httpServletRequest = new MockHttpServletRequest() { - @Override - public int getServerPort() { - return port; - } - }; - - /* execute */ - guard.doFilterInternal(httpServletRequest, httpServletResponse, filterChain); - - /* test */ - verify(httpServletResponse, never()).sendError(anyInt()); - verify(filterChain).doFilter(httpServletRequest, httpServletResponse); - } - - @Test - void do_filter_internal_does_send_error_403_forbidden_when_requested_port_is_not_allowed() throws ServletException, IOException { - /* prepare */ - int allowedPort = 4443; - PortAccessGuard guard = new PortAccessGuard(allowedPort); - HttpServletRequest httpServletRequest = new MockHttpServletRequest() { - @Override - public int getServerPort() { - return allowedPort + 1; - } - }; - - /* execute */ - guard.doFilterInternal(httpServletRequest, httpServletResponse, filterChain); - - /* test */ - verify(httpServletResponse).sendError(HttpServletResponse.SC_FORBIDDEN); - verify(filterChain, never()).doFilter(httpServletRequest, httpServletResponse); - } -} \ No newline at end of file diff --git a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/TestCookieRequestPostProcessor.java b/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/TestCookieRequestPostProcessor.java deleted file mode 100644 index c78a89cce9..0000000000 --- a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/TestCookieRequestPostProcessor.java +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.test.web.servlet.request.RequestPostProcessor; - -import jakarta.servlet.http.Cookie; - -/** - * {@code TestCookieRequestPostProcessor} is a custom - * {@link RequestPostProcessor} implementation that adds a custom cookie to the - * request headers. {@link MockHttpServletRequest} . This is useful for testing - * endpoints that require cookie authentication. - * - * @author hamidonos - */ -public class TestCookieRequestPostProcessor implements RequestPostProcessor { - - private final Cookie cookie; - - public TestCookieRequestPostProcessor(Cookie cookie) { - this.cookie = cookie; - } - - @Override - @SuppressWarnings("NullableProblems") - public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) { - request.setCookies(cookie); - return request; - } -} \ No newline at end of file diff --git a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/TestSecurityController.java b/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/TestSecurityController.java deleted file mode 100644 index 1aedaec910..0000000000 --- a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/TestSecurityController.java +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * This controller spins up a mock API for testing the - * {@link SecurityConfiguration} of the SecHub Web UI server application. - * - * @author hamidonos - */ -@RestController -class TestSecurityController { - - private static final String OK = HttpStatus.OK.getReasonPhrase(); - - @GetMapping("/actuator") - String actuator() { - return OK; - } - - @GetMapping("/login") - String login() { - return OK; - } - - @GetMapping("/home") - String home() { - return OK; - } - - @GetMapping("/css") - String css() { - return OK; - } - - @GetMapping("/js") - String js() { - return OK; - } - - @GetMapping("/images") - String images() { - return OK; - } - - @GetMapping("/oauth2") - String oauth2() { - return OK; - } - - @GetMapping("/sechub-logo.svg") - String sechubLogoSvg() { - return OK; - } - - @GetMapping("/error") - String errorPage() { - return OK; - } -} diff --git a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/TestWebServerSecurityConfiguration.java b/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/TestWebServerSecurityConfiguration.java deleted file mode 100644 index 41f677662a..0000000000 --- a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/TestWebServerSecurityConfiguration.java +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Import; -import org.springframework.test.web.servlet.request.RequestPostProcessor; - -import com.mercedesbenz.sechub.testframework.spring.TestJwtMockAuthenticationConfiguration; -import com.mercedesbenz.sechub.webserver.encryption.AES256Encryption; - -import jakarta.servlet.http.Cookie; - -@TestConfiguration -@Import({ WebServerSecurityConfiguration.class, TestJwtMockAuthenticationConfiguration.class, OAuth2PropertiesConfig.class, AES256Encryption.class }) -public class TestWebServerSecurityConfiguration { - - @Bean - public RequestPostProcessor requestPostProcessor() { - Cookie cookie = new Cookie(TestJwtMockAuthenticationConfiguration.ACCESS_TOKEN, TestJwtMockAuthenticationConfiguration.ENCRYPTED_JWT_B64_ENCODED); - return new TestCookieRequestPostProcessor(cookie); - } -} diff --git a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/WebServerSecurityConfigurationTest.java b/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/WebServerSecurityConfigurationTest.java deleted file mode 100644 index 52e68fb448..0000000000 --- a/sechub-web-server/src/test/java/com/mercedesbenz/sechub/webserver/security/WebServerSecurityConfigurationTest.java +++ /dev/null @@ -1,99 +0,0 @@ -// SPDX-License-Identifier: MIT -package com.mercedesbenz.sechub.webserver.security; - -import static org.mockito.Mockito.mock; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.http.HttpStatus; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; - -import com.mercedesbenz.sechub.testframework.spring.YamlPropertyLoaderFactory; -import com.mercedesbenz.sechub.webserver.encryption.AES256Encryption; -import com.mercedesbenz.sechub.webserver.server.ManagementServerProperties; -import com.mercedesbenz.sechub.webserver.server.ServerProperties; -import com.mercedesbenz.sechub.webserver.server.ServerPropertiesConfiguration; - -@WebMvcTest -@ActiveProfiles("classic-auth-enabled") -@TestPropertySource(locations = "classpath:application-test.yml", factory = YamlPropertyLoaderFactory.class) -class WebServerSecurityConfigurationTest { - - private final MockMvc mockMvc; - private final ServerProperties serverProperties; - private final ManagementServerProperties managementServerProperties; - - @Autowired - WebServerSecurityConfigurationTest(MockMvc mockMvc, ServerProperties serverProperties, ManagementServerProperties managementServerProperties) { - this.mockMvc = mockMvc; - this.serverProperties = serverProperties; - this.managementServerProperties = managementServerProperties; - } - - @Test - void actuator_is_accessible_anonymously_at_management_port() throws Exception { - /* prepare */ - String url = "http://localhost:%d/actuator".formatted(managementServerProperties.getPort()); - - /* execute & test */ - getAndExpect(url, HttpStatus.OK); - } - - @Test - void actuator_is_not_accessible_at_server_port() throws Exception { - /* prepare */ - String url = "http://localhost:%d/actuator".formatted(serverProperties.getPort()); - - /* execute & test */ - getAndExpect(url, HttpStatus.FORBIDDEN); - } - - @Test - void public_path_is_accessible_at_management_port() throws Exception { - /* prepare */ - String url = "http://localhost:%d/login".formatted(managementServerProperties.getPort()); - - /* execute & test */ - getAndExpect(url, HttpStatus.FORBIDDEN); - } - - @Test - void public_path_is_accessible_at_server_port() throws Exception { - /* prepare */ - String url = "http://localhost:%d/login".formatted(serverProperties.getPort()); - - /* execute & test */ - getAndExpect(url, HttpStatus.OK); - } - - private void getAndExpect(String path, HttpStatus httpStatus) throws Exception { - /* @formatter:off */ - mockMvc - .perform(MockMvcRequestBuilders.get(path)) - .andExpect(status().is(httpStatus.value())); - /* @formatter:on */ - } - - @Configuration - @Import({ WebServerSecurityConfiguration.class, ServerPropertiesConfiguration.class }) - static class TestConfig { - - @Bean - TestSecurityController testSecurityController() { - return new TestSecurityController(); - } - - @Bean - AES256Encryption aes256Encryption() { - return mock(); - } - } -} diff --git a/sechub-web-server/src/test/resources/application-test.yml b/sechub-web-server/src/test/resources/application-test.yml deleted file mode 100644 index efbc838bb7..0000000000 --- a/sechub-web-server/src/test/resources/application-test.yml +++ /dev/null @@ -1,26 +0,0 @@ -# SPDX-License-Identifier: MIT - -sechub: - security: - oauth2: - client-id: client-id - client-secret: client-secret - provider: provider - redirect-uri: redirect-uri - issuer-uri: issuer-uri - authorization-uri: authorization-uri - token-uri: token-uri - user-info-uri: user-info-uri - jwk-set-uri: https://example.org/jwk-set-uri - encryption: - secret-key: test-test-test-test-test-test-32 - -server: - port: - 4443 - ssl: - enabled: false - -management: - server: - port: 10250 \ No newline at end of file diff --git a/sechub-web-server/src/test/resources/jwt-response.json b/sechub-web-server/src/test/resources/jwt-response.json deleted file mode 100644 index 2bec6853e9..0000000000 --- a/sechub-web-server/src/test/resources/jwt-response.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "access_token":"access_token", - "token_type":"Bearer", - "expires_in":3600, - "refresh_token": "refresh_token", - "id_token":"id_token" -} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 1161414d72..ce32e89add 100644 --- a/settings.gradle +++ b/settings.gradle @@ -110,11 +110,7 @@ include 'sechub-cli', 'sechub-pds-tools', // Examples (are below 'sechub-examples' folder) -'sechub-examples:example-sechub-api-java', - -/* Web Server and UI */ -'sechub-web-server', -'sechub-web-server-solution' +'sechub-examples:example-sechub-api-java'