diff --git a/.codecov.yml b/.codecov.yml deleted file mode 100644 index 4a94c8f..0000000 --- a/.codecov.yml +++ /dev/null @@ -1,16 +0,0 @@ -coverage: - precision: 2 - round: down - range: "70...100" - status: - patch: - default: - threshold: 2% - if_no_uploads: error - changes: true - project: - default: - target: auto - threshold: 2% - if_no_uploads: error -comment: false diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 60f116c..63af35e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @auth0/dx-sdks-engineer +* @OpenGov/platform-access-control diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml deleted file mode 100644 index 19ed08d..0000000 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: 🐞 Report a bug -description: Have you found a bug or issue? Create a bug report for this library -labels: ["bug"] - -body: - - type: markdown - attributes: - value: | - **Please do not report security vulnerabilities here**. The [Responsible Disclosure Program](https://auth0.com/responsible-disclosure-policy) details the procedure for disclosing security issues. - - - type: checkboxes - id: checklist - attributes: - label: Checklist - options: - - label: The issue can be reproduced in the [mvc-auth-commons sample app](https://github.com/auth0-samples/auth0-servlet-sample/tree/master/01-Login) (or N/A). - required: true - - label: I have looked into the [Readme](https://github.com/auth0/auth0-java-mvc-common#readme) and the [Examples](https://github.com/auth0/auth0-java-mvc-common/blob/master/EXAMPLES.md), and have not found a suitable solution or answer. - required: true - - label: I have looked into the [API documentation](https://javadoc.io/doc/com.auth0/mvc-auth-commons/latest/index.html) and have not found a suitable solution or answer. - required: true - - label: I have searched the [issues](https://github.com/auth0/auth0-java-mvc-common/issues) and have not found a suitable solution or answer. - required: true - - label: I have searched the [Auth0 Community](https://community.auth0.com) forums and have not found a suitable solution or answer. - required: true - - label: I agree to the terms within the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md). - required: true - - - type: textarea - id: description - attributes: - label: Description - description: Provide a clear and concise description of the issue, including what you expected to happen. - validations: - required: true - - - type: textarea - id: reproduction - attributes: - label: Reproduction - description: Detail the steps taken to reproduce this error, and whether this issue can be reproduced consistently or if it is intermittent. - placeholder: | - 1. Step 1... - 2. Step 2... - 3. ... - validations: - required: true - - - type: textarea - id: additional-context - attributes: - label: Additional context - description: Other libraries that might be involved, or any other relevant information you think would be useful. - validations: - required: false - - - type: input - id: environment-version - attributes: - label: mvc-auth-commons version - validations: - required: true - - - type: input - id: environment-java-version - attributes: - label: Java version - validations: - required: true diff --git a/.github/ISSUE_TEMPLATE/Feature Request.yml b/.github/ISSUE_TEMPLATE/Feature Request.yml deleted file mode 100644 index 1844d7a..0000000 --- a/.github/ISSUE_TEMPLATE/Feature Request.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: 🧩 Feature request -description: Suggest an idea or a feature for this library -labels: ["feature request"] - -body: - - type: checkboxes - id: checklist - attributes: - label: Checklist - options: - - label: I have looked into the [Readme](https://github.com/auth0/auth0-java-mvc-common#readme) and the [Examples](https://github.com/auth0/auth0-java-mvc-common/blob/master/EXAMPLES.md), and have not found a suitable solution or answer. - required: true - - label: I have looked into the [API documentation](https://javadoc.io/doc/com.auth0/mvc-auth-commons/latest/index.html) and have not found a suitable solution or answer. - required: true - - label: I have searched the [issues](https://github.com/auth0/auth0-java-mvc-common/issues) and have not found a suitable solution or answer. - required: true - - label: I have searched the [Auth0 Community](https://community.auth0.com) forums and have not found a suitable solution or answer. - required: true - - label: I agree to the terms within the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md). - required: true - - - type: textarea - id: description - attributes: - label: Describe the problem you'd like to have solved - description: A clear and concise description of what the problem is. - placeholder: I'm always frustrated when... - validations: - required: true - - - type: textarea - id: ideal-solution - attributes: - label: Describe the ideal solution - description: A clear and concise description of what you want to happen. - validations: - required: true - - - type: textarea - id: alternatives-and-workarounds - attributes: - label: Alternatives and current workarounds - description: A clear and concise description of any alternatives you've considered or any workarounds that are currently in place. - validations: - required: false - - - type: textarea - id: additional-context - attributes: - label: Additional context - description: Add any other context or screenshots about the feature request here. - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 65c99a9..0000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,5 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: Auth0 Community - url: https://community.auth0.com - about: Discuss this SDK in the Auth0 Community forums diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 8675fc7..0000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,31 +0,0 @@ -### Changes - -Please describe both what is changing and why this is important. Include: - -- Endpoints added, deleted, deprecated, or changed -- Classes and methods added, deleted, deprecated, or changed -- Screenshots of new or changed UI, if applicable -- A summary of usage if this is a new feature or change to a public API (this should also be added to relevant documentation once released) -- Any alternative designs or approaches considered - -### References - -Please include relevant links supporting this change such as a: - -- support ticket -- community post -- StackOverflow post -- support forum thread - -### Testing - -Please describe how this can be tested by reviewers. Be specific about anything not tested and reasons why. If this library has unit and/or integration testing, tests should be added for new functionality and existing tests should complete without errors. - -- [ ] This change adds test coverage -- [ ] This change has been tested on the latest version of Java or why not - -### Checklist - -- [ ] I have read the [Auth0 general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) -- [ ] I have read the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) -- [ ] All existing and new tests complete without errors diff --git a/.github/actions/get-prerelease/action.yml b/.github/actions/get-prerelease/action.yml deleted file mode 100644 index ce7acdc..0000000 --- a/.github/actions/get-prerelease/action.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Return a boolean indicating if the version contains prerelease identifiers - -# -# Returns a simple true/false boolean indicating whether the version indicates it's a prerelease or not. -# -# TODO: Remove once the common repo is public. -# - -inputs: - version: - required: true - -outputs: - prerelease: - value: ${{ steps.get_prerelease.outputs.PRERELEASE }} - -runs: - using: composite - - steps: - - id: get_prerelease - shell: bash - run: | - if [[ "${VERSION}" == *"beta"* || "${VERSION}" == *"alpha"* ]]; then - echo "PRERELEASE=true" >> $GITHUB_OUTPUT - else - echo "PRERELEASE=false" >> $GITHUB_OUTPUT - fi - env: - VERSION: ${{ inputs.version }} diff --git a/.github/actions/get-release-notes/action.yml b/.github/actions/get-release-notes/action.yml deleted file mode 100644 index 287d206..0000000 --- a/.github/actions/get-release-notes/action.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Return the release notes extracted from the body of the PR associated with the release. - -# -# Returns the release notes from the content of a pull request linked to a release branch. It expects the branch name to be in the format release/vX.Y.Z, release/X.Y.Z, release/vX.Y.Z-beta.N. etc. -# -# TODO: Remove once the common repo is public. -# -inputs: - version: - required: true - repo_name: - required: false - repo_owner: - required: true - token: - required: true - -outputs: - release-notes: - value: ${{ steps.get_release_notes.outputs.RELEASE_NOTES }} - -runs: - using: composite - - steps: - - uses: actions/github-script@v7 - id: get_release_notes - with: - result-encoding: string - script: | - const { data: pulls } = await github.rest.pulls.list({ - owner: process.env.REPO_OWNER, - repo: process.env.REPO_NAME, - state: 'all', - head: `${process.env.REPO_OWNER}:release/${process.env.VERSION}`, - }); - core.setOutput('RELEASE_NOTES', pulls[0].body); - env: - GITHUB_TOKEN: ${{ inputs.token }} - REPO_OWNER: ${{ inputs.repo_owner }} - REPO_NAME: ${{ inputs.repo_name }} - VERSION: ${{ inputs.version }} diff --git a/.github/actions/get-version/action.yml b/.github/actions/get-version/action.yml deleted file mode 100644 index 9440ec9..0000000 --- a/.github/actions/get-version/action.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Return the version extracted from the branch name - -# -# Returns the version from the .version file. -# -# TODO: Remove once the common repo is public. -# - -outputs: - version: - value: ${{ steps.get_version.outputs.VERSION }} - -runs: - using: composite - - steps: - - id: get_version - shell: bash - run: | - VERSION=$(head -1 .version) - echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT diff --git a/.github/actions/maven-publish/action.yml b/.github/actions/maven-publish/action.yml deleted file mode 100644 index ee47706..0000000 --- a/.github/actions/maven-publish/action.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Publish release to Java - -inputs: - ossr-username: - required: true - ossr-password: - required: true - signing-key: - required: true - signing-password: - required: true - java-version: - required: true - is-android: - required: true - version: - required: true - -runs: - using: composite - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Java - shell: bash - run: | - curl -s "https://get.sdkman.io" | bash - source "/home/runner/.sdkman/bin/sdkman-init.sh" - sdk list java - sdk install java ${{ inputs.java-version }} && sdk default java ${{ inputs.java-version }} - - - uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4 # pin@1.1.0 - - - name: Publish Java - shell: bash - if: inputs.is-android == 'false' - run: ./gradlew clean assemble sign publishMavenJavaPublicationToMavenRepository -PisSnapshot=false -Pversion="${{ inputs.version }}" -PossrhUsername="${{ inputs.ossr-username }}" -PossrhPassword="${{ inputs.ossr-password }}" -PsigningKey="${{ inputs.signing-key }}" -PsigningPassword="${{ inputs.signing-password }}" - - - name: Publish Android - shell: bash - if: inputs.is-android == 'true' - run: ./gradlew clean assemble sign publishAndroidLibraryPublicationToMavenRepository -PisSnapshot=false -Pversion="${{ inputs.version }}" -PossrhUsername="${{ inputs.ossr-username }}" -PossrhPassword="${{ inputs.ossr-password }}" -PsigningKey="${{ inputs.signing-key }}" -PsigningPassword="${{ inputs.signing-password }}" diff --git a/.github/actions/release-create/action.yml b/.github/actions/release-create/action.yml deleted file mode 100644 index 6a2bf80..0000000 --- a/.github/actions/release-create/action.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Create a GitHub release - -# -# Creates a GitHub release with the given version. -# -# TODO: Remove once the common repo is public. -# - -inputs: - token: - required: true - files: - required: false - name: - required: true - body: - required: true - tag: - required: true - commit: - required: true - draft: - default: false - required: false - prerelease: - default: false - required: false - fail_on_unmatched_files: - default: true - required: false - -runs: - using: composite - - steps: - - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 - with: - body: ${{ inputs.body }} - name: ${{ inputs.name }} - tag_name: ${{ inputs.tag }} - target_commitish: ${{ inputs.commit }} - draft: ${{ inputs.draft }} - prerelease: ${{ inputs.prerelease }} - fail_on_unmatched_files: ${{ inputs.fail_on_unmatched_files }} - files: ${{ inputs.files }} - env: - GITHUB_TOKEN: ${{ inputs.token }} diff --git a/.github/actions/tag-exists/action.yml b/.github/actions/tag-exists/action.yml deleted file mode 100644 index b5fbdb7..0000000 --- a/.github/actions/tag-exists/action.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Return a boolean indicating if a tag already exists for the repository - -# -# Returns a simple true/false boolean indicating whether the tag exists or not. -# -# TODO: Remove once the common repo is public. -# - -inputs: - token: - required: true - tag: - required: true - -outputs: - exists: - description: 'Whether the tag exists or not' - value: ${{ steps.tag-exists.outputs.EXISTS }} - -runs: - using: composite - - steps: - - id: tag-exists - shell: bash - run: | - GET_API_URL="https://api.github.com/repos/${GITHUB_REPOSITORY}/git/ref/tags/${TAG_NAME}" - http_status_code=$(curl -LI $GET_API_URL -o /dev/null -w '%{http_code}\n' -s -H "Authorization: token ${GITHUB_TOKEN}") - if [ "$http_status_code" -ne "404" ] ; then - echo "EXISTS=true" >> $GITHUB_OUTPUT - else - echo "EXISTS=false" >> $GITHUB_OUTPUT - fi - env: - TAG_NAME: ${{ inputs.tag }} - GITHUB_TOKEN: ${{ inputs.token }} diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index b2e13fc..0000000 --- a/.github/stale.yml +++ /dev/null @@ -1,20 +0,0 @@ -# Configuration for probot-stale - https://github.com/probot/stale - -# Number of days of inactivity before an Issue or Pull Request becomes stale -daysUntilStale: 90 - -# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. -daysUntilClose: 7 - -# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable -exemptLabels: [] - -# Set to true to ignore issues with an assignee (defaults to false) -exemptAssignees: true - -# Label to use when marking as stale -staleLabel: closed:stale - -# Comment to post when marking as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you have not received a response for our team (apologies for the delay) and this is still a blocker, please reply with additional information or just a ping. Thank you for your contribution! 🙇‍♂️ \ No newline at end of file diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml deleted file mode 100644 index 25155e8..0000000 --- a/.github/workflows/build-and-test.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: auth0/auth0-java-mvc-common/build-and-test - -on: - pull_request: - merge_group: - push: - branches: ["master", "main", "v1"] - -jobs: - gradle: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-java@v3 - with: - distribution: temurin - java-version: 8 - - uses: gradle/gradle-build-action@a4cf152f482c7ca97ef56ead29bf08bcd953284c - with: - arguments: assemble apiDiff check jacocoTestReport --continue --console=plain - - uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d - with: - flags: unittests - - uses: actions/upload-artifact@v3 - with: - name: Reports - path: lib/build/reports diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..43bf525 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,37 @@ +name: ci +on: + push: + branches: + - main + pull_request: + branches: + - '*' +jobs: + build: + runs-on: ubuntu-latest + env: + INTERNAL_MAVEN_USER: ${{ secrets.JF_ARTIFACTORY_USER_INTEGRATION }} + INTERNAL_MAVEN_PASS: ${{ secrets.JF_ARTIFACTORY_API_KEY_INTEGRATION }} + steps: + - name: Checkout Repo + uses: actions/checkout@v3 + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17' + - name: Cache Gradle + uses: actions/cache@v3 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Run Linting and Tests + run: ./gradlew check + - name: Run SonarQube + run: ./gradlew sonarqube -Dsonar.host.url='${{ secrets.SONAR_EXTERNAL_URL }}' -Dsonar.login=${{ secrets.SONAR_API_TOKEN }} + - name: Kill Gradle Daemons for caching + run: ./gradlew --stop diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index 8e62d8d..0000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: "CodeQL" - -on: - push: - branches: [ "master", "2.0.0-dev" ] - pull_request: - branches: [ "master" ] - schedule: - - cron: "30 19 * * 6" - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ java ] - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - queries: +security-and-quality - - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 - with: - category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml deleted file mode 100644 index f91f71d..0000000 --- a/.github/workflows/dependabot.yml +++ /dev/null @@ -1,14 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "daily" - - - package-ecosystem: "gradle" - directory: "/" - schedule: - interval: "daily" - ignore: - - dependency-name: "*" - update-types: ["version-update:semver-major"] \ No newline at end of file diff --git a/.github/workflows/java-release.yml b/.github/workflows/java-release.yml deleted file mode 100644 index 3f81eb1..0000000 --- a/.github/workflows/java-release.yml +++ /dev/null @@ -1,88 +0,0 @@ -name: Create Java and GitHub Release - -on: - workflow_call: - inputs: - java-version: - required: true - type: string - is-android: - required: true - type: string - secrets: - ossr-username: - required: true - ossr-password: - required: true - signing-key: - required: true - signing-password: - required: true - github-token: - required: true - -### TODO: Replace instances of './.github/actions/' w/ `auth0/dx-sdk-actions/` and append `@latest` after the common `dx-sdk-actions` repo is made public. -### TODO: Also remove `get-prerelease`, `get-version`, `release-create`, `tag-create` and `tag-exists` actions from this repo's .github/actions folder once the repo is public. - -jobs: - release: - if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.pull_request.merged && startsWith(github.event.pull_request.head.ref, 'release/')) - runs-on: ubuntu-latest - environment: release - - steps: - # Checkout the code - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - # Get the version from the branch name - - id: get_version - uses: ./.github/actions/get-version - - # Get the prerelease flag from the branch name - - id: get_prerelease - uses: ./.github/actions/get-prerelease - with: - version: ${{ steps.get_version.outputs.version }} - - # Get the release notes - - id: get_release_notes - uses: ./.github/actions/get-release-notes - with: - token: ${{ secrets.github-token }} - version: ${{ steps.get_version.outputs.version }} - repo_owner: ${{ github.repository_owner }} - repo_name: ${{ github.event.repository.name }} - - # Check if the tag already exists - - id: tag_exists - uses: ./.github/actions/tag-exists - with: - tag: ${{ steps.get_version.outputs.version }} - token: ${{ secrets.github-token }} - - # If the tag already exists, exit with an error - - if: steps.tag_exists.outputs.exists == 'true' - run: exit 1 - - # Publish the release to Maven - - uses: ./.github/actions/maven-publish - with: - java-version: ${{ inputs.java-version }} - is-android: ${{ inputs.is-android }} - version: ${{ steps.get_version.outputs.version }} - ossr-username: ${{ secrets.ossr-username }} - ossr-password: ${{ secrets.ossr-password }} - signing-key: ${{ secrets.signing-key }} - signing-password: ${{ secrets.signing-password }} - - # Create a release for the tag - - uses: ./.github/actions/release-create - with: - token: ${{ secrets.github-token }} - name: ${{ steps.get_version.outputs.version }} - body: ${{ steps.get_release_notes.outputs.release-notes }} - tag: ${{ steps.get_version.outputs.version }} - commit: ${{ github.sha }} - prerelease: ${{ steps.get_prerelease.outputs.prerelease }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 63482cc..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Create GitHub Release - -on: - pull_request: - types: - - closed - workflow_dispatch: - -permissions: - contents: write - -### TODO: Replace instances of './.github/workflows/' w/ `auth0/dx-sdk-actions/workflows/` and append `@latest` after the common `dx-sdk-actions` repo is made public. -### TODO: Also remove `get-prerelease`, `get-release-notes`, `get-version`, `maven-publish`, `release-create`, and `tag-exists` actions from this repo's .github/actions folder once the repo is public. -### TODO: Also remove `java-release` workflow from this repo's .github/workflows folder once the repo is public. - -jobs: - release: - uses: ./.github/workflows/java-release.yml - with: - java-version: 8.0.382-tem - is-android: false - secrets: - ossr-username: ${{ secrets.OSSR_USERNAME }} - ossr-password: ${{ secrets.OSSR_PASSWORD }} - signing-key: ${{ secrets.SIGNING_KEY }} - signing-password: ${{ secrets.SIGNING_PASSWORD }} - github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml deleted file mode 100644 index e0227e3..0000000 --- a/.github/workflows/semgrep.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Semgrep - -on: - pull_request: {} - - push: - branches: ["master", "main"] - - schedule: - - cron: '30 0 1,15 * *' - -jobs: - semgrep: - name: Scan - runs-on: ubuntu-latest - container: - image: returntocorp/semgrep - if: (github.actor != 'dependabot[bot]') - steps: - - uses: actions/checkout@v3 - - - run: semgrep ci - env: - SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.shiprc b/.shiprc deleted file mode 100644 index edfe142..0000000 --- a/.shiprc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "files": { - "README.md": [], - ".version": [], - "build.gradle": ["version = \"{MAJOR}.{MINOR}.{PATCH}\""] - }, - "prefixVersion": false -} \ No newline at end of file diff --git a/.version b/.version deleted file mode 100644 index 169f19b..0000000 --- a/.version +++ /dev/null @@ -1 +0,0 @@ -1.11.0 \ No newline at end of file diff --git a/EXAMPLES.md b/EXAMPLES.md index 975df40..e318aef 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -96,11 +96,3 @@ AuthenticationController authController = AuthenticationController.newBuilder("Y .build(); ``` -## HTTP logging - -Once you have created the instance of the `AuthenticationController`, you can enable HTTP logging for all Requests and Responses to debug a specific endpoint. -**This will log everything including sensitive information** - do not use it in a production environment. - -```java -authController.setLoggingEnabled(true); -``` diff --git a/LICENSE b/LICENSE deleted file mode 100644 index f7c61ba..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Auth0, Inc. (http://auth0.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md index 1ee3030..a12929a 100644 --- a/README.md +++ b/README.md @@ -1,161 +1 @@ -![Auth0 SDK to add authentication to your Java Servlet applications.](https://cdn.auth0.com/website/sdks/banners/auth0-java-mvc-common-banner.png) - -![Build Status](https://img.shields.io/github/checks-status/auth0/auth0-java-mvc-common/master) -[![Coverage Status](https://img.shields.io/codecov/c/github/auth0/auth0-java-mvc-common.svg?style=flat-square)](https://codecov.io/github/auth0/auth0-java-mvc-common) -[![License](http://img.shields.io/:license-mit-blue.svg?style=flat)](https://doge.mit-license.org/) -[![Maven Central](https://img.shields.io/maven-central/v/com.auth0/mvc-auth-commons.svg?style=flat-square)](https://mvnrepository.com/artifact/com.auth0/mvc-auth-commons) -[![javadoc](https://javadoc.io/badge2/com.auth0/auth0-java-mvc-common/javadoc.svg)](https://javadoc.io/doc/com.auth0/mvc-auth-commons) - -> **Note** -> As part of our ongoing commitment to best security practices, we have rotated the signing keys used to sign previous releases of this SDK. As a result, new patch builds have been released using the new signing key. Please upgrade at your earliest convenience. -> -> While this change won't affect most developers, if you have implemented a dependency signature validation step in your build process, you may notice a warning that past releases can't be verified. This is expected, and a result of the key rotation process. Updating to the latest version will resolve this for you. - -:books: [Documentation](#documentation) - :rocket: [Getting Started](#getting-started) - :computer: [API Reference](#api-reference) :speech_balloon: [Feedback](#feedback) - -## Documentation - -- [Quickstart](https://auth0.com/docs/quickstart/webapp/java) - our interactive guide for quickly adding login, logout and user information to a Java Servlet application using Auth0. -- [Sample App](https://github.com/auth0-samples/auth0-servlet-sample/tree/master/01-Login) - a sample Java Servlet application integrated with Auth0. -- [Examples](./EXAMPLES.md) - code samples for common scenarios. -- [Docs site](https://www.auth0.com/docs) - explore our docs site and learn more about Auth0. - -## Getting Started - -### Requirements - -Java 8 or above and `javax.servlet` version 3. - -> If you are using Spring, we recommend leveraging Spring's OIDC and OAuth2 support, as demonstrated by the [Spring Boot Quickstart](https://auth0.com/docs/quickstart/webapp/java-spring-boot). - -### Installation - -Add the dependency via Maven: - -```xml - - com.auth0 - mvc-auth-commons - 1.11.0 - -``` - -or Gradle: - -```gradle -implementation 'com.auth0:mvc-auth-commons:1.11.0' -``` - -### Configure Auth0 - -Create a **Regular Web Application** in the [Auth0 Dashboard](https://manage.auth0.com/#/applications). Verify that the "Token Endpoint Authentication Method" is set to `POST`. - -Next, configure the callback and logout URLs for your application under the "Application URIs" section of the "Settings" page: - -- **Allowed Callback URLs**: The URL of your application where Auth0 will redirect to during authentication, e.g., `http://localhost:3000/callback`. -- **Allowed Logout URLs**: The URL of your application where Auth0 will redirect to after user logout, e.g., `http://localhost:3000/login`. - -Note the **Domain**, **Client ID**, and **Client Secret**. These values will be used later. - -### Add login to your application - -Create a new `AuthenticationController` using your Auth0 domain, and Auth0 application client ID and secret. -Configure the builder with a `JwkProvider` for your Auth0 domain. - -```java -public class AuthenticationControllerProvider { - private String domain = "YOUR-AUTH0-DOMAIN"; - private String clientId = "YOUR-CLIENT-ID"; - private String clientSecret = "YOUR-CLIENT-SECRET"; - - private AuthenticationController authenticationController; - - static { - JwkProvider jwkProvider = new JwkProviderBuilder("YOUR-AUTH0-DOMAIN").build(); - authenticationController = AuthenticationController.newBuilder(domain, clientId, clientSecret) - .withJwkProvider(jwkProvider) - .build(); - } - - public getInstance() { - return authenticationController; - } -} -``` - -> Note: The `AuthenticationController.Builder` is not to be reused, and an `IllegalStateException` will be thrown if `build()` is called more than once. - -Redirect users to the Auth0 login page using the `AuthenticationController`: - -```java -@WebServlet(urlPatterns = {"/login"}) -public class LoginServlet extends HttpServlet { - - @Override - protected void doGet(final HttpServletRequest req, final HttpServletResponse res) throws ServletException, IOException { - // Where your application will handle the authoriztion callback - String redirectUrl = "http://localhost:3000/callback"; - - String authorizeUrl = AuthenticationControllerProvider - .getInstance() - .buildAuthorizeUrl(req, res, redirectUrl) - .build(); - res.sendRedirect(authorizeUrl); - } -} -``` - -Finally, complete the authentication and obtain the tokens by calling `handle()` on the `AuthenticationController`. - -```java -@WebServlet(urlPatterns = {"/callback"}) -public class CallbackServlet extends HttpServlet { - - @Override - public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { - try { - // authentication complete; the tokens can be stored as needed - Tokens tokens = AuthenticationControllerProvider - .getInstance() - .handle(req, res); - res.sendRedirect("URL-AFTER-AUTHENTICATED"); - } catch (IdentityVerificationException e) { - // handle authentication error - } - } -} -``` - -That's it! You have authenticated the user using Auth0. - -## API Reference - -- [JavaDocs](https://javadoc.io/doc/com.auth0/mvc-auth-commons) - -## Feedback - -### Contributing - -We appreciate feedback and contribution to this repo! Before you get started, please see the following: - -- [Auth0's general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) -- [Auth0's code of conduct guidelines](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) - -### Raise an issue -To provide feedback or report a bug, [please raise an issue on our issue tracker](https://github.com/auth0/auth0-java-mvc-common/issues). - -### Vulnerability Reporting -Please do not report security vulnerabilities on the public Github issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues. - ---- - -

- - - - Auth0 Logo - -

-

Auth0 is an easy to implement, adaptable authentication and authorization platform. To learn more checkout Why Auth0?

-

-This project is licensed under the MIT license. See the LICENSE file for more info.

+Clone of https://github.com/auth0/auth0-java-mvc-common/ as they wouldn't update their Servlet versions to use `jakarta` instead of `javax` \ No newline at end of file diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 74eefe1..0000000 --- a/build.gradle +++ /dev/null @@ -1,94 +0,0 @@ -plugins { - id 'java' - id 'jacoco' - id 'com.auth0.gradle.oss-library.java' -} - -repositories { - mavenCentral() -} - -group 'com.auth0' - -logger.lifecycle("Using version ${version} for ${name} group $group") - -def signingKey = findProperty('signingKey') -def signingKeyPwd = findProperty('signingPassword') - -oss { - name 'mvc-auth-commons' - repository 'auth0-java-mvc-common' - organization 'auth0' - description 'Java library that simplifies the use of Auth0 for server-side MVC web apps' - baselineCompareVersion '1.5.0' - skipAssertSigningConfiguration true - - developers { - auth0 { - displayName = 'Auth0' - email = 'oss@auth0.com' - } - lbalmaceda { - displayName = 'Luciano Balmaceda' - email = 'luciano.balmaceda@auth0.com' - } - } -} - -signing { - useInMemoryPgpKeys(signingKey, signingKeyPwd) -} - -jacocoTestReport { - reports { - xml.enabled = true - html.enabled = true - } -} - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(8) - } - // Needed because of broken gradle metadata, see https://github.com/google/guava/issues/6612#issuecomment-1614992368 - sourceSets.all { - configurations.getByName(runtimeClasspathConfigurationName) { - attributes.attribute(Attribute.of("org.gradle.jvm.environment", String), "standard-jvm") - } - configurations.getByName(compileClasspathConfigurationName) { - attributes.attribute(Attribute.of("org.gradle.jvm.environment", String), "standard-jvm") - } - } -} - -compileJava { - sourceCompatibility '1.8' - targetCompatibility '1.8' -} - -test { - useJUnitPlatform() - testLogging { - events "skipped", "failed" - exceptionFormat "short" - } -} - -dependencies { - implementation 'javax.servlet:javax.servlet-api:3.1.0' - implementation 'org.apache.commons:commons-lang3:3.12.0' - implementation 'com.google.guava:guava-annotations:r03' - implementation 'commons-codec:commons-codec:1.15' - - api 'com.auth0:auth0:1.45.1' - api 'com.auth0:java-jwt:3.19.4' - api 'com.auth0:jwks-rsa:0.22.1' - - testImplementation 'org.bouncycastle:bcprov-jdk15on:1.64' - testImplementation 'org.hamcrest:java-hamcrest:2.0.0.0' - testImplementation 'org.hamcrest:hamcrest-core:1.3' - testImplementation 'org.mockito:mockito-core:2.8.9' - testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1' - testImplementation 'org.springframework:spring-test:4.3.14.RELEASE' - testImplementation 'com.squareup.okhttp3:okhttp:4.11.0' -} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..5542fe9 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + id("org.sonarqube") +} + +tasks.wrapper { + gradleVersion = "8.7" +} \ No newline at end of file diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 0000000..16c21ed --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,20 @@ +plugins { + `kotlin-dsl` +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +repositories { + gradlePluginPortal() +} + +dependencies { + implementation("com.diffplug.spotless:spotless-plugin-gradle:6.25.0") + implementation("net.ltgt.gradle:gradle-errorprone-plugin:3.1.0") + implementation("org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:4.0.0.2929") + implementation("pl.allegro.tech.build:axion-release-plugin:1.17.0") +} diff --git a/buildSrc/src/main/kotlin/java-common-conventions.gradle.kts b/buildSrc/src/main/kotlin/java-common-conventions.gradle.kts new file mode 100644 index 0000000..846dc81 --- /dev/null +++ b/buildSrc/src/main/kotlin/java-common-conventions.gradle.kts @@ -0,0 +1,68 @@ +import net.ltgt.gradle.errorprone.errorprone + +plugins { + java + jacoco + id("com.diffplug.spotless") + id("net.ltgt.errorprone") + id("org.sonarqube") +} + +repositories { + mavenCentral() //TODO: Remove this once we have all packages cached by Artifactory + maven { + url = uri("https://artifactory.opengov.zone:443/artifactory/maven-all/") + credentials { + username = System.getenv("INTERNAL_MAVEN_USER") + password = System.getenv("INTERNAL_MAVEN_PASS") + } + } +} + +jacoco { + toolVersion = "0.8.8" +} + + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +dependencies { + errorprone("com.google.errorprone:error_prone_core:2.26.1") + testImplementation("org.junit.jupiter:junit-jupiter:5.10.2") +} + + +spotless { + java { + googleJavaFormat("1.15.0") + } +} + + +// Disabled this as a lot of stuff is deprecated +//tasks.withType { +// options.compilerArgs.addAll(listOf("-Xlint:unchecked", "-Xlint:deprecation", "-Werror")) +// options.errorprone.isEnabled.set(false) +// options.errorprone.disable("SameNameButDifferent", "MissingSummary", "JavaTimeDefaultTimeZone", "ObjectEqualsForPrimitives", "AlmostJavadoc","UnusedVariable") +//} + +tasks.named("check") { + dependsOn("spotlessCheck") +} + +tasks.withType { + useJUnitPlatform() + finalizedBy("jacocoTestReport") +} + +tasks.jacocoTestReport { + reports { + xml.required.set(true) + csv.required.set(true) + html.outputLocation.set(layout.buildDirectory.dir("jacocoHtml")) + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..4257286 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,5 @@ +org.gradle.jvmargs=--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ + --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \ + --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \ + --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \ + --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c..e644113 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6499169..b82aa23 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4f906e0..1aa94a4 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,99 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +119,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,88 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index ac1b06f..7101f8e 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,13 +41,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/main/build.gradle.kts b/main/build.gradle.kts new file mode 100644 index 0000000..6c4b7f2 --- /dev/null +++ b/main/build.gradle.kts @@ -0,0 +1,63 @@ +plugins { + id("java-common-conventions") + id("maven-publish") + id("pl.allegro.tech.build.axion-release") +} + +dependencies { + implementation("org.springframework.boot:spring-boot-starter-webflux:3.2.5") + + implementation("jakarta.servlet:jakarta.servlet-api:6.0.0") + implementation("org.apache.commons:commons-lang3:3.12.0") + implementation("com.google.guava:guava-annotations:r03") + implementation("commons-codec:commons-codec:1.15") + + implementation("com.auth0:auth0:2.12.0") + implementation("com.auth0:java-jwt:3.19.4") + implementation("com.auth0:jwks-rsa:0.22.1") + + testImplementation("org.bouncycastle:bcprov-jdk18on:1.78.1") + testImplementation("org.hamcrest:hamcrest:2.2") + testImplementation("org.mockito:mockito-core:5.12.0") + testImplementation("org.junit.jupiter:junit-jupiter:5.10.2") + testImplementation("org.springframework:spring-test:6.1.8") + testImplementation("com.squareup.okhttp3:okhttp:4.12.0") +} + +version = "1.0.1-SNAPSHOT" + +publishing { + publications { + create("mavenJava") { + groupId = "com.opengov" + artifactId = "opengov-auth0-mvc-auth-commons" + from(components["java"]) + } + } + repositories { + maven { + val releasesRepoUrl = uri("https://artifactory.opengov.zone:443/artifactory/maven-release-local/") + val snapshotsRepoUrl = uri("https://artifactory.opengov.zone:443/artifactory/maven-snapshot-local/") + url = if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl + credentials { + username = System.getenv("INTERNAL_MAVEN_PUBLISH_USER") + password = System.getenv("INTERNAL_MAVEN_PUBLISH_PASS") + } + } + } +} + +tasks.jacocoTestReport { + finalizedBy("jacocoTestCoverageVerification") +} + +tasks.jacocoTestCoverageVerification { + violationRules { + rule { + limit { + counter = "INSTRUCTION" + minimum = "0.15".toBigDecimal() + } + } + } +} diff --git a/src/main/java/com/auth0/AlgorithmNameVerifier.java b/main/src/main/java/com/auth0/AlgorithmNameVerifier.java similarity index 100% rename from src/main/java/com/auth0/AlgorithmNameVerifier.java rename to main/src/main/java/com/auth0/AlgorithmNameVerifier.java diff --git a/src/main/java/com/auth0/AsymmetricSignatureVerifier.java b/main/src/main/java/com/auth0/AsymmetricSignatureVerifier.java similarity index 99% rename from src/main/java/com/auth0/AsymmetricSignatureVerifier.java rename to main/src/main/java/com/auth0/AsymmetricSignatureVerifier.java index b8b82b4..07cff11 100644 --- a/src/main/java/com/auth0/AsymmetricSignatureVerifier.java +++ b/main/src/main/java/com/auth0/AsymmetricSignatureVerifier.java @@ -7,7 +7,6 @@ import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.RSAKeyProvider; - import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; diff --git a/src/main/java/com/auth0/AuthCookie.java b/main/src/main/java/com/auth0/AuthCookie.java similarity index 99% rename from src/main/java/com/auth0/AuthCookie.java rename to main/src/main/java/com/auth0/AuthCookie.java index f82cdb0..bbfc925 100644 --- a/src/main/java/com/auth0/AuthCookie.java +++ b/main/src/main/java/com/auth0/AuthCookie.java @@ -1,10 +1,9 @@ package com.auth0; -import org.apache.commons.lang3.Validate; - import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import org.apache.commons.lang3.Validate; /** * Represents a cookie to be used for transfer of authentiction-based data such as state and nonce. diff --git a/src/main/java/com/auth0/AuthenticationController.java b/main/src/main/java/com/auth0/AuthenticationController.java similarity index 70% rename from src/main/java/com/auth0/AuthenticationController.java rename to main/src/main/java/com/auth0/AuthenticationController.java index 1aed380..0c1a4fe 100644 --- a/src/main/java/com/auth0/AuthenticationController.java +++ b/main/src/main/java/com/auth0/AuthenticationController.java @@ -3,12 +3,10 @@ import com.auth0.client.HttpOptions; import com.auth0.client.auth.AuthAPI; import com.auth0.jwk.JwkProvider; -import com.auth0.net.Telemetry; import com.google.common.annotations.VisibleForTesting; import org.apache.commons.lang3.Validate; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; /** @@ -196,8 +194,7 @@ public Builder withInvitation(String invitation) { * @throws UnsupportedOperationException if the Implicit Grant is chosen and the environment doesn't support UTF-8 encoding. */ public AuthenticationController build() throws UnsupportedOperationException { - AuthAPI apiClient = createAPIClient(domain, clientId, clientSecret, httpOptions); - setupTelemetry(apiClient); + AuthAPI apiClient = createAPIClient(domain, clientId, clientSecret, null); final boolean expectedAlgorithmIsExplicitlySetAndAsymmetric = jwkProvider != null; final SignatureVerifier signatureVerifier; @@ -214,15 +211,9 @@ public AuthenticationController build() throws UnsupportedOperationException { String issuer = getIssuer(domain); IdTokenVerifier.Options verifyOptions = createIdTokenVerificationOptions(issuer, clientId, signatureVerifier); - verifyOptions.setClockSkew(clockSkew); - verifyOptions.setMaxAge(authenticationMaxAge); - verifyOptions.setOrganization(this.organization); RequestProcessor processor = new RequestProcessor.Builder(apiClient, responseType, verifyOptions) .withLegacySameSiteCookie(useLegacySameSiteCookie) - .withOrganization(organization) - .withInvitation(invitation) - .withCookiePath(cookiePath) .build(); return new AuthenticationController(processor); @@ -242,9 +233,8 @@ AuthAPI createAPIClient(String domain, String clientId, String clientSecret, Htt } @VisibleForTesting - void setupTelemetry(AuthAPI client) { - Telemetry telemetry = new Telemetry("auth0-java-mvc-common", obtainPackageVersion()); - client.setTelemetry(telemetry); + AuthAPI createAPIClient(String domain, String clientId, String clientSecret) { + return new AuthAPI(domain, clientId, clientSecret, null); } @VisibleForTesting @@ -265,22 +255,6 @@ private String getIssuer(String domain) { } } - /** - * Whether to enable or not the HTTP Logger for every Request and Response. - * Enabling this can expose sensitive information. - * - * @param enabled whether to enable the HTTP logger or not. - */ - public void setLoggingEnabled(boolean enabled) { - requestProcessor.getClient().setLoggingEnabled(enabled); - } - - /** - * Disable sending the Telemetry header on every request to the Auth0 API - */ - public void doNotSendTelemetry() { - requestProcessor.getClient().doNotSendTelemetry(); - } /** * Process a request to obtain a set of {@link Tokens} that represent successful authentication or authorization. @@ -289,99 +263,51 @@ public void doNotSendTelemetry() { * authentication-related request parameters, handle performing a Code Exchange request if using * the "code" response type, and verify the integrity of the ID token (if present). * - *

Important: When using this API, you must also use {@link AuthenticationController#buildAuthorizeUrl(HttpServletRequest, HttpServletResponse, String)} + *

Important: When using this API, you must also use the {@link AuthenticationController#buildAuthorizeUrl(ServerWebExchange, String)} * when building the {@link AuthorizeUrl} that the user will be redirected to to login. Failure to do so may result * in a broken login experience for the user.

* - * @param request the received request to process. - * @param response the received response to process. - * @return the Tokens obtained after the user authentication. - * @throws InvalidRequestException if the error is result of making an invalid authentication request. - * @throws IdentityVerificationException if an error occurred while verifying the request tokens. - */ - public Tokens handle(HttpServletRequest request, HttpServletResponse response) throws IdentityVerificationException { - Validate.notNull(request, "request must not be null"); - Validate.notNull(response, "response must not be null"); - - return requestProcessor.process(request, response); - } - - /** - * Process a request to obtain a set of {@link Tokens} that represent successful authentication or authorization. - * - * This method should be called when processing the callback request to your application. It will validate - * authentication-related request parameters, handle performing a Code Exchange request if using - * the "code" response type, and verify the integrity of the ID token (if present). - * - *

Important: When using this API, you must also use the {@link AuthenticationController#buildAuthorizeUrl(HttpServletRequest, String)} - * when building the {@link AuthorizeUrl} that the user will be redirected to to login. Failure to do so may result - * in a broken login experience for the user.

- * - * @deprecated This method uses the {@link javax.servlet.http.HttpSession} for auth-based data, and is incompatible + * @deprecated This method uses the {@link jakarta.servlet.http.HttpSession} for auth-based data, and is incompatible * with clients that are using the "id_token" or "token" responseType with browsers that enforce SameSite cookie * restrictions. This method will be removed in version 2.0.0. Use - * {@link AuthenticationController#handle(HttpServletRequest, HttpServletResponse)} instead. + * {@link AuthenticationController#handle(ServerWebExchange)} instead. * - * @param request the received request to process. + * @param serverWebExchange the received serverWebExchange to process. * @return the Tokens obtained after the user authentication. * @throws InvalidRequestException if the error is result of making an invalid authentication request. * @throws IdentityVerificationException if an error occurred while verifying the request tokens. */ @Deprecated - public Tokens handle(HttpServletRequest request) throws IdentityVerificationException { - Validate.notNull(request, "request must not be null"); + public Mono handle(ServerWebExchange serverWebExchange) { + Validate.notNull(serverWebExchange, "serverWebExchange must not be null"); - return requestProcessor.process(request, null); + return requestProcessor.process(serverWebExchange); } /** * Pre builds an Auth0 Authorize Url with the given redirect URI using a random state and a random nonce if applicable. * *

Important: When using this API, you must also obtain the tokens using the - * {@link AuthenticationController#handle(HttpServletRequest)} method. Failure to do so may result in a broken login + * {@link AuthenticationController#handle(ServerWebExchange)} method. Failure to do so may result in a broken login * experience for users.

* - * @deprecated This method stores data in the {@link javax.servlet.http.HttpSession}, and is incompatible with clients + * @deprecated This method stores data in the {@link jakarta.servlet.http.HttpSession}, and is incompatible with clients * that are using the "id_token" or "token" responseType with browsers that enforce SameSite cookie restrictions. * This method will be removed in version 2.0.0. Use - * {@link AuthenticationController#buildAuthorizeUrl(HttpServletRequest, HttpServletResponse, String)} instead. + * {@link AuthenticationController#buildAuthorizeUrl(ServerWebExchange, String)} instead. * - * @param request the caller request. Used to keep the session context. + * @param serverWebExchange the caller serverWebExchange. Used to keep the session context. * @param redirectUri the url to call back with the authentication result. * @return the authorize url builder to continue any further parameter customization. */ @Deprecated - public AuthorizeUrl buildAuthorizeUrl(HttpServletRequest request, String redirectUri) { - Validate.notNull(request, "request must not be null"); + public AuthorizeUrl buildAuthorizeUrl(ServerWebExchange serverWebExchange, String redirectUri) { + Validate.notNull(serverWebExchange, "serverWebExchange must not be null"); Validate.notNull(redirectUri, "redirectUri must not be null"); String state = StorageUtils.secureRandomString(); String nonce = StorageUtils.secureRandomString(); - return requestProcessor.buildAuthorizeUrl(request, null, redirectUri, state, nonce); + return requestProcessor.buildAuthorizeUrl(serverWebExchange, redirectUri, state, nonce); } - - /** - * Pre builds an Auth0 Authorize Url with the given redirect URI using a random state and a random nonce if applicable. - * - *

Important: When using this API, you must also obtain the tokens using the - * {@link AuthenticationController#handle(HttpServletRequest, HttpServletResponse)} method. Failure to do so will result in a broken login - * experience for users.

- * - * @param request the HTTP request - * @param response the HTTP response. Used to store auth-based cookies. - * @param redirectUri the url to call back with the authentication result. - * @return the authorize url builder to continue any further parameter customization. - */ - public AuthorizeUrl buildAuthorizeUrl(HttpServletRequest request, HttpServletResponse response, String redirectUri) { - Validate.notNull(request, "request must not be null"); - Validate.notNull(response, "response must not be null"); - Validate.notNull(redirectUri, "redirectUri must not be null"); - - String state = StorageUtils.secureRandomString(); - String nonce = StorageUtils.secureRandomString(); - - return requestProcessor.buildAuthorizeUrl(request, response, redirectUri, state, nonce); - } - } diff --git a/src/main/java/com/auth0/AuthorizeUrl.java b/main/src/main/java/com/auth0/AuthorizeUrl.java similarity index 71% rename from src/main/java/com/auth0/AuthorizeUrl.java rename to main/src/main/java/com/auth0/AuthorizeUrl.java index e871ca6..e79423d 100644 --- a/src/main/java/com/auth0/AuthorizeUrl.java +++ b/main/src/main/java/com/auth0/AuthorizeUrl.java @@ -1,15 +1,22 @@ package com.auth0; +import static com.auth0.IdentityVerificationException.API_ERROR; + import com.auth0.client.auth.AuthAPI; import com.auth0.client.auth.AuthorizeUrlBuilder; import com.auth0.exception.Auth0Exception; import com.auth0.json.auth.PushedAuthorizationResponse; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.util.*; - -import static com.auth0.IdentityVerificationException.API_ERROR; +import com.auth0.net.Response; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.springframework.http.server.reactive.AbstractServerHttpResponse; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; /** * Class to create and customize an Auth0 Authorize URL. @@ -20,8 +27,7 @@ public class AuthorizeUrl { private static final String SCOPE_OPENID = "openid"; - private HttpServletResponse response; - private HttpServletRequest request; + private ServerWebExchange serverWebExchange; private final String responseType; private boolean useLegacySameSiteCookie = true; private boolean setSecureCookie = false; @@ -37,20 +43,18 @@ public class AuthorizeUrl { /** * Creates a new instance that can be used to build an Auth0 Authorization URL. * - * Using this constructor with a non-null {@link HttpServletResponse} will store the state and nonce as + * Using this constructor with a non-null {@link AbstractServerHttpResponse} will store the state and nonce as * cookies when the {@link AuthorizeUrl#build()} method is called, with the appropriate SameSite attribute depending - * on the responseType. State and nonce will also be stored in the {@link javax.servlet.http.HttpSession} as a fallback, + * on the responseType. State and nonce will also be stored in the {@link jakarta.servlet.http.HttpSession} as a fallback, * but this behavior will be removed in a future release, and only cookies will be used. * * @param client the Auth0 Authentication API client * @parem request the HTTP request. Used to store state and nonce as a fallback if cookies not set. - * @param response the response where the state and nonce will be stored as cookies * @param redirectUri the url to redirect to after authentication * @param responseType the response type to use */ - AuthorizeUrl(AuthAPI client, HttpServletRequest request, HttpServletResponse response, String redirectUri, String responseType) { - this.request = request; - this.response = response; + AuthorizeUrl(AuthAPI client, ServerWebExchange serverWebExchange, String redirectUri, String responseType) { + this.serverWebExchange = serverWebExchange; this.responseType = responseType; this.authAPI = client; this.redirectUri = redirectUri; @@ -111,7 +115,7 @@ public AuthorizeUrl withSecureCookie(boolean secureCookie) { /** * Sets whether a fallback cookie should be used for clients that do not support "SameSite=None". - * Only applicable when this instance is created with {@link AuthorizeUrl#AuthorizeUrl(AuthAPI, HttpServletRequest, HttpServletResponse, String, String)}. + * Only applicable when this instance is created with {@link AuthorizeUrl#AuthorizeUrl(AuthAPI, ServerWebExchange, String, String)}. * * @param useLegacySameSiteCookie whether or not to set fallback auth cookies for clients that do not support "SameSite=None" * @return the builder instance @@ -205,11 +209,13 @@ public AuthorizeUrl withParameter(String name, String value) { * @return the string URL * @throws IllegalStateException if it's called more than once */ - public String build() throws IllegalStateException { - storeTransient(); - AuthorizeUrlBuilder builder = authAPI.authorizeUrl(redirectUri).withResponseType(responseType); - params.forEach(builder::withParameter); - return builder.build(); + public Mono build() throws IllegalStateException { + return storeTransient() + .then(Mono.fromCallable(() -> { + AuthorizeUrlBuilder builder = authAPI.authorizeUrl(redirectUri).withResponseType(responseType); + params.forEach(builder::withParameter); + return builder.build(); + })); } /** @@ -220,29 +226,35 @@ public String build() throws IllegalStateException { * @throws InvalidRequestException if there is an error when making the request. * @see RFC 9126 */ - public String fromPushedAuthorizationRequest() throws InvalidRequestException { - storeTransient(); - - try { - PushedAuthorizationResponse pushedAuthResponse = authAPI.pushedAuthorizationRequest(redirectUri, responseType, params).execute(); - String requestUri = pushedAuthResponse.getRequestURI(); - if (requestUri == null || requestUri.isEmpty()) { - throw new InvalidRequestException(API_ERROR, "The PAR request returned a missing or empty request_uri value"); - } - if (pushedAuthResponse.getExpiresIn() == null) { - throw new InvalidRequestException(API_ERROR, "The PAR request returned a missing expires_in value"); - } - return authAPI.authorizeUrlWithPAR(pushedAuthResponse.getRequestURI()); - } catch (Auth0Exception e) { - throw new InvalidRequestException(API_ERROR, e.getMessage(), e); - } + public Mono fromPushedAuthorizationRequest() throws InvalidRequestException { + return storeTransient() + .then(Mono.fromCallable(() -> { + try { + Response pushedAuthResponse = authAPI.pushedAuthorizationRequest(redirectUri, responseType, params).execute(); + if (pushedAuthResponse == null || pushedAuthResponse.getBody() == null) { + throw new InvalidRequestException(API_ERROR, "The PAR request returned a missing or empty response"); + } + String requestUri = pushedAuthResponse.getBody().getRequestURI(); + if (requestUri == null || requestUri.isEmpty()) { + throw new InvalidRequestException(API_ERROR, "The PAR request returned a missing or empty request_uri value"); + } + if (pushedAuthResponse.getBody().getExpiresIn() == null) { + throw new InvalidRequestException(API_ERROR, "The PAR request returned a missing expires_in value"); + } + return authAPI.authorizeUrlWithPAR(pushedAuthResponse.getBody().getRequestURI()); + } catch (Auth0Exception e) { + throw new InvalidRequestException(API_ERROR, e.getMessage(), e); + } + })); } - private void storeTransient() { + private Mono storeTransient() { if (used) { throw new IllegalStateException("The AuthorizeUrl instance must not be reused."); } + ServerHttpResponse response = serverWebExchange.getResponse(); + ServerHttpRequest request = serverWebExchange.getRequest(); if (response != null) { SameSite sameSiteValue = containsFormPost() ? SameSite.NONE : SameSite.LAX; @@ -250,12 +262,12 @@ private void storeTransient() { TransientCookieStore.storeNonce(response, nonce, sameSiteValue, useLegacySameSiteCookie, setSecureCookie, cookiePath); } - // Also store in Session just in case developer uses deprecated - // AuthenticationController.handle(HttpServletRequest) API - RandomStorage.setSessionState(request, state); - RandomStorage.setSessionNonce(request, nonce); - - used = true; + return Mono.fromCallable(() -> RandomStorage.setSessionState(serverWebExchange, state)) + .flatMap(webSessionMono -> RandomStorage.setSessionNonce(serverWebExchange, nonce)) + .flatMap(webSessionMono -> { + used = true; + return Mono.empty(); + }); } private boolean containsFormPost() { diff --git a/src/main/java/com/auth0/IdTokenVerifier.java b/main/src/main/java/com/auth0/IdTokenVerifier.java similarity index 99% rename from src/main/java/com/auth0/IdTokenVerifier.java rename to main/src/main/java/com/auth0/IdTokenVerifier.java index d163e71..96a47e3 100644 --- a/src/main/java/com/auth0/IdTokenVerifier.java +++ b/main/src/main/java/com/auth0/IdTokenVerifier.java @@ -1,11 +1,10 @@ package com.auth0; import com.auth0.jwt.interfaces.DecodedJWT; -import org.apache.commons.lang3.Validate; - import java.util.Calendar; import java.util.Date; import java.util.List; +import org.apache.commons.lang3.Validate; /** * Token verification utility class. diff --git a/src/main/java/com/auth0/IdentityVerificationException.java b/main/src/main/java/com/auth0/IdentityVerificationException.java similarity index 100% rename from src/main/java/com/auth0/IdentityVerificationException.java rename to main/src/main/java/com/auth0/IdentityVerificationException.java diff --git a/src/main/java/com/auth0/InvalidRequestException.java b/main/src/main/java/com/auth0/InvalidRequestException.java similarity index 100% rename from src/main/java/com/auth0/InvalidRequestException.java rename to main/src/main/java/com/auth0/InvalidRequestException.java diff --git a/main/src/main/java/com/auth0/RandomStorage.java b/main/src/main/java/com/auth0/RandomStorage.java new file mode 100644 index 0000000..033addc --- /dev/null +++ b/main/src/main/java/com/auth0/RandomStorage.java @@ -0,0 +1,56 @@ +package com.auth0; + + +import jakarta.servlet.http.HttpSession; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebSession; +import reactor.core.publisher.Mono; + +class RandomStorage extends SessionUtils { + + /** + * Check's if the request {@link HttpSession} saved state is equal to the given state. + * After the check, the value will be removed from the session. + * + * @param exchange the serverWebExchange + * @param state the state value to compare against. + * @return whether the state matches the expected one or not. + */ + static Mono checkSessionState(ServerWebExchange exchange, String state) { + return remove(exchange, StorageUtils.STATE_KEY) + .map(currentState -> ((currentState == null && state == null) || currentState != null && currentState.equals(state))); + } + + /** + * Saves the given state in the request {@link HttpSession}. + * If a state is already bound to the session, the value is replaced. + * + * @param exchange the serverWebExchange. + * @param state the state value to set. + */ + static Mono setSessionState(ServerWebExchange exchange, String state) { + return set(exchange, StorageUtils.STATE_KEY, state); + } + + /** + * Saves the given nonce in the request {@link HttpSession}. + * If a nonce is already bound to the session, the value is replaced. + * + * @param exchange the serverWebExchange. + * @param nonce the nonce value to set. + */ + static Mono setSessionNonce(ServerWebExchange exchange, String nonce) { + return set(exchange, StorageUtils.NONCE_KEY, nonce); + } + + /** + * Removes the nonce present in the request {@link HttpSession} and then returns it. + * + * @param exchange the serverWebExchange. + * @return the nonce value or null if it was not set. + */ + static Mono removeSessionNonce(ServerWebExchange exchange) { + return remove(exchange, StorageUtils.NONCE_KEY) + .map(nonce -> nonce != null ? nonce.toString() : null); + } +} \ No newline at end of file diff --git a/src/main/java/com/auth0/RequestProcessor.java b/main/src/main/java/com/auth0/RequestProcessor.java similarity index 66% rename from src/main/java/com/auth0/RequestProcessor.java rename to main/src/main/java/com/auth0/RequestProcessor.java index 6796982..b39f903 100644 --- a/src/main/java/com/auth0/RequestProcessor.java +++ b/main/src/main/java/com/auth0/RequestProcessor.java @@ -1,16 +1,22 @@ package com.auth0; +import static com.auth0.InvalidRequestException.API_ERROR; +import static com.auth0.InvalidRequestException.INVALID_STATE_ERROR; +import static com.auth0.InvalidRequestException.JWT_VERIFICATION_ERROR; +import static com.auth0.InvalidRequestException.MISSING_ACCESS_TOKEN; +import static com.auth0.InvalidRequestException.MISSING_ID_TOKEN; + import com.auth0.client.auth.AuthAPI; import com.auth0.exception.Auth0Exception; import com.auth0.json.auth.TokenHolder; -import org.apache.commons.lang3.Validate; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import com.auth0.net.Response; import java.util.Arrays; import java.util.List; - -import static com.auth0.InvalidRequestException.*; +import org.apache.commons.lang3.Validate; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; /** * Main class to handle the Authorize Redirect request. @@ -121,17 +127,16 @@ AuthAPI getClient() { /** * Pre builds an Auth0 Authorize Url with the given redirect URI, state and nonce parameters. * - * @param request the request, used to store state and nonce in the Session - * @param response the response, used to set state and nonce as cookies. If null, session will be used instead. + * @param serverWebExchange the serverWebExchange, used to store state and nonce in the Session * @param redirectUri the url to call with the authentication result. * @param state a valid state value. * @param nonce the nonce value that will be used if the response type contains 'id_token'. Can be null. * @return the authorize url builder to continue any further parameter customization. */ - AuthorizeUrl buildAuthorizeUrl(HttpServletRequest request, HttpServletResponse response, String redirectUri, + AuthorizeUrl buildAuthorizeUrl(ServerWebExchange serverWebExchange, String redirectUri, String state, String nonce) { - AuthorizeUrl creator = new AuthorizeUrl(client, request, response, redirectUri, responseType) + AuthorizeUrl creator = new AuthorizeUrl(client, serverWebExchange, redirectUri, responseType) .withState(state); if (this.organization != null) { @@ -145,7 +150,7 @@ AuthorizeUrl buildAuthorizeUrl(HttpServletRequest request, HttpServletResponse r } // null response means state and nonce will be stored in session, so legacy cookie flag does not apply - if (response != null) { + if (serverWebExchange.getResponse() != null) { creator.withLegacySameSiteCookie(useLegacySameSiteCookie); } @@ -162,20 +167,27 @@ AuthorizeUrl buildAuthorizeUrl(HttpServletRequest request, HttpServletResponse r * 4). Clearing the stored state, nonce and max_age values. * 5). Handling success and any failure outcomes. * - * @throws IdentityVerificationException if an error occurred while processing the request */ - Tokens process(HttpServletRequest request, HttpServletResponse response) throws IdentityVerificationException { - assertNoError(request); - assertValidState(request, response); + Mono process(ServerWebExchange serverWebExchange) { + + ServerHttpRequest request = serverWebExchange.getRequest(); + ServerHttpResponse response = serverWebExchange.getResponse(); + + return assertNoError(request) + .then(assertValidState(serverWebExchange)) + .then(getTokens(serverWebExchange, request, response)); + } + private Mono getTokens(ServerWebExchange serverWebExchange, + ServerHttpRequest request, ServerHttpResponse response) { Tokens frontChannelTokens = getFrontChannelTokens(request); List responseTypeList = getResponseType(); if (responseTypeList.contains(KEY_ID_TOKEN) && frontChannelTokens.getIdToken() == null) { - throw new InvalidRequestException(MISSING_ID_TOKEN, "ID Token is missing from the response."); + return Mono.error(new InvalidRequestException(MISSING_ID_TOKEN, "ID Token is missing from the response.")); } if (responseTypeList.contains(KEY_TOKEN) && frontChannelTokens.getAccessToken() == null) { - throw new InvalidRequestException(MISSING_ACCESS_TOKEN, "Access Token is missing from the response."); + return Mono.error(new InvalidRequestException(MISSING_ACCESS_TOKEN, "Access Token is missing from the response.")); } String nonce; @@ -185,15 +197,24 @@ Tokens process(HttpServletRequest request, HttpServletResponse response) throws // Just in case the developer created the authorizeUrl that stores state/nonce in the session if (nonce == null) { - nonce = RandomStorage.removeSessionNonce(request); + return RandomStorage.removeSessionNonce(serverWebExchange) + .flatMap(newNonce -> { + verifyOptions.setNonce(newNonce); + return getVerifiedTokens(serverWebExchange, frontChannelTokens, + responseTypeList); + }); + } else { + verifyOptions.setNonce(nonce); + return getVerifiedTokens(serverWebExchange, frontChannelTokens, responseTypeList); } } else { - nonce = RandomStorage.removeSessionNonce(request); + return RandomStorage.removeSessionNonce(serverWebExchange) + .flatMap(newNonce -> { + verifyOptions.setNonce(newNonce); + return getVerifiedTokens(serverWebExchange, frontChannelTokens, + responseTypeList); + }); } - - verifyOptions.setNonce(nonce); - - return getVerifiedTokens(request, frontChannelTokens, responseTypeList); } static boolean requiresFormPostResponseMode(List responseType) { @@ -203,16 +224,15 @@ static boolean requiresFormPostResponseMode(List responseType) { /** * Obtains code request tokens (if using Code flow) and validates the ID token. - * @param request the HTTP request + * @param exchange the ServerWebExchange * @param frontChannelTokens the tokens obtained from the front channel * @param responseTypeList the reponse types * @return a Tokens object that wraps the values obtained from the front-channel and/or the code request response. - * @throws IdentityVerificationException */ - private Tokens getVerifiedTokens(HttpServletRequest request, Tokens frontChannelTokens, List responseTypeList) - throws IdentityVerificationException { + private Mono getVerifiedTokens(ServerWebExchange exchange, Tokens frontChannelTokens, List responseTypeList) { + ServerHttpRequest request = exchange.getRequest(); - String authorizationCode = request.getParameter(KEY_CODE); + String authorizationCode = request.getQueryParams().getFirst(KEY_CODE); Tokens codeExchangeTokens = null; try { @@ -222,7 +242,7 @@ private Tokens getVerifiedTokens(HttpServletRequest request, Tokens frontChannel } if (responseTypeList.contains(KEY_CODE)) { // Code/Hybrid flow - String redirectUri = request.getRequestURL().toString(); + String redirectUri = request.getURI().toString(); codeExchangeTokens = exchangeCodeForTokens(authorizationCode, redirectUri); if (!responseTypeList.contains(KEY_ID_TOKEN)) { // If we already verified the front-channel token, don't verify it again. @@ -233,9 +253,9 @@ private Tokens getVerifiedTokens(HttpServletRequest request, Tokens frontChannel } } } catch (TokenValidationException e) { - throw new IdentityVerificationException(JWT_VERIFICATION_ERROR, "An error occurred while trying to verify the ID Token.", e); + return Mono.error(new IdentityVerificationException(JWT_VERIFICATION_ERROR, "An error occurred while trying to verify the ID Token.", e)); } catch (Auth0Exception e) { - throw new IdentityVerificationException(API_ERROR, "An error occurred while exchanging the authorization code.", e); + return Mono.error(new IdentityVerificationException(API_ERROR, "An error occurred while exchanging the authorization code.", e)); } // Keep the front-channel ID Token and the code-exchange Access Token. return mergeTokens(frontChannelTokens, codeExchangeTokens); @@ -265,9 +285,9 @@ private AuthorizeUrl getAuthorizeUrl(String nonce, AuthorizeUrl creator) { * @param request the request * @return a new instance of Tokens wrapping the values present in the request parameters. */ - private Tokens getFrontChannelTokens(HttpServletRequest request) { - Long expiresIn = request.getParameter(KEY_EXPIRES_IN) == null ? null : Long.parseLong(request.getParameter(KEY_EXPIRES_IN)); - return new Tokens(request.getParameter(KEY_ACCESS_TOKEN), request.getParameter(KEY_ID_TOKEN), null, request.getParameter(KEY_TOKEN_TYPE), expiresIn); + private Tokens getFrontChannelTokens(ServerHttpRequest request) { + Long expiresIn = request.getQueryParams().getFirst(KEY_EXPIRES_IN) == null ? null : Long.parseLong(request.getQueryParams().getFirst(KEY_EXPIRES_IN)); + return new Tokens(request.getQueryParams().getFirst(KEY_ACCESS_TOKEN), request.getQueryParams().getFirst(KEY_ID_TOKEN), null, request.getQueryParams().getFirst(KEY_TOKEN_TYPE), expiresIn); } /** @@ -276,38 +296,35 @@ private Tokens getFrontChannelTokens(HttpServletRequest request) { * @param request the request * @throws InvalidRequestException if the request contains an error */ - private void assertNoError(HttpServletRequest request) throws InvalidRequestException { - String error = request.getParameter(KEY_ERROR); + private Mono assertNoError(ServerHttpRequest request) { + String error = request.getQueryParams().getFirst(KEY_ERROR); if (error != null) { - String errorDescription = request.getParameter(KEY_ERROR_DESCRIPTION); - throw new InvalidRequestException(error, errorDescription); + String errorDescription = request.getQueryParams().getFirst(KEY_ERROR_DESCRIPTION); + return Mono.error(new InvalidRequestException(error, errorDescription)); } + return Mono.empty(); } /** * Checks whether the state received in the request parameters is the same as the one in the state cookie or session * for this request. * - * @param request the request + * @param serverWebExchange the serverWebExchange * @throws InvalidRequestException if the request contains a different state from the expected one */ - private void assertValidState(HttpServletRequest request, HttpServletResponse response) throws InvalidRequestException { - // TODO in v2: - // - only store state/nonce in cookies, remove session storage - // - create specific exception classes for various state validation failures (missing from auth response, missing - // state cookie, mismatch) - - String stateFromRequest = request.getParameter(KEY_STATE); + private Mono assertValidState(ServerWebExchange serverWebExchange) { + ServerHttpRequest request = serverWebExchange.getRequest(); + ServerHttpResponse response = serverWebExchange.getResponse(); + String stateFromRequest = request.getQueryParams().getFirst(KEY_STATE); if (stateFromRequest == null) { - throw new InvalidRequestException(INVALID_STATE_ERROR, "The received state doesn't match the expected one. No state parameter was found on the authorization response."); + return Mono.error(new InvalidRequestException(INVALID_STATE_ERROR, "The received state doesn't match the expected one. No state parameter was found on the authorization response.")); } // If response is null, check the Session. // This can happen when the deprecated handle method that only takes the request parameter is called if (response == null) { - checkSessionState(request, stateFromRequest); - return; + return checkSessionState(serverWebExchange, stateFromRequest); } String cookieState = TransientCookieStore.getState(request, response); @@ -315,23 +332,30 @@ private void assertValidState(HttpServletRequest request, HttpServletResponse re // Just in case state was stored in Session by building auth URL with deprecated method, but then called the // supported handle method with the request and response if (cookieState == null) { - if (SessionUtils.get(request, StorageUtils.STATE_KEY) == null) { - throw new InvalidRequestException(INVALID_STATE_ERROR, "The received state doesn't match the expected one. No state cookie or state session attribute found. Check that you are using non-deprecated methods and that cookies are not being removed on the server."); - } - checkSessionState(request, stateFromRequest); - return; + return SessionUtils.get(serverWebExchange, StorageUtils.STATE_KEY) + .flatMap(state -> { + if (state == null) { + return Mono.error(new InvalidRequestException(INVALID_STATE_ERROR, "The received state doesn't match the expected one. No state cookie or state session attribute found. Check that you are using non-deprecated methods and that cookies are not being removed on the server.")); + } + return checkSessionState(serverWebExchange, stateFromRequest); + }); } if (!cookieState.equals(stateFromRequest)) { - throw new InvalidRequestException(INVALID_STATE_ERROR, "The received state doesn't match the expected one."); + return Mono.error(new InvalidRequestException(INVALID_STATE_ERROR, "The received state doesn't match the expected one.")); } + + return Mono.empty(); } - private void checkSessionState(HttpServletRequest request, String stateFromRequest) throws InvalidRequestException { - boolean valid = RandomStorage.checkSessionState(request, stateFromRequest); - if (!valid) { - throw new InvalidRequestException(INVALID_STATE_ERROR, "The received state doesn't match the expected one."); - } + private Mono checkSessionState(ServerWebExchange serverWebExchange, String stateFromRequest) { + return RandomStorage.checkSessionState(serverWebExchange, stateFromRequest) + .flatMap(valid -> { + if (!valid) { + return Mono.error(new InvalidRequestException(INVALID_STATE_ERROR, "The received state doesn't match the expected one.")); + } + return Mono.empty(); + }); } /** @@ -344,9 +368,10 @@ private void checkSessionState(HttpServletRequest request, String stateFromReque * @see AuthAPI#exchangeCode(String, String) */ private Tokens exchangeCodeForTokens(String authorizationCode, String redirectUri) throws Auth0Exception { - TokenHolder holder = client + Response tokenHolderResponse = client .exchangeCode(authorizationCode, redirectUri) .execute(); + TokenHolder holder = tokenHolderResponse.getBody(); return new Tokens(holder.getAccessToken(), holder.getIdToken(), holder.getRefreshToken(), holder.getTokenType(), holder.getExpiresIn()); } @@ -358,9 +383,9 @@ private Tokens exchangeCodeForTokens(String authorizationCode, String redirectUr * @param codeExchangeTokens the code-exchange obtained tokens. * @return a merged version of Tokens using the best tokens when possible. */ - private Tokens mergeTokens(Tokens frontChannelTokens, Tokens codeExchangeTokens) { + private Mono mergeTokens(Tokens frontChannelTokens, Tokens codeExchangeTokens) { if (codeExchangeTokens == null) { - return frontChannelTokens; + return Mono.just(frontChannelTokens); } // Prefer access token from the code exchange @@ -384,7 +409,7 @@ private Tokens mergeTokens(Tokens frontChannelTokens, Tokens codeExchangeTokens) // Refresh token only available from the code exchange String refreshToken = codeExchangeTokens.getRefreshToken(); - return new Tokens(accessToken, idToken, refreshToken, type, expiresIn); + return Mono.just(new Tokens(accessToken, idToken, refreshToken, type, expiresIn)); } } \ No newline at end of file diff --git a/src/main/java/com/auth0/SameSite.java b/main/src/main/java/com/auth0/SameSite.java similarity index 92% rename from src/main/java/com/auth0/SameSite.java rename to main/src/main/java/com/auth0/SameSite.java index f714d74..fc3059b 100644 --- a/src/main/java/com/auth0/SameSite.java +++ b/main/src/main/java/com/auth0/SameSite.java @@ -10,7 +10,7 @@ enum SameSite { NONE("None"), STRICT("Strict"); - private String value; + private final String value; String getValue() { return this.value; diff --git a/main/src/main/java/com/auth0/SessionUtils.java b/main/src/main/java/com/auth0/SessionUtils.java new file mode 100644 index 0000000..b926b3e --- /dev/null +++ b/main/src/main/java/com/auth0/SessionUtils.java @@ -0,0 +1,69 @@ +package com.auth0; + +import org.apache.commons.lang3.Validate; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebSession; +import reactor.core.publisher.Mono; + +/** + * Helper class to handle easy session key-value storage. + */ +@SuppressWarnings({"WeakerAccess", "unused"}) +public abstract class SessionUtils { + + /** + * Extracts the HttpSession from the given request. + * + * @param serverWebExchange a valid request to get the session from + * @return the session of the request + */ + protected static Mono getSession(ServerWebExchange serverWebExchange) { + return serverWebExchange.getSession(); + } + + /** + * Set's the attribute value to the request session. + * + * @param serverWebExchange a valid request to get the session from + * @param name the name of the attribute + * @param value the value to set + */ + public static Mono set(ServerWebExchange serverWebExchange, String name, Object value) { + Validate.notNull(serverWebExchange); + Validate.notNull(name); + return serverWebExchange.getSession().map(session -> { + session.getAttributes().put(name, value); + return session; + }); + } + + /** + * Get the attribute with the given name from the request session. + * + * @param serverWebExchange a valid request to get the session from + * @param name the name of the attribute + * @return the attribute stored in the session or null if it doesn't exists + */ + public static Mono get(ServerWebExchange serverWebExchange, String name) { + Validate.notNull(serverWebExchange); + Validate.notNull(name); + + return serverWebExchange.getSession() + .map(session -> session.getAttributes().get(name)); + } + + /** + * Same as {@link #get(ServerWebExchange, String)} but it also removes the value from the request session. + * + * @param serverWebExchange a valid request to get the session from + * @param name the name of the attribute + * @return the attribute stored in the session or null if it doesn't exists + */ + public static Mono remove(ServerWebExchange serverWebExchange, String name) { + Validate.notNull(serverWebExchange); + Validate.notNull(name); + Object value = get(serverWebExchange, name); + return serverWebExchange.getSession() + .map(session -> session.getAttributes().remove(name)); + } +} diff --git a/src/main/java/com/auth0/SignatureVerifier.java b/main/src/main/java/com/auth0/SignatureVerifier.java similarity index 99% rename from src/main/java/com/auth0/SignatureVerifier.java rename to main/src/main/java/com/auth0/SignatureVerifier.java index 3d41df0..4d25415 100644 --- a/src/main/java/com/auth0/SignatureVerifier.java +++ b/main/src/main/java/com/auth0/SignatureVerifier.java @@ -6,10 +6,9 @@ import com.auth0.jwt.exceptions.JWTVerificationException; import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.interfaces.DecodedJWT; -import org.apache.commons.lang3.Validate; - import java.util.Arrays; import java.util.List; +import org.apache.commons.lang3.Validate; abstract class SignatureVerifier { diff --git a/src/main/java/com/auth0/StorageUtils.java b/main/src/main/java/com/auth0/StorageUtils.java similarity index 99% rename from src/main/java/com/auth0/StorageUtils.java rename to main/src/main/java/com/auth0/StorageUtils.java index 162d4d3..af206b0 100644 --- a/src/main/java/com/auth0/StorageUtils.java +++ b/main/src/main/java/com/auth0/StorageUtils.java @@ -1,8 +1,7 @@ package com.auth0; -import org.apache.commons.codec.binary.Base64; - import java.security.SecureRandom; +import org.apache.commons.codec.binary.Base64; class StorageUtils { diff --git a/src/main/java/com/auth0/SymmetricSignatureVerifier.java b/main/src/main/java/com/auth0/SymmetricSignatureVerifier.java similarity index 100% rename from src/main/java/com/auth0/SymmetricSignatureVerifier.java rename to main/src/main/java/com/auth0/SymmetricSignatureVerifier.java diff --git a/src/main/java/com/auth0/TokenValidationException.java b/main/src/main/java/com/auth0/TokenValidationException.java similarity index 100% rename from src/main/java/com/auth0/TokenValidationException.java rename to main/src/main/java/com/auth0/TokenValidationException.java diff --git a/src/main/java/com/auth0/Tokens.java b/main/src/main/java/com/auth0/Tokens.java similarity index 100% rename from src/main/java/com/auth0/Tokens.java rename to main/src/main/java/com/auth0/Tokens.java diff --git a/src/main/java/com/auth0/TransientCookieStore.java b/main/src/main/java/com/auth0/TransientCookieStore.java similarity index 64% rename from src/main/java/com/auth0/TransientCookieStore.java rename to main/src/main/java/com/auth0/TransientCookieStore.java index df5dd3c..5557c41 100644 --- a/src/main/java/com/auth0/TransientCookieStore.java +++ b/main/src/main/java/com/auth0/TransientCookieStore.java @@ -1,13 +1,15 @@ package com.auth0; -import org.apache.commons.lang3.Validate; - -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; +import java.util.List; +import org.apache.commons.lang3.Validate; +import org.springframework.http.HttpCookie; +import org.springframework.http.ResponseCookie; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.util.MultiValueMap; /** * Allows storage and retrieval/removal of cookies. @@ -27,7 +29,7 @@ private TransientCookieStore() {} * @param useLegacySameSiteCookie whether to set a fallback cookie or not * @param isSecureCookie whether to always set the Secure cookie attribute or not */ - static void storeState(HttpServletResponse response, String state, SameSite sameSite, boolean useLegacySameSiteCookie, boolean isSecureCookie, String cookiePath) { + static void storeState(ServerHttpResponse response, String state, SameSite sameSite, boolean useLegacySameSiteCookie, boolean isSecureCookie, String cookiePath) { store(response, StorageUtils.STATE_KEY, state, sameSite, useLegacySameSiteCookie, isSecureCookie, cookiePath); } @@ -40,7 +42,7 @@ static void storeState(HttpServletResponse response, String state, SameSite same * @param useLegacySameSiteCookie whether to set a fallback cookie or not * @param isSecureCookie whether to always set the Secure cookie attribute or not */ - static void storeNonce(HttpServletResponse response, String nonce, SameSite sameSite, boolean useLegacySameSiteCookie, boolean isSecureCookie, String cookiePath) { + static void storeNonce(ServerHttpResponse response, String nonce, SameSite sameSite, boolean useLegacySameSiteCookie, boolean isSecureCookie, String cookiePath) { store(response, StorageUtils.NONCE_KEY, nonce, sameSite, useLegacySameSiteCookie, isSecureCookie, cookiePath); } @@ -51,7 +53,7 @@ static void storeNonce(HttpServletResponse response, String nonce, SameSite same * @param response the response object * @return the value of the state cookie, if it exists */ - static String getState(HttpServletRequest request, HttpServletResponse response) { + static String getState(ServerHttpRequest request, ServerHttpResponse response) { return getOnce(StorageUtils.STATE_KEY, request, response); } @@ -62,11 +64,11 @@ static String getState(HttpServletRequest request, HttpServletResponse response) * @param response the response object * @return the value of the nonce cookie, if it exists */ - static String getNonce(HttpServletRequest request, HttpServletResponse response) { + static String getNonce(ServerHttpRequest request, ServerHttpResponse response) { return getOnce(StorageUtils.NONCE_KEY, request, response); } - private static void store(HttpServletResponse response, String key, String value, SameSite sameSite, boolean useLegacySameSiteCookie, boolean isSecureCookie, String cookiePath) { + private static void store(ServerHttpResponse response, String key, String value, SameSite sameSite, boolean useLegacySameSiteCookie, boolean isSecureCookie, String cookiePath) { Validate.notNull(response, "response must not be null"); Validate.notNull(key, "key must not be null"); Validate.notNull(sameSite, "sameSite must not be null"); @@ -85,28 +87,30 @@ private static void store(HttpServletResponse response, String key, String value } // Servlet Cookie API does not yet support setting the SameSite attribute, so just set cookie on header - response.addHeader("Set-Cookie", sameSiteCookie.buildHeaderString()); + response.getHeaders().add("Set-Cookie", sameSiteCookie.buildHeaderString()); // set legacy fallback cookie (if configured) for clients that won't accept SameSite=None if (isSameSiteNone && useLegacySameSiteCookie) { AuthCookie legacyCookie = new AuthCookie("_" + key, value); legacyCookie.setSecure(isSecureCookie); - response.addHeader("Set-Cookie", legacyCookie.buildHeaderString()); + response.getHeaders().add("Set-Cookie", legacyCookie.buildHeaderString()); } } - private static String getOnce(String cookieName, HttpServletRequest request, HttpServletResponse response) { - Cookie[] requestCookies = request.getCookies(); + private static String getOnce(String cookieName, ServerHttpRequest request, ServerHttpResponse response) { + MultiValueMap requestCookies = request.getCookies(); if (requestCookies == null) { return null; } - Cookie foundCookie = null; - for (Cookie c : requestCookies) { - if (cookieName.equals(c.getName())) { - foundCookie = c; - break; + HttpCookie foundCookie = null; + for (List cs : requestCookies.values()) { + for (HttpCookie c : cs) { + if (cookieName.equals(c.getName())) { + foundCookie = c; + break; + } } } @@ -116,11 +120,13 @@ private static String getOnce(String cookieName, HttpServletRequest request, Htt delete(foundCookie, response); } - Cookie foundLegacyCookie = null; - for (Cookie c : requestCookies) { - if (("_" + cookieName).equals(c.getName())) { - foundLegacyCookie = c; - break; + HttpCookie foundLegacyCookie = null; + for (List cs : requestCookies.values()) { + for (HttpCookie c : cs) { + if (("_" + cookieName).equals(c.getName())) { + foundLegacyCookie = c; + break; + } } } @@ -133,10 +139,12 @@ private static String getOnce(String cookieName, HttpServletRequest request, Htt return foundCookieVal != null ? foundCookieVal : foundLegacyCookieVal; } - private static void delete(Cookie cookie, HttpServletResponse response) { - cookie.setMaxAge(0); - cookie.setValue(""); - response.addCookie(cookie); + private static void delete(HttpCookie cookie, ServerHttpResponse response) { + ResponseCookie newCookie = ResponseCookie.from(cookie.getName(), "") + .maxAge(0) + .build(); + response.getCookies() + .add(cookie.getName(), newCookie); } private static String decode(String valueToDecode) { diff --git a/src/test/java/com/auth0/AuthenticationControllerTest.java b/main/src/test/java/com/auth0/AuthenticationControllerTest.java similarity index 84% rename from src/test/java/com/auth0/AuthenticationControllerTest.java rename to main/src/test/java/com/auth0/AuthenticationControllerTest.java index 25302f0..66bbabb 100644 --- a/src/test/java/com/auth0/AuthenticationControllerTest.java +++ b/main/src/test/java/com/auth0/AuthenticationControllerTest.java @@ -1,12 +1,32 @@ package com.auth0; -import com.auth0.client.HttpOptions; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.everyItem; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.auth0.client.auth.AuthAPI; import com.auth0.client.auth.AuthorizeUrlBuilder; import com.auth0.json.auth.TokenHolder; import com.auth0.jwk.JwkProvider; -import com.auth0.net.Telemetry; +import com.auth0.net.Response; import com.auth0.net.TokenRequest; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @@ -16,16 +36,6 @@ import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.util.List; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.*; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.*; - @SuppressWarnings("deprecated") public class AuthenticationControllerTest { @@ -45,105 +55,11 @@ public void setUp() { AuthenticationController.Builder builder = AuthenticationController.newBuilder("domain", "clientId", "clientSecret"); builderSpy = spy(builder); - doReturn(client).when(builderSpy).createAPIClient(eq("domain"), eq("clientId"), eq("clientSecret"), eq(null)); + doReturn(client).when(builderSpy).createAPIClient(eq("domain"), eq("clientId"), eq("clientSecret")); doReturn(verificationOptions).when(builderSpy).createIdTokenVerificationOptions(eq("https://domain/"), eq("clientId"), signatureVerifierCaptor.capture()); doReturn("1.2.3").when(builderSpy).obtainPackageVersion(); } - @Test - public void shouldSetupClientWithTelemetry() { - AuthenticationController controller = builderSpy.build(); - - ArgumentCaptor telemetryCaptor = ArgumentCaptor.forClass(Telemetry.class); - - assertThat(controller, is(notNullValue())); - RequestProcessor requestProcessor = controller.getRequestProcessor(); - assertThat(requestProcessor.getClient(), is(client)); - verify(client).setTelemetry(telemetryCaptor.capture()); - - Telemetry capturedTelemetry = telemetryCaptor.getValue(); - assertThat(capturedTelemetry, is(notNullValue())); - assertThat(capturedTelemetry.getName(), is("auth0-java-mvc-common")); - assertThat(capturedTelemetry.getVersion(), is("1.2.3")); - } - - @Test - public void shouldCreateAuthAPIClientWithoutCustomHttpOptions() { - ArgumentCaptor captor = ArgumentCaptor.forClass(HttpOptions.class); - AuthenticationController.Builder spy = spy(AuthenticationController.newBuilder("domain", "clientId", "clientSecret")); - - spy.build(); - verify(spy).createAPIClient(eq("domain"), eq("clientId"), eq("clientSecret"), captor.capture()); - - HttpOptions actual = captor.getValue(); - assertThat(actual, is(nullValue())); - - } - - @Test - public void shouldCreateAuthAPIClientWithCustomHttpOptions() { - HttpOptions options = new HttpOptions(); - options.setConnectTimeout(5); - options.setReadTimeout(6); - - ArgumentCaptor captor = ArgumentCaptor.forClass(HttpOptions.class); - AuthenticationController.Builder spy = spy(AuthenticationController.newBuilder("domain", "clientId", "clientSecret") - .withHttpOptions(options)); - - spy.build(); - verify(spy).createAPIClient(eq("domain"), eq("clientId"), eq("clientSecret"), captor.capture()); - - HttpOptions actual = captor.getValue(); - assertThat(actual, is(notNullValue())); - assertThat(actual.getConnectTimeout(), is(5)); - assertThat(actual.getReadTimeout(), is(6)); - } - - @Test - public void shouldDisableTelemetry() { - AuthenticationController controller = builderSpy.build(); - controller.doNotSendTelemetry(); - - verify(client).doNotSendTelemetry(); - } - - @Test - public void shouldEnableLogging() { - AuthenticationController controller = builderSpy.build(); - - controller.setLoggingEnabled(true); - verify(client).setLoggingEnabled(true); - } - - @Test - public void shouldDisableLogging() { - AuthenticationController controller = builderSpy.build(); - - controller.setLoggingEnabled(true); - verify(client).setLoggingEnabled(true); - } - - @Test - public void shouldCreateWithSymmetricSignatureVerifierForNoCodeGrants() { - AuthenticationController controller = builderSpy - .withResponseType("id_token") - .build(); - - SignatureVerifier signatureVerifier = signatureVerifierCaptor.getValue(); - assertThat(signatureVerifier, is(notNullValue())); - assertThat(signatureVerifier, instanceOf(SymmetricSignatureVerifier.class)); - assertThat(verificationOptions, is(controller.getRequestProcessor().verifyOptions)); - - controller = builderSpy - .withResponseType("token") - .build(); - - signatureVerifier = signatureVerifierCaptor.getValue(); - assertThat(signatureVerifier, is(notNullValue())); - assertThat(signatureVerifier, instanceOf(SymmetricSignatureVerifier.class)); - assertThat(verificationOptions, is(controller.getRequestProcessor().verifyOptions)); - } - @Test public void shouldCreateWithAsymmetricSignatureVerifierWhenJwkProviderIsExplicitlySet() { JwkProvider jwkProvider = mock(JwkProvider.class); @@ -402,7 +318,6 @@ public void shouldSetLaxCookiesAndNoLegacyCookieWhenCodeFlow() { MockHttpServletResponse response = new MockHttpServletResponse(); AuthenticationController controller = AuthenticationController.newBuilder("domain", "clientId", "clientSecret") - .withResponseType("code") .build(); controller.buildAuthorizeUrl(new MockHttpServletRequest(), response, "https://redirect.uri/here") @@ -463,8 +378,10 @@ public void shouldCheckSessionFallbackWhenHandleCalledWithRequestAndResponse() t AuthenticationController controller = builderSpy.withResponseType("code").build(); TokenRequest codeExchangeRequest = mock(TokenRequest.class); + Response tokenHolderResponse = mock(Response.class); TokenHolder tokenHolder = mock(TokenHolder.class); - when(codeExchangeRequest.execute()).thenReturn(tokenHolder); + when(tokenHolderResponse.getBody()).thenReturn(tokenHolder); + when(codeExchangeRequest.execute()).thenReturn(tokenHolderResponse); when(client.exchangeCode("abc123", "http://localhost")).thenReturn(codeExchangeRequest); AuthorizeUrlBuilder mockBuilder = mock(AuthorizeUrlBuilder.class); @@ -496,11 +413,13 @@ public void shouldCheckSessionFallbackWhenHandleCalledWithRequestAndResponse() t @Test public void shouldCheckSessionFallbackWhenHandleCalledWithRequest() throws Exception { - AuthenticationController controller = builderSpy.withResponseType("code").build(); + AuthenticationController controller = builderSpy.build(); TokenRequest codeExchangeRequest = mock(TokenRequest.class); + Response tokenHolderResponse = mock(Response.class); TokenHolder tokenHolder = mock(TokenHolder.class); - when(codeExchangeRequest.execute()).thenReturn(tokenHolder); + when(tokenHolderResponse.getBody()).thenReturn(tokenHolder); + when(codeExchangeRequest.execute()).thenReturn(tokenHolderResponse); when(client.exchangeCode("abc123", "http://localhost")).thenReturn(codeExchangeRequest); AuthorizeUrlBuilder mockBuilder = mock(AuthorizeUrlBuilder.class); diff --git a/src/test/java/com/auth0/AuthorizeUrlTest.java b/main/src/test/java/com/auth0/AuthorizeUrlTest.java similarity index 97% rename from src/test/java/com/auth0/AuthorizeUrlTest.java rename to main/src/test/java/com/auth0/AuthorizeUrlTest.java index 5818265..bc7a956 100644 --- a/src/test/java/com/auth0/AuthorizeUrlTest.java +++ b/main/src/test/java/com/auth0/AuthorizeUrlTest.java @@ -1,29 +1,33 @@ package com.auth0; +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.auth0.client.HttpOptions; import com.auth0.client.auth.AuthAPI; import com.auth0.exception.Auth0Exception; import com.auth0.json.auth.PushedAuthorizationResponse; import com.auth0.net.Request; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.util.Collection; +import java.util.Map; import okhttp3.HttpUrl; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.util.Collection; -import java.util.Map; - -import static org.hamcrest.CoreMatchers.*; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - public class AuthorizeUrlTest { private AuthAPI client; diff --git a/src/test/java/com/auth0/IdTokenVerifierTest.java b/main/src/test/java/com/auth0/IdTokenVerifierTest.java similarity index 99% rename from src/test/java/com/auth0/IdTokenVerifierTest.java rename to main/src/test/java/com/auth0/IdTokenVerifierTest.java index ced54c7..e6ebb3d 100644 --- a/src/test/java/com/auth0/IdTokenVerifierTest.java +++ b/main/src/test/java/com/auth0/IdTokenVerifierTest.java @@ -1,18 +1,17 @@ package com.auth0; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.DecodedJWT; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - import java.util.Calendar; import java.util.Date; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class IdTokenVerifierTest { diff --git a/src/test/java/com/auth0/IdentityVerificationExceptionMatcher.java b/main/src/test/java/com/auth0/IdentityVerificationExceptionMatcher.java similarity index 100% rename from src/test/java/com/auth0/IdentityVerificationExceptionMatcher.java rename to main/src/test/java/com/auth0/IdentityVerificationExceptionMatcher.java diff --git a/src/test/java/com/auth0/IdentityVerificationExceptionTest.java b/main/src/test/java/com/auth0/IdentityVerificationExceptionTest.java similarity index 100% rename from src/test/java/com/auth0/IdentityVerificationExceptionTest.java rename to main/src/test/java/com/auth0/IdentityVerificationExceptionTest.java index 0f70c4f..b11b893 100644 --- a/src/test/java/com/auth0/IdentityVerificationExceptionTest.java +++ b/main/src/test/java/com/auth0/IdentityVerificationExceptionTest.java @@ -1,12 +1,12 @@ package com.auth0; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.core.Is.is; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; import static org.mockito.Mockito.mock; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + public class IdentityVerificationExceptionTest { private Throwable cause; private IdentityVerificationException exception; diff --git a/src/test/java/com/auth0/InvalidRequestExceptionMatcher.java b/main/src/test/java/com/auth0/InvalidRequestExceptionMatcher.java similarity index 100% rename from src/test/java/com/auth0/InvalidRequestExceptionMatcher.java rename to main/src/test/java/com/auth0/InvalidRequestExceptionMatcher.java diff --git a/src/test/java/com/auth0/InvalidRequestExceptionTest.java b/main/src/test/java/com/auth0/InvalidRequestExceptionTest.java similarity index 100% rename from src/test/java/com/auth0/InvalidRequestExceptionTest.java rename to main/src/test/java/com/auth0/InvalidRequestExceptionTest.java index e513d58..2905a51 100644 --- a/src/test/java/com/auth0/InvalidRequestExceptionTest.java +++ b/main/src/test/java/com/auth0/InvalidRequestExceptionTest.java @@ -1,11 +1,11 @@ package com.auth0; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.hamcrest.core.Is.is; -import static org.hamcrest.MatcherAssert.assertThat; - public class InvalidRequestExceptionTest { private InvalidRequestException exception; diff --git a/src/test/java/com/auth0/RandomStorageTest.java b/main/src/test/java/com/auth0/RandomStorageTest.java similarity index 100% rename from src/test/java/com/auth0/RandomStorageTest.java rename to main/src/test/java/com/auth0/RandomStorageTest.java index 49a4af7..106014f 100644 --- a/src/test/java/com/auth0/RandomStorageTest.java +++ b/main/src/test/java/com/auth0/RandomStorageTest.java @@ -1,12 +1,12 @@ package com.auth0; -import org.junit.jupiter.api.Test; -import org.springframework.mock.web.MockHttpServletRequest; - import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; +import org.junit.jupiter.api.Test; +import org.springframework.mock.web.MockHttpServletRequest; + public class RandomStorageTest { @Test diff --git a/src/test/java/com/auth0/RequestProcessorTest.java b/main/src/test/java/com/auth0/RequestProcessorTest.java similarity index 97% rename from src/test/java/com/auth0/RequestProcessorTest.java rename to main/src/test/java/com/auth0/RequestProcessorTest.java index 7ffcf60..f7684dc 100644 --- a/src/test/java/com/auth0/RequestProcessorTest.java +++ b/main/src/test/java/com/auth0/RequestProcessorTest.java @@ -1,9 +1,31 @@ package com.auth0; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + import com.auth0.client.auth.AuthAPI; import com.auth0.exception.Auth0Exception; import com.auth0.json.auth.TokenHolder; import com.auth0.net.TokenRequest; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -12,19 +34,6 @@ import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import static org.hamcrest.CoreMatchers.*; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.not; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.*; - public class RequestProcessorTest { @Mock diff --git a/src/test/java/com/auth0/SessionUtilsTest.java b/main/src/test/java/com/auth0/SessionUtilsTest.java similarity index 100% rename from src/test/java/com/auth0/SessionUtilsTest.java rename to main/src/test/java/com/auth0/SessionUtilsTest.java index d7edf62..d6beb98 100644 --- a/src/test/java/com/auth0/SessionUtilsTest.java +++ b/main/src/test/java/com/auth0/SessionUtilsTest.java @@ -1,12 +1,12 @@ package com.auth0; -import org.junit.jupiter.api.Test; -import org.springframework.mock.web.MockHttpServletRequest; - import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; +import org.junit.jupiter.api.Test; +import org.springframework.mock.web.MockHttpServletRequest; + public class SessionUtilsTest { @Test public void shouldGetAndRemoveAttribute() { diff --git a/src/test/java/com/auth0/SignatureVerifierTest.java b/main/src/test/java/com/auth0/SignatureVerifierTest.java similarity index 99% rename from src/test/java/com/auth0/SignatureVerifierTest.java rename to main/src/test/java/com/auth0/SignatureVerifierTest.java index 326387f..7ed79c5 100644 --- a/src/test/java/com/auth0/SignatureVerifierTest.java +++ b/main/src/test/java/com/auth0/SignatureVerifierTest.java @@ -1,12 +1,16 @@ package com.auth0; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.auth0.jwk.Jwk; import com.auth0.jwk.JwkException; import com.auth0.jwk.JwkProvider; import com.auth0.jwt.interfaces.DecodedJWT; -import org.bouncycastle.util.io.pem.PemReader; -import org.junit.jupiter.api.Test; - import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; @@ -19,13 +23,8 @@ import java.security.spec.EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Scanner; - -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import org.bouncycastle.util.io.pem.PemReader; +import org.junit.jupiter.api.Test; public class SignatureVerifierTest { diff --git a/src/test/java/com/auth0/TokensTest.java b/main/src/test/java/com/auth0/TokensTest.java similarity index 100% rename from src/test/java/com/auth0/TokensTest.java rename to main/src/test/java/com/auth0/TokensTest.java index 5034bce..cd2750f 100644 --- a/src/test/java/com/auth0/TokensTest.java +++ b/main/src/test/java/com/auth0/TokensTest.java @@ -1,10 +1,10 @@ package com.auth0; -import org.junit.jupiter.api.Test; - +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNull.nullValue; -import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; public class TokensTest { diff --git a/src/test/java/com/auth0/TransientCookieStoreTest.java b/main/src/test/java/com/auth0/TransientCookieStoreTest.java similarity index 97% rename from src/test/java/com/auth0/TransientCookieStoreTest.java rename to main/src/test/java/com/auth0/TransientCookieStoreTest.java index 949fb05..c667970 100644 --- a/src/test/java/com/auth0/TransientCookieStoreTest.java +++ b/main/src/test/java/com/auth0/TransientCookieStoreTest.java @@ -1,19 +1,22 @@ package com.auth0; +import static org.hamcrest.CoreMatchers.everyItem; +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +import jakarta.servlet.http.Cookie; +import java.net.URLEncoder; +import java.util.Arrays; +import java.util.List; import org.hamcrest.beans.HasPropertyWithValue; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; -import javax.servlet.http.Cookie; -import java.net.URLEncoder; -import java.util.Arrays; -import java.util.List; - -import static org.hamcrest.CoreMatchers.*; -import static org.hamcrest.MatcherAssert.assertThat; - public class TransientCookieStoreTest { private MockHttpServletRequest request; diff --git a/src/test/resources/bad-public.pem b/main/src/test/resources/bad-public.pem similarity index 100% rename from src/test/resources/bad-public.pem rename to main/src/test/resources/bad-public.pem diff --git a/src/test/resources/certificate.pem b/main/src/test/resources/certificate.pem similarity index 100% rename from src/test/resources/certificate.pem rename to main/src/test/resources/certificate.pem diff --git a/src/test/resources/private.pem b/main/src/test/resources/private.pem similarity index 100% rename from src/test/resources/private.pem rename to main/src/test/resources/private.pem diff --git a/src/test/resources/public.pem b/main/src/test/resources/public.pem similarity index 100% rename from src/test/resources/public.pem rename to main/src/test/resources/public.pem diff --git a/opslevel.yml b/opslevel.yml deleted file mode 100644 index 009a5ec..0000000 --- a/opslevel.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -version: 1 -repository: - owner: dx_sdks - tier: - tags: diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index a83fe1a..0000000 --- a/settings.gradle +++ /dev/null @@ -1,10 +0,0 @@ -pluginManagement { - repositories { - gradlePluginPortal() - } - plugins { - id 'com.auth0.gradle.oss-library.java' version '0.18.0' - } -} - -rootProject.name = 'mvc-auth-commons' diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..3eac2f0 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,12 @@ +pluginManagement { + repositories { + gradlePluginPortal() + } + plugins { + id("com.auth0.gradle.oss-library.java") version "0.18.0" + } +} + +rootProject.name = "opengov-auth0-mvc-auth-commons" + +include("main") \ No newline at end of file diff --git a/src/main/java/com/auth0/RandomStorage.java b/src/main/java/com/auth0/RandomStorage.java deleted file mode 100644 index 66659a0..0000000 --- a/src/main/java/com/auth0/RandomStorage.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.auth0; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; - -class RandomStorage extends SessionUtils { - - /** - * Check's if the request {@link HttpSession} saved state is equal to the given state. - * After the check, the value will be removed from the session. - * - * @param req the request - * @param state the state value to compare against. - * @return whether the state matches the expected one or not. - */ - static boolean checkSessionState(HttpServletRequest req, String state) { - String currentState = (String) remove(req, StorageUtils.STATE_KEY); - return (currentState == null && state == null) || currentState != null && currentState.equals(state); - } - - /** - * Saves the given state in the request {@link HttpSession}. - * If a state is already bound to the session, the value is replaced. - * - * @param req the request. - * @param state the state value to set. - */ - static void setSessionState(HttpServletRequest req, String state) { - set(req, StorageUtils.STATE_KEY, state); - } - - /** - * Saves the given nonce in the request {@link HttpSession}. - * If a nonce is already bound to the session, the value is replaced. - * - * @param req the request. - * @param nonce the nonce value to set. - */ - static void setSessionNonce(HttpServletRequest req, String nonce) { - set(req, StorageUtils.NONCE_KEY, nonce); - } - - /** - * Removes the nonce present in the request {@link HttpSession} and then returns it. - * - * @param req the HTTP Servlet request. - * @return the nonce value or null if it was not set. - */ - static String removeSessionNonce(HttpServletRequest req) { - return (String) remove(req, StorageUtils.NONCE_KEY); - } -} \ No newline at end of file diff --git a/src/main/java/com/auth0/SessionUtils.java b/src/main/java/com/auth0/SessionUtils.java deleted file mode 100644 index a6906dc..0000000 --- a/src/main/java/com/auth0/SessionUtils.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.auth0; - -import org.apache.commons.lang3.Validate; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; - -/** - * Helper class to handle easy session key-value storage. - */ -@SuppressWarnings({"WeakerAccess", "unused"}) -public abstract class SessionUtils { - - /** - * Extracts the HttpSession from the given request. - * - * @param req a valid request to get the session from - * @return the session of the request - */ - protected static HttpSession getSession(HttpServletRequest req) { - return req.getSession(true); - } - - /** - * Set's the attribute value to the request session. - * - * @param req a valid request to get the session from - * @param name the name of the attribute - * @param value the value to set - */ - public static void set(HttpServletRequest req, String name, Object value) { - Validate.notNull(req); - Validate.notNull(name); - getSession(req).setAttribute(name, value); - } - - /** - * Get the attribute with the given name from the request session. - * - * @param req a valid request to get the session from - * @param name the name of the attribute - * @return the attribute stored in the session or null if it doesn't exists - */ - public static Object get(HttpServletRequest req, String name) { - Validate.notNull(req); - Validate.notNull(name); - return getSession(req).getAttribute(name); - } - - /** - * Same as {@link #get(HttpServletRequest, String)} but it also removes the value from the request session. - * - * @param req a valid request to get the session from - * @param name the name of the attribute - * @return the attribute stored in the session or null if it doesn't exists - */ - public static Object remove(HttpServletRequest req, String name) { - Validate.notNull(req); - Validate.notNull(name); - Object value = get(req, name); - getSession(req).removeAttribute(name); - return value; - } -}