From 613bb08ed90abeada5f25094e8419d898c9fbf28 Mon Sep 17 00:00:00 2001 From: Ludy Date: Mon, 14 Jul 2025 21:53:11 +0200 Subject: [PATCH] refactor: move modules under app/ directory and update file paths (#3938) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description of Changes - **What was changed:** - Renamed top-level directories: `stirling-pdf` → `app/core`, `common` → `app/common`, `proprietary` → `app/proprietary`. - Updated all path references in `.gitattributes`, GitHub workflows (`.github/workflows/*`), scripts (`.github/scripts/*`), `.gitignore`, Dockerfiles, license files, and template settings to reflect the new structure. - Added a new CI job `check-generateOpenApiDocs` to generate and upload OpenAPI documentation. - Removed redundant `@Autowired` annotations from `TempFileShutdownHook` and `UnlockPDFFormsController`. - Minor formatting and comment adjustments in YAML templates and resource files. - **Why the change was made:** - To introduce a clear `app/` directory hierarchy for core, common, and proprietary modules, improving organization and maintainability. - To ensure continuous integration and Docker builds continue to work seamlessly with the reorganized structure. - To automate OpenAPI documentation generation as part of the CI pipeline. --- ## Checklist ### General - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [x] I have performed a self-review of my own code - [x] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details. --- .github/workflows/build.yml | 121 ++---------------- .../AuthenticationFailureException.java | 13 ++ ...tSaml2AuthenticationRequestRepository.java | 0 .../security/saml2/SAML2Configuration.java | 0 .../security/service/JwtService.java | 0 .../security/service/JwtServiceInterface.java | 90 +++++++++++++ ...l2AuthenticationRequestRepositoryTest.java | 0 7 files changed, 114 insertions(+), 110 deletions(-) create mode 100644 app/proprietary/src/main/java/stirling/software/proprietary/security/model/exception/AuthenticationFailureException.java rename {proprietary => app/proprietary}/src/main/java/stirling/software/proprietary/security/saml2/JwtSaml2AuthenticationRequestRepository.java (100%) rename proprietary/src/main/java/stirling/software/proprietary/security/saml2/Saml2Configuration.java => app/proprietary/src/main/java/stirling/software/proprietary/security/saml2/SAML2Configuration.java (100%) rename {proprietary => app/proprietary}/src/main/java/stirling/software/proprietary/security/service/JwtService.java (100%) create mode 100644 app/proprietary/src/main/java/stirling/software/proprietary/security/service/JwtServiceInterface.java rename {proprietary => app/proprietary}/src/test/java/stirling/software/proprietary/security/saml2/JwtSaml2AuthenticationRequestRepositoryTest.java (100%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index db847f570..f00b927c9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,9 +1,8 @@ -name: Build and Test Workflow +name: Build repo on: - workflow_dispatch: - # push: - # branches: ["main"] + push: + branches: ["main"] pull_request: branches: ["main"] @@ -23,24 +22,6 @@ permissions: contents: read jobs: - files-changed: - name: detect what files changed - runs-on: ubuntu-latest - timeout-minutes: 3 - # Map a step output to a job output - outputs: - build: ${{ steps.changes.outputs.build }} - app: ${{ steps.changes.outputs.app }} - project: ${{ steps.changes.outputs.project }} - openapi: ${{ steps.changes.outputs.openapi }} - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - - name: Check for file changes - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 - id: changes - with: - filters: ".github/config/.files.yaml" build: runs-on: ubuntu-latest @@ -56,7 +37,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit @@ -69,11 +50,6 @@ jobs: java-version: ${{ matrix.jdk-version }} distribution: "temurin" - - name: Setup Gradle - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 - with: - gradle-version: 8.14 - - name: Build with Gradle and spring security ${{ matrix.spring-security }} run: ./gradlew clean build env: @@ -124,17 +100,14 @@ jobs: if-no-files-found: warn check-generateOpenApiDocs: - if: needs.files-changed.outputs.openapi == 'true' - needs: [files-changed, build] runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit - - name: Checkout repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up JDK 17 uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 @@ -142,8 +115,7 @@ jobs: java-version: "17" distribution: "temurin" - - name: Setup Gradle - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 + - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 - name: Generate OpenAPI documentation run: ./gradlew :stirling-pdf:generateOpenApiDocs @@ -155,12 +127,10 @@ jobs: path: ./SwaggerDoc.json check-licence: - if: needs.files-changed.outputs.build == 'true' - needs: [files-changed, build] runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit @@ -171,7 +141,7 @@ jobs: uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: java-version: "17" - distribution: "temurin" + distribution: "adopt" - name: check the licenses for compatibility run: ./gradlew clean checkLicense @@ -186,8 +156,6 @@ jobs: retention-days: 3 docker-compose-tests: - if: needs.files-changed.outputs.project == 'true' - needs: files-changed # if: github.event_name == 'push' && github.ref == 'refs/heads/main' || # (github.event_name == 'pull_request' && # contains(github.event.pull_request.labels.*.name, 'licenses') == false && @@ -206,7 +174,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 with: egress-policy: audit @@ -217,7 +185,7 @@ jobs: uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: java-version: "17" - distribution: "temurin" + distribution: "adopt" - name: Set up Docker Buildx uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 @@ -232,7 +200,6 @@ jobs: with: python-version: "3.12" cache: 'pip' # caching pip dependencies - cache-dependency-path: ./testing/cucumber/requirements.txt - name: Pip requirements run: | @@ -244,69 +211,3 @@ jobs: chmod +x ./testing/test.sh chmod +x ./testing/test_disabledEndpoints.sh ./testing/test.sh - - test-build-docker-images: - if: github.event_name == 'pull_request' && needs.files-changed.outputs.project == 'true' - needs: [files-changed, build, check-generateOpenApiDocs, check-licence] - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - docker-rev: ["Dockerfile", "Dockerfile.ultra-lite", "Dockerfile.fat"] - steps: - - name: Harden Runner - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 - with: - egress-policy: audit - - - name: Checkout Repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - - name: Set up JDK 17 - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 - with: - java-version: "17" - distribution: "temurin" - - - name: Set up Gradle - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 - with: - gradle-version: 8.14 - - - name: Build application - run: ./gradlew clean build - env: - DISABLE_ADDITIONAL_FEATURES: true - STIRLING_PDF_DESKTOP_UI: false - - - name: Set up QEMU - uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - - - name: Build ${{ matrix.docker-rev }} - uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 - with: - builder: ${{ steps.buildx.outputs.name }} - context: . - file: ./${{ matrix.docker-rev }} - push: false - cache-from: type=gha - cache-to: type=gha,mode=max - platforms: linux/amd64,linux/arm64/v8 - provenance: true - sbom: true - - - name: Upload Reports - if: always() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: reports-docker-${{ matrix.docker-rev }} - path: | - build/reports/tests/ - build/test-results/ - build/reports/problems/ - retention-days: 3 - if-no-files-found: warn diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/model/exception/AuthenticationFailureException.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/model/exception/AuthenticationFailureException.java new file mode 100644 index 000000000..f2cd5e242 --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/model/exception/AuthenticationFailureException.java @@ -0,0 +1,13 @@ +package stirling.software.proprietary.security.model.exception; + +import org.springframework.security.core.AuthenticationException; + +public class AuthenticationFailureException extends AuthenticationException { + public AuthenticationFailureException(String message) { + super(message); + } + + public AuthenticationFailureException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/JwtSaml2AuthenticationRequestRepository.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/saml2/JwtSaml2AuthenticationRequestRepository.java similarity index 100% rename from proprietary/src/main/java/stirling/software/proprietary/security/saml2/JwtSaml2AuthenticationRequestRepository.java rename to app/proprietary/src/main/java/stirling/software/proprietary/security/saml2/JwtSaml2AuthenticationRequestRepository.java diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/Saml2Configuration.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/saml2/SAML2Configuration.java similarity index 100% rename from proprietary/src/main/java/stirling/software/proprietary/security/saml2/Saml2Configuration.java rename to app/proprietary/src/main/java/stirling/software/proprietary/security/saml2/SAML2Configuration.java diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/service/JwtService.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/service/JwtService.java similarity index 100% rename from proprietary/src/main/java/stirling/software/proprietary/security/service/JwtService.java rename to app/proprietary/src/main/java/stirling/software/proprietary/security/service/JwtService.java diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/service/JwtServiceInterface.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/service/JwtServiceInterface.java new file mode 100644 index 000000000..664d812d8 --- /dev/null +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/service/JwtServiceInterface.java @@ -0,0 +1,90 @@ +package stirling.software.proprietary.security.service; + +import java.util.Map; + +import org.springframework.security.core.Authentication; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +public interface JwtServiceInterface { + + /** + * Generate a JWT token for the authenticated user + * + * @param authentication Spring Security authentication object + * @return JWT token as a string + */ + String generateToken(Authentication authentication, Map claims); + + /** + * Generate a JWT token for a specific username + * + * @param username the username for which to generate the token + * @param claims additional claims to include in the token + * @return JWT token as a string + */ + String generateToken(String username, Map claims); + + /** + * Validate a JWT token + * + * @param token the JWT token to validate + * @return true if token is valid, false otherwise + */ + void validateToken(String token); + + /** + * Extract username from JWT token + * + * @param token the JWT token + * @return username extracted from token + */ + String extractUsername(String token); + + /** + * Extract all claims from JWT token + * + * @param token the JWT token + * @return map of claims + */ + Map extractAllClaims(String token); + + /** + * Check if token is expired + * + * @param token the JWT token + * @return true if token is expired, false otherwise + */ + boolean isTokenExpired(String token); + + /** + * Extract JWT token from HTTP request (header or cookie) + * + * @param request HTTP servlet request + * @return JWT token if found, null otherwise + */ + String extractTokenFromRequest(HttpServletRequest request); + + /** + * Add JWT token to HTTP response (header and cookie) + * + * @param response HTTP servlet response + * @param token JWT token to add + */ + void addTokenToResponse(HttpServletResponse response, String token); + + /** + * Clear JWT token from HTTP response (remove cookie) + * + * @param response HTTP servlet response + */ + void clearTokenFromResponse(HttpServletResponse response); + + /** + * Check if JWT authentication is enabled + * + * @return true if JWT is enabled, false otherwise + */ + boolean isJwtEnabled(); +} diff --git a/proprietary/src/test/java/stirling/software/proprietary/security/saml2/JwtSaml2AuthenticationRequestRepositoryTest.java b/app/proprietary/src/test/java/stirling/software/proprietary/security/saml2/JwtSaml2AuthenticationRequestRepositoryTest.java similarity index 100% rename from proprietary/src/test/java/stirling/software/proprietary/security/saml2/JwtSaml2AuthenticationRequestRepositoryTest.java rename to app/proprietary/src/test/java/stirling/software/proprietary/security/saml2/JwtSaml2AuthenticationRequestRepositoryTest.java