diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 7958e8bd..00000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @auth0/project-dx-sdks-engineer-codeowner diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml deleted file mode 100644 index d5d861e0..00000000 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ /dev/null @@ -1,67 +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: I have looked into the [Readme](https://github.com/auth0/java-jwt#readme) and [Examples](https://github.com/auth0/java-jwt/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/java-jwt/latest/index.html) and have not found a suitable solution or answer. - required: true - - label: I have searched the [issues](https://github.com/auth0/java-jwt/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: java-jwt 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 38fee433..00000000 --- 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/java-jwt#readme) and [Examples](https://github.com/auth0/java-jwt/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/java-jwt/latest/index.html) and have not found a suitable solution or answer. - required: true - - label: I have searched the [issues](https://github.com/auth0/java-jwt/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 f58e0249..00000000 --- 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 library in the Auth0 Community forums diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 8675fc7e..00000000 --- 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 ce7acdc3..00000000 --- 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 287d2066..00000000 --- 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 9440ec92..00000000 --- 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 01e3a621..00000000 --- a/.github/actions/maven-publish/action.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Publish release to Java - -inputs: - java-version: - required: true - ossr-username: - required: true - ossr-token: - required: true - signing-key: - required: true - signing-password: - 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 }} - export JAVA_HOME=${SDKMAN_DIR}/candidates/java/current - echo "JAVA_HOME is set to $JAVA_HOME" - - - uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4 # pin@1.1.0 - env: - JAVA_HOME: ${{ env.JAVA_HOME }} - - - name: Publish Android/Java Packages to Maven - shell: bash - run: ./gradlew publish -PisSnapshot=false --stacktrace - env: - JAVA_HOME: ${{ env.JAVA_HOME }} - MAVEN_USERNAME: ${{ inputs.ossr-username }} - MAVEN_PASSWORD: ${{ inputs.ossr-token }} - SIGNING_KEY: ${{ inputs.signing-key}} - SIGNING_PASSWORD: ${{ inputs.signing-password}} \ No newline at end of file diff --git a/.github/actions/release-create/action.yml b/.github/actions/release-create/action.yml deleted file mode 100644 index 6a2bf804..00000000 --- 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/rl-scanner/action.yml b/.github/actions/rl-scanner/action.yml deleted file mode 100644 index fbf81217..00000000 --- a/.github/actions/rl-scanner/action.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: 'Reversing Labs Scanner' -description: 'Runs the Reversing Labs scanner on a specified artifact.' -inputs: - artifact-path: - description: 'Path to the artifact to be scanned.' - required: true - version: - description: 'Version of the artifact.' - required: true - -runs: - using: 'composite' - steps: - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.10' - - - name: Install Python dependencies - shell: bash - run: | - pip install boto3 requests - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - role-to-assume: ${{ env.PRODSEC_TOOLS_ARN }} - aws-region: us-east-1 - mask-aws-account-id: true - - - name: Install RL Wrapper - shell: bash - run: | - pip install rl-wrapper>=1.0.0 --index-url "https://${{ env.PRODSEC_TOOLS_USER }}:${{ env.PRODSEC_TOOLS_TOKEN }}@a0us.jfrog.io/artifactory/api/pypi/python-local/simple" - - name: Run RL Scanner - shell: bash - env: - RLSECURE_LICENSE: ${{ env.RLSECURE_LICENSE }} - RLSECURE_SITE_KEY: ${{ env.RLSECURE_SITE_KEY }} - SIGNAL_HANDLER_TOKEN: ${{ env.SIGNAL_HANDLER_TOKEN }} - PYTHONUNBUFFERED: 1 - run: | - if [ ! -f "${{ inputs.artifact-path }}" ]; then - echo "Artifact not found: ${{ inputs.artifact-path }}" - exit 1 - fi - rl-wrapper \ - --artifact "${{ inputs.artifact-path }}" \ - --name "${{ github.event.repository.name }}" \ - --version "${{ inputs.version }}" \ - --repository "${{ github.repository }}" \ - --commit "${{ github.sha }}" \ - --build-env "github_actions" \ - --suppress_output - # Check the outcome of the scanner - if [ $? -ne 0 ]; then - echo "RL Scanner failed." - echo "scan-status=failed" >> $GITHUB_ENV - exit 1 - else - echo "RL Scanner passed." - echo "scan-status=success" >> $GITHUB_ENV - fi -outputs: - scan-status: - description: 'The outcome of the scan process.' - value: ${{ env.scan-status }} \ No newline at end of file diff --git a/.github/actions/tag-exists/action.yml b/.github/actions/tag-exists/action.yml deleted file mode 100644 index b5fbdb73..00000000 --- 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 b2e13fc7..00000000 --- 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 f86ed60e..00000000 --- a/.github/workflows/build-and-test.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: auth0/java-jwt/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: 11 - - 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/dependabot.yml b/.github/workflows/dependabot.yml deleted file mode 100644 index f2839f50..00000000 --- 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: "lib" - schedule: - interval: "daily" - ignore: - - dependency-name: "*" - update-types: ["version-update:semver-major"] \ No newline at end of file diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml deleted file mode 100644 index ce302cb4..00000000 --- a/.github/workflows/gradle-wrapper-validation.yml +++ /dev/null @@ -1,10 +0,0 @@ -name: "Validate Gradle Wrapper" -on: [push, pull_request] - -jobs: - validation: - name: "validation/gradlew" - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: gradle/wrapper-validation-action@8d49e559aae34d3e0eb16cde532684bc9702762b # pin@v1.0.6 diff --git a/.github/workflows/java-release.yml b/.github/workflows/java-release.yml deleted file mode 100644 index 00771307..00000000 --- a/.github/workflows/java-release.yml +++ /dev/null @@ -1,91 +0,0 @@ -name: Create Java and GitHub Release - -on: - workflow_call: - inputs: - java-version: - required: true - type: string - secrets: - ossr-username: - required: true - ossr-token: - 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 - - # Set JAVA_HOME here and pass it to subsequent steps - - name: Set JAVA_HOME for Gradle - run: echo "JAVA_HOME=/home/runner/.sdkman/candidates/java/current" >> $GITHUB_ENV # This ensures JAVA_HOME is set globally - env: - SDKMAN_DIR: /home/runner/.sdkman - - # Publish the release to Maven - - uses: ./.github/actions/maven-publish - with: - java-version: ${{ inputs.java-version }} - ossr-username: ${{ secrets.ossr-username }} - ossr-token: ${{ secrets.ossr-token }} - signing-key: ${{ secrets.signing-key }} - signing-password: ${{ secrets.signing-password }} - env: - JAVA_HOME: ${{ env.JAVA_HOME }} - - # 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 2b00e426..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Create GitHub Release - -on: - pull_request: - types: - - closed - workflow_dispatch: - -permissions: - contents: write - id-token: write # This is required for requesting the JWT - -### 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: - rl-scanner: - uses: ./.github/workflows/rl-secure.yml - with: - java-version: 11 - artifact-name: 'java-jwt.tgz' - secrets: - RLSECURE_LICENSE: ${{ secrets.RLSECURE_LICENSE }} - RLSECURE_SITE_KEY: ${{ secrets.RLSECURE_SITE_KEY }} - SIGNAL_HANDLER_TOKEN: ${{ secrets.SIGNAL_HANDLER_TOKEN }} - PRODSEC_TOOLS_USER: ${{ secrets.PRODSEC_TOOLS_USER }} - PRODSEC_TOOLS_TOKEN: ${{ secrets.PRODSEC_TOOLS_TOKEN }} - PRODSEC_TOOLS_ARN: ${{ secrets.PRODSEC_TOOLS_ARN }} - release: - uses: ./.github/workflows/java-release.yml - needs: rl-scanner - with: - java-version: 11.0.21-tem - secrets: - ossr-username: ${{ secrets.OSSR_USERNAME }} - ossr-token: ${{ secrets.OSSR_TOKEN }} - signing-key: ${{ secrets.SIGNING_KEY }} - signing-password: ${{ secrets.SIGNING_PASSWORD }} - github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/rl-secure.yml b/.github/workflows/rl-secure.yml deleted file mode 100644 index ef329594..00000000 --- a/.github/workflows/rl-secure.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: RL-Secure Workflow - -on: - workflow_call: - inputs: - java-version: - required: true - type: string - artifact-name: - required: true - type: string - secrets: - RLSECURE_LICENSE: - required: true - RLSECURE_SITE_KEY: - required: true - SIGNAL_HANDLER_TOKEN: - required: true - PRODSEC_TOOLS_USER: - required: true - PRODSEC_TOOLS_TOKEN: - required: true - PRODSEC_TOOLS_ARN: - required: true - -jobs: - checkout-build-scan-only: - 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 - outputs: - scan-status: ${{ steps.rl-scan-conclusion.outcome }} - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Set up Java - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: ${{ inputs.java-version }} - - - name: Build with Gradle - uses: gradle/gradle-build-action@a4cf152f482c7ca97ef56ead29bf08bcd953284c - with: - arguments: assemble apiDiff check jacocoTestReport --continue --console=plain - - - name: Get Artifact Version - id: get_version - uses: ./.github/actions/get-version - - - name: Create tgz build artifact - run: | - tar -czvf ${{ inputs.artifact-name }} * - - - name: Run RL Scanner - id: rl-scan-conclusion - uses: ./.github/actions/rl-scanner - with: - artifact-path: "$(pwd)/${{ inputs.artifact-name }}" - version: "${{ steps.get_version.outputs.version }}" - env: - RLSECURE_LICENSE: ${{ secrets.RLSECURE_LICENSE }} - RLSECURE_SITE_KEY: ${{ secrets.RLSECURE_SITE_KEY }} - SIGNAL_HANDLER_TOKEN: ${{ secrets.SIGNAL_HANDLER_TOKEN }} - PRODSEC_TOOLS_USER: ${{ secrets.PRODSEC_TOOLS_USER }} - PRODSEC_TOOLS_TOKEN: ${{ secrets.PRODSEC_TOOLS_TOKEN }} - PRODSEC_TOOLS_ARN: ${{ secrets.PRODSEC_TOOLS_ARN }} - - - name: Output scan result - run: echo "scan-status=${{ steps.rl-scan-conclusion.outcome }}" >> $GITHUB_ENV \ No newline at end of file diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml deleted file mode 100644 index e0227e37..00000000 --- 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/.github/workflows/snyk.yml b/.github/workflows/snyk.yml deleted file mode 100644 index 457b6afa..00000000 --- a/.github/workflows/snyk.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Snyk - -on: - merge_group: - workflow_dispatch: - pull_request: - types: - - opened - - synchronize - push: - branches: - - master - schedule: - - cron: '30 0 1,15 * *' - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} - -jobs: - - check: - name: Check for Vulnerabilities - runs-on: ubuntu-latest - - steps: - - if: github.actor == 'dependabot[bot]' || github.event_name == 'merge_group' - run: exit 0 # Skip unnecessary test runs for dependabot and merge queues. Artifically flag as successful, as this is a required check for branch protection. - - - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha || github.ref }} - - - uses: snyk/actions/gradle-jdk11@b98d498629f1c368650224d6d212bf7dfa89e4bf # pin@0.4.0 - env: - SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index e706fbb1..999c86de 100644 --- a/.gitignore +++ b/.gitignore @@ -1,97 +1,173 @@ -# Created by .ignore support plugin (hsz.mobi) -### OSX template -*.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - - -### JetBrains template -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# Intellij -.idea/ -*.iml - -## File-based project format: -*.iws - -## Plugin-specific files: - -# IntelliJ -bin/ -/out/ -/lib/out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml +# Maven Shaded Jar Artifact +dependency-reduced-pom.xml -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties +node_modules -# Eclipse IDE -.classpath +# Ignore Eclipse stuff .project -.settings/ - -### Java template -*.class - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.ear - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* +.settings +.classpath -### Gradle template -.gradle -build/ -target/ -dependency-reduced-pom.xml -local.properties +# Ignore Java and IntelliJ IDEA stuff +.idea +target +*.iml -# Ignore Gradle GUI config -gradle-app.setting +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. -# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) -!gradle-wrapper.jar +packages -# Cache of project -.gradletasknamecache +# User-specific files +*.suo +*.user +*.sln.docstates -# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 -# gradle/wrapper/gradle-wrapper.properties +# Build results +[Dd]ebug/ +[Rr]elease/ +x64/ +build/ +[Bb]in/ +[Oo]bj/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +#packages/ + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml +*.pfx +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + + +#LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac desktop service store files +.DS_Store diff --git a/.shiprc b/.shiprc deleted file mode 100644 index 1b83cc62..00000000 --- a/.shiprc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "files": { - "README.md": [], - ".version": [], - "lib/build.gradle": ["version = \"{MAJOR}.{MINOR}.{PATCH}\""] - }, - "prefixVersion": false -} \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..ef0da2f7 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: java +jdk: +- oraclejdk7 +branches: + only: + - master +after_success: + - bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/.version b/.version deleted file mode 100644 index ae153944..00000000 --- a/.version +++ /dev/null @@ -1 +0,0 @@ -4.5.0 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index b97fab71..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,498 +0,0 @@ -# Change Log - -## [4.5.0](https://github.com/auth0/java-jwt/tree/4.5.0) (2025-01-29) -[Full Changelog](https://github.com/auth0/java-jwt/compare/4.4.0...4.5.0) - -**Added** -- Upgraded Plugin [\#711](https://github.com/auth0/java-jwt/pull/711) ([tanya732](https://github.com/tanya732)) -- Fix jackson vuln [\#705](https://github.com/auth0/java-jwt/pull/705) ([tanya732](https://github.com/tanya732)) -- Fix typo in example code [\#682](https://github.com/auth0/java-jwt/pull/682) ([kasperkarlsson](https://github.com/kasperkarlsson)) -- Remove dead README links [\#676](https://github.com/auth0/java-jwt/pull/676) ([jimmyjames](https://github.com/jimmyjames)) -- Fix typo on a comment in JWTCreator.java [\#672](https://github.com/auth0/java-jwt/pull/672) ([sgc109](https://github.com/sgc109)) -- Remove CircleCI [\#670](https://github.com/auth0/java-jwt/pull/670) ([jimmyjames](https://github.com/jimmyjames)) -- Empty string audience claim should be deserialized as empty string [\#663](https://github.com/auth0/java-jwt/pull/663) ([jimmyjames](https://github.com/jimmyjames)) - -**Fixed** -- empty expected audience array should throw InvalidClaimException [\#679](https://github.com/auth0/java-jwt/pull/679) ([jimmyjames](https://github.com/jimmyjames)) - -## [4.5.0](https://github.com/auth0/java-jwt/tree/4.5.0) (2025-01-28) -[Full Changelog](https://github.com/auth0/java-jwt/compare/4.4.0...4.5.0) - -**Added** -- Upgraded Plugin [\#711](https://github.com/auth0/java-jwt/pull/711) ([tanya732](https://github.com/tanya732)) -- Fix jackson vuln [\#705](https://github.com/auth0/java-jwt/pull/705) ([tanya732](https://github.com/tanya732)) -- Fix typo in example code [\#682](https://github.com/auth0/java-jwt/pull/682) ([kasperkarlsson](https://github.com/kasperkarlsson)) -- Remove dead README links [\#676](https://github.com/auth0/java-jwt/pull/676) ([jimmyjames](https://github.com/jimmyjames)) -- Fix typo on a comment in JWTCreator.java [\#672](https://github.com/auth0/java-jwt/pull/672) ([sgc109](https://github.com/sgc109)) -- Remove CircleCI [\#670](https://github.com/auth0/java-jwt/pull/670) ([jimmyjames](https://github.com/jimmyjames)) -- Empty string audience claim should be deserialized as empty string [\#663](https://github.com/auth0/java-jwt/pull/663) ([jimmyjames](https://github.com/jimmyjames)) - -**Fixed** -- empty expected audience array should throw InvalidClaimException [\#679](https://github.com/auth0/java-jwt/pull/679) ([jimmyjames](https://github.com/jimmyjames)) - -## [4.5.0](https://github.com/auth0/java-jwt/tree/4.5.0) (2025-01-22) -[Full Changelog](https://github.com/auth0/java-jwt/compare/4.4.0...4.5.0) - -**Added** -- Fix jackson vuln [\#705](https://github.com/auth0/java-jwt/pull/705) ([tanya732](https://github.com/tanya732)) -- Fix typo in example code [\#682](https://github.com/auth0/java-jwt/pull/682) ([kasperkarlsson](https://github.com/kasperkarlsson)) -- Remove dead README links [\#676](https://github.com/auth0/java-jwt/pull/676) ([jimmyjames](https://github.com/jimmyjames)) -- Fix typo on a comment in JWTCreator.java [\#672](https://github.com/auth0/java-jwt/pull/672) ([sgc109](https://github.com/sgc109)) -- Remove CircleCI [\#670](https://github.com/auth0/java-jwt/pull/670) ([jimmyjames](https://github.com/jimmyjames)) -- Empty string audience claim should be deserialized as empty string [\#663](https://github.com/auth0/java-jwt/pull/663) ([jimmyjames](https://github.com/jimmyjames)) - -**Fixed** -- empty expected audience array should throw InvalidClaimException [\#679](https://github.com/auth0/java-jwt/pull/679) ([jimmyjames](https://github.com/jimmyjames)) - -## [4.4.0](https://github.com/auth0/java-jwt/tree/4.4.0) (2023-03-31) -[Full Changelog](https://github.com/auth0/java-jwt/compare/4.3.0...4.4.0) - -**Changed** -- Add support for passing json values for header and payload [\#643](https://github.com/auth0/java-jwt/pull/643) ([andrewrigas](https://github.com/andrewrigas)) -- Preserve insertion order for claims [\#656](https://github.com/auth0/java-jwt/pull/656) ([snago](https://github.com/snago)) -- Update Jackson to 2.14.2 [\#657](https://github.com/auth0/java-jwt/pull/657) ([jimmyjames](https://github.com/jimmyjames)) - -## [4.3.0](https://github.com/auth0/java-jwt/tree/4.3.0) (2023-02-10) -[Full Changelog](https://github.com/auth0/java-jwt/compare/4.2.2...4.3.0) - -**Changed** -- Improve JWT parse/decode performance [\#620](https://github.com/auth0/java-jwt/pull/620) ([noetro](https://github.com/noetro)) - -**Fixed** -- Fix for exp claim considered valid if equal to now [\#652](https://github.com/auth0/java-jwt/pull/652) ([jimmyjames](https://github.com/jimmyjames)) -- Code cleanup [\#642](https://github.com/auth0/java-jwt/pull/642) ([CodeDead](https://github.com/CodeDead)) - -## [4.2.2](https://github.com/auth0/java-jwt/tree/4.2.2) (2023-01-11) -[Full Changelog](https://github.com/auth0/java-jwt/compare/4.2.1...4.2.2) - -This patch release does not contain any functional changes, but is being released using an updated signing key for verification as part of our commitment to best security practices. -Please review [the README note for additional details.](https://github.com/auth0/java-jwt/blob/master/README.md) - -## [4.2.1](https://github.com/auth0/java-jwt/tree/4.2.1) (2022-10-24) -[Full Changelog](https://github.com/auth0/java-jwt/compare/4.2.0...4.2.1) - -**Security** -- Use latest ship orb [\#634](https://github.com/auth0/java-jwt/pull/634) ([jimmyjames](https://github.com/jimmyjames)) -- Bump `com.fasterxml.jackson.core:jackson-databind` to 2.13.4.2 [\#630](https://github.com/auth0/java-jwt/pull/630) ([evansims](https://github.com/evansims)) - -## [4.2.0](https://github.com/auth0/java-jwt/tree/4.2.0) (2022-10-19) -[Full Changelog](https://github.com/auth0/java-jwt/compare/4.1.0...4.2.0) - -**Changed** -- Re-enable japicmp API diff checking [\#619](https://github.com/auth0/java-jwt/pull/619) ([jimmyjames](https://github.com/jimmyjames)) -- Update .shiprc to only update lib version in build.gradle [\#625](https://github.com/auth0/java-jwt/pull/625) ([jimmyjames](https://github.com/jimmyjames)) -- Optimise TokenUtils parsing [\#611](https://github.com/auth0/java-jwt/pull/611) ([noetro](https://github.com/noetro)) -- Update Circle Ship Orb configuration [\#616](https://github.com/auth0/java-jwt/pull/616) ([frederikprijck](https://github.com/frederikprijck)) - -**Fixed** -- Update Claim#asString documentation [\#615](https://github.com/auth0/java-jwt/pull/615) ([jimmyjames](https://github.com/jimmyjames)) - -## [4.1.0](https://github.com/auth0/java-jwt/tree/4.1.0) (2022-10-06) -[Full Changelog](https://github.com/auth0/java-jwt/compare/4.0.0...4.1.0) - -**⚠️ BREAKING CHANGES** -- Make JWT constants final values [\#604](https://github.com/auth0/java-jwt/pull/604) ([poovamraj](https://github.com/poovamraj)) - -**Added** -- Add integration with our Shipping orb [\#612](https://github.com/auth0/java-jwt/pull/612) ([frederikprijck](https://github.com/frederikprijck)) -- Add Ship CLI support [\#609](https://github.com/auth0/java-jwt/pull/609) ([jimmyjames](https://github.com/jimmyjames)) -- Provide straightforward example for JWKS [\#600](https://github.com/auth0/java-jwt/pull/600) ([poovamraj](https://github.com/poovamraj)) - -**Changed** -- Update to gradle 6.9.2 [\#608](https://github.com/auth0/java-jwt/pull/608) ([jimmyjames](https://github.com/jimmyjames)) -- Update OSS plugin to latest [\#607](https://github.com/auth0/java-jwt/pull/607) ([jimmyjames](https://github.com/jimmyjames)) -- [SDK-3466] Upgrade Codecov [\#595](https://github.com/auth0/java-jwt/pull/595) ([evansims](https://github.com/evansims)) -- Update README.md [\#590](https://github.com/auth0/java-jwt/pull/590) ([poovamraj](https://github.com/poovamraj)) - -**Fixed** -- Check for null token before splitting [\#606](https://github.com/auth0/java-jwt/pull/606) ([jimmyjames](https://github.com/jimmyjames)) -- [SDK-3816] Update docs for verification thread-safety [\#605](https://github.com/auth0/java-jwt/pull/605) ([jimmyjames](https://github.com/jimmyjames)) - -## [4.0.0](https://github.com/auth0/java-jwt/tree/4.0.0) (2022-06-24) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.19.2...4.0.0) - -**This is a major release and contains breaking changes!** - -- Check the [Migration Guide](https://github.com/auth0/java-jwt/blob/master/MIGRATION_GUIDE.md) to understand the changes required to migrate your application to v4. - -### Main features -- Predicates based claim verification -- Support for Instant API and Lambda functions -- Improved Exceptions API -- Consistent null handling - -See the changelog entries for additional details. - -## [4.0.0-beta.0](https://github.com/auth0/java-jwt/tree/4.0.0-beta.0) (2022-05-06) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.19.2...4.0.0-beta.0) - -💡 Check the [Migration Guide](https://github.com/auth0/java-jwt/blob/master/MIGRATION_GUIDE.md) to understand the changes required to migrate your application to v4. - -**Added** -- JavaDoc updated [\#577](https://github.com/auth0/java-jwt/pull/577) ([poovamraj](https://github.com/poovamraj)) -- Add Migration Guide [\#576](https://github.com/auth0/java-jwt/pull/576) ([jimmyjames](https://github.com/jimmyjames)) -- Expose claim name and header constants [\#574](https://github.com/auth0/java-jwt/pull/574) ([jimmyjames](https://github.com/jimmyjames)) -- Added support for multiple checks on a single claim [\#573](https://github.com/auth0/java-jwt/pull/573) ([poovamraj](https://github.com/poovamraj)) -- Improved README structure [\#571](https://github.com/auth0/java-jwt/pull/571) ([poovamraj](https://github.com/poovamraj)) -- Improved Exception Handling [\#568](https://github.com/auth0/java-jwt/pull/568) ([poovamraj](https://github.com/poovamraj)) -- Predicate based Claim verification [\#562](https://github.com/auth0/java-jwt/pull/562) ([poovamraj](https://github.com/poovamraj)) -- Add lint checks [\#561](https://github.com/auth0/java-jwt/pull/561) ([poovamraj](https://github.com/poovamraj)) -- Support date/time custom claim validation [\#538](https://github.com/auth0/java-jwt/pull/538) ([jimmyjames](https://github.com/jimmyjames)) -- Add Instant support [\#537](https://github.com/auth0/java-jwt/pull/537) ([jimmyjames](https://github.com/jimmyjames)) -- Testing Java LTS versions [\#536](https://github.com/auth0/java-jwt/pull/536) ([poovamraj](https://github.com/poovamraj)) - -**Changed** -- Null claim handling [\#564](https://github.com/auth0/java-jwt/pull/564) ([poovamraj](https://github.com/poovamraj)) -- Undeprecate Single Key Constructor for Algorithms [\#551](https://github.com/auth0/java-jwt/pull/551) ([poovamraj](https://github.com/poovamraj)) -- Update documentation and undeprecate single content sign methods [\#550](https://github.com/auth0/java-jwt/pull/550) ([poovamraj](https://github.com/poovamraj)) -- Update test deps [\#539](https://github.com/auth0/java-jwt/pull/539) ([jimmyjames](https://github.com/jimmyjames)) - -**Deprecated** -- Deprecate secp256k1 curve for EC Algorithms [\#540](https://github.com/auth0/java-jwt/pull/540) ([poovamraj](https://github.com/poovamraj)) - -**Removed** -- Remove ES256K support [\#556](https://github.com/auth0/java-jwt/pull/556) ([poovamraj](https://github.com/poovamraj)) -- Remove impl package export in module-info [\#553](https://github.com/auth0/java-jwt/pull/553) ([poovamraj](https://github.com/poovamraj)) -- Remove internal Clock [\#533](https://github.com/auth0/java-jwt/pull/533) ([jimmyjames](https://github.com/jimmyjames)) - -**Fixed** -- Improve keyprovider reliability [\#570](https://github.com/auth0/java-jwt/pull/570) ([poovamraj](https://github.com/poovamraj)) -- Support date/time custom claim validation [\#538](https://github.com/auth0/java-jwt/pull/538) ([jimmyjames](https://github.com/jimmyjames)) -- Test only change - remove unnecessary throws clause from tests [\#535](https://github.com/auth0/java-jwt/pull/535) ([jimmyjames](https://github.com/jimmyjames)) - -**Security** -- Updated documentation regarding HMAC Key length [\#580](https://github.com/auth0/java-jwt/pull/580) ([poovamraj](https://github.com/poovamraj)) - -**Breaking changes** -- Added support for multiple checks on a single claim [\#573](https://github.com/auth0/java-jwt/pull/573) ([poovamraj](https://github.com/poovamraj)) -- Improve keyprovider reliability [\#570](https://github.com/auth0/java-jwt/pull/570) ([poovamraj](https://github.com/poovamraj)) -- Remove ES256K support [\#556](https://github.com/auth0/java-jwt/pull/556) ([poovamraj](https://github.com/poovamraj)) -- Remove impl package export in module-info [\#553](https://github.com/auth0/java-jwt/pull/553) ([poovamraj](https://github.com/poovamraj)) -- Fix header claims serialization [\#549](https://github.com/auth0/java-jwt/pull/549) ([jimmyjames](https://github.com/jimmyjames)) -- Serialize dates in collections as seconds since epoch [\#534](https://github.com/auth0/java-jwt/pull/534) ([jimmyjames](https://github.com/jimmyjames)) -- Replace com.auth0.jwt.interfaces.Clock with java.time.Clock [\#532](https://github.com/auth0/java-jwt/pull/532) ([jimmyjames](https://github.com/jimmyjames)) - -## [3.19.2](https://github.com/auth0/java-jwt/tree/3.19.2) (2022-05-05) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.19.1...3.19.2) - -**Security** -- [SDK-3311] Added protection against CVE-2022-21449 [\#579](https://github.com/auth0/java-jwt/pull/579) ([poovamraj](https://github.com/poovamraj)) - -## [3.19.1](https://github.com/auth0/java-jwt/tree/3.19.1) (2022-03-30) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.19.0...3.19.1) - -**Security** -- Security: Bump `jackson-databind` to 2.13.2.2 [\#566](https://github.com/auth0/java-jwt/pull/566) ([evansims](https://github.com/evansims)) - -## [3.19.0](https://github.com/auth0/java-jwt/tree/3.19.0) (2022-03-14) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.18.3...3.19.0) - -**Deprecated** -- Deprecate ES256K Algorithm [\#543](https://github.com/auth0/java-jwt/pull/543) ([poovamraj](https://github.com/poovamraj)) - -**Fixed** -- fix typos in JWTVerifier#verify docstring [\#526](https://github.com/auth0/java-jwt/pull/526) ([OdunlamiZO](https://github.com/OdunlamiZO)) - -**Security** -- Bump `jackson-databind` dependency to 2.13.2 [\#542](https://github.com/auth0/java-jwt/pull/542) ([evansims](https://github.com/evansims)) - -## [3.18.3](https://github.com/auth0/java-jwt/tree/3.18.3) (2022-01-13) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.18.2...3.18.3) - -**Security** -- Update jackson dependency [\#523](https://github.com/auth0/java-jwt/pull/523) ([poovamraj](https://github.com/poovamraj)) - -## [3.18.2](https://github.com/auth0/java-jwt/tree/3.18.2) (2021-09-16) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.18.1...3.18.2) - -**Fixed** -- [SDK-2758] Restore withIssuer [\#513](https://github.com/auth0/java-jwt/pull/513) ([jimmyjames](https://github.com/jimmyjames)) -- [SDK-2751] Serialize audience claim when a List [\#512](https://github.com/auth0/java-jwt/pull/512) ([jimmyjames](https://github.com/jimmyjames)) - -## [3.18.1](https://github.com/auth0/java-jwt/tree/3.18.1) (2021-07-06) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.18.0...3.18.1) - -**Fixed** -- Fix min JDK version regression [\#504](https://github.com/auth0/java-jwt/pull/504) ([lbalmaceda](https://github.com/lbalmaceda)) - -## [3.18.0](https://github.com/auth0/java-jwt/tree/3.18.0) (2021-07-05) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.17.0...3.18.0) - -**Changed** -- Update OSS release plugin version [\#501](https://github.com/auth0/java-jwt/pull/501) ([lbalmaceda](https://github.com/lbalmaceda)) - -## [3.17.0](https://github.com/auth0/java-jwt/tree/3.17.0) (2021-06-25) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.16.0...3.17.0) - -**Added** -- Add module system support [\#484](https://github.com/auth0/java-jwt/pull/484) ([XakepSDK](https://github.com/XakepSDK)) - -## [3.16.0](https://github.com/auth0/java-jwt/tree/3.16.0) (2021-05-10) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.15.0...3.16.0) - -**Changed** -- Improve Javadoc generation [\#496](https://github.com/auth0/java-jwt/pull/496) ([Marcono1234](https://github.com/Marcono1234)) -- Add package-info.java for internal `impl` package [\#495](https://github.com/auth0/java-jwt/pull/495) ([Marcono1234](https://github.com/Marcono1234)) - -## [3.15.0](https://github.com/auth0/java-jwt/tree/3.15.0) (2021-04-05) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.14.0...3.15.0) - -**Changed** -- Remove jcenter [\#482](https://github.com/auth0/java-jwt/pull/482) ([jimmyjames](https://github.com/jimmyjames)) -- Move form commons-codec Base64 to j.u.Base64 [\#478](https://github.com/auth0/java-jwt/pull/478) ([XakepSDK](https://github.com/XakepSDK)) - -## [3.14.0](https://github.com/auth0/java-jwt/tree/3.14.0) (2021-02-26) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.13.0...3.14.0) - -**Added** -- Add withPayload to JWTCreator.Builder [\#475](https://github.com/auth0/java-jwt/pull/475) ([jimmyjames](https://github.com/jimmyjames)) - -## [3.13.0](https://github.com/auth0/java-jwt/tree/3.13.0) (2021-02-05) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.12.1...3.13.0) - -**Added** -- Add ability to verify audience contains at least one of those expected [\#472](https://github.com/auth0/java-jwt/pull/472) ([jimmyjames](https://github.com/jimmyjames)) -- Add toString to Claim objects [SDK-2225] [\#469](https://github.com/auth0/java-jwt/pull/469) ([jimmyjames](https://github.com/jimmyjames)) - -## [3.12.1](https://github.com/auth0/java-jwt/tree/3.12.1) (2021-01-20) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.12.0...3.12.1) - -**Changed** -- Update jackson-databind to 2.11.0 [\#464](https://github.com/auth0/java-jwt/pull/464) ([darveshsingh](https://github.com/darveshsingh)) - -## [3.12.0](https://github.com/auth0/java-jwt/tree/3.12.0) (2020-12-18) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.11.0...3.12.0) - -**Changed** -- Thread-safe classes should be Shared statically [\#462](https://github.com/auth0/java-jwt/pull/462) ([LeeHainie](https://github.com/LeeHainie)) - -**Security** -- Update jackson-databind to 2.10.5.1 (fixes CVE-2020-25649) [\#463](https://github.com/auth0/java-jwt/pull/463) ([overheadhunter](https://github.com/overheadhunter)) - -**Breaking changes** -- Target Java 8 [\#455](https://github.com/auth0/java-jwt/pull/455) ([lbalmaceda](https://github.com/lbalmaceda)) - -## [3.11.0](https://github.com/auth0/java-jwt/tree/3.11.0) (2020-09-25) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.10.3...3.11.0) - -**Added** -- Add ability to verify claim presence [\#442](https://github.com/auth0/java-jwt/pull/442) ([jimmyjames](https://github.com/jimmyjames)) -- Add Support for secp256k1 algorithms (AKA ES256K) [\#439](https://github.com/auth0/java-jwt/pull/439) ([jimmyjames](https://github.com/jimmyjames)) - -**Fixed** -- Fix and document thread-safety [\#427](https://github.com/auth0/java-jwt/pull/427) ([lbalmaceda](https://github.com/lbalmaceda)) -- Wrap IllegalArgumentException into JWTDecodeException [\#426](https://github.com/auth0/java-jwt/pull/426) ([lbalmaceda](https://github.com/lbalmaceda)) - -## [3.10.3](https://github.com/auth0/java-jwt/tree/3.10.3) (2020-04-24) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.10.2...3.10.3) - -**Fixed** -- Fixed an NPE on null map and list claims [\#417](https://github.com/auth0/java-jwt/pull/417) ([Vorotyntsev](https://github.com/Vorotyntsev)) - -## [3.10.2](https://github.com/auth0/java-jwt/tree/3.10.2) (2020-03-27) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.10.1...3.10.2) - -**Fixed** -- JavaDoc fix [\#413](https://github.com/auth0/java-jwt/pull/413) ([jimmyjames](https://github.com/jimmyjames)) -- Check varargs null values in JWTVerifier [\#412](https://github.com/auth0/java-jwt/pull/412) ([jimmyjames](https://github.com/jimmyjames)) - -## [3.10.1](https://github.com/auth0/java-jwt/tree/3.10.1) (2020-03-13) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.10.0...3.10.1) - -**Changed** -- Update Jackson and Commons Codec dependencies [\#407](https://github.com/auth0/java-jwt/pull/407) ([jimmyjames](https://github.com/jimmyjames)) - -**Security** -- Update jackson-databind to 2.10.2 [\#399](https://github.com/auth0/java-jwt/pull/399) ([gexclaude](https://github.com/gexclaude)) - -## [3.10.0](https://github.com/auth0/java-jwt/tree/3.10.0) (2020-02-14) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.9.0...3.10.0) -**Closed issues** -- NullPointerException when the claim doesn't exist in the token [\#384](https://github.com/auth0/java-jwt/issues/384) - -**Added** -- Add Javadoc URL and badge to the README [\#382](https://github.com/auth0/java-jwt/pull/382) ([lbalmaceda](https://github.com/lbalmaceda)) -- Allow to customize the typ header claim [\#381](https://github.com/auth0/java-jwt/pull/381) ([lbalmaceda](https://github.com/lbalmaceda)) -- JWTCreator for basic types [\#282](https://github.com/auth0/java-jwt/pull/282) ([skjolber](https://github.com/skjolber)) -- Support verification of Long[] datatype like in JWTCreator [\#278](https://github.com/auth0/java-jwt/pull/278) ([skjolber](https://github.com/skjolber)) - -**Changed** -- Update to Gradle 6.1.1 [\#389](https://github.com/auth0/java-jwt/pull/389) ([jimmyjames](https://github.com/jimmyjames)) - -**Fixed** -- Handle missing expected array claim [\#393](https://github.com/auth0/java-jwt/pull/393) ([lbalmaceda](https://github.com/lbalmaceda)) -- Update tests to use valid Base64 URL-encoded tokens [\#386](https://github.com/auth0/java-jwt/pull/386) ([jimmyjames](https://github.com/jimmyjames)) - -## [3.9.0](https://github.com/auth0/java-jwt/tree/3.9.0) (2020-01-02) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.8.3...3.9.0) - -**Added** -- Support serialization of DecodedJWT [\#370](https://github.com/auth0/java-jwt/pull/370) ([jimmyjames](https://github.com/jimmyjames)) - -**Fixed** -- Fixing JwtCreator builder when setting headers as a map [\#320](https://github.com/auth0/java-jwt/pull/320) ([maxbalan](https://github.com/maxbalan)) - -## [3.8.3](https://github.com/auth0/java-jwt/tree/3.8.3) (2019-09-25) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.8.2...3.8.3) - -**Security** -- Fix: updated jackson-databind to 2.10.0.pr3 to block CVE [\#356](https://github.com/auth0/java-jwt/pull/356) ([danbrodsky](https://github.com/danbrodsky)) - -## [3.8.2](https://github.com/auth0/java-jwt/tree/3.8.2) (2019-08-15) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.8.1...3.8.2) - -**Security** -- Fix: updated jackson-databind to 2.9.9.3 to block CVE [\#347](https://github.com/auth0/java-jwt/pull/347) ([danbrodsky](https://github.com/danbrodsky)) - -## [3.8.1](https://github.com/auth0/java-jwt/tree/3.8.1) (2019-05-22) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.8.0...3.8.1) - -**Security** -- Bump dependencies and fix security issue [\#337](https://github.com/auth0/java-jwt/pull/337) ([lbalmaceda](https://github.com/lbalmaceda)) - -## [3.8.0](https://github.com/auth0/java-jwt/tree/3.8.0) (2019-03-14) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.7.0...3.8.0) - -**Added** -- Support multiple issuers #246 [\#288](https://github.com/auth0/java-jwt/pull/288) ([itdevelopmentapps](https://github.com/itdevelopmentapps)) - -## [3.7.0](https://github.com/auth0/java-jwt/tree/3.7.0) (2019-01-29) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.6.0...3.7.0) - -**Added** -- Performance improvements [\#255](https://github.com/auth0/java-jwt/pull/255) ([skjolber](https://github.com/skjolber)) - -## [3.6.0](https://github.com/auth0/java-jwt/tree/3.6.0) (2019-01-24) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.5.0...3.6.0) - -**Added** -- Allow to skip "issued at" validation [\#297](https://github.com/auth0/java-jwt/pull/297) ([complanboy2](https://github.com/complanboy2)) - -## [3.5.0](https://github.com/auth0/java-jwt/tree/3.5.0) (2019-01-03) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.4.1...3.5.0) - -**Added** -- Verify a DecodedJWT [\#308](https://github.com/auth0/java-jwt/pull/308) ([martinoconnor](https://github.com/martinoconnor)) - -**Changed** -- Add an interface for JWTVerifier. [\#205](https://github.com/auth0/java-jwt/pull/205) ([jebbench](https://github.com/jebbench)) - -**Fixed** -- Remove unnecessary cast between long/double and floor call [\#296](https://github.com/auth0/java-jwt/pull/296) ([jhorstmann](https://github.com/jhorstmann)) - -**Security** -- Bump jackson-databind to patch security issues [\#309](https://github.com/auth0/java-jwt/pull/309) ([lbalmaceda](https://github.com/lbalmaceda)) - -## [3.4.1](https://github.com/auth0/java-jwt/tree/3.4.1) (2018-10-24) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.4.0...3.4.1) - -**Security** -- Update jackson-databind dependency [\#292](https://github.com/auth0/java-jwt/pull/292) ([lbalmaceda](https://github.com/lbalmaceda)) - -## [3.4.0](https://github.com/auth0/java-jwt/tree/3.4.0) (2018-06-13) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.3.0...3.4.0) - -**Breaking Changes** -- Fix for [\#236](https://github.com/auth0/java-jwt/pull/236) - refactored HMACAlgorithm so that it doesn't throw an UnsupportedEncodingException [\#242](https://github.com/auth0/java-jwt/pull/242) ([obecker](https://github.com/obecker)). - -Clients using the following methods may need to update their code to not catch an `UnsupportedEncodingException`: -- `public static Algorithm HMAC384(String secret)` -- `public static Algorithm HMAC256(String secret)` -- `public static Algorithm HMAC512(String secret)` - -**Changed** -- Throw JWTDecodeException when date claim format is invalid [\#241](https://github.com/auth0/java-jwt/pull/241) ([lbalmaceda](https://github.com/lbalmaceda)) - -**Security** -- Bump Jackson dependency [\#244](https://github.com/auth0/java-jwt/pull/244) ([skjolber](https://github.com/skjolber)) - -## [3.3.0](https://github.com/auth0/java-jwt/tree/3.3.0) (2017-11-06) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.2.0...3.3.0) -**Closed issues** -- Wrong ES256 signature length [\#187](https://github.com/auth0/java-jwt/issues/187) - -**Fixed** -- Rework ECDSA [\#212](https://github.com/auth0/java-jwt/pull/212) ([lbalmaceda](https://github.com/lbalmaceda)) -- Instantiate exception only when required [\#198](https://github.com/auth0/java-jwt/pull/198) ([rumdidumdum](https://github.com/rumdidumdum)) - -## [3.2.0](https://github.com/auth0/java-jwt/tree/3.2.0) (2017-05-04) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.1.0...3.2.0) -**Closed issues** -- Claim.isNull() returns true for JSON Object constructed claims [\#160](https://github.com/auth0/java-jwt/issues/160) -- Incorrectly rejects whitespace after JSON header as invalid [\#144](https://github.com/auth0/java-jwt/issues/144) -- No token type [\#136](https://github.com/auth0/java-jwt/issues/136) -- Timestamps are limited by Integer/int to 2038-01-19T04:14:07.000+0100 [\#132](https://github.com/auth0/java-jwt/issues/132) - -**Added** -- Refactor KeyProvider to receive the "Key Id" [\#167](https://github.com/auth0/java-jwt/pull/167) ([lbalmaceda](https://github.com/lbalmaceda)) -- Add Sign/Verify of Long type claims [\#157](https://github.com/auth0/java-jwt/pull/157) ([vrancic](https://github.com/vrancic)) -- added date validation dedicated exception [\#155](https://github.com/auth0/java-jwt/pull/155) ([Spyna](https://github.com/Spyna)) -- Allow to get a Claim as Map [\#152](https://github.com/auth0/java-jwt/pull/152) ([lbalmaceda](https://github.com/lbalmaceda)) -- Add Algorithm KeyProvider interface [\#149](https://github.com/auth0/java-jwt/pull/149) ([lbalmaceda](https://github.com/lbalmaceda)) -- Instantiate RSA/EC Algorithm with both keys [\#147](https://github.com/auth0/java-jwt/pull/147) ([lbalmaceda](https://github.com/lbalmaceda)) -- Add Key Id setter and set JWT Type after signing [\#138](https://github.com/auth0/java-jwt/pull/138) ([lbalmaceda](https://github.com/lbalmaceda)) - -**Changed** -- Change the JWT.decode() return type to DecodedJWT [\#150](https://github.com/auth0/java-jwt/pull/150) ([lbalmaceda](https://github.com/lbalmaceda)) - -**Fixed** -- Fix Claim.isNull() method for JSON Objects [\#161](https://github.com/auth0/java-jwt/pull/161) ([lbalmaceda](https://github.com/lbalmaceda)) -- Accept blanks, new line and carriage returns on JSON [\#151](https://github.com/auth0/java-jwt/pull/151) ([lbalmaceda](https://github.com/lbalmaceda)) -- Fix Date value conversion [\#137](https://github.com/auth0/java-jwt/pull/137) ([lbalmaceda](https://github.com/lbalmaceda)) - -## [3.1.0](https://github.com/auth0/java-jwt/tree/3.1.0) (2017-01-04) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.0.2...3.1.0) - -**Added** -- Make Clock customization accessible for verification [\#125](https://github.com/auth0/java-jwt/pull/125) ([lbalmaceda](https://github.com/lbalmaceda)) -- Add getter for all the Payload's Claims [\#124](https://github.com/auth0/java-jwt/pull/124) ([lbalmaceda](https://github.com/lbalmaceda)) -- Accept Array type on verification and creation. [\#123](https://github.com/auth0/java-jwt/pull/123) ([lbalmaceda](https://github.com/lbalmaceda)) - -## [3.0.2](https://github.com/auth0/java-jwt/tree/3.0.2) (2016-12-13) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.0.1...3.0.2) - -**Fixed** -- Add targetCompatibility to 1.7 [\#121](https://github.com/auth0/java-jwt/pull/121) ([hzalaz](https://github.com/hzalaz)) - -## [3.0.1](https://github.com/auth0/java-jwt/tree/3.0.0) (2016-12-05) -[Full Changelog](https://github.com/auth0/java-jwt/compare/3.0.0...3.0.1) - -Update to allow sync with Maven Central - -## [3.0.0](https://github.com/auth0/java-jwt/tree/3.0.0) (2016-12-05) - -Reimplemented java-jwt to improve API and include more signing algorithms - -## Installation - -### Maven - -```xml - - com.auth0 - java-jwt - 3.0.0 - -``` - -### Gradle - -```gradle -compile 'com.auth0:java-jwt:3.0.0' -``` - -## Available Algorithms - -The library implements JWT Verification and Signing using the following algorithms: - -| JWS | Algorithm | Description | -| :-------------: | :-------------: | :----- | -| HS256 | HMAC256 | HMAC with SHA-256 | -| HS384 | HMAC384 | HMAC with SHA-384 | -| HS512 | HMAC512 | HMAC with SHA-512 | -| RS256 | RSA256 | RSASSA-PKCS1-v1_5 with SHA-256 | -| RS384 | RSA384 | RSASSA-PKCS1-v1_5 with SHA-384 | -| RS512 | RSA512 | RSASSA-PKCS1-v1_5 with SHA-512 | -| ES256 | ECDSA256 | ECDSA with curve P-256 and SHA-256 | -| ES384 | ECDSA384 | ECDSA with curve P-384 and SHA-384 | -| ES512 | ECDSA512 | ECDSA with curve P-521 and SHA-512 | diff --git a/EXAMPLES.md b/EXAMPLES.md deleted file mode 100644 index 995e4c1d..00000000 --- a/EXAMPLES.md +++ /dev/null @@ -1,130 +0,0 @@ -# Examples using java-jwt - -* [Inspecting a DecodedJWT](#inspecting-a-decodedjwt) -* [DateTime Claim Validation](#datetime-claim-validation) -* [Using custom claims](#using-custom-claims) -* [Using a KeyProvider](#using-a-keyprovider) - -## Inspecting a DecodedJWT - -The successful verification of a JWT returns a `DecodedJWT`, from which you can obtain its contents. - -```java -DecodedJWT jwt = JWT.require(algorithm) - .build() - .verify("a.b.c"); - -// standard claims can be retrieved through first-class methods -String subject = jwt.getSubject(); -String aud = jwt.getAudience(); -// ... - -// custom claims can also be obtained -String customStringClaim = jwt.getClaim("custom-string-claim").asString(); -``` - -When retrieving custom claims, a [Claim](https://javadoc.io/doc/com.auth0/java-jwt/latest/com/auth0/jwt/interfaces/Claim.html) is returned, which can then be used to obtain the value depending on the value's underlying type. - -## DateTime Claim Validation - -A JWT token may include DateNumber fields that can be used to validate that: - -* The token was issued in a past date `"iat" < NOW` -* The token hasn't expired yet `"exp" > NOW` -* The token can already be used. `"nbf" < NOW` - -When verifying a JWT, the standard DateTime claims are validated by default. A `JWTVerificationException` is thrown if any of the claim values are invalid. - -To specify a **leeway** in which the JWT should still be considered valid, use the `acceptLeeway()` method in the `JWTVerifier` builder and pass a positive seconds value. This applies to every item listed above. - -```java -JWTVerifier verifier = JWT.require(algorithm) - .acceptLeeway(1) // 1 sec for nbf, iat and exp - .build(); -``` - -You can also specify a custom value for a given DateTime claim and override the default one for only that claim. - -```java -JWTVerifier verifier = JWT.require(algorithm) - .acceptLeeway(1) //1 sec for nbf and iat - .acceptExpiresAt(5) //5 secs for exp - .build(); -``` - -If you need to test this behavior in your application, cast the `Verification` instance to a `BaseVerification` to gain visibility of the `verification.build()` method that accepts a `java.time.Clock`. e.g.: - -```java -BaseVerification verification = (BaseVerification) JWT.require(algorithm) - .acceptLeeway(1) - .acceptExpiresAt(5); -private final Clock mockNow = Clock.fixed(Instant.ofEpochSecond(1477592), ZoneId.of("UTC")); -JWTVerifier verifier = verification.build(clock); -``` - -## Using custom claims - -### JWT creation -A JWT can be built with custom payload and header claims, by using the `withHeader` and `withClaim` methods. - -```java -String jwt = JWT.create() - .withHeader(headerMap) - .withClaim("string-claim", "string-value") - .withClaim("number-claim", 42) - .withClaim("bool-claim", true) - .withClaim("datetime-claim", Instant.now()) - .sign(algorithm); -``` - -See the [JavaDoc](https://javadoc.io/doc/com.auth0/java-jwt/latest/com/auth0/jwt/JWTCreator.Builder.html) for all available custom claim methods. - -### JWT verification - -You can also verify a JWT's custom claims: - -```java -JWTVerifier verifier = JWT.require(algorithm) - .withClaim("number-claim", 123) - .withClaimPresence("some-claim-that-just-needs-to-be-present") - .withClaim("predicate-claim", (claim, decodedJWT) -> "custom value".equals(claim.asString())) - .build(); -DecodedJWT jwt = verifier.verify("my.jwt.token"); -``` - -See the [JavaDoc](https://javadoc.io/doc/com.auth0/java-jwt/latest/com/auth0/jwt/JWTVerifier.BaseVerification.html) for all available custom claim verification methods. - -## Using a KeyProvider - -A `KeyProvider` can be used to obtain the keys needed for signing and verifying a JWT. How these keys are constructed are beyond the scope of this library, but the [jwks-rsa-java](https://github.com/auth0/jwks-rsa-java) library provides the ability to obtain the public key from a JWK. -The example below demonstrates this for the RSA algorithm (`ECDSAKeyProvider` can be used for ECDSA). - -```java -JwkProvider provider = new JwkProviderBuilder("https://samples.auth0.com/") - .cached(10, 24, TimeUnit.HOURS) - .rateLimited(10, 1, TimeUnit.MINUTES) - .build(); -final RSAPrivateKey privateKey = // private key -final String privateKeyId = // private key ID - -RSAKeyProvider keyProvider = new RSAKeyProvider() { - @Override - public RSAPublicKey getPublicKeyById(String kid) { - return (RSAPublicKey) jwkProvider.get(kid).getPublicKey(); - } - - @Override - public RSAPrivateKey getPrivateKey() { - // return the private key used - return rsaPrivateKey; - } - - @Override - public String getPrivateKeyId() { - return rsaPrivateKeyId; - } -}; - -Algorithm algorithm = Algorithm.RSA256(keyProvider); -//Use the Algorithm to create and verify JWTs. -``` diff --git a/LICENSE b/LICENSE.txt similarity index 100% rename from LICENSE rename to LICENSE.txt diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md deleted file mode 100644 index c47b95c2..00000000 --- a/MIGRATION_GUIDE.md +++ /dev/null @@ -1,85 +0,0 @@ -# Migration Guide - -## Upgrading from v3.x -> v4.0 - -The version 4 release contains several improvements: - -- Support for `java.time.Instant` when creating or verifying JWTs with Numeric Date claim values. -- Improvements to JWT claim validation, including support for custom claim validation using Predicates. -- Improved exception handling when validating JWTs, to better inform of the reason for failed validation. -- Consistent handling of `null` claim values both when creating and validation JWTs. - -This guide captures the changes you should be aware of when planning and upgrading to version 4. - -### Compile or runtime breaking changes - -**Classes or methods removed:** -- The `impl` package has been removed as an export in `module-info.java`. This package contains implementation-specific code that may change at any point. -- Support for the ES256K algorithm has been removed, as it is disabled in Java 15+. The `Algorithm#ECDSA256K(ECDSAKeyProvider keyProvider)` and `Algorithm#ECDSA256K(ECPublicKey publicKey, ECPrivateKey privateKey)` methods have been removed. -- `com.auth0.jwt.interfaces.Clock` has been removed. Instead, an implementation of `java.time.Clock` can be passed to the `BaseVerification` for testing purposes. -- `com.auth0.jwt.impl.NullClaim` has been removed. `Claim#isNull` can be used to determine if a claim's value is `null`. -- `com.auth0.jwt.impl.PublicClaims` was removed, and replaced by `com.auth0.jwt.RegisteredClaims` and `com.auth0.jwt.HeaderParams`. -- `com.auth0.jwt.interfaces.Verification#withAnyOfAudience` no longer provides a default implementation. - -### Behavioral potentially breaking changes - -#### JWT creation - -- All date/time claim values are now serialized as **seconds since the epoch**, in both the payload and header. In version 3, date/time claims nested in a list or map, as well as any header parameters with date/time values, were serialized as milliseconds since the epoch. -- When creating a JWT, passing `null` as the value no longer removes the claim if it was previously added to the builder. It now adds the claim with a `null` value. - -#### JWT validation - -- In version 3, specifying multiple claim expectations for the same claim name would override any previous expectations for that claim. In version 4, all expectations for that claim will be validated. -- In version 3, passing `null` for the value of a claim expectation would remove that expectation from the validation. In version 4, passing `null` does not remove that expectation, but instead validates that the claim has the literal value `null`. -- When validating a JWT, if an expected claim is present in the JWT but contains a value different from the one expected, an `IncorrectClaimException` (subclass of `InvalidClaimException`) will now be thrown instead of an `InvalidClaimException`. -- When validating a JWT, if an expected claim is not present in the JWT, an `MissingClaimException` (subclass of `InvalidClaimException`) will now be thrown instead of an `InvalidClaimException`. -- `withClaimPresence(String claimName)` now validates that the claim is present in the JWT, and a claim with a `null` value is considered present. Previously, a claim with a value of `null` would be considered as missing and fail the validation. -- When validating a date/time claim value, the validation no longer checks for strict equality of the claim's value and the provided `Date` (or `Instant`). Instead, the expected `Date` or `Instant` will be compared to the claim's value only considering seconds (because JWT date/time claims are represented as seconds since the epoch). - -#### Claim changes - -- `com.auth0.jwt.interfaces.Claim#isNull()` now returns true only if the claim is present and its value is `null`. Previously, it returned true if the claim was present and its value was `null`, or if the claim was not present in the JWT. To check if the claim is present or not in the JWT, use `isMissing()`. - -### New classes or methods - -#### `IncorrectClaimException` added - -This class extends `InvalidClaimException` and represents that when validating a JWT, an expected claim exists in the JWT but does not match the expected value. - -#### `MissingClaimException` added - -This class extends `InvalidClaimException` and represents that when validating a JWT, an expected claim is missing from the JWT. - -#### `HeaderParams` added - -This class contains constants representing common header parameter names. - -#### `RegisteredClaims` added - -This class contains constants representing the registered claim names. - -#### `JWTCreator` new methods - -- `JWTCreator.Builder#withExpiresAt(Instant expiresAt)` - adds the `exp` claim to the JWT from a `java.time.Instant`. -- `JWTCreator.Builder#withNotBefore(Instant notBefore)` - adds the `nbf` claim to the JWT from a `java.time.Instant`. -- `JWTCreator.Builder#withIssuedAt(Instant issuedAt)` - adds the `iat` claim to the JWT from a `java.time.Instant`. -- `JWTCreator.Builder#withClaim(String claimName, Instant value)` - adds a claim to the JWT from a `java.time.Instant`. -- `JWTCreator.Builder#withNullClaim(String claimName)` - adds a claim to the JWT with the literal value `null`. - -#### `DecodedJWT` new methods - -- `Instant getExpiresAtAsInstant()` - Returns a JWT's `exp` claim as a `java.time.Instant`. -- `Instant getNotBeforeAsInstant()` - Returns a JWT's `nbf` claim as a `java.time.Instant`. -- `Instant getIssuedAtAsInstant()` - Returns a JWT's `iat` claim as a `java.time.Instant`. - -#### `Claim` new methods - -- `Instant asInstant()` - Gets a claim as a `java.time.Instant`. -- `boolean isMissing()` - Returns whether the claim is present or not. - -#### `Verification` new methods - -- `Verification withClaim(String name, Instant value)` - Adds an expectation that a claim with the provided name has a value equal to the provided `java.time.Instant`. -- `Verification withClaim(String name, BiPredicate predicate)` - Allows for a claim to be validated with the supplied predicate. -- `Verification withNullClaim(String name)` - Adds an expectation that a claim with the provided name has a value equal to the literal `null`. diff --git a/README.md b/README.md index 9d0ae41c..93236bbd 100644 --- a/README.md +++ b/README.md @@ -1,137 +1,88 @@ -> **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. +# Java JWT -![A Java implementation of JSON Web Token (JWT) - RFC 7519.](https://cdn.auth0.com/website/sdks/banners/java-jwt-banner.png) +[![Build Status](https://travis-ci.org/auth0/java-jwt.svg?branch=master)](https://travis-ci.org/auth0/java-jwt) +[![Coverage Status](https://img.shields.io/codecov/c/github/auth0/java-jwt/master.svg?style=flat-square)](https://codecov.io/github/auth0/java-jwt) +[![License](http://img.shields.io/:license-mit-blue.svg?style=flat)](http://doge.mit-license.org) +[![Maven Central](https://img.shields.io/maven-central/v/com.auth0/java-jwt.svg)](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22java-jwt%22) -![Build Status](https://img.shields.io/github/checks-status/auth0/java-jwt/master) -[![Coverage Status](https://img.shields.io/codecov/c/github/auth0/java-jwt.svg?style=flat-square)](https://codecov.io/github/auth0/java-jwt) -[![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/java-jwt.svg?style=flat-square)](https://mvnrepository.com/artifact/com.auth0/java-jwt) -[![javadoc](https://javadoc.io/badge2/com.auth0/auth0/javadoc.svg)](https://javadoc.io/doc/com.auth0/java-jwt) +An implementation of [JSON Web Tokens](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html) developed against `draft-ietf-oauth-json-web-token-08`. -:books: [Documentation](#documentation) - :rocket: [Getting Started](#getting-started) - :computer: [API Reference](#api-reference) :speech_balloon: [Feedback](#feedback) +## Installation -## Documentation -- [Examples](./EXAMPLES.md) - code samples for common java-jwt scenarios. -- [Docs site](https://www.auth0.com/docs) - explore our docs site and learn more about Auth0. - -## Getting Started - -### Requirements - -This library is supported for Java LTS versions 8, 11, and 17. For issues on non-LTS versions above 8, consideration will be given on a case-by-case basis. - -> `java-jwt` is intended for server-side JVM applications. Android applications should use [JWTDecode.Android](https://github.com/auth0/JWTDecode.Android). - -`java-jwt` supports the following algorithms for both signing and verification: - -| JWS | Algorithm | Description | -| :-------------: | :-------------: | :----- | -| HS256 | HMAC256 | HMAC with SHA-256 | -| HS384 | HMAC384 | HMAC with SHA-384 | -| HS512 | HMAC512 | HMAC with SHA-512 | -| RS256 | RSA256 | RSASSA-PKCS1-v1_5 with SHA-256 | -| RS384 | RSA384 | RSASSA-PKCS1-v1_5 with SHA-384 | -| RS512 | RSA512 | RSASSA-PKCS1-v1_5 with SHA-512 | -| ES256 | ECDSA256 | ECDSA with curve P-256 and SHA-256 | -| ES384 | ECDSA384 | ECDSA with curve P-384 and SHA-384 | -| ES512 | ECDSA512 | ECDSA with curve P-521 and SHA-512 | - -> Note - Support for ECDSA with curve secp256k1 and SHA-256 (ES256K) has been dropped since it has been [disabled in Java 15](https://www.oracle.com/java/technologies/javase/15-relnote-issues.html#JDK-8237219) - -> :warning: **Important security note:** JVM has a critical vulnerability for ECDSA Algorithms - [CVE-2022-21449](https://nvd.nist.gov/vuln/detail/CVE-2022-21449). Please review the details of the vulnerability and update your environment. -### Installation - -Add the dependency via Maven: +### Maven ```xml - com.auth0 - java-jwt - 4.5.0 + com.auth0 + java-jwt + 2.2.1 ``` -or Gradle: +### Gradle ```gradle -implementation 'com.auth0:java-jwt:4.5.0' +compile 'com.auth0:java-jwt:2.2.1' ``` -### Create a JWT - -Use `JWT.create()`, configure the claims, and then call `sign(algorithm)` to sign the JWT. +## Usage -The example below demonstrates this using the `RS256` signing algorithm: +### Sign JWT (HS256) ```java -try { - Algorithm algorithm = Algorithm.RSA256(rsaPublicKey, rsaPrivateKey); - String token = JWT.create() - .withIssuer("auth0") - .sign(algorithm); -} catch (JWTCreationException exception){ - // Invalid Signing configuration / Couldn't convert Claims. -} -``` +final String issuer = "https://mydomain.com/"; +final String secret = "{{secret used for signing}}"; -### Verify a JWT +final long iat = System.currentTimeMillis() / 1000L; // issued at claim +final long exp = iat + 60L; // expires claim. In this case the token expires in 60 seconds -Create a `JWTVerifier` passing the `Algorithm`, and specify any required claim values. +final JWTSigner signer = new JWTSigner(secret); +final HashMap claims = new HashMap(); +claims.put("iss", issuer); +claims.put("exp", exp); +claims.put("iat", iat); + +final String jwt = signer.sign(claims); +``` -The following example uses `RS256` to verify the JWT. +### Verify JWT (HS256) ```java -String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; -DecodedJWT decodedJWT; +final String secret = "{{secret used for signing}}"; try { - Algorithm algorithm = Algorithm.RSA256(rsaPublicKey, rsaPrivateKey); - JWTVerifier verifier = JWT.require(algorithm) - // specify any specific claim validations - .withIssuer("auth0") - // reusable verifier instance - .build(); - - decodedJWT = verifier.verify(token); -} catch (JWTVerificationException exception){ - // Invalid signature/claims + final JWTVerifier verifier = new JWTVerifier(secret); + final Map claims= verifier.verify(jwt); +} catch (JWTVerifyException e) { + // Invalid Token } ``` -If the token has an invalid signature or the Claim requirement is not met, a `JWTVerificationException` will be thrown. +### Validate aud & iss claims -See the [examples](./EXAMPLES.md) and [JavaDocs](https://javadoc.io/doc/com.auth0/java-jwt/latest) for additional documentation. - -## API Reference +```java +final String secret = "{{secret used for signing}}"; +try { + final JWTVerifier verifier = new JWTVerifier(secret, "{{my-audience}}", "{{my-issuer}}"); + final Map claims= verifier.verify(jwt); +} catch (JWTVerifyException e) { + // Invalid Token +} +``` -- [java-jwt JavaDocs](https://javadoc.io/doc/com.auth0/java-jwt/latest) -## Feedback +### Why another JSON Web Token implementation for Java? -### Contributing +We believe existing JWT implementations in Java are either too complex or not tested enough. +This library aims to be simple and achieve the right level of abstraction. -We appreciate feedback and contribution to this repo! Before you get started, please see the following: +## Issue Reporting -- [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)) +If you have found a bug or if you have a feature request, please report them at this repository issues section. 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. -### Raise an issue -To provide feedback or report a bug, [please raise an issue on our issue tracker](https://github.com/auth0/java-jwt/issues). +## Author -### 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](https://auth0.com/) ---- +## License -

- - - - 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.

+This project is licensed under the MIT license. See the [LICENSE](LICENSE.txt) file for more info. diff --git a/build.gradle b/build.gradle deleted file mode 100644 index c938b200..00000000 --- a/build.gradle +++ /dev/null @@ -1,9 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -allprojects { - group = 'com.auth0' - - repositories { - mavenCentral() - } -} diff --git a/.codecov.yml b/codecov.yml similarity index 71% rename from .codecov.yml rename to codecov.yml index de278af2..63e5785f 100644 --- a/.codecov.yml +++ b/codecov.yml @@ -5,12 +5,10 @@ coverage: status: patch: default: - if_no_uploads: success - if_ci_failed: error + if_no_uploads: error changes: true project: default: target: auto - threshold: 1% if_no_uploads: error comment: false \ No newline at end of file diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml deleted file mode 100644 index b97ccc37..00000000 --- a/config/checkstyle/checkstyle.xml +++ /dev/null @@ -1,358 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index 74a5a049..00000000 --- a/gradle.properties +++ /dev/null @@ -1,38 +0,0 @@ -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx1536m - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true - -GROUP=com.auth0 -POM_ARTIFACT_ID=java-jwt - -POM_NAME=java jwt -POM_DESCRIPTION=Java client library for the Auth0 platform -POM_PACKAGING=jar - -POM_URL=https://github.com/auth0/java-jwt -POM_SCM_URL=https://github.com/auth0/java-jwt - -POM_SCM_CONNECTION=scm:git:https://github.com/auth0/java-jwt.git -POM_SCM_DEV_CONNECTION=scm:git:https://github.com/auth0/java-jwt.git - -POM_LICENCE_NAME=The MIT License (MIT) -POM_LICENCE_URL=https://raw.githubusercontent.com/auth0/java-jwt/master/LICENSE -POM_LICENCE_DIST=repo - -POM_DEVELOPER_ID=auth0 -POM_DEVELOPER_NAME=Auth0 -POM_DEVELOPER_EMAIL=oss@auth0.com \ No newline at end of file diff --git a/gradle/maven-publish.gradle b/gradle/maven-publish.gradle deleted file mode 100644 index a9ad38d3..00000000 --- a/gradle/maven-publish.gradle +++ /dev/null @@ -1,113 +0,0 @@ -apply plugin: 'maven-publish' -apply plugin: 'signing' - -task('sourcesJar', type: Jar, dependsOn: classes) { - archiveClassifier = 'sources' - from sourceSets.main.allSource -} - -task('javadocJar', type: Jar, dependsOn: javadoc) { - archiveClassifier = 'javadoc' - from javadoc.getDestinationDir() -} -tasks.withType(Javadoc).configureEach { - javadocTool = javaToolchains.javadocToolFor { - // Use latest JDK for javadoc generation - languageVersion = JavaLanguageVersion.of(17) - } -} - -javadoc { - // Specify the Java version that the project will use - options.addStringOption('-release', "11") -} -artifacts { - archives sourcesJar, javadocJar -} - - -final releaseRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" -final snapshotRepositoryUrl = "https://oss.sonatype.org/content/repositories/snapshots/" - -publishing { - publications { - mavenJava(MavenPublication) { - - groupId = GROUP - artifactId = POM_ARTIFACT_ID - version = getVersionName() - - artifact("$buildDir/libs/${project.name}-${version}.jar") - artifact sourcesJar - artifact javadocJar - - pom { - name = POM_NAME - packaging = POM_PACKAGING - description = POM_DESCRIPTION - url = POM_URL - - licenses { - license { - name = POM_LICENCE_NAME - url = POM_LICENCE_URL - distribution = POM_LICENCE_DIST - } - } - - developers { - developer { - id = POM_DEVELOPER_ID - name = POM_DEVELOPER_NAME - email = POM_DEVELOPER_EMAIL - } - } - - scm { - url = POM_SCM_URL - connection = POM_SCM_CONNECTION - developerConnection = POM_SCM_DEV_CONNECTION - } - - pom.withXml { - def dependenciesNode = asNode().appendNode('dependencies') - - project.configurations.implementation.allDependencies.each { - def dependencyNode = dependenciesNode.appendNode('dependency') - dependencyNode.appendNode('groupId', it.group) - dependencyNode.appendNode('artifactId', it.name) - dependencyNode.appendNode('version', it.version) - } - } - } - } - } - repositories { - maven { - name = "sonatype" - url = version.endsWith('SNAPSHOT') ? snapshotRepositoryUrl : releaseRepositoryUrl - credentials { - username = System.getenv("MAVEN_USERNAME") - password = System.getenv("MAVEN_PASSWORD") - } - } - } -} - -signing { - def signingKey = System.getenv("SIGNING_KEY") - def signingPassword = System.getenv("SIGNING_PASSWORD") - useInMemoryPgpKeys(signingKey, signingPassword) - - sign publishing.publications.mavenJava -} - -javadoc { - if(JavaVersion.current().isJava9Compatible()) { - options.addBooleanOption('html5', true) - } -} - -tasks.named('publish').configure { - dependsOn tasks.named('assemble') -} \ No newline at end of file diff --git a/gradle/versioning.gradle b/gradle/versioning.gradle deleted file mode 100644 index 3441ae11..00000000 --- a/gradle/versioning.gradle +++ /dev/null @@ -1,17 +0,0 @@ -def getVersionFromFile() { - def versionFile = rootProject.file('.version') - return versionFile.text.readLines().first().trim() -} - -def isSnapshot() { - return hasProperty('isSnapshot') ? isSnapshot.toBoolean() : true -} - -def getVersionName() { - return isSnapshot() ? project.version+"-SNAPSHOT" : project.version -} - -ext { - getVersionName = this.&getVersionName - getVersionFromFile = this.&getVersionFromFile -} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e708b1c0..00000000 Binary files a/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index ec991f9a..00000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew deleted file mode 100755 index 4f906e0c..00000000 --- a/gradlew +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env sh - -# -# Copyright 2015 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# 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 -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"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# 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 - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -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" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -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. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -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 -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 - -# 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 - # 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\"" - fi - i=`expr $i + 1` - 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" - -exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index ac1b06f9..00000000 --- a/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "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. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -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. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="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 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/lib/.gitignore b/lib/.gitignore deleted file mode 100644 index 796b96d1..00000000 --- a/lib/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/lib/build.gradle b/lib/build.gradle deleted file mode 100644 index 83093fc1..00000000 --- a/lib/build.gradle +++ /dev/null @@ -1,244 +0,0 @@ -buildscript { - repositories { - jcenter() - } - - dependencies { - // https://github.com/melix/japicmp-gradle-plugin/issues/36 - classpath 'com.google.guava:guava:31.1-jre' - } -} - -plugins { - id 'java' - id 'jacoco' - id 'checkstyle' - id 'me.champeau.gradle.japicmp' version '0.4.1' -} - -sourceSets { - jmh { - - } -} - -configurations { - jmhImplementation { - extendsFrom implementation - } -} - -checkstyle { - toolVersion '10.0' -} -//We are disabling lint checks for tests -tasks.named("checkstyleTest").configure({ - enabled = false -}) -tasks.named("checkstyleJmh").configure({ - enabled = false -}) - -apply from: rootProject.file('gradle/versioning.gradle') - -version = getVersionFromFile() -group = GROUP -logger.lifecycle("Using version ${version} for ${name} group $group") - -import me.champeau.gradle.japicmp.JapicmpTask - -project.afterEvaluate { - - def versions = project.ext.testInJavaVersions - for (pluginJavaTestVersion in versions) { - def taskName = "testInJava-${pluginJavaTestVersion}" - tasks.register(taskName, Test) { - def versionToUse = taskName.split("-").getAt(1) as Integer - description = "Runs unit tests on Java version ${versionToUse}." - project.logger.quiet("Test will be running in ${versionToUse}") - group = 'verification' - javaLauncher.set(javaToolchains.launcherFor { - languageVersion = JavaLanguageVersion.of(versionToUse) - }) - shouldRunAfter(tasks.named('test')) - } - tasks.named('check') { - dependsOn(taskName) - } - } - - project.configure(project) { - def baselineVersion = project.ext.baselineCompareVersion - task('apiDiff', type: JapicmpTask, dependsOn: 'jar') { - oldClasspath.from(files(getBaselineJar(project, baselineVersion))) - newClasspath.from(files(jar.archiveFile)) - onlyModified = true - failOnModification = true - ignoreMissingClasses = true - htmlOutputFile = file("$buildDir/reports/apiDiff/apiDiff.html") - txtOutputFile = file("$buildDir/reports/apiDiff/apiDiff.txt") - doLast { - project.logger.quiet("Comparing against baseline version ${baselineVersion}") - } - } - } -} - -private static File getBaselineJar(Project project, String baselineVersion) { - // Use detached configuration: https://github.com/square/okhttp/blob/master/build.gradle#L270 - def group = project.group - try { - def baseline = "${project.group}:${project.name}:$baselineVersion" - project.group = 'virtual_group_for_japicmp' - def dependency = project.dependencies.create(baseline + "@jar") - return project.configurations.detachedConfiguration(dependency).files.find { - it.name == "${project.name}-${baselineVersion}.jar" - } - } finally { - project.group = group - } -} - -ext { - baselineCompareVersion = '4.1.0' - testInJavaVersions = [8, 11, 17, 21] -} - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(11) - } -} - -compileJava { - exclude 'module-info.java' - // Required to be compatible with JDK 8+ - options.release = 8 -} - -javadoc { - // Exclude internal implementation package from javadoc - excludes = ['com/auth0/jwt/impl', 'module-info.java'] -} - -dependencies { - implementation 'com.fasterxml.jackson.core:jackson-core:2.15.4' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.4' - - testImplementation 'org.bouncycastle:bcprov-jdk15on:1.70' - testImplementation 'junit:junit:4.13.2' - testImplementation 'net.jodah:concurrentunit:0.4.6' - testImplementation 'org.hamcrest:hamcrest:2.2' - testImplementation 'org.mockito:mockito-core:4.4.0' - - jmhImplementation sourceSets.main.output - jmhImplementation 'org.openjdk.jmh:jmh-core:1.35' - jmhAnnotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.35' -} - -jacoco { - toolVersion = "0.8.10" -} - -jacocoTestReport { - reports { - xml.enabled = true - html.enabled = true - } -} - -test { - testLogging { - events "skipped", "failed", "standardError" - exceptionFormat "short" - } -} - -task compileModuleInfoJava(type: JavaCompile) { - classpath = files() - source = 'src/main/java/module-info.java' - destinationDir = compileJava.destinationDir - doLast { - def descriptor = new File(compileJava.destinationDir, 'module-info.class') - def dest = new File(compileJava.destinationDir, 'META-INF/versions/9') - ant.move file: descriptor, todir: dest - } - - doFirst { - options.compilerArgs = [ - '--release', '9', - '--module-path', compileJava.classpath.asPath - ] - } -} - -compileTestJava { - options.release = 8 - options.compilerArgs = ["-Xlint:deprecation"] -} - -def testJava8 = tasks.register('testJava8', Test) { - description = 'Runs unit tests on Java 8.' - group = 'verification' - - javaLauncher.set(javaToolchains.launcherFor { - languageVersion = JavaLanguageVersion.of(8) - }) - shouldRunAfter(tasks.named('test')) -} - -def testJava17 = tasks.register('testJava17', Test) { - description = 'Runs unit tests on Java 17.' - group = 'verification' - - javaLauncher.set(javaToolchains.launcherFor { - languageVersion = JavaLanguageVersion.of(17) - }) - shouldRunAfter(tasks.named('test')) -} - -def testJava21 = tasks.register('testJava21', Test) { - description = 'Runs unit tests on Java 21.' - group = 'verification' - - javaLauncher.set(javaToolchains.launcherFor { - languageVersion = JavaLanguageVersion.of(21) - }) - shouldRunAfter(tasks.named('test')) -} - -tasks.named('check') { - dependsOn(testJava8) - dependsOn(testJava17) - dependsOn(testJava21) -} - -jar { - manifest.attributes('Multi-Release': 'true') -} - -compileModuleInfoJava.dependsOn compileJava -classes.dependsOn compileModuleInfoJava - -// you can pass any arguments JMH accepts via Gradle args. -// Example: ./gradlew runJMH --args="-lrf" -tasks.register('runJMH', JavaExec) { - description 'Run JMH benchmarks.' - group 'verification' - - main 'org.openjdk.jmh.Main' - classpath sourceSets.jmh.runtimeClasspath - - args project.hasProperty("args") ? project.property("args").split() : "" -} -tasks.register('jmhHelp', JavaExec) { - description 'Prints the available command line options for JMH.' - group 'help' - - main 'org.openjdk.jmh.Main' - classpath sourceSets.jmh.runtimeClasspath - - args '-h' -} - -apply from: rootProject.file('gradle/maven-publish.gradle') diff --git a/lib/src/jmh/java/com/auth0/jwt/benchmark/JWTDecoderBenchmark.java b/lib/src/jmh/java/com/auth0/jwt/benchmark/JWTDecoderBenchmark.java deleted file mode 100644 index 81d3737a..00000000 --- a/lib/src/jmh/java/com/auth0/jwt/benchmark/JWTDecoderBenchmark.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.auth0.jwt.benchmark; - -import com.auth0.jwt.JWT; -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.infra.Blackhole; - -/** - * This class is a JMH benchmark for decoding JWTs. - */ -public class JWTDecoderBenchmark { - private static final String TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"; - - @Benchmark - @BenchmarkMode(Mode.Throughput) - public void throughputDecodeTime(Blackhole blackhole) { - blackhole.consume(JWT.decode(TOKEN)); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/HeaderParams.java b/lib/src/main/java/com/auth0/jwt/HeaderParams.java deleted file mode 100644 index 1107f313..00000000 --- a/lib/src/main/java/com/auth0/jwt/HeaderParams.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.auth0.jwt; - -/** - * Contains constants representing the JWT header parameter names. - */ -public final class HeaderParams { - - private HeaderParams() {} - - /** - * The algorithm used to sign a JWT. - */ - public static final String ALGORITHM = "alg"; - - /** - * The content type of the JWT. - */ - public static final String CONTENT_TYPE = "cty"; - - /** - * The media type of the JWT. - */ - public static final String TYPE = "typ"; - - /** - * The key ID of a JWT used to specify the key for signature validation. - */ - public static final String KEY_ID = "kid"; -} diff --git a/lib/src/main/java/com/auth0/jwt/JWT.java b/lib/src/main/java/com/auth0/jwt/JWT.java deleted file mode 100644 index 696abe40..00000000 --- a/lib/src/main/java/com/auth0/jwt/JWT.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.auth0.jwt; - -import com.auth0.jwt.algorithms.Algorithm; -import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.impl.JWTParser; -import com.auth0.jwt.interfaces.DecodedJWT; -import com.auth0.jwt.interfaces.Verification; - -/** - * Exposes all the JWT functionalities. - */ -@SuppressWarnings("WeakerAccess") -public class JWT { - - private final JWTParser parser; - - /** - * Constructs a new instance of the JWT library. Use this if you need to decode many JWT - * tokens on the fly and do not wish to instantiate a new parser for each invocation. - */ - public JWT() { - parser = new JWTParser(); - } - - /** - * Decode a given Json Web Token. - *

- * Note that this method doesn't verify the token's signature! - * Use it only if you trust the token or if you have already verified it. - * - * @param token with jwt format as string. - * @return a decoded JWT. - * @throws JWTDecodeException if any part of the token contained an invalid jwt - * or JSON format of each of the jwt parts. - */ - public DecodedJWT decodeJwt(String token) throws JWTDecodeException { - return new JWTDecoder(parser, token); - } - - /** - * Decode a given Json Web Token. - *

- * Note that this method doesn't verify the token's signature! - * Use it only if you trust the token or if you have already verified it. - * - * @param token with jwt format as string. - * @return a decoded JWT. - * @throws JWTDecodeException if any part of the token contained an invalid jwt - * or JSON format of each of the jwt parts. - */ - public static DecodedJWT decode(String token) throws JWTDecodeException { - return new JWTDecoder(token); - } - - /** - * Returns a {@link Verification} builder with the algorithm to be used to validate token signature. - * - * @param algorithm that will be used to verify the token's signature. - * @return {@link Verification} builder - * @throws IllegalArgumentException if the provided algorithm is null. - */ - public static Verification require(Algorithm algorithm) { - return JWTVerifier.init(algorithm); - } - - /** - * Returns a Json Web Token builder used to create and sign tokens. - * - * @return a token builder. - */ - public static JWTCreator.Builder create() { - return JWTCreator.init(); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java deleted file mode 100644 index bfcb9147..00000000 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ /dev/null @@ -1,631 +0,0 @@ -package com.auth0.jwt; - -import com.auth0.jwt.algorithms.Algorithm; -import com.auth0.jwt.exceptions.JWTCreationException; -import com.auth0.jwt.exceptions.SignatureGenerationException; -import com.auth0.jwt.impl.*; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.MapperFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.json.JsonMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; - -import java.nio.charset.StandardCharsets; -import java.time.Instant; -import java.util.*; -import java.util.Map.Entry; - -/** - * The JWTCreator class holds the sign method to generate a complete JWT (with Signature) - * from a given Header and Payload content. - *

- * This class is thread-safe. - */ -@SuppressWarnings("WeakerAccess") -public final class JWTCreator { - - private final Algorithm algorithm; - private final String headerJson; - private final String payloadJson; - - private static final ObjectMapper mapper; - private static final SimpleModule module; - - static { - module = new SimpleModule(); - module.addSerializer(PayloadClaimsHolder.class, new PayloadSerializer()); - module.addSerializer(HeaderClaimsHolder.class, new HeaderSerializer()); - - mapper = JsonMapper.builder() - .configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true) - .build() - .registerModule(module); - } - - private JWTCreator(Algorithm algorithm, Map headerClaims, Map payloadClaims) - throws JWTCreationException { - this.algorithm = algorithm; - try { - headerJson = mapper.writeValueAsString(new HeaderClaimsHolder(headerClaims)); - payloadJson = mapper.writeValueAsString(new PayloadClaimsHolder(payloadClaims)); - } catch (JsonProcessingException e) { - throw new JWTCreationException("Some of the Claims couldn't be converted to a valid JSON format.", e); - } - } - - - /** - * Initialize a JWTCreator instance. - * - * @return a JWTCreator.Builder instance to configure. - */ - static JWTCreator.Builder init() { - return new Builder(); - } - - /** - * The Builder class holds the Claims that defines the JWT to be created. - */ - public static class Builder { - private final Map payloadClaims; - private final Map headerClaims; - - Builder() { - this.payloadClaims = new LinkedHashMap<>(); - this.headerClaims = new LinkedHashMap<>(); - } - - /** - * Add specific Claims to set as the Header. - * If provided map is null then nothing is changed - * - * @param headerClaims the values to use as Claims in the token's Header. - * @return this same Builder instance. - */ - public Builder withHeader(Map headerClaims) { - if (headerClaims == null) { - return this; - } - - for (Map.Entry entry : headerClaims.entrySet()) { - if (entry.getValue() == null) { - this.headerClaims.remove(entry.getKey()); - } else { - this.headerClaims.put(entry.getKey(), entry.getValue()); - } - } - - return this; - } - - /** - * Add specific Claims to set as the Header. - * If provided json is null then nothing is changed - * - * @param headerClaimsJson the values to use as Claims in the token's Header. - * @return this same Builder instance. - * @throws IllegalArgumentException if json value has invalid structure - */ - public Builder withHeader(String headerClaimsJson) throws IllegalArgumentException { - if (headerClaimsJson == null) { - return this; - } - - try { - Map headerClaims = mapper.readValue(headerClaimsJson, LinkedHashMap.class); - return withHeader(headerClaims); - } catch (JsonProcessingException e) { - throw new IllegalArgumentException("Invalid header JSON", e); - } - } - - /** - * Add a specific Key Id ("kid") claim to the Header. - * If the {@link Algorithm} used to sign this token was instantiated with a KeyProvider, - * the 'kid' value will be taken from that provider and this one will be ignored. - * - * @param keyId the Key Id value. - * @return this same Builder instance. - */ - public Builder withKeyId(String keyId) { - this.headerClaims.put(HeaderParams.KEY_ID, keyId); - return this; - } - - /** - * Add a specific Issuer ("iss") claim to the Payload. - * - * @param issuer the Issuer value. - * @return this same Builder instance. - */ - public Builder withIssuer(String issuer) { - addClaim(RegisteredClaims.ISSUER, issuer); - return this; - } - - /** - * Add a specific Subject ("sub") claim to the Payload. - * - * @param subject the Subject value. - * @return this same Builder instance. - */ - public Builder withSubject(String subject) { - addClaim(RegisteredClaims.SUBJECT, subject); - return this; - } - - /** - * Add a specific Audience ("aud") claim to the Payload. - * - * @param audience the Audience value. - * @return this same Builder instance. - */ - public Builder withAudience(String... audience) { - addClaim(RegisteredClaims.AUDIENCE, audience); - return this; - } - - /** - * Add a specific Expires At ("exp") claim to the payload. The claim will be written as seconds since the epoch. - * Milliseconds will be truncated by rounding down to the nearest second. - * - * @param expiresAt the Expires At value. - * @return this same Builder instance. - */ - public Builder withExpiresAt(Date expiresAt) { - addClaim(RegisteredClaims.EXPIRES_AT, expiresAt); - return this; - } - - /** - * Add a specific Expires At ("exp") claim to the payload. The claim will be written as seconds since the epoch; - * Milliseconds will be truncated by rounding down to the nearest second. - * - * @param expiresAt the Expires At value. - * @return this same Builder instance. - */ - public Builder withExpiresAt(Instant expiresAt) { - addClaim(RegisteredClaims.EXPIRES_AT, expiresAt); - return this; - } - - /** - * Add a specific Not Before ("nbf") claim to the Payload. The claim will be written as seconds since the epoch; - * Milliseconds will be truncated by rounding down to the nearest second. - * - * @param notBefore the Not Before value. - * @return this same Builder instance. - */ - public Builder withNotBefore(Date notBefore) { - addClaim(RegisteredClaims.NOT_BEFORE, notBefore); - return this; - } - - /** - * Add a specific Not Before ("nbf") claim to the Payload. The claim will be written as seconds since the epoch; - * Milliseconds will be truncated by rounding down to the nearest second. - * - * @param notBefore the Not Before value. - * @return this same Builder instance. - */ - public Builder withNotBefore(Instant notBefore) { - addClaim(RegisteredClaims.NOT_BEFORE, notBefore); - return this; - } - - /** - * Add a specific Issued At ("iat") claim to the Payload. The claim will be written as seconds since the epoch; - * Milliseconds will be truncated by rounding down to the nearest second. - * - * @param issuedAt the Issued At value. - * @return this same Builder instance. - */ - public Builder withIssuedAt(Date issuedAt) { - addClaim(RegisteredClaims.ISSUED_AT, issuedAt); - return this; - } - - /** - * Add a specific Issued At ("iat") claim to the Payload. The claim will be written as seconds since the epoch; - * Milliseconds will be truncated by rounding down to the nearest second. - * - * @param issuedAt the Issued At value. - * @return this same Builder instance. - */ - public Builder withIssuedAt(Instant issuedAt) { - addClaim(RegisteredClaims.ISSUED_AT, issuedAt); - return this; - } - - /** - * Add a specific JWT Id ("jti") claim to the Payload. - * - * @param jwtId the Token Id value. - * @return this same Builder instance. - */ - public Builder withJWTId(String jwtId) { - addClaim(RegisteredClaims.JWT_ID, jwtId); - return this; - } - - /** - * Add a custom Claim value. - * - * @param name the Claim's name. - * @param value the Claim's value. - * @return this same Builder instance. - * @throws IllegalArgumentException if the name is null. - */ - public Builder withClaim(String name, Boolean value) throws IllegalArgumentException { - assertNonNull(name); - addClaim(name, value); - return this; - } - - /** - * Add a custom Claim value. - * - * @param name the Claim's name. - * @param value the Claim's value. - * @return this same Builder instance. - * @throws IllegalArgumentException if the name is null. - */ - public Builder withClaim(String name, Integer value) throws IllegalArgumentException { - assertNonNull(name); - addClaim(name, value); - return this; - } - - /** - * Add a custom Claim value. - * - * @param name the Claim's name. - * @param value the Claim's value. - * @return this same Builder instance. - * @throws IllegalArgumentException if the name is null. - */ - public Builder withClaim(String name, Long value) throws IllegalArgumentException { - assertNonNull(name); - addClaim(name, value); - return this; - } - - /** - * Add a custom Claim value. - * - * @param name the Claim's name. - * @param value the Claim's value. - * @return this same Builder instance. - * @throws IllegalArgumentException if the name is null. - */ - public Builder withClaim(String name, Double value) throws IllegalArgumentException { - assertNonNull(name); - addClaim(name, value); - return this; - } - - /** - * Add a custom Claim value. - * - * @param name the Claim's name. - * @param value the Claim's value. - * @return this same Builder instance. - * @throws IllegalArgumentException if the name is null. - */ - public Builder withClaim(String name, String value) throws IllegalArgumentException { - assertNonNull(name); - addClaim(name, value); - return this; - } - - /** - * Add a custom Claim value. The claim will be written as seconds since the epoch. - * Milliseconds will be truncated by rounding down to the nearest second. - * - * @param name the Claim's name. - * @param value the Claim's value. - * @return this same Builder instance. - * @throws IllegalArgumentException if the name is null. - */ - public Builder withClaim(String name, Date value) throws IllegalArgumentException { - assertNonNull(name); - addClaim(name, value); - return this; - } - - /** - * Add a custom Claim value. The claim will be written as seconds since the epoch. - * Milliseconds will be truncated by rounding down to the nearest second. - * - * @param name the Claim's name. - * @param value the Claim's value. - * @return this same Builder instance. - * @throws IllegalArgumentException if the name is null. - */ - public Builder withClaim(String name, Instant value) throws IllegalArgumentException { - assertNonNull(name); - addClaim(name, value); - return this; - } - - /** - * Add a custom Map Claim with the given items. - *

- * Accepted nested types are {@linkplain Map} and {@linkplain List} with basic types - * {@linkplain Boolean}, {@linkplain Integer}, {@linkplain Long}, {@linkplain Double}, - * {@linkplain String} and {@linkplain Date}. {@linkplain Map}s cannot contain null keys or values. - * {@linkplain List}s can contain null elements. - * - * @param name the Claim's name. - * @param map the Claim's key-values. - * @return this same Builder instance. - * @throws IllegalArgumentException if the name is null, or if the map contents does not validate. - */ - public Builder withClaim(String name, Map map) throws IllegalArgumentException { - assertNonNull(name); - // validate map contents - if (map != null && !validateClaim(map)) { - throw new IllegalArgumentException("Expected map containing Map, List, Boolean, Integer, " - + "Long, Double, String and Date"); - } - addClaim(name, map); - return this; - } - - /** - * Add a custom List Claim with the given items. - *

- * Accepted nested types are {@linkplain Map} and {@linkplain List} with basic types - * {@linkplain Boolean}, {@linkplain Integer}, {@linkplain Long}, {@linkplain Double}, - * {@linkplain String} and {@linkplain Date}. {@linkplain Map}s cannot contain null keys or values. - * {@linkplain List}s can contain null elements. - * - * @param name the Claim's name. - * @param list the Claim's list of values. - * @return this same Builder instance. - * @throws IllegalArgumentException if the name is null, or if the list contents does not validate. - */ - public Builder withClaim(String name, List list) throws IllegalArgumentException { - assertNonNull(name); - // validate list contents - if (list != null && !validateClaim(list)) { - throw new IllegalArgumentException("Expected list containing Map, List, Boolean, Integer, " - + "Long, Double, String and Date"); - } - addClaim(name, list); - return this; - } - - /** - * Add a custom claim with null value. - * - * @param name the Claim's name. - * @return this same Builder instance. - * @throws IllegalArgumentException if the name is null - */ - public Builder withNullClaim(String name) throws IllegalArgumentException { - assertNonNull(name); - addClaim(name, null); - return this; - } - - /** - * Add a custom Array Claim with the given items. - * - * @param name the Claim's name. - * @param items the Claim's value. - * @return this same Builder instance. - * @throws IllegalArgumentException if the name is null. - */ - public Builder withArrayClaim(String name, String[] items) throws IllegalArgumentException { - assertNonNull(name); - addClaim(name, items); - return this; - } - - /** - * Add a custom Array Claim with the given items. - * - * @param name the Claim's name. - * @param items the Claim's value. - * @return this same Builder instance. - * @throws IllegalArgumentException if the name is null. - */ - public Builder withArrayClaim(String name, Integer[] items) throws IllegalArgumentException { - assertNonNull(name); - addClaim(name, items); - return this; - } - - /** - * Add a custom Array Claim with the given items. - * - * @param name the Claim's name. - * @param items the Claim's value. - * @return this same Builder instance. - * @throws IllegalArgumentException if the name is null - */ - public Builder withArrayClaim(String name, Long[] items) throws IllegalArgumentException { - assertNonNull(name); - addClaim(name, items); - return this; - } - - /** - * Add specific Claims to set as the Payload. If the provided map is null then - * nothing is changed. - *

- * Accepted types are {@linkplain Map} and {@linkplain List} with basic types - * {@linkplain Boolean}, {@linkplain Integer}, {@linkplain Long}, {@linkplain Double}, - * {@linkplain String} and {@linkplain Date}. - * {@linkplain Map}s and {@linkplain List}s can contain null elements. - *

- * - *

- * If any of the claims are invalid, none will be added. - *

- * - * @param payloadClaims the values to use as Claims in the token's payload. - * @return this same Builder instance. - * @throws IllegalArgumentException if any of the claim keys or null, - * or if the values are not of a supported type. - */ - public Builder withPayload(Map payloadClaims) throws IllegalArgumentException { - if (payloadClaims == null) { - return this; - } - - if (!validatePayload(payloadClaims)) { - throw new IllegalArgumentException("Claim values must only be of types Map, List, Boolean, Integer, " - + "Long, Double, String, Date, Instant, and Null"); - } - - // add claims only after validating all claims so as not to corrupt the claims map of this builder - for (Map.Entry entry : payloadClaims.entrySet()) { - addClaim(entry.getKey(), entry.getValue()); - } - - return this; - } - - /** - * Add specific Claims to set as the Payload. If the provided json is null then - * nothing is changed. - * - *

- * If any of the claims are invalid, none will be added. - *

- * - * @param payloadClaimsJson the values to use as Claims in the token's payload. - * @return this same Builder instance. - * @throws IllegalArgumentException if any of the claim keys or null, - * or if the values are not of a supported type, - * or if json value has invalid structure. - */ - public Builder withPayload(String payloadClaimsJson) throws IllegalArgumentException { - if (payloadClaimsJson == null) { - return this; - } - - try { - Map payloadClaims = mapper.readValue(payloadClaimsJson, LinkedHashMap.class); - return withPayload(payloadClaims); - } catch (JsonProcessingException e) { - throw new IllegalArgumentException("Invalid payload JSON", e); - } - } - - private boolean validatePayload(Map payload) { - for (Map.Entry entry : payload.entrySet()) { - String key = entry.getKey(); - assertNonNull(key); - - Object value = entry.getValue(); - if (value instanceof List && !validateClaim((List) value)) { - return false; - } else if (value instanceof Map && !validateClaim((Map) value)) { - return false; - } else if (!isSupportedType(value)) { - return false; - } - } - return true; - } - - private static boolean validateClaim(Map map) { - // do not accept null values in maps - for (Entry entry : map.entrySet()) { - Object value = entry.getValue(); - if (!isSupportedType(value)) { - return false; - } - - if (!(entry.getKey() instanceof String)) { - return false; - } - } - return true; - } - - private static boolean validateClaim(List list) { - // accept null values in list - for (Object object : list) { - if (!isSupportedType(object)) { - return false; - } - } - return true; - } - - private static boolean isSupportedType(Object value) { - if (value instanceof List) { - return validateClaim((List) value); - } else if (value instanceof Map) { - return validateClaim((Map) value); - } else { - return isBasicType(value); - } - } - - private static boolean isBasicType(Object value) { - if (value == null) { - return true; - } else { - Class c = value.getClass(); - - if (c.isArray()) { - return c == Integer[].class || c == Long[].class || c == String[].class; - } - return c == String.class || c == Integer.class || c == Long.class || c == Double.class - || c == Date.class || c == Instant.class || c == Boolean.class; - } - } - - /** - * Creates a new JWT and signs it with the given algorithm. - * - * @param algorithm used to sign the JWT - * @return a new JWT token - * @throws IllegalArgumentException if the provided algorithm is null. - * @throws JWTCreationException if the claims could not be converted to a valid JSON - * or there was a problem with the signing key. - */ - public String sign(Algorithm algorithm) throws IllegalArgumentException, JWTCreationException { - if (algorithm == null) { - throw new IllegalArgumentException("The Algorithm cannot be null."); - } - headerClaims.put(HeaderParams.ALGORITHM, algorithm.getName()); - if (!headerClaims.containsKey(HeaderParams.TYPE)) { - headerClaims.put(HeaderParams.TYPE, "JWT"); - } - String signingKeyId = algorithm.getSigningKeyId(); - if (signingKeyId != null) { - withKeyId(signingKeyId); - } - return new JWTCreator(algorithm, headerClaims, payloadClaims).sign(); - } - - private void assertNonNull(String name) { - if (name == null) { - throw new IllegalArgumentException("The Custom Claim's name can't be null."); - } - } - - private void addClaim(String name, Object value) { - payloadClaims.put(name, value); - } - } - - private String sign() throws SignatureGenerationException { - String header = Base64.getUrlEncoder().withoutPadding() - .encodeToString(headerJson.getBytes(StandardCharsets.UTF_8)); - String payload = Base64.getUrlEncoder().withoutPadding() - .encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8)); - - byte[] signatureBytes = algorithm.sign(header.getBytes(StandardCharsets.UTF_8), - payload.getBytes(StandardCharsets.UTF_8)); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString((signatureBytes)); - - return String.format("%s.%s.%s", header, payload, signature); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/JWTDecoder.java b/lib/src/main/java/com/auth0/jwt/JWTDecoder.java deleted file mode 100644 index cc283095..00000000 --- a/lib/src/main/java/com/auth0/jwt/JWTDecoder.java +++ /dev/null @@ -1,156 +0,0 @@ -package com.auth0.jwt; - -import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.impl.JWTParser; -import com.auth0.jwt.interfaces.Claim; -import com.auth0.jwt.interfaces.DecodedJWT; -import com.auth0.jwt.interfaces.Header; -import com.auth0.jwt.interfaces.Payload; - -import java.io.Serializable; -import java.nio.charset.StandardCharsets; -import java.time.Instant; -import java.util.Base64; -import java.util.Date; -import java.util.List; -import java.util.Map; - -/** - * The JWTDecoder class holds the decode method to parse a given JWT token into it's JWT representation. - *

- * This class is thread-safe. - */ -@SuppressWarnings("WeakerAccess") -final class JWTDecoder implements DecodedJWT, Serializable { - - private static final long serialVersionUID = 1873362438023312895L; - - private final String[] parts; - private final Header header; - private final Payload payload; - - JWTDecoder(String jwt) throws JWTDecodeException { - this(new JWTParser(), jwt); - } - - JWTDecoder(JWTParser converter, String jwt) throws JWTDecodeException { - parts = TokenUtils.splitToken(jwt); - String headerJson; - String payloadJson; - try { - headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); - } catch (NullPointerException e) { - throw new JWTDecodeException("The UTF-8 Charset isn't initialized.", e); - } catch (IllegalArgumentException e) { - throw new JWTDecodeException("The input is not a valid base 64 encoded string.", e); - } - header = converter.parseHeader(headerJson); - payload = converter.parsePayload(payloadJson); - } - - @Override - public String getAlgorithm() { - return header.getAlgorithm(); - } - - @Override - public String getType() { - return header.getType(); - } - - @Override - public String getContentType() { - return header.getContentType(); - } - - @Override - public String getKeyId() { - return header.getKeyId(); - } - - @Override - public Claim getHeaderClaim(String name) { - return header.getHeaderClaim(name); - } - - @Override - public String getIssuer() { - return payload.getIssuer(); - } - - @Override - public String getSubject() { - return payload.getSubject(); - } - - @Override - public List getAudience() { - return payload.getAudience(); - } - - @Override - public Date getExpiresAt() { - return payload.getExpiresAt(); - } - - @Override - public Instant getExpiresAtAsInstant() { - return payload.getExpiresAtAsInstant(); - } - - @Override - public Date getNotBefore() { - return payload.getNotBefore(); - } - - @Override - public Instant getNotBeforeAsInstant() { - return payload.getNotBeforeAsInstant(); - } - - @Override - public Date getIssuedAt() { - return payload.getIssuedAt(); - } - - @Override - public Instant getIssuedAtAsInstant() { - return payload.getIssuedAtAsInstant(); - } - - @Override - public String getId() { - return payload.getId(); - } - - @Override - public Claim getClaim(String name) { - return payload.getClaim(name); - } - - @Override - public Map getClaims() { - return payload.getClaims(); - } - - @Override - public String getHeader() { - return parts[0]; - } - - @Override - public String getPayload() { - return parts[1]; - } - - @Override - public String getSignature() { - return parts[2]; - } - - @Override - public String getToken() { - return String.format("%s.%s.%s", parts[0], parts[1], parts[2]); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java deleted file mode 100644 index bf180300..00000000 --- a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java +++ /dev/null @@ -1,500 +0,0 @@ -package com.auth0.jwt; - -import com.auth0.jwt.algorithms.Algorithm; -import com.auth0.jwt.exceptions.*; -import com.auth0.jwt.impl.JWTParser; -import com.auth0.jwt.interfaces.Claim; -import com.auth0.jwt.interfaces.DecodedJWT; -import com.auth0.jwt.impl.ExpectedCheckHolder; -import com.auth0.jwt.interfaces.Verification; - -import java.time.Clock; -import java.time.Duration; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.*; -import java.util.function.BiPredicate; - -/** - * The JWTVerifier class holds the verify method to assert that a given Token has not only a proper JWT format, - * but also its signature matches. - *

- * This class is thread-safe. - * - * @see com.auth0.jwt.interfaces.JWTVerifier - */ -public final class JWTVerifier implements com.auth0.jwt.interfaces.JWTVerifier { - private final Algorithm algorithm; - final List expectedChecks; - private final JWTParser parser; - - JWTVerifier(Algorithm algorithm, List expectedChecks) { - this.algorithm = algorithm; - this.expectedChecks = Collections.unmodifiableList(expectedChecks); - this.parser = new JWTParser(); - } - - /** - * Initialize a {@link Verification} instance using the given Algorithm. - * - * @param algorithm the Algorithm to use on the JWT verification. - * @return a {@link Verification} instance to configure. - * @throws IllegalArgumentException if the provided algorithm is null. - */ - static Verification init(Algorithm algorithm) throws IllegalArgumentException { - return new BaseVerification(algorithm); - } - - /** - * {@link Verification} implementation that accepts all the expected Claim values for verification, and - * builds a {@link com.auth0.jwt.interfaces.JWTVerifier} used to verify a JWT's signature and expected claims. - * - * Note that this class is not thread-safe. Calling {@link #build()} returns an instance of - * {@link com.auth0.jwt.interfaces.JWTVerifier} which can be reused. - */ - public static class BaseVerification implements Verification { - private final Algorithm algorithm; - private final List expectedChecks; - private long defaultLeeway; - private final Map customLeeways; - private boolean ignoreIssuedAt; - private Clock clock; - - BaseVerification(Algorithm algorithm) throws IllegalArgumentException { - if (algorithm == null) { - throw new IllegalArgumentException("The Algorithm cannot be null."); - } - - this.algorithm = algorithm; - this.expectedChecks = new ArrayList<>(); - this.customLeeways = new HashMap<>(); - this.defaultLeeway = 0; - } - - @Override - public Verification withIssuer(String... issuer) { - List value = isNullOrEmpty(issuer) ? null : Arrays.asList(issuer); - addCheck(RegisteredClaims.ISSUER, ((claim, decodedJWT) -> { - if (verifyNull(claim, value)) { - return true; - } - if (value == null || !value.contains(claim.asString())) { - throw new IncorrectClaimException( - "The Claim 'iss' value doesn't match the required issuer.", RegisteredClaims.ISSUER, claim); - } - return true; - })); - return this; - } - - @Override - public Verification withSubject(String subject) { - addCheck(RegisteredClaims.SUBJECT, (claim, decodedJWT) -> - verifyNull(claim, subject) || subject.equals(claim.asString())); - return this; - } - - @Override - public Verification withAudience(String... audience) { - List value = isNullOrEmpty(audience) ? null : Arrays.asList(audience); - addCheck(RegisteredClaims.AUDIENCE, ((claim, decodedJWT) -> { - if (verifyNull(claim, value)) { - return true; - } - if (!assertValidAudienceClaim(decodedJWT.getAudience(), value, true)) { - throw new IncorrectClaimException("The Claim 'aud' value doesn't contain the required audience.", - RegisteredClaims.AUDIENCE, claim); - } - return true; - })); - return this; - } - - @Override - public Verification withAnyOfAudience(String... audience) { - List value = isNullOrEmpty(audience) ? null : Arrays.asList(audience); - addCheck(RegisteredClaims.AUDIENCE, ((claim, decodedJWT) -> { - if (verifyNull(claim, value)) { - return true; - } - if (!assertValidAudienceClaim(decodedJWT.getAudience(), value, false)) { - throw new IncorrectClaimException("The Claim 'aud' value doesn't contain the required audience.", - RegisteredClaims.AUDIENCE, claim); - } - return true; - })); - return this; - } - - @Override - public Verification acceptLeeway(long leeway) throws IllegalArgumentException { - assertPositive(leeway); - this.defaultLeeway = leeway; - return this; - } - - @Override - public Verification acceptExpiresAt(long leeway) throws IllegalArgumentException { - assertPositive(leeway); - customLeeways.put(RegisteredClaims.EXPIRES_AT, leeway); - return this; - } - - @Override - public Verification acceptNotBefore(long leeway) throws IllegalArgumentException { - assertPositive(leeway); - customLeeways.put(RegisteredClaims.NOT_BEFORE, leeway); - return this; - } - - @Override - public Verification acceptIssuedAt(long leeway) throws IllegalArgumentException { - assertPositive(leeway); - customLeeways.put(RegisteredClaims.ISSUED_AT, leeway); - return this; - } - - @Override - public Verification ignoreIssuedAt() { - this.ignoreIssuedAt = true; - return this; - } - - @Override - public Verification withJWTId(String jwtId) { - addCheck(RegisteredClaims.JWT_ID, ((claim, decodedJWT) -> - verifyNull(claim, jwtId) || jwtId.equals(claim.asString()))); - return this; - } - - @Override - public Verification withClaimPresence(String name) throws IllegalArgumentException { - assertNonNull(name); - //since addCheck already checks presence, we just return true - withClaim(name, ((claim, decodedJWT) -> true)); - return this; - } - - @Override - public Verification withNullClaim(String name) throws IllegalArgumentException { - assertNonNull(name); - withClaim(name, ((claim, decodedJWT) -> claim.isNull())); - return this; - } - - @Override - public Verification withClaim(String name, Boolean value) throws IllegalArgumentException { - assertNonNull(name); - addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, value) - || value.equals(claim.asBoolean()))); - return this; - } - - @Override - public Verification withClaim(String name, Integer value) throws IllegalArgumentException { - assertNonNull(name); - addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, value) - || value.equals(claim.asInt()))); - return this; - } - - @Override - public Verification withClaim(String name, Long value) throws IllegalArgumentException { - assertNonNull(name); - addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, value) - || value.equals(claim.asLong()))); - return this; - } - - @Override - public Verification withClaim(String name, Double value) throws IllegalArgumentException { - assertNonNull(name); - addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, value) - || value.equals(claim.asDouble()))); - return this; - } - - @Override - public Verification withClaim(String name, String value) throws IllegalArgumentException { - assertNonNull(name); - addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, value) - || value.equals(claim.asString()))); - return this; - } - - @Override - public Verification withClaim(String name, Date value) throws IllegalArgumentException { - return withClaim(name, value != null ? value.toInstant() : null); - } - - @Override - public Verification withClaim(String name, Instant value) throws IllegalArgumentException { - assertNonNull(name); - // Since date-time claims are serialized as epoch seconds, - // we need to compare them with only seconds-granularity - addCheck(name, - ((claim, decodedJWT) -> verifyNull(claim, value) - || value.truncatedTo(ChronoUnit.SECONDS).equals(claim.asInstant()))); - return this; - } - - @Override - public Verification withClaim(String name, BiPredicate predicate) - throws IllegalArgumentException { - assertNonNull(name); - addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, predicate) - || predicate.test(claim, decodedJWT))); - return this; - } - - @Override - public Verification withArrayClaim(String name, String... items) throws IllegalArgumentException { - assertNonNull(name); - addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, items) - || assertValidCollectionClaim(claim, items))); - return this; - } - - @Override - public Verification withArrayClaim(String name, Integer... items) throws IllegalArgumentException { - assertNonNull(name); - addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, items) - || assertValidCollectionClaim(claim, items))); - return this; - } - - @Override - public Verification withArrayClaim(String name, Long... items) throws IllegalArgumentException { - assertNonNull(name); - addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, items) - || assertValidCollectionClaim(claim, items))); - return this; - } - - @Override - public JWTVerifier build() { - return this.build(Clock.systemUTC()); - } - - /** - * Creates a new and reusable instance of the JWTVerifier with the configuration already provided. - * ONLY FOR TEST PURPOSES. - * - * @param clock the instance that will handle the current time. - * @return a new JWTVerifier instance with a custom {@link java.time.Clock} - */ - public JWTVerifier build(Clock clock) { - this.clock = clock; - addMandatoryClaimChecks(); - return new JWTVerifier(algorithm, expectedChecks); - } - - /** - * Fetches the Leeway set for claim or returns the {@link BaseVerification#defaultLeeway}. - * - * @param name Claim for which leeway is fetched - * @return Leeway value set for the claim - */ - public long getLeewayFor(String name) { - return customLeeways.getOrDefault(name, defaultLeeway); - } - - private void addMandatoryClaimChecks() { - long expiresAtLeeway = getLeewayFor(RegisteredClaims.EXPIRES_AT); - long notBeforeLeeway = getLeewayFor(RegisteredClaims.NOT_BEFORE); - long issuedAtLeeway = getLeewayFor(RegisteredClaims.ISSUED_AT); - - expectedChecks.add(constructExpectedCheck(RegisteredClaims.EXPIRES_AT, (claim, decodedJWT) -> - assertValidInstantClaim(RegisteredClaims.EXPIRES_AT, claim, expiresAtLeeway, true))); - expectedChecks.add(constructExpectedCheck(RegisteredClaims.NOT_BEFORE, (claim, decodedJWT) -> - assertValidInstantClaim(RegisteredClaims.NOT_BEFORE, claim, notBeforeLeeway, false))); - if (!ignoreIssuedAt) { - expectedChecks.add(constructExpectedCheck(RegisteredClaims.ISSUED_AT, (claim, decodedJWT) -> - assertValidInstantClaim(RegisteredClaims.ISSUED_AT, claim, issuedAtLeeway, false))); - } - } - - private boolean assertValidCollectionClaim(Claim claim, Object[] expectedClaimValue) { - List claimArr; - Object[] claimAsObject = claim.as(Object[].class); - - // Jackson uses 'natural' mapping which uses Integer if value fits in 32 bits. - if (expectedClaimValue instanceof Long[]) { - // convert Integers to Longs for comparison with equals - claimArr = new ArrayList<>(claimAsObject.length); - for (Object cao : claimAsObject) { - if (cao instanceof Integer) { - claimArr.add(((Integer) cao).longValue()); - } else { - claimArr.add(cao); - } - } - } else { - claimArr = Arrays.asList(claim.as(Object[].class)); - } - List valueArr = Arrays.asList(expectedClaimValue); - return claimArr.containsAll(valueArr); - } - - private boolean assertValidInstantClaim(String claimName, Claim claim, long leeway, boolean shouldBeFuture) { - Instant claimVal = claim.asInstant(); - Instant now = clock.instant().truncatedTo(ChronoUnit.SECONDS); - boolean isValid; - if (shouldBeFuture) { - isValid = assertInstantIsFuture(claimVal, leeway, now); - if (!isValid) { - throw new TokenExpiredException(String.format("The Token has expired on %s.", claimVal), claimVal); - } - } else { - isValid = assertInstantIsLessThanOrEqualToNow(claimVal, leeway, now); - if (!isValid) { - throw new IncorrectClaimException( - String.format("The Token can't be used before %s.", claimVal), claimName, claim); - } - } - return true; - } - - private boolean assertInstantIsFuture(Instant claimVal, long leeway, Instant now) { - return claimVal == null || now.minus(Duration.ofSeconds(leeway)).isBefore(claimVal); - } - - private boolean assertInstantIsLessThanOrEqualToNow(Instant claimVal, long leeway, Instant now) { - return !(claimVal != null && now.plus(Duration.ofSeconds(leeway)).isBefore(claimVal)); - } - - private boolean assertValidAudienceClaim( - List actualAudience, - List expectedAudience, - boolean shouldContainAll - ) { - if (actualAudience == null || expectedAudience == null) { - return false; - } - - if (shouldContainAll) { - return actualAudience.containsAll(expectedAudience); - } else { - return !Collections.disjoint(actualAudience, expectedAudience); - } - } - - private void assertPositive(long leeway) { - if (leeway < 0) { - throw new IllegalArgumentException("Leeway value can't be negative."); - } - } - - private void assertNonNull(String name) { - if (name == null) { - throw new IllegalArgumentException("The Custom Claim's name can't be null."); - } - } - - private void addCheck(String name, BiPredicate predicate) { - expectedChecks.add(constructExpectedCheck(name, (claim, decodedJWT) -> { - if (claim.isMissing()) { - throw new MissingClaimException(name); - } - return predicate.test(claim, decodedJWT); - })); - } - - private ExpectedCheckHolder constructExpectedCheck(String claimName, BiPredicate check) { - return new ExpectedCheckHolder() { - @Override - public String getClaimName() { - return claimName; - } - - @Override - public boolean verify(Claim claim, DecodedJWT decodedJWT) { - return check.test(claim, decodedJWT); - } - }; - } - - private boolean verifyNull(Claim claim, Object value) { - return value == null && claim.isNull(); - } - - private boolean isNullOrEmpty(String[] args) { - if (args == null || args.length == 0) { - return true; - } - boolean isAllNull = true; - for (String arg : args) { - if (arg != null) { - isAllNull = false; - break; - } - } - return isAllNull; - } - } - - - /** - * Perform the verification against the given Token, using any previous configured options. - * - * @param token to verify. - * @return a verified and decoded JWT. - * @throws AlgorithmMismatchException if the algorithm stated in the token's header is not equal to - * the one defined in the {@link JWTVerifier}. - * @throws SignatureVerificationException if the signature is invalid. - * @throws TokenExpiredException if the token has expired. - * @throws MissingClaimException if a claim to be verified is missing. - * @throws IncorrectClaimException if a claim contained a different value than the expected one. - */ - @Override - public DecodedJWT verify(String token) throws JWTVerificationException { - DecodedJWT jwt = new JWTDecoder(parser, token); - return verify(jwt); - } - - /** - * Perform the verification against the given decoded JWT, using any previous configured options. - * - * @param jwt to verify. - * @return a verified and decoded JWT. - * @throws AlgorithmMismatchException if the algorithm stated in the token's header is not equal to - * the one defined in the {@link JWTVerifier}. - * @throws SignatureVerificationException if the signature is invalid. - * @throws TokenExpiredException if the token has expired. - * @throws MissingClaimException if a claim to be verified is missing. - * @throws IncorrectClaimException if a claim contained a different value than the expected one. - */ - @Override - public DecodedJWT verify(DecodedJWT jwt) throws JWTVerificationException { - verifyAlgorithm(jwt, algorithm); - algorithm.verify(jwt); - verifyClaims(jwt, expectedChecks); - return jwt; - } - - private void verifyAlgorithm(DecodedJWT jwt, Algorithm expectedAlgorithm) throws AlgorithmMismatchException { - if (!expectedAlgorithm.getName().equals(jwt.getAlgorithm())) { - throw new AlgorithmMismatchException( - "The provided Algorithm doesn't match the one defined in the JWT's Header."); - } - } - - private void verifyClaims(DecodedJWT jwt, List expectedChecks) - throws TokenExpiredException, InvalidClaimException { - for (ExpectedCheckHolder expectedCheck : expectedChecks) { - boolean isValid; - String claimName = expectedCheck.getClaimName(); - Claim claim = jwt.getClaim(claimName); - - isValid = expectedCheck.verify(claim, jwt); - - if (!isValid) { - throw new IncorrectClaimException( - String.format("The Claim '%s' value doesn't match the required one.", claimName), - claimName, - claim - ); - } - } - } -} diff --git a/lib/src/main/java/com/auth0/jwt/RegisteredClaims.java b/lib/src/main/java/com/auth0/jwt/RegisteredClaims.java deleted file mode 100644 index c5509716..00000000 --- a/lib/src/main/java/com/auth0/jwt/RegisteredClaims.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.auth0.jwt; - -/** - * Contains constants representing the name of the Registered Claim Names as defined in Section 4.1 of - * RFC 7529 - */ -public final class RegisteredClaims { - - private RegisteredClaims() { - } - - /** - * The "iss" (issuer) claim identifies the principal that issued the JWT. - * Refer RFC 7529 Section 4.1.1 - */ - public static final String ISSUER = "iss"; - - /** - * The "sub" (subject) claim identifies the principal that is the subject of the JWT. - * Refer RFC 7529 Section 4.1.2 - */ - public static final String SUBJECT = "sub"; - - /** - * The "aud" (audience) claim identifies the recipients that the JWT is intended for. - * Refer RFC 7529 Section 4.1.3 - */ - public static final String AUDIENCE = "aud"; - - /** - * The "exp" (expiration time) claim identifies the expiration time on or after which the JWT MUST NOT be - * accepted for processing. - * Refer RFC 7529 Section 4.1.4 - */ - public static final String EXPIRES_AT = "exp"; - - /** - * The "nbf" (not before) claim identifies the time before which the JWT MUST NOT be accepted for processing. - * Refer RFC 7529 Section 4.1.5 - */ - public static final String NOT_BEFORE = "nbf"; - - /** - * The "iat" (issued at) claim identifies the time at which the JWT was issued. - * Refer RFC 7529 Section 4.1.6 - */ - public static final String ISSUED_AT = "iat"; - - /** - * The "jti" (JWT ID) claim provides a unique identifier for the JWT. - * Refer RFC 7529 Section 4.1.7 - */ - public static final String JWT_ID = "jti"; - -} diff --git a/lib/src/main/java/com/auth0/jwt/TokenUtils.java b/lib/src/main/java/com/auth0/jwt/TokenUtils.java deleted file mode 100644 index e62b9832..00000000 --- a/lib/src/main/java/com/auth0/jwt/TokenUtils.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.auth0.jwt; - -import com.auth0.jwt.exceptions.JWTDecodeException; - -abstract class TokenUtils { - - /** - * Splits the given token on the "." chars into a String array with 3 parts. - * - * @param token the string to split. - * @return the array representing the 3 parts of the token. - * @throws JWTDecodeException if the Token doesn't have 3 parts. - */ - static String[] splitToken(String token) throws JWTDecodeException { - if (token == null) { - throw new JWTDecodeException("The token is null."); - } - - char delimiter = '.'; - - int firstPeriodIndex = token.indexOf(delimiter); - if (firstPeriodIndex == -1) { - throw wrongNumberOfParts(0); - } - - int secondPeriodIndex = token.indexOf(delimiter, firstPeriodIndex + 1); - if (secondPeriodIndex == -1) { - throw wrongNumberOfParts(2); - } - - // too many ? - if (token.indexOf(delimiter, secondPeriodIndex + 1) != -1) { - throw wrongNumberOfParts("> 3"); - } - - String[] parts = new String[3]; - parts[0] = token.substring(0, firstPeriodIndex); - parts[1] = token.substring(firstPeriodIndex + 1, secondPeriodIndex); - parts[2] = token.substring(secondPeriodIndex + 1); - - return parts; - } - - private static JWTDecodeException wrongNumberOfParts(Object partCount) { - return new JWTDecodeException(String.format("The token was expected to have 3 parts, but got %s.", partCount)); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java deleted file mode 100644 index 248af7c5..00000000 --- a/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java +++ /dev/null @@ -1,398 +0,0 @@ -package com.auth0.jwt.algorithms; - -import com.auth0.jwt.exceptions.SignatureGenerationException; -import com.auth0.jwt.exceptions.SignatureVerificationException; -import com.auth0.jwt.interfaces.DecodedJWT; -import com.auth0.jwt.interfaces.ECDSAKeyProvider; -import com.auth0.jwt.interfaces.RSAKeyProvider; - -import java.security.interfaces.*; - -/** - * The Algorithm class represents an algorithm to be used in the Signing or Verification process of a Token. - *

- * This class and its subclasses are thread-safe. - */ -@SuppressWarnings("WeakerAccess") -public abstract class Algorithm { - - private final String name; - private final String description; - - /** - * Creates a new Algorithm instance using SHA256withRSA. Tokens specify this as "RS256". - * - * @param keyProvider the provider of the Public Key and Private Key for the verify and signing instance. - * @return a valid RSA256 Algorithm. - * @throws IllegalArgumentException if the provided Key is null. - */ - public static Algorithm RSA256(RSAKeyProvider keyProvider) throws IllegalArgumentException { - return new RSAAlgorithm("RS256", "SHA256withRSA", keyProvider); - } - - /** - * Creates a new Algorithm instance using SHA256withRSA. Tokens specify this as "RS256". - * - * @param publicKey the key to use in the verify instance. - * @param privateKey the key to use in the signing instance. - * @return a valid RSA256 Algorithm. - * @throws IllegalArgumentException if both provided Keys are null. - */ - public static Algorithm RSA256(RSAPublicKey publicKey, RSAPrivateKey privateKey) throws IllegalArgumentException { - return RSA256(RSAAlgorithm.providerForKeys(publicKey, privateKey)); - } - - /** - * Creates a new Algorithm instance using SHA256withRSA. Tokens specify this as "RS256". - * - * @param key the key to use in the verify or signing instance. - * @return a valid RSA256 Algorithm. - * @throws IllegalArgumentException if the Key Provider is null. - */ - public static Algorithm RSA256(RSAKey key) throws IllegalArgumentException { - RSAPublicKey publicKey = key instanceof RSAPublicKey ? (RSAPublicKey) key : null; - RSAPrivateKey privateKey = key instanceof RSAPrivateKey ? (RSAPrivateKey) key : null; - return RSA256(publicKey, privateKey); - } - - /** - * Creates a new Algorithm instance using SHA384withRSA. Tokens specify this as "RS384". - * - * @param keyProvider the provider of the Public Key and Private Key for the verify and signing instance. - * @return a valid RSA384 Algorithm. - * @throws IllegalArgumentException if the Key Provider is null. - */ - public static Algorithm RSA384(RSAKeyProvider keyProvider) throws IllegalArgumentException { - return new RSAAlgorithm("RS384", "SHA384withRSA", keyProvider); - } - - /** - * Creates a new Algorithm instance using SHA384withRSA. Tokens specify this as "RS384". - * - * @param publicKey the key to use in the verify instance. - * @param privateKey the key to use in the signing instance. - * @return a valid RSA384 Algorithm. - * @throws IllegalArgumentException if both provided Keys are null. - */ - public static Algorithm RSA384(RSAPublicKey publicKey, RSAPrivateKey privateKey) throws IllegalArgumentException { - return RSA384(RSAAlgorithm.providerForKeys(publicKey, privateKey)); - } - - /** - * Creates a new Algorithm instance using SHA384withRSA. Tokens specify this as "RS384". - * - * @param key the key to use in the verify or signing instance. - * @return a valid RSA384 Algorithm. - * @throws IllegalArgumentException if the provided Key is null. - */ - public static Algorithm RSA384(RSAKey key) throws IllegalArgumentException { - RSAPublicKey publicKey = key instanceof RSAPublicKey ? (RSAPublicKey) key : null; - RSAPrivateKey privateKey = key instanceof RSAPrivateKey ? (RSAPrivateKey) key : null; - return RSA384(publicKey, privateKey); - } - - /** - * Creates a new Algorithm instance using SHA512withRSA. Tokens specify this as "RS512". - * - * @param keyProvider the provider of the Public Key and Private Key for the verify and signing instance. - * @return a valid RSA512 Algorithm. - * @throws IllegalArgumentException if the Key Provider is null. - */ - public static Algorithm RSA512(RSAKeyProvider keyProvider) throws IllegalArgumentException { - return new RSAAlgorithm("RS512", "SHA512withRSA", keyProvider); - } - - /** - * Creates a new Algorithm instance using SHA512withRSA. Tokens specify this as "RS512". - * - * @param publicKey the key to use in the verify instance. - * @param privateKey the key to use in the signing instance. - * @return a valid RSA512 Algorithm. - * @throws IllegalArgumentException if both provided Keys are null. - */ - public static Algorithm RSA512(RSAPublicKey publicKey, RSAPrivateKey privateKey) throws IllegalArgumentException { - return RSA512(RSAAlgorithm.providerForKeys(publicKey, privateKey)); - } - - /** - * Creates a new Algorithm instance using SHA512withRSA. Tokens specify this as "RS512". - * - * @param key the key to use in the verify or signing instance. - * @return a valid RSA512 Algorithm. - * @throws IllegalArgumentException if the provided Key is null. - */ - public static Algorithm RSA512(RSAKey key) throws IllegalArgumentException { - RSAPublicKey publicKey = key instanceof RSAPublicKey ? (RSAPublicKey) key : null; - RSAPrivateKey privateKey = key instanceof RSAPrivateKey ? (RSAPrivateKey) key : null; - return RSA512(publicKey, privateKey); - } - - /** - * Creates a new Algorithm instance using HmacSHA256. Tokens specify this as "HS256". - * - * @param secret the secret bytes to use in the verify or signing instance. - * Ensure the length of the secret is at least 256 bit long - * @return a valid HMAC256 Algorithm. - * @throws IllegalArgumentException if the provided Secret is null. - */ - public static Algorithm HMAC256(String secret) throws IllegalArgumentException { - return new HMACAlgorithm("HS256", "HmacSHA256", secret); - } - - /** - * Creates a new Algorithm instance using HmacSHA256. Tokens specify this as "HS256". - * - * @param secret the secret bytes to use in the verify or signing instance. - * Ensure the length of the secret is at least 256 bit long - * @return a valid HMAC256 Algorithm. - * @throws IllegalArgumentException if the provided Secret is null. - */ - public static Algorithm HMAC256(byte[] secret) throws IllegalArgumentException { - return new HMACAlgorithm("HS256", "HmacSHA256", secret); - } - - /** - * Creates a new Algorithm instance using HmacSHA384. Tokens specify this as "HS384". - * - * @param secret the secret bytes to use in the verify or signing instance. - * Ensure the length of the secret is at least 384 bit long - * @return a valid HMAC384 Algorithm. - * @throws IllegalArgumentException if the provided Secret is null. - */ - public static Algorithm HMAC384(String secret) throws IllegalArgumentException { - return new HMACAlgorithm("HS384", "HmacSHA384", secret); - } - - /** - * Creates a new Algorithm instance using HmacSHA384. Tokens specify this as "HS384". - * - * @param secret the secret bytes to use in the verify or signing instance. - * Ensure the length of the secret is at least 384 bit long - * @return a valid HMAC384 Algorithm. - * @throws IllegalArgumentException if the provided Secret is null. - */ - public static Algorithm HMAC384(byte[] secret) throws IllegalArgumentException { - return new HMACAlgorithm("HS384", "HmacSHA384", secret); - } - - /** - * Creates a new Algorithm instance using HmacSHA512. Tokens specify this as "HS512". - * - * @param secret the secret bytes to use in the verify or signing instance. - * Ensure the length of the secret is at least 512 bit long - * @return a valid HMAC512 Algorithm. - * @throws IllegalArgumentException if the provided Secret is null. - */ - public static Algorithm HMAC512(String secret) throws IllegalArgumentException { - return new HMACAlgorithm("HS512", "HmacSHA512", secret); - } - - /** - * Creates a new Algorithm instance using HmacSHA512. Tokens specify this as "HS512". - * - * @param secret the secret bytes to use in the verify or signing instance. - * Ensure the length of the secret is at least 512 bit long - * @return a valid HMAC512 Algorithm. - * @throws IllegalArgumentException if the provided Secret is null. - */ - public static Algorithm HMAC512(byte[] secret) throws IllegalArgumentException { - return new HMACAlgorithm("HS512", "HmacSHA512", secret); - } - - - /** - * Creates a new Algorithm instance using SHA256withECDSA. Tokens specify this as "ES256". - * - * @param keyProvider the provider of the Public Key and Private Key for the verify and signing instance. - * @return a valid ECDSA256 Algorithm. - * @throws IllegalArgumentException if the Key Provider is null. - */ - public static Algorithm ECDSA256(ECDSAKeyProvider keyProvider) throws IllegalArgumentException { - return new ECDSAAlgorithm("ES256", "SHA256withECDSA", 32, keyProvider); - } - - /** - * Creates a new Algorithm instance using SHA256withECDSA. Tokens specify this as "ES256". - * - * @param publicKey the key to use in the verify instance. - * @param privateKey the key to use in the signing instance. - * @return a valid ECDSA256 Algorithm. - * @throws IllegalArgumentException if the provided Key is null. - */ - public static Algorithm ECDSA256(ECPublicKey publicKey, ECPrivateKey privateKey) throws IllegalArgumentException { - return ECDSA256(ECDSAAlgorithm.providerForKeys(publicKey, privateKey)); - } - - /** - * Creates a new Algorithm instance using SHA256withECDSA. Tokens specify this as "ES256". - * - * @param key the key to use in the verify or signing instance. - * @return a valid ECDSA256 Algorithm. - * @throws IllegalArgumentException if the provided Key is null. - */ - public static Algorithm ECDSA256(ECKey key) throws IllegalArgumentException { - ECPublicKey publicKey = key instanceof ECPublicKey ? (ECPublicKey) key : null; - ECPrivateKey privateKey = key instanceof ECPrivateKey ? (ECPrivateKey) key : null; - return ECDSA256(publicKey, privateKey); - } - - /** - * Creates a new Algorithm instance using SHA384withECDSA. Tokens specify this as "ES384". - * - * @param keyProvider the provider of the Public Key and Private Key for the verify and signing instance. - * @return a valid ECDSA384 Algorithm. - * @throws IllegalArgumentException if the Key Provider is null. - */ - public static Algorithm ECDSA384(ECDSAKeyProvider keyProvider) throws IllegalArgumentException { - return new ECDSAAlgorithm("ES384", "SHA384withECDSA", 48, keyProvider); - } - - /** - * Creates a new Algorithm instance using SHA384withECDSA. Tokens specify this as "ES384". - * - * @param publicKey the key to use in the verify instance. - * @param privateKey the key to use in the signing instance. - * @return a valid ECDSA384 Algorithm. - * @throws IllegalArgumentException if the provided Key is null. - */ - public static Algorithm ECDSA384(ECPublicKey publicKey, ECPrivateKey privateKey) throws IllegalArgumentException { - return ECDSA384(ECDSAAlgorithm.providerForKeys(publicKey, privateKey)); - } - - /** - * Creates a new Algorithm instance using SHA384withECDSA. Tokens specify this as "ES384". - * - * @param key the key to use in the verify or signing instance. - * @return a valid ECDSA384 Algorithm. - * @throws IllegalArgumentException if the provided Key is null. - */ - public static Algorithm ECDSA384(ECKey key) throws IllegalArgumentException { - ECPublicKey publicKey = key instanceof ECPublicKey ? (ECPublicKey) key : null; - ECPrivateKey privateKey = key instanceof ECPrivateKey ? (ECPrivateKey) key : null; - return ECDSA384(publicKey, privateKey); - } - - /** - * Creates a new Algorithm instance using SHA512withECDSA. Tokens specify this as "ES512". - * - * @param keyProvider the provider of the Public Key and Private Key for the verify and signing instance. - * @return a valid ECDSA512 Algorithm. - * @throws IllegalArgumentException if the Key Provider is null. - */ - public static Algorithm ECDSA512(ECDSAKeyProvider keyProvider) throws IllegalArgumentException { - return new ECDSAAlgorithm("ES512", "SHA512withECDSA", 66, keyProvider); - } - - /** - * Creates a new Algorithm instance using SHA512withECDSA. Tokens specify this as "ES512". - * - * @param publicKey the key to use in the verify instance. - * @param privateKey the key to use in the signing instance. - * @return a valid ECDSA512 Algorithm. - * @throws IllegalArgumentException if the provided Key is null. - */ - public static Algorithm ECDSA512(ECPublicKey publicKey, ECPrivateKey privateKey) throws IllegalArgumentException { - return ECDSA512(ECDSAAlgorithm.providerForKeys(publicKey, privateKey)); - } - - /** - * Creates a new Algorithm instance using SHA512withECDSA. Tokens specify this as "ES512". - * - * @param key the key to use in the verify or signing instance. - * @return a valid ECDSA512 Algorithm. - * @throws IllegalArgumentException if the provided Key is null. - */ - public static Algorithm ECDSA512(ECKey key) throws IllegalArgumentException { - ECPublicKey publicKey = key instanceof ECPublicKey ? (ECPublicKey) key : null; - ECPrivateKey privateKey = key instanceof ECPrivateKey ? (ECPrivateKey) key : null; - return ECDSA512(publicKey, privateKey); - } - - - public static Algorithm none() { - return new NoneAlgorithm(); - } - - protected Algorithm(String name, String description) { - this.name = name; - this.description = description; - } - - /** - * Getter for the Id of the Private Key used to sign the tokens. - * This is usually specified as the `kid` claim in the Header. - * - * @return the Key Id that identifies the Signing Key or null if it's not specified. - */ - public String getSigningKeyId() { - return null; - } - - /** - * Getter for the name of this Algorithm, as defined in the JWT Standard. i.e. "HS256" - * - * @return the algorithm name. - */ - public String getName() { - return name; - } - - /** - * Getter for the description of this Algorithm, - * required when instantiating a Mac or Signature object. i.e. "HmacSHA256" - * - * @return the algorithm description. - */ - String getDescription() { - return description; - } - - @Override - public String toString() { - return description; - } - - /** - * Verify the given token using this Algorithm instance. - * - * @param jwt the already decoded JWT that it's going to be verified. - * @throws SignatureVerificationException if the Token's Signature is invalid, - * meaning that it doesn't match the signatureBytes, - * or if the Key is invalid. - */ - public abstract void verify(DecodedJWT jwt) throws SignatureVerificationException; - - /** - * Sign the given content using this Algorithm instance. - * - * @param headerBytes an array of bytes representing the base64 encoded header content - * to be verified against the signature. - * @param payloadBytes an array of bytes representing the base64 encoded payload content - * to be verified against the signature. - * @return the signature in a base64 encoded array of bytes - * @throws SignatureGenerationException if the Key is invalid. - */ - public byte[] sign(byte[] headerBytes, byte[] payloadBytes) throws SignatureGenerationException { - // default implementation; keep around until sign(byte[]) method is removed - byte[] contentBytes = new byte[headerBytes.length + 1 + payloadBytes.length]; - - System.arraycopy(headerBytes, 0, contentBytes, 0, headerBytes.length); - contentBytes[headerBytes.length] = (byte) '.'; - System.arraycopy(payloadBytes, 0, contentBytes, headerBytes.length + 1, payloadBytes.length); - - return sign(contentBytes); - } - - /** - * Sign the given content using this Algorithm instance. - * To get the correct JWT Signature, ensure the content is in the format {HEADER}.{PAYLOAD} - * - * @param contentBytes an array of bytes representing the base64 encoded content - * to be verified against the signature. - * @return the signature in a base64 encoded array of bytes - * @throws SignatureGenerationException if the Key is invalid. - */ - - public abstract byte[] sign(byte[] contentBytes) throws SignatureGenerationException; - -} diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/CryptoHelper.java b/lib/src/main/java/com/auth0/jwt/algorithms/CryptoHelper.java deleted file mode 100644 index 7b8c5c2a..00000000 --- a/lib/src/main/java/com/auth0/jwt/algorithms/CryptoHelper.java +++ /dev/null @@ -1,208 +0,0 @@ -package com.auth0.jwt.algorithms; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import java.nio.charset.StandardCharsets; -import java.security.*; - -/** - * Class used to perform the signature hash calculations. - *

- * This class is thread-safe. - */ -class CryptoHelper { - - private static final byte JWT_PART_SEPARATOR = (byte) 46; - - /** - * Verify signature for JWT header and payload. - * - * @param algorithm algorithm name. - * @param secretBytes algorithm secret. - * @param header JWT header. - * @param payload JWT payload. - * @param signatureBytes JWT signature. - * @return true if signature is valid. - * @throws NoSuchAlgorithmException if the algorithm is not supported. - * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. - */ - - boolean verifySignatureFor( - String algorithm, - byte[] secretBytes, - String header, - String payload, - byte[] signatureBytes - ) throws NoSuchAlgorithmException, InvalidKeyException { - return verifySignatureFor(algorithm, secretBytes, - header.getBytes(StandardCharsets.UTF_8), payload.getBytes(StandardCharsets.UTF_8), signatureBytes); - } - - /** - * Verify signature for JWT header and payload. - * - * @param algorithm algorithm name. - * @param secretBytes algorithm secret. - * @param headerBytes JWT header. - * @param payloadBytes JWT payload. - * @param signatureBytes JWT signature. - * @return true if signature is valid. - * @throws NoSuchAlgorithmException if the algorithm is not supported. - * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. - */ - - boolean verifySignatureFor( - String algorithm, - byte[] secretBytes, - byte[] headerBytes, - byte[] payloadBytes, - byte[] signatureBytes - ) throws NoSuchAlgorithmException, InvalidKeyException { - return MessageDigest.isEqual(createSignatureFor(algorithm, secretBytes, headerBytes, payloadBytes), - signatureBytes); - } - - /** - * Verify signature for JWT header and payload. - * - * @param algorithm algorithm name. - * @param publicKey algorithm public key. - * @param header JWT header. - * @param payload JWT payload. - * @param signatureBytes JWT signature. - * @return true if signature is valid. - * @throws NoSuchAlgorithmException if the algorithm is not supported. - * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. - */ - boolean verifySignatureFor( - String algorithm, - PublicKey publicKey, - String header, - String payload, - byte[] signatureBytes - ) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { - return verifySignatureFor(algorithm, publicKey, header.getBytes(StandardCharsets.UTF_8), - payload.getBytes(StandardCharsets.UTF_8), signatureBytes); - } - - /** - * Verify signature for JWT header and payload using a public key. - * - * @param algorithm algorithm name. - * @param publicKey the public key to use for verification. - * @param headerBytes JWT header. - * @param payloadBytes JWT payload. - * @param signatureBytes JWT signature. - * @return true if signature is valid. - * @throws NoSuchAlgorithmException if the algorithm is not supported. - * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. - */ - boolean verifySignatureFor( - String algorithm, - PublicKey publicKey, - byte[] headerBytes, - byte[] payloadBytes, - byte[] signatureBytes - ) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { - final Signature s = Signature.getInstance(algorithm); - s.initVerify(publicKey); - s.update(headerBytes); - s.update(JWT_PART_SEPARATOR); - s.update(payloadBytes); - return s.verify(signatureBytes); - } - - /** - * Create signature for JWT header and payload using a private key. - * - * @param algorithm algorithm name. - * @param privateKey the private key to use for signing. - * @param headerBytes JWT header. - * @param payloadBytes JWT payload. - * @return the signature bytes. - * @throws NoSuchAlgorithmException if the algorithm is not supported. - * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. - * @throws SignatureException if this signature object is not initialized properly - * or if this signature algorithm is unable to process the input data provided. - */ - byte[] createSignatureFor( - String algorithm, - PrivateKey privateKey, - byte[] headerBytes, - byte[] payloadBytes - ) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { - final Signature s = Signature.getInstance(algorithm); - s.initSign(privateKey); - s.update(headerBytes); - s.update(JWT_PART_SEPARATOR); - s.update(payloadBytes); - return s.sign(); - } - - /** - * Create signature for JWT header and payload. - * - * @param algorithm algorithm name. - * @param secretBytes algorithm secret. - * @param headerBytes JWT header. - * @param payloadBytes JWT payload. - * @return the signature bytes. - * @throws NoSuchAlgorithmException if the algorithm is not supported. - * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. - */ - byte[] createSignatureFor( - String algorithm, - byte[] secretBytes, - byte[] headerBytes, - byte[] payloadBytes - ) throws NoSuchAlgorithmException, InvalidKeyException { - final Mac mac = Mac.getInstance(algorithm); - mac.init(new SecretKeySpec(secretBytes, algorithm)); - mac.update(headerBytes); - mac.update(JWT_PART_SEPARATOR); - return mac.doFinal(payloadBytes); - } - - /** - * Create signature. - * To get the correct JWT Signature, ensure the content is in the format {HEADER}.{PAYLOAD} - * - * @param algorithm algorithm name. - * @param secretBytes algorithm secret. - * @param contentBytes the content to be signed. - * @return the signature bytes. - * @throws NoSuchAlgorithmException if the algorithm is not supported. - * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. - */ - byte[] createSignatureFor(String algorithm, byte[] secretBytes, byte[] contentBytes) - throws NoSuchAlgorithmException, InvalidKeyException { - final Mac mac = Mac.getInstance(algorithm); - mac.init(new SecretKeySpec(secretBytes, algorithm)); - return mac.doFinal(contentBytes); - } - - /** - * Create signature using a private key. - * To get the correct JWT Signature, ensure the content is in the format {HEADER}.{PAYLOAD} - * - * @param algorithm algorithm name. - * @param privateKey the private key to use for signing. - * @param contentBytes the content to be signed. - * @return the signature bytes. - * @throws NoSuchAlgorithmException if the algorithm is not supported. - * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. - * @throws SignatureException if this signature object is not initialized properly - * or if this signature algorithm is unable to process the input data provided. - */ - - byte[] createSignatureFor( - String algorithm, - PrivateKey privateKey, - byte[] contentBytes - ) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { - final Signature s = Signature.getInstance(algorithm); - s.initSign(privateKey); - s.update(contentBytes); - return s.sign(); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java deleted file mode 100644 index b3046097..00000000 --- a/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java +++ /dev/null @@ -1,306 +0,0 @@ -package com.auth0.jwt.algorithms; - -import com.auth0.jwt.exceptions.SignatureGenerationException; -import com.auth0.jwt.exceptions.SignatureVerificationException; -import com.auth0.jwt.interfaces.DecodedJWT; -import com.auth0.jwt.interfaces.ECDSAKeyProvider; - -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.SignatureException; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.util.Base64; - -/** - * Subclass representing an Elliptic Curve signing algorithm - *

- * This class is thread-safe. - */ -class ECDSAAlgorithm extends Algorithm { - - private final ECDSAKeyProvider keyProvider; - private final CryptoHelper crypto; - private final int ecNumberSize; - - //Visible for testing - ECDSAAlgorithm(CryptoHelper crypto, String id, String algorithm, int ecNumberSize, ECDSAKeyProvider keyProvider) - throws IllegalArgumentException { - super(id, algorithm); - if (keyProvider == null) { - throw new IllegalArgumentException("The Key Provider cannot be null."); - } - this.keyProvider = keyProvider; - this.crypto = crypto; - this.ecNumberSize = ecNumberSize; - } - - ECDSAAlgorithm(String id, String algorithm, int ecNumberSize, ECDSAKeyProvider keyProvider) - throws IllegalArgumentException { - this(new CryptoHelper(), id, algorithm, ecNumberSize, keyProvider); - } - - @Override - public void verify(DecodedJWT jwt) throws SignatureVerificationException { - try { - byte[] signatureBytes = Base64.getUrlDecoder().decode(jwt.getSignature()); - ECPublicKey publicKey = keyProvider.getPublicKeyById(jwt.getKeyId()); - if (publicKey == null) { - throw new IllegalStateException("The given Public Key is null."); - } - validateSignatureStructure(signatureBytes, publicKey); - boolean valid = crypto.verifySignatureFor( - getDescription(), publicKey, jwt.getHeader(), jwt.getPayload(), JOSEToDER(signatureBytes)); - - if (!valid) { - throw new SignatureVerificationException(this); - } - } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException - | IllegalStateException | IllegalArgumentException e) { - throw new SignatureVerificationException(this, e); - } - } - - @Override - public byte[] sign(byte[] headerBytes, byte[] payloadBytes) throws SignatureGenerationException { - try { - ECPrivateKey privateKey = keyProvider.getPrivateKey(); - if (privateKey == null) { - throw new IllegalStateException("The given Private Key is null."); - } - byte[] signature = crypto.createSignatureFor(getDescription(), privateKey, headerBytes, payloadBytes); - return DERToJOSE(signature); - } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException | IllegalStateException e) { - throw new SignatureGenerationException(this, e); - } - } - - @Override - public byte[] sign(byte[] contentBytes) throws SignatureGenerationException { - try { - ECPrivateKey privateKey = keyProvider.getPrivateKey(); - if (privateKey == null) { - throw new IllegalStateException("The given Private Key is null."); - } - byte[] signature = crypto.createSignatureFor(getDescription(), privateKey, contentBytes); - return DERToJOSE(signature); - } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException | IllegalStateException e) { - throw new SignatureGenerationException(this, e); - } - } - - @Override - public String getSigningKeyId() { - return keyProvider.getPrivateKeyId(); - } - - //Visible for testing - byte[] DERToJOSE(byte[] derSignature) throws SignatureException { - // DER Structure: http://crypto.stackexchange.com/a/1797 - boolean derEncoded = derSignature[0] == 0x30 && derSignature.length != ecNumberSize * 2; - if (!derEncoded) { - throw new SignatureException("Invalid DER signature format."); - } - - final byte[] joseSignature = new byte[ecNumberSize * 2]; - - //Skip 0x30 - int offset = 1; - if (derSignature[1] == (byte) 0x81) { - //Skip sign - offset++; - } - - //Convert to unsigned. Should match DER length - offset - int encodedLength = derSignature[offset++] & 0xff; - if (encodedLength != derSignature.length - offset) { - throw new SignatureException("Invalid DER signature format."); - } - - //Skip 0x02 - offset++; - - //Obtain R number length (Includes padding) and skip it - int rlength = derSignature[offset++]; - if (rlength > ecNumberSize + 1) { - throw new SignatureException("Invalid DER signature format."); - } - int rpadding = ecNumberSize - rlength; - //Retrieve R number - System.arraycopy(derSignature, offset + Math.max(-rpadding, 0), - joseSignature, Math.max(rpadding, 0), rlength + Math.min(rpadding, 0)); - - //Skip R number and 0x02 - offset += rlength + 1; - - //Obtain S number length. (Includes padding) - int slength = derSignature[offset++]; - if (slength > ecNumberSize + 1) { - throw new SignatureException("Invalid DER signature format."); - } - int spadding = ecNumberSize - slength; - //Retrieve R number - System.arraycopy(derSignature, offset + Math.max(-spadding, 0), joseSignature, - ecNumberSize + Math.max(spadding, 0), slength + Math.min(spadding, 0)); - - return joseSignature; - } - - /** - * Added check for extra protection against CVE-2022-21449. - * This method ensures the signature's structure is as expected. - * - * @param joseSignature is the signature from the JWT - * @param publicKey public key used to verify the JWT - * @throws SignatureException if the signature's structure is not as per expectation - */ - // Visible for testing - void validateSignatureStructure(byte[] joseSignature, ECPublicKey publicKey) throws SignatureException { - // check signature length, moved this check from JOSEToDER method - if (joseSignature.length != ecNumberSize * 2) { - throw new SignatureException("Invalid JOSE signature format."); - } - - if (isAllZeros(joseSignature)) { - throw new SignatureException("Invalid signature format."); - } - - // get R - byte[] rBytes = new byte[ecNumberSize]; - System.arraycopy(joseSignature, 0, rBytes, 0, ecNumberSize); - if (isAllZeros(rBytes)) { - throw new SignatureException("Invalid signature format."); - } - - // get S - byte[] sBytes = new byte[ecNumberSize]; - System.arraycopy(joseSignature, ecNumberSize, sBytes, 0, ecNumberSize); - if (isAllZeros(sBytes)) { - throw new SignatureException("Invalid signature format."); - } - - //moved this check from JOSEToDER method - int rPadding = countPadding(joseSignature, 0, ecNumberSize); - int sPadding = countPadding(joseSignature, ecNumberSize, joseSignature.length); - int rLength = ecNumberSize - rPadding; - int sLength = ecNumberSize - sPadding; - - int length = 2 + rLength + 2 + sLength; - if (length > 255) { - throw new SignatureException("Invalid JOSE signature format."); - } - - BigInteger order = publicKey.getParams().getOrder(); - BigInteger r = new BigInteger(1, rBytes); - BigInteger s = new BigInteger(1, sBytes); - - // R and S must be less than N - if (order.compareTo(r) < 1) { - throw new SignatureException("Invalid signature format."); - } - - if (order.compareTo(s) < 1) { - throw new SignatureException("Invalid signature format."); - } - } - - //Visible for testing - byte[] JOSEToDER(byte[] joseSignature) throws SignatureException { - // Retrieve R and S number's length and padding. - int rPadding = countPadding(joseSignature, 0, ecNumberSize); - int sPadding = countPadding(joseSignature, ecNumberSize, joseSignature.length); - int rLength = ecNumberSize - rPadding; - int sLength = ecNumberSize - sPadding; - - int length = 2 + rLength + 2 + sLength; - - final byte[] derSignature; - int offset; - if (length > 0x7f) { - derSignature = new byte[3 + length]; - derSignature[1] = (byte) 0x81; - offset = 2; - } else { - derSignature = new byte[2 + length]; - offset = 1; - } - - // DER Structure: http://crypto.stackexchange.com/a/1797 - // Header with signature length info - derSignature[0] = (byte) 0x30; - derSignature[offset++] = (byte) (length & 0xff); - - // Header with "min R" number length - derSignature[offset++] = (byte) 0x02; - derSignature[offset++] = (byte) rLength; - - // R number - if (rPadding < 0) { - //Sign - derSignature[offset++] = (byte) 0x00; - System.arraycopy(joseSignature, 0, derSignature, offset, ecNumberSize); - offset += ecNumberSize; - } else { - int copyLength = Math.min(ecNumberSize, rLength); - System.arraycopy(joseSignature, rPadding, derSignature, offset, copyLength); - offset += copyLength; - } - - // Header with "min S" number length - derSignature[offset++] = (byte) 0x02; - derSignature[offset++] = (byte) sLength; - - // S number - if (sPadding < 0) { - //Sign - derSignature[offset++] = (byte) 0x00; - System.arraycopy(joseSignature, ecNumberSize, derSignature, offset, ecNumberSize); - } else { - System.arraycopy(joseSignature, ecNumberSize + sPadding, derSignature, offset, - Math.min(ecNumberSize, sLength)); - } - - return derSignature; - } - - private boolean isAllZeros(byte[] bytes) { - for (byte b : bytes) { - if (b != 0) { - return false; - } - } - return true; - } - - private int countPadding(byte[] bytes, int fromIndex, int toIndex) { - int padding = 0; - while (fromIndex + padding < toIndex && bytes[fromIndex + padding] == 0) { - padding++; - } - return (bytes[fromIndex + padding] & 0xff) > 0x7f ? padding - 1 : padding; - } - - //Visible for testing - static ECDSAKeyProvider providerForKeys(final ECPublicKey publicKey, final ECPrivateKey privateKey) { - if (publicKey == null && privateKey == null) { - throw new IllegalArgumentException("Both provided Keys cannot be null."); - } - return new ECDSAKeyProvider() { - @Override - public ECPublicKey getPublicKeyById(String keyId) { - return publicKey; - } - - @Override - public ECPrivateKey getPrivateKey() { - return privateKey; - } - - @Override - public String getPrivateKeyId() { - return null; - } - }; - } -} diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/HMACAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/HMACAlgorithm.java deleted file mode 100644 index 0306e7c4..00000000 --- a/lib/src/main/java/com/auth0/jwt/algorithms/HMACAlgorithm.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.auth0.jwt.algorithms; - -import com.auth0.jwt.exceptions.SignatureGenerationException; -import com.auth0.jwt.exceptions.SignatureVerificationException; -import com.auth0.jwt.interfaces.DecodedJWT; - -import java.nio.charset.StandardCharsets; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.Base64; - -/** - * Subclass representing an Hash-based MAC signing algorithm - *

- * This class is thread-safe. - */ -class HMACAlgorithm extends Algorithm { - - private final CryptoHelper crypto; - private final byte[] secret; - - //Visible for testing - HMACAlgorithm(CryptoHelper crypto, String id, String algorithm, byte[] secretBytes) - throws IllegalArgumentException { - super(id, algorithm); - if (secretBytes == null) { - throw new IllegalArgumentException("The Secret cannot be null"); - } - this.secret = Arrays.copyOf(secretBytes, secretBytes.length); - this.crypto = crypto; - } - - HMACAlgorithm(String id, String algorithm, byte[] secretBytes) throws IllegalArgumentException { - this(new CryptoHelper(), id, algorithm, secretBytes); - } - - HMACAlgorithm(String id, String algorithm, String secret) throws IllegalArgumentException { - this(new CryptoHelper(), id, algorithm, getSecretBytes(secret)); - } - - //Visible for testing - static byte[] getSecretBytes(String secret) throws IllegalArgumentException { - if (secret == null) { - throw new IllegalArgumentException("The Secret cannot be null"); - } - return secret.getBytes(StandardCharsets.UTF_8); - } - - @Override - public void verify(DecodedJWT jwt) throws SignatureVerificationException { - try { - byte[] signatureBytes = Base64.getUrlDecoder().decode(jwt.getSignature()); - boolean valid = crypto.verifySignatureFor( - getDescription(), secret, jwt.getHeader(), jwt.getPayload(), signatureBytes); - if (!valid) { - throw new SignatureVerificationException(this); - } - } catch (IllegalStateException | InvalidKeyException | NoSuchAlgorithmException | IllegalArgumentException e) { - throw new SignatureVerificationException(this, e); - } - } - - @Override - public byte[] sign(byte[] headerBytes, byte[] payloadBytes) throws SignatureGenerationException { - try { - return crypto.createSignatureFor(getDescription(), secret, headerBytes, payloadBytes); - } catch (NoSuchAlgorithmException | InvalidKeyException e) { - throw new SignatureGenerationException(this, e); - } - } - - @Override - public byte[] sign(byte[] contentBytes) throws SignatureGenerationException { - try { - return crypto.createSignatureFor(getDescription(), secret, contentBytes); - } catch (NoSuchAlgorithmException | InvalidKeyException e) { - throw new SignatureGenerationException(this, e); - } - } -} diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/NoneAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/NoneAlgorithm.java deleted file mode 100644 index 5c6c0fc5..00000000 --- a/lib/src/main/java/com/auth0/jwt/algorithms/NoneAlgorithm.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.auth0.jwt.algorithms; - -import com.auth0.jwt.exceptions.SignatureGenerationException; -import com.auth0.jwt.exceptions.SignatureVerificationException; -import com.auth0.jwt.interfaces.DecodedJWT; -import java.util.Base64; - -class NoneAlgorithm extends Algorithm { - - NoneAlgorithm() { - super("none", "none"); - } - - @Override - public void verify(DecodedJWT jwt) throws SignatureVerificationException { - try { - byte[] signatureBytes = Base64.getUrlDecoder().decode(jwt.getSignature()); - - if (signatureBytes.length > 0) { - throw new SignatureVerificationException(this); - } - } catch (IllegalArgumentException e) { - throw new SignatureVerificationException(this, e); - } - } - - @Override - public byte[] sign(byte[] headerBytes, byte[] payloadBytes) throws SignatureGenerationException { - return new byte[0]; - } - - @Override - public byte[] sign(byte[] contentBytes) throws SignatureGenerationException { - return new byte[0]; - } -} diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java deleted file mode 100644 index ca892e60..00000000 --- a/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.auth0.jwt.algorithms; - -import com.auth0.jwt.exceptions.SignatureGenerationException; -import com.auth0.jwt.exceptions.SignatureVerificationException; -import com.auth0.jwt.interfaces.DecodedJWT; -import com.auth0.jwt.interfaces.RSAKeyProvider; - -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.SignatureException; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; -import java.util.Base64; - -/** - * Subclass representing an RSA signing algorithm - *

- * This class is thread-safe. - */ -class RSAAlgorithm extends Algorithm { - - private final RSAKeyProvider keyProvider; - private final CryptoHelper crypto; - - //Visible for testing - RSAAlgorithm(CryptoHelper crypto, String id, String algorithm, RSAKeyProvider keyProvider) - throws IllegalArgumentException { - super(id, algorithm); - if (keyProvider == null) { - throw new IllegalArgumentException("The Key Provider cannot be null."); - } - this.keyProvider = keyProvider; - this.crypto = crypto; - } - - RSAAlgorithm(String id, String algorithm, RSAKeyProvider keyProvider) throws IllegalArgumentException { - this(new CryptoHelper(), id, algorithm, keyProvider); - } - - @Override - public void verify(DecodedJWT jwt) throws SignatureVerificationException { - try { - byte[] signatureBytes = Base64.getUrlDecoder().decode(jwt.getSignature()); - RSAPublicKey publicKey = keyProvider.getPublicKeyById(jwt.getKeyId()); - if (publicKey == null) { - throw new IllegalStateException("The given Public Key is null."); - } - boolean valid = crypto.verifySignatureFor( - getDescription(), publicKey, jwt.getHeader(), jwt.getPayload(), signatureBytes); - if (!valid) { - throw new SignatureVerificationException(this); - } - } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException - | IllegalArgumentException | IllegalStateException e) { - throw new SignatureVerificationException(this, e); - } - } - - @Override - public byte[] sign(byte[] headerBytes, byte[] payloadBytes) throws SignatureGenerationException { - try { - RSAPrivateKey privateKey = keyProvider.getPrivateKey(); - if (privateKey == null) { - throw new IllegalStateException("The given Private Key is null."); - } - return crypto.createSignatureFor(getDescription(), privateKey, headerBytes, payloadBytes); - } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException | IllegalStateException e) { - throw new SignatureGenerationException(this, e); - } - } - - @Override - public byte[] sign(byte[] contentBytes) throws SignatureGenerationException { - try { - RSAPrivateKey privateKey = keyProvider.getPrivateKey(); - if (privateKey == null) { - throw new IllegalStateException("The given Private Key is null."); - } - return crypto.createSignatureFor(getDescription(), privateKey, contentBytes); - } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException | IllegalStateException e) { - throw new SignatureGenerationException(this, e); - } - } - - @Override - public String getSigningKeyId() { - return keyProvider.getPrivateKeyId(); - } - - //Visible for testing - static RSAKeyProvider providerForKeys(final RSAPublicKey publicKey, final RSAPrivateKey privateKey) { - if (publicKey == null && privateKey == null) { - throw new IllegalArgumentException("Both provided Keys cannot be null."); - } - return new RSAKeyProvider() { - @Override - public RSAPublicKey getPublicKeyById(String keyId) { - return publicKey; - } - - @Override - public RSAPrivateKey getPrivateKey() { - return privateKey; - } - - @Override - public String getPrivateKeyId() { - return null; - } - }; - } -} diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/AlgorithmMismatchException.java b/lib/src/main/java/com/auth0/jwt/exceptions/AlgorithmMismatchException.java deleted file mode 100644 index d6b71205..00000000 --- a/lib/src/main/java/com/auth0/jwt/exceptions/AlgorithmMismatchException.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.auth0.jwt.exceptions; - -/** - * The exception that will be thrown if the exception doesn't match the one mentioned in the JWT Header. - */ -public class AlgorithmMismatchException extends JWTVerificationException { - public AlgorithmMismatchException(String message) { - super(message); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/IncorrectClaimException.java b/lib/src/main/java/com/auth0/jwt/exceptions/IncorrectClaimException.java deleted file mode 100644 index 712e937b..00000000 --- a/lib/src/main/java/com/auth0/jwt/exceptions/IncorrectClaimException.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.auth0.jwt.exceptions; - -import com.auth0.jwt.interfaces.Claim; - -/** - * This exception is thrown when the expected value is not found while verifying the Claims. - */ -public class IncorrectClaimException extends InvalidClaimException { - private final String claimName; - - private final Claim claimValue; - - /** - * Used internally to construct the IncorrectClaimException which is thrown when there is verification - * failure for a Claim that exists. - * - * @param message The error message - * @param claimName The Claim name for which verification failed - * @param claim The Claim value for which verification failed - */ - public IncorrectClaimException(String message, String claimName, Claim claim) { - super(message); - this.claimName = claimName; - this.claimValue = claim; - } - - /** - * This method can be used to fetch the name for which the Claim verification failed. - * - * @return The claim name for which the verification failed. - */ - public String getClaimName() { - return claimName; - } - - /** - * This method can be used to fetch the value for which the Claim verification failed. - * - * @return The value for which the verification failed - */ - public Claim getClaimValue() { - return claimValue; - } -} \ No newline at end of file diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/InvalidClaimException.java b/lib/src/main/java/com/auth0/jwt/exceptions/InvalidClaimException.java deleted file mode 100644 index c5b8eb64..00000000 --- a/lib/src/main/java/com/auth0/jwt/exceptions/InvalidClaimException.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.auth0.jwt.exceptions; - -/** - * The exception that will be thrown while verifying Claims of a JWT. - */ -public class InvalidClaimException extends JWTVerificationException { - public InvalidClaimException(String message) { - super(message); - } -} \ No newline at end of file diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/JWTCreationException.java b/lib/src/main/java/com/auth0/jwt/exceptions/JWTCreationException.java deleted file mode 100644 index c7e162ea..00000000 --- a/lib/src/main/java/com/auth0/jwt/exceptions/JWTCreationException.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.auth0.jwt.exceptions; - -/** - * The exception that is thrown when a JWT cannot be created. - */ -public class JWTCreationException extends RuntimeException { - public JWTCreationException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/JWTDecodeException.java b/lib/src/main/java/com/auth0/jwt/exceptions/JWTDecodeException.java deleted file mode 100644 index 448714e9..00000000 --- a/lib/src/main/java/com/auth0/jwt/exceptions/JWTDecodeException.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.auth0.jwt.exceptions; - -/** - * The exception that is thrown when any part of the token contained an invalid JWT or JSON format. - */ -public class JWTDecodeException extends JWTVerificationException { - public JWTDecodeException(String message) { - this(message, null); - } - - public JWTDecodeException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/JWTVerificationException.java b/lib/src/main/java/com/auth0/jwt/exceptions/JWTVerificationException.java deleted file mode 100644 index dd36dcd3..00000000 --- a/lib/src/main/java/com/auth0/jwt/exceptions/JWTVerificationException.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.auth0.jwt.exceptions; - -/** - * Parent to all the exception thrown while verifying a JWT. - */ -public class JWTVerificationException extends RuntimeException { - public JWTVerificationException(String message) { - this(message, null); - } - - public JWTVerificationException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/MissingClaimException.java b/lib/src/main/java/com/auth0/jwt/exceptions/MissingClaimException.java deleted file mode 100644 index 3bcc2121..00000000 --- a/lib/src/main/java/com/auth0/jwt/exceptions/MissingClaimException.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.auth0.jwt.exceptions; - -/** - * This exception is thrown when the claim to be verified is missing. - */ -public class MissingClaimException extends InvalidClaimException { - - private final String claimName; - - public MissingClaimException(String claimName) { - super(String.format("The Claim '%s' is not present in the JWT.", claimName)); - this.claimName = claimName; - } - - /** - * This method can be used to fetch the name for which the Claim is missing during the verification. - * - * @return The name of the Claim that doesn't exist. - */ - public String getClaimName() { - return claimName; - } -} diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/SignatureGenerationException.java b/lib/src/main/java/com/auth0/jwt/exceptions/SignatureGenerationException.java deleted file mode 100644 index 4b7668a0..00000000 --- a/lib/src/main/java/com/auth0/jwt/exceptions/SignatureGenerationException.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.auth0.jwt.exceptions; - -import com.auth0.jwt.algorithms.Algorithm; - -/** - * The exception that is thrown when signature is not able to be generated. - */ -public class SignatureGenerationException extends JWTCreationException { - public SignatureGenerationException(Algorithm algorithm, Throwable cause) { - super("The Token's Signature couldn't be generated when signing using the Algorithm: " + algorithm, cause); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/SignatureVerificationException.java b/lib/src/main/java/com/auth0/jwt/exceptions/SignatureVerificationException.java deleted file mode 100644 index fa7c3cab..00000000 --- a/lib/src/main/java/com/auth0/jwt/exceptions/SignatureVerificationException.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.auth0.jwt.exceptions; - -import com.auth0.jwt.algorithms.Algorithm; - -/** - * The exception that is thrown if the Signature verification fails. - */ -public class SignatureVerificationException extends JWTVerificationException { - public SignatureVerificationException(Algorithm algorithm) { - this(algorithm, null); - } - - public SignatureVerificationException(Algorithm algorithm, Throwable cause) { - super("The Token's Signature resulted invalid when verified using the Algorithm: " + algorithm, cause); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/TokenExpiredException.java b/lib/src/main/java/com/auth0/jwt/exceptions/TokenExpiredException.java deleted file mode 100644 index 42ab090d..00000000 --- a/lib/src/main/java/com/auth0/jwt/exceptions/TokenExpiredException.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.auth0.jwt.exceptions; - -import java.time.Instant; - -/** - * The exception that is thrown if the token is expired. - */ -public class TokenExpiredException extends JWTVerificationException { - - private static final long serialVersionUID = -7076928975713577708L; - - private final Instant expiredOn; - - public TokenExpiredException(String message, Instant expiredOn) { - super(message); - this.expiredOn = expiredOn; - } - - public Instant getExpiredOn() { - return expiredOn; - } -} diff --git a/lib/src/main/java/com/auth0/jwt/impl/BasicHeader.java b/lib/src/main/java/com/auth0/jwt/impl/BasicHeader.java deleted file mode 100644 index 5a881ab5..00000000 --- a/lib/src/main/java/com/auth0/jwt/impl/BasicHeader.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.auth0.jwt.impl; - -import com.auth0.jwt.interfaces.Claim; -import com.auth0.jwt.interfaces.Header; -import com.fasterxml.jackson.core.ObjectCodec; -import com.fasterxml.jackson.databind.JsonNode; - -import java.io.Serializable; -import java.util.Collections; -import java.util.Map; - -import static com.auth0.jwt.impl.JsonNodeClaim.extractClaim; - -/** - * The BasicHeader class implements the Header interface. - */ -class BasicHeader implements Header, Serializable { - private static final long serialVersionUID = -4659137688548605095L; - - private final String algorithm; - private final String type; - private final String contentType; - private final String keyId; - private final Map tree; - private final ObjectCodec objectCodec; - - BasicHeader( - String algorithm, - String type, - String contentType, - String keyId, - Map tree, - ObjectCodec objectCodec - ) { - this.algorithm = algorithm; - this.type = type; - this.contentType = contentType; - this.keyId = keyId; - this.tree = tree == null ? Collections.emptyMap() : Collections.unmodifiableMap(tree); - this.objectCodec = objectCodec; - } - - Map getTree() { - return tree; - } - - @Override - public String getAlgorithm() { - return algorithm; - } - - @Override - public String getType() { - return type; - } - - @Override - public String getContentType() { - return contentType; - } - - @Override - public String getKeyId() { - return keyId; - } - - @Override - public Claim getHeaderClaim(String name) { - return extractClaim(name, tree, objectCodec); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/impl/ClaimsHolder.java b/lib/src/main/java/com/auth0/jwt/impl/ClaimsHolder.java deleted file mode 100644 index 30f6ab18..00000000 --- a/lib/src/main/java/com/auth0/jwt/impl/ClaimsHolder.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.auth0.jwt.impl; - -import java.util.HashMap; -import java.util.Map; - -/** - * The ClaimsHolder class is just a wrapper for the Map of Claims used for building a JWT. - */ -public abstract class ClaimsHolder { - private Map claims; - - protected ClaimsHolder(Map claims) { - this.claims = claims == null ? new HashMap<>() : claims; - } - - Map getClaims() { - return claims; - } -} diff --git a/lib/src/main/java/com/auth0/jwt/impl/ClaimsSerializer.java b/lib/src/main/java/com/auth0/jwt/impl/ClaimsSerializer.java deleted file mode 100644 index b1f8e6d3..00000000 --- a/lib/src/main/java/com/auth0/jwt/impl/ClaimsSerializer.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.auth0.jwt.impl; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; - -import java.io.IOException; -import java.time.Instant; -import java.util.Date; -import java.util.List; -import java.util.Map; - -/** - * Custom serializer used to write the resulting JWT. - * - * @param the type this serializer operates on. - */ -public class ClaimsSerializer extends StdSerializer { - - public ClaimsSerializer(Class t) { - super(t); - } - - @Override - public void serialize(T holder, JsonGenerator gen, SerializerProvider provider) throws IOException { - gen.writeStartObject(); - for (Map.Entry entry : holder.getClaims().entrySet()) { - writeClaim(entry, gen); - } - gen.writeEndObject(); - } - - /** - * Writes the given entry to the JSON representation. Custom claim serialization handling can override this method - * to provide use-case specific serialization. Implementors who override this method must write - * the field name and the field value. - * - * @param entry The entry that corresponds to the JSON field to write - * @param gen The {@code JsonGenerator} to use - * @throws IOException if there is either an underlying I/O problem or encoding issue at format layer - */ - protected void writeClaim(Map.Entry entry, JsonGenerator gen) throws IOException { - gen.writeFieldName(entry.getKey()); - handleSerialization(entry.getValue(), gen); - } - - private static void handleSerialization(Object value, JsonGenerator gen) throws IOException { - if (value instanceof Date) { - gen.writeNumber(dateToSeconds((Date) value)); - } else if (value instanceof Instant) { // EXPIRES_AT, ISSUED_AT, NOT_BEFORE, custom Instant claims - gen.writeNumber(instantToSeconds((Instant) value)); - } else if (value instanceof Map) { - serializeMap((Map) value, gen); - } else if (value instanceof List) { - serializeList((List) value, gen); - } else { - gen.writeObject(value); - } - } - - private static void serializeMap(Map map, JsonGenerator gen) throws IOException { - gen.writeStartObject(); - for (Map.Entry entry : map.entrySet()) { - gen.writeFieldName((String) entry.getKey()); - Object value = entry.getValue(); - handleSerialization(value, gen); - } - gen.writeEndObject(); - } - - private static void serializeList(List list, JsonGenerator gen) throws IOException { - gen.writeStartArray(); - for (Object entry : list) { - handleSerialization(entry, gen); - } - gen.writeEndArray(); - } - - private static long instantToSeconds(Instant instant) { - return instant.getEpochSecond(); - } - - private static long dateToSeconds(Date date) { - return date.getTime() / 1000; - } -} diff --git a/lib/src/main/java/com/auth0/jwt/impl/ExpectedCheckHolder.java b/lib/src/main/java/com/auth0/jwt/impl/ExpectedCheckHolder.java deleted file mode 100644 index 6737031c..00000000 --- a/lib/src/main/java/com/auth0/jwt/impl/ExpectedCheckHolder.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.auth0.jwt.impl; - -import com.auth0.jwt.interfaces.Claim; -import com.auth0.jwt.interfaces.DecodedJWT; - -/** - * This holds the checks that are run to verify a JWT. - */ -public interface ExpectedCheckHolder { - /** - * The claim name that will be checked. - * - * @return the claim name - */ - String getClaimName(); - - /** - * The verification that will be run. - * - * @param claim the claim for which verification is done - * @param decodedJWT the JWT on which verification is done - * @return whether the verification passed or not - */ - boolean verify(Claim claim, DecodedJWT decodedJWT); -} diff --git a/lib/src/main/java/com/auth0/jwt/impl/HeaderClaimsHolder.java b/lib/src/main/java/com/auth0/jwt/impl/HeaderClaimsHolder.java deleted file mode 100644 index 9b480116..00000000 --- a/lib/src/main/java/com/auth0/jwt/impl/HeaderClaimsHolder.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.auth0.jwt.impl; - -import java.util.Map; - -/** - * Holds the header claims when serializing a JWT. - */ -public final class HeaderClaimsHolder extends ClaimsHolder { - public HeaderClaimsHolder(Map claims) { - super(claims); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java b/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java deleted file mode 100644 index ad6e4ce0..00000000 --- a/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.auth0.jwt.impl; - -import com.auth0.jwt.HeaderParams; -import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.interfaces.Header; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; - -import java.io.IOException; -import java.util.Map; - -/** - * Jackson deserializer implementation for converting from JWT Header parts. - *

- * This class is thread-safe. - * - * @see JWTParser - */ -class HeaderDeserializer extends StdDeserializer

{ - - HeaderDeserializer() { - super(Header.class); - } - - @Override - public Header deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - Map tree = p.getCodec().readValue(p, new TypeReference>() { - }); - if (tree == null) { - throw new JWTDecodeException("Parsing the Header's JSON resulted on a Null map"); - } - - String algorithm = getString(tree, HeaderParams.ALGORITHM); - String type = getString(tree, HeaderParams.TYPE); - String contentType = getString(tree, HeaderParams.CONTENT_TYPE); - String keyId = getString(tree, HeaderParams.KEY_ID); - return new BasicHeader(algorithm, type, contentType, keyId, tree, p.getCodec()); - } - - String getString(Map tree, String claimName) { - JsonNode node = tree.get(claimName); - if (node == null || node.isNull()) { - return null; - } - return node.asText(null); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/impl/HeaderSerializer.java b/lib/src/main/java/com/auth0/jwt/impl/HeaderSerializer.java deleted file mode 100644 index 5c7cf0fc..00000000 --- a/lib/src/main/java/com/auth0/jwt/impl/HeaderSerializer.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.auth0.jwt.impl; - -/** - * Responsible for serializing a JWT's header representation to JSON. - */ -public class HeaderSerializer extends ClaimsSerializer { - public HeaderSerializer() { - super(HeaderClaimsHolder.class); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/impl/JWTParser.java b/lib/src/main/java/com/auth0/jwt/impl/JWTParser.java deleted file mode 100644 index 022520f5..00000000 --- a/lib/src/main/java/com/auth0/jwt/impl/JWTParser.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.auth0.jwt.impl; - -import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.interfaces.Header; -import com.auth0.jwt.interfaces.JWTPartsParser; -import com.auth0.jwt.interfaces.Payload; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectReader; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.module.SimpleModule; -import java.io.IOException; - -/** - * This class helps in decoding the Header and Payload of the JWT using - * {@link HeaderSerializer} and {@link PayloadSerializer}. - */ -public class JWTParser implements JWTPartsParser { - private static final ObjectMapper DEFAULT_OBJECT_MAPPER = createDefaultObjectMapper(); - private static final ObjectReader DEFAULT_PAYLOAD_READER = DEFAULT_OBJECT_MAPPER.readerFor(Payload.class); - private static final ObjectReader DEFAULT_HEADER_READER = DEFAULT_OBJECT_MAPPER.readerFor(Header.class); - - private final ObjectReader payloadReader; - private final ObjectReader headerReader; - - public JWTParser() { - this.payloadReader = DEFAULT_PAYLOAD_READER; - this.headerReader = DEFAULT_HEADER_READER; - } - - JWTParser(ObjectMapper mapper) { - addDeserializers(mapper); - - this.payloadReader = mapper.readerFor(Payload.class); - this.headerReader = mapper.readerFor(Header.class); - } - - @Override - public Payload parsePayload(String json) throws JWTDecodeException { - if (json == null) { - throw decodeException(); - } - - try { - return payloadReader.readValue(json); - } catch (IOException e) { - throw decodeException(json); - } - } - - @Override - public Header parseHeader(String json) throws JWTDecodeException { - if (json == null) { - throw decodeException(); - } - - try { - return headerReader.readValue(json); - } catch (IOException e) { - throw decodeException(json); - } - } - - static void addDeserializers(ObjectMapper mapper) { - SimpleModule module = new SimpleModule(); - module.addDeserializer(Payload.class, new PayloadDeserializer()); - module.addDeserializer(Header.class, new HeaderDeserializer()); - mapper.registerModule(module); - } - - static ObjectMapper getDefaultObjectMapper() { - return DEFAULT_OBJECT_MAPPER; - } - - private static ObjectMapper createDefaultObjectMapper() { - ObjectMapper mapper = new ObjectMapper(); - mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); - mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); - - addDeserializers(mapper); - - return mapper; - } - - private static JWTDecodeException decodeException() { - return decodeException(null); - } - - private static JWTDecodeException decodeException(String json) { - return new JWTDecodeException(String.format("The string '%s' doesn't have a valid JSON format.", json)); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java b/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java deleted file mode 100644 index 0a7e22f3..00000000 --- a/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java +++ /dev/null @@ -1,182 +0,0 @@ -package com.auth0.jwt.impl; - -import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.interfaces.Claim; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.ObjectCodec; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.JsonNode; - -import java.io.IOException; -import java.lang.reflect.Array; -import java.time.Instant; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; - -/** - * The JsonNodeClaim retrieves a claim value from a JsonNode object. - */ -class JsonNodeClaim implements Claim { - - private final ObjectCodec codec; - private final JsonNode data; - - private JsonNodeClaim(JsonNode node, ObjectCodec codec) { - this.data = node; - this.codec = codec; - } - - @Override - public Boolean asBoolean() { - return isMissing() || isNull() || !data.isBoolean() ? null : data.asBoolean(); - } - - @Override - public Integer asInt() { - return isMissing() || isNull() || !data.isNumber() ? null : data.asInt(); - } - - @Override - public Long asLong() { - return isMissing() || isNull() || !data.isNumber() ? null : data.asLong(); - } - - @Override - public Double asDouble() { - return isMissing() || isNull() || !data.isNumber() ? null : data.asDouble(); - } - - @Override - public String asString() { - return isMissing() || isNull() || !data.isTextual() ? null : data.asText(); - } - - @Override - public Date asDate() { - if (isMissing() || isNull() || !data.canConvertToLong()) { - return null; - } - long seconds = data.asLong(); - return new Date(seconds * 1000); - } - - @Override - public Instant asInstant() { - if (isMissing() || isNull() || !data.canConvertToLong()) { - return null; - } - long seconds = data.asLong(); - return Instant.ofEpochSecond(seconds); - } - - @Override - @SuppressWarnings("unchecked") - public T[] asArray(Class clazz) throws JWTDecodeException { - if (isMissing() || isNull() || !data.isArray()) { - return null; - } - - T[] arr = (T[]) Array.newInstance(clazz, data.size()); - for (int i = 0; i < data.size(); i++) { - try { - arr[i] = codec.treeToValue(data.get(i), clazz); - } catch (JsonProcessingException e) { - throw new JWTDecodeException("Couldn't map the Claim's array contents to " + clazz.getSimpleName(), e); - } - } - return arr; - } - - @Override - public List asList(Class clazz) throws JWTDecodeException { - if (isMissing() || isNull() || !data.isArray()) { - return null; - } - - List list = new ArrayList<>(); - for (int i = 0; i < data.size(); i++) { - try { - list.add(codec.treeToValue(data.get(i), clazz)); - } catch (JsonProcessingException e) { - throw new JWTDecodeException("Couldn't map the Claim's array contents to " + clazz.getSimpleName(), e); - } - } - return list; - } - - @Override - public Map asMap() throws JWTDecodeException { - if (isMissing() || isNull() || !data.isObject()) { - return null; - } - - TypeReference> mapType = new TypeReference>() { - }; - - try (JsonParser parser = codec.treeAsTokens(data)) { - return parser.readValueAs(mapType); - } catch (IOException e) { - throw new JWTDecodeException("Couldn't map the Claim value to Map", e); - } - } - - @Override - public T as(Class clazz) throws JWTDecodeException { - try { - if (isMissing() || isNull()) { - return null; - } - return codec.treeToValue(data, clazz); - } catch (JsonProcessingException e) { - throw new JWTDecodeException("Couldn't map the Claim value to " + clazz.getSimpleName(), e); - } - } - - @Override - public boolean isNull() { - return !isMissing() && data.isNull(); - } - - @Override - public boolean isMissing() { - return data == null || data.isMissingNode(); - } - - @Override - public String toString() { - if (isMissing()) { - return "Missing claim"; - } else if (isNull()) { - return "Null claim"; - } - return data.toString(); - } - - /** - * Helper method to extract a Claim from the given JsonNode tree. - * - * @param claimName the Claim to search for. - * @param tree the JsonNode tree to search the Claim in. - * @param objectCodec the object codec in use for deserialization - * @return a valid non-null Claim. - */ - static Claim extractClaim(String claimName, Map tree, ObjectCodec objectCodec) { - JsonNode node = tree.get(claimName); - return claimFromNode(node, objectCodec); - } - - /** - * Helper method to create a Claim representation from the given JsonNode. - * - * @param node the JsonNode to convert into a Claim. - * @param objectCodec the object codec in use for deserialization - * @return a valid Claim instance. If the node is null or missing, a NullClaim will be returned. - */ - static Claim claimFromNode(JsonNode node, ObjectCodec objectCodec) { - return new JsonNodeClaim(node, objectCodec); - } - -} \ No newline at end of file diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadClaimsHolder.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadClaimsHolder.java deleted file mode 100644 index 7055a2ce..00000000 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadClaimsHolder.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.auth0.jwt.impl; - -import java.util.Map; - -/** - * Holds the payload claims when serializing a JWT. - */ -public final class PayloadClaimsHolder extends ClaimsHolder { - public PayloadClaimsHolder(Map claims) { - super(claims); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java deleted file mode 100644 index b1d32a12..00000000 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.auth0.jwt.impl; - -import com.auth0.jwt.RegisteredClaims; -import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.interfaces.Payload; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.ObjectCodec; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectReader; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; - -import java.io.IOException; -import java.time.Instant; -import java.util.*; - -/** - * Jackson deserializer implementation for converting from JWT Payload parts. - *

- * This class is thread-safe. - * - * @see JWTParser - */ -class PayloadDeserializer extends StdDeserializer { - - PayloadDeserializer() { - super(Payload.class); - } - - @Override - public Payload deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - Map tree = p.getCodec().readValue(p, new TypeReference>() { - }); - if (tree == null) { - throw new JWTDecodeException("Parsing the Payload's JSON resulted on a Null map"); - } - - String issuer = getString(tree, RegisteredClaims.ISSUER); - String subject = getString(tree, RegisteredClaims.SUBJECT); - List audience = getStringOrArray(p.getCodec(), tree, RegisteredClaims.AUDIENCE); - Instant expiresAt = getInstantFromSeconds(tree, RegisteredClaims.EXPIRES_AT); - Instant notBefore = getInstantFromSeconds(tree, RegisteredClaims.NOT_BEFORE); - Instant issuedAt = getInstantFromSeconds(tree, RegisteredClaims.ISSUED_AT); - String jwtId = getString(tree, RegisteredClaims.JWT_ID); - - return new PayloadImpl(issuer, subject, audience, expiresAt, notBefore, issuedAt, jwtId, tree, p.getCodec()); - } - - List getStringOrArray(ObjectCodec codec, Map tree, String claimName) - throws JWTDecodeException { - JsonNode node = tree.get(claimName); - if (node == null || node.isNull() || !(node.isArray() || node.isTextual())) { - return null; - } - if (node.isTextual()) { - return Collections.singletonList(node.asText()); - } - - List list = new ArrayList<>(node.size()); - for (int i = 0; i < node.size(); i++) { - try { - list.add(codec.treeToValue(node.get(i), String.class)); - } catch (JsonProcessingException e) { - throw new JWTDecodeException("Couldn't map the Claim's array contents to String", e); - } - } - return list; - } - - Instant getInstantFromSeconds(Map tree, String claimName) { - JsonNode node = tree.get(claimName); - if (node == null || node.isNull()) { - return null; - } - if (!node.canConvertToLong()) { - throw new JWTDecodeException( - String.format("The claim '%s' contained a non-numeric date value.", claimName)); - } - return Instant.ofEpochSecond(node.asLong()); - } - - String getString(Map tree, String claimName) { - JsonNode node = tree.get(claimName); - if (node == null || node.isNull()) { - return null; - } - return node.asText(null); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java deleted file mode 100644 index bfd9b0ea..00000000 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java +++ /dev/null @@ -1,129 +0,0 @@ -package com.auth0.jwt.impl; - -import com.auth0.jwt.interfaces.Claim; -import com.auth0.jwt.interfaces.Payload; -import com.fasterxml.jackson.core.ObjectCodec; -import com.fasterxml.jackson.databind.JsonNode; - -import java.io.Serializable; -import java.time.Instant; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static com.auth0.jwt.impl.JsonNodeClaim.extractClaim; - -/** - * Decoder of string JSON Web Tokens into their POJO representations. - *

- * This class is thread-safe. - * - * @see Payload - */ -class PayloadImpl implements Payload, Serializable { - - private static final long serialVersionUID = 1659021498824562311L; - - private final String issuer; - private final String subject; - private final List audience; - private final Instant expiresAt; - private final Instant notBefore; - private final Instant issuedAt; - private final String jwtId; - private final Map tree; - private final ObjectCodec objectCodec; - - PayloadImpl( - String issuer, - String subject, - List audience, - Instant expiresAt, - Instant notBefore, - Instant issuedAt, - String jwtId, - Map tree, - ObjectCodec objectCodec - ) { - this.issuer = issuer; - this.subject = subject; - this.audience = audience != null ? Collections.unmodifiableList(audience) : null; - this.expiresAt = expiresAt; - this.notBefore = notBefore; - this.issuedAt = issuedAt; - this.jwtId = jwtId; - this.tree = tree != null ? Collections.unmodifiableMap(tree) : Collections.emptyMap(); - this.objectCodec = objectCodec; - } - - Map getTree() { - return tree; - } - - @Override - public String getIssuer() { - return issuer; - } - - @Override - public String getSubject() { - return subject; - } - - @Override - public List getAudience() { - return audience; - } - - @Override - public Date getExpiresAt() { - return (expiresAt != null) ? Date.from(expiresAt) : null; - } - - - @Override - public Instant getExpiresAtAsInstant() { - return expiresAt; - } - - @Override - public Date getIssuedAt() { - return (issuedAt != null) ? Date.from(issuedAt) : null; - } - - @Override - public Instant getIssuedAtAsInstant() { - return issuedAt; - } - - @Override - public Date getNotBefore() { - return (notBefore != null) ? Date.from(notBefore) : null; - } - - @Override - public Instant getNotBeforeAsInstant() { - return notBefore; - } - - @Override - public String getId() { - return jwtId; - } - - @Override - public Claim getClaim(String name) { - return extractClaim(name, tree, objectCodec); - } - - @Override - public Map getClaims() { - Map claims = new HashMap<>(tree.size() * 2); - for (String name : tree.keySet()) { - claims.put(name, extractClaim(name, tree, objectCodec)); - } - return Collections.unmodifiableMap(claims); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java deleted file mode 100644 index 24fe37b7..00000000 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.auth0.jwt.impl; - -import com.auth0.jwt.RegisteredClaims; -import com.fasterxml.jackson.core.JsonGenerator; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -/** - * Jackson serializer implementation for converting into JWT Payload parts. - *

- * This class is thread-safe. - * - * @see com.auth0.jwt.JWTCreator - */ -public class PayloadSerializer extends ClaimsSerializer { - public PayloadSerializer() { - super(PayloadClaimsHolder.class); - } - - @Override - protected void writeClaim(Map.Entry entry, JsonGenerator gen) throws IOException { - if (RegisteredClaims.AUDIENCE.equals(entry.getKey())) { - writeAudience(gen, entry); - } else { - super.writeClaim(entry, gen); - } - } - - /** - * Audience may be a list of strings or a single string. This is needed to properly handle the aud claim when - * added with the {@linkplain com.auth0.jwt.JWTCreator.Builder#withPayload(Map)} method. - */ - private void writeAudience(JsonGenerator gen, Map.Entry e) throws IOException { - if (e.getValue() instanceof String) { - gen.writeFieldName(e.getKey()); - gen.writeString((String) e.getValue()); - } else { - List audArray = new ArrayList<>(); - if (e.getValue() instanceof String[]) { - audArray = Arrays.asList((String[]) e.getValue()); - } else if (e.getValue() instanceof List) { - List audList = (List) e.getValue(); - for (Object aud : audList) { - if (aud instanceof String) { - audArray.add((String) aud); - } - } - } - if (audArray.size() == 1) { - gen.writeFieldName(e.getKey()); - gen.writeString(audArray.get(0)); - } else if (audArray.size() > 1) { - gen.writeFieldName(e.getKey()); - gen.writeStartArray(); - for (String aud : audArray) { - gen.writeString(aud); - } - gen.writeEndArray(); - } - } - } -} diff --git a/lib/src/main/java/com/auth0/jwt/impl/package-info.java b/lib/src/main/java/com/auth0/jwt/impl/package-info.java deleted file mode 100644 index 334ccb8a..00000000 --- a/lib/src/main/java/com/auth0/jwt/impl/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Contains parts of the internal implementation of this library. - * - *

Do not use any of the classes in this package. They might be removed - * or changed at any point without prior warning. - */ -package com.auth0.jwt.impl; diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java b/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java deleted file mode 100644 index ca5244d6..00000000 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.auth0.jwt.interfaces; - -import com.auth0.jwt.exceptions.JWTDecodeException; - -import java.time.Instant; -import java.util.Date; -import java.util.List; -import java.util.Map; - -/** - * The Claim class holds the value in a generic way so that it can be recovered in many representations. - */ -public interface Claim { - - /** - * Whether this Claim has a null value or not. - * If the claim is not present, it will return false hence checking {@link Claim#isMissing} is advised as well - * - * @return whether this Claim has a null value or not. - */ - boolean isNull(); - - /** - * Can be used to verify whether the Claim is found or not. - * This will be true even if the Claim has {@code null} value associated to it. - * - * @return whether this Claim is present or not - */ - boolean isMissing(); - - /** - * Get this Claim as a Boolean. - * If the value isn't of type Boolean or it can't be converted to a Boolean, {@code null} will be returned. - * - * @return the value as a Boolean or null. - */ - Boolean asBoolean(); - - /** - * Get this Claim as an Integer. - * If the value isn't of type Integer or it can't be converted to an Integer, {@code null} will be returned. - * - * @return the value as an Integer or null. - */ - Integer asInt(); - - /** - * Get this Claim as an Long. - * If the value isn't of type Long or it can't be converted to a Long, {@code null} will be returned. - * - * @return the value as an Long or null. - */ - Long asLong(); - - /** - * Get this Claim as a Double. - * If the value isn't of type Double or it can't be converted to a Double, {@code null} will be returned. - * - * @return the value as a Double or null. - */ - Double asDouble(); - - /** - * Get this Claim as a String. - * If the value isn't of type String, {@code null} will be returned. For a String representation of non-textual - * claim types, clients can call {@code toString()}. - * - * @return the value as a String or null if the underlying value is not a string. - */ - String asString(); - - /** - * Get this Claim as a Date. - * If the value can't be converted to a Date, {@code null} will be returned. - * - * @return the value as a Date or null. - */ - Date asDate(); - - /** - * Get this Claim as an Instant. - * If the value can't be converted to an Instant, {@code null} will be returned. - * - * @return the value as a Date or null. - */ - default Instant asInstant() { - Date date = asDate(); - return date != null ? date.toInstant() : null; - } - - /** - * Get this Claim as an Array of type T. - * If the value isn't an Array, {@code null} will be returned. - * - * @param type - * @param clazz the type class - * @return the value as an Array or null. - * @throws JWTDecodeException if the values inside the Array can't be converted to a class T. - */ - T[] asArray(Class clazz) throws JWTDecodeException; - - /** - * Get this Claim as a List of type T. - * If the value isn't an Array, {@code null} will be returned. - * - * @param type - * @param clazz the type class - * @return the value as a List or null. - * @throws JWTDecodeException if the values inside the List can't be converted to a class T. - */ - List asList(Class clazz) throws JWTDecodeException; - - /** - * Get this Claim as a generic Map of values. - * - * @return the value as instance of Map. - * @throws JWTDecodeException if the value can't be converted to a Map. - */ - Map asMap() throws JWTDecodeException; - - /** - * Get this Claim as a custom type T. - * This method will return null if {@link Claim#isMissing()} or {@link Claim#isNull()} is true - * - * @param type - * @param clazz the type class - * @return the value as instance of T. - * @throws JWTDecodeException if the value can't be converted to a class T. - */ - T as(Class clazz) throws JWTDecodeException; -} diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/DecodedJWT.java b/lib/src/main/java/com/auth0/jwt/interfaces/DecodedJWT.java deleted file mode 100644 index 04307b28..00000000 --- a/lib/src/main/java/com/auth0/jwt/interfaces/DecodedJWT.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.auth0.jwt.interfaces; - -/** - * Class that represents a Json Web Token that was decoded from it's string representation. - */ -public interface DecodedJWT extends Payload, Header { - /** - * Getter for the String Token used to create this JWT instance. - * - * @return the String Token. - */ - String getToken(); - - /** - * Getter for the Header contained in the JWT as a Base64 encoded String. - * This represents the first part of the token. - * - * @return the Header of the JWT. - */ - String getHeader(); - - /** - * Getter for the Payload contained in the JWT as a Base64 encoded String. - * This represents the second part of the token. - * - * @return the Payload of the JWT. - */ - String getPayload(); - - /** - * Getter for the Signature contained in the JWT as a Base64 encoded String. - * This represents the third part of the token. - * - * @return the Signature of the JWT. - */ - String getSignature(); -} diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/ECDSAKeyProvider.java b/lib/src/main/java/com/auth0/jwt/interfaces/ECDSAKeyProvider.java deleted file mode 100644 index 55df451d..00000000 --- a/lib/src/main/java/com/auth0/jwt/interfaces/ECDSAKeyProvider.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.auth0.jwt.interfaces; - -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; - -/** - * Elliptic Curve (EC) Public/Private Key provider. - */ -public interface ECDSAKeyProvider extends KeyProvider { -} diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Header.java b/lib/src/main/java/com/auth0/jwt/interfaces/Header.java deleted file mode 100644 index 52b3ba56..00000000 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Header.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.auth0.jwt.interfaces; - -/** - * The Header class represents the 1st part of the JWT, where the Header value is held. - */ -public interface Header { - - /** - * Getter for the Algorithm "alg" claim defined in the JWT's Header. If the claim is missing it will return null. - * - * @return the Algorithm defined or null. - */ - String getAlgorithm(); - - /** - * Getter for the Type "typ" claim defined in the JWT's Header. If the claim is missing it will return null. - * - * @return the Type defined or null. - */ - String getType(); - - /** - * Getter for the Content Type "cty" claim defined in the JWT's Header. If the claim is missing it will return null. - * - * @return the Content Type defined or null. - */ - String getContentType(); - - /** - * Get the value of the "kid" claim, or null if it's not available. - * - * @return the Key ID value or null. - */ - String getKeyId(); - - /** - * Get a Private Claim given it's name. If the Claim wasn't specified in the Header, a 'null claim' will be - * returned. All the methods of that claim will return {@code null}. - * - * @param name the name of the Claim to retrieve. - * @return a non-null Claim. - */ - Claim getHeaderClaim(String name); -} diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/JWTPartsParser.java b/lib/src/main/java/com/auth0/jwt/interfaces/JWTPartsParser.java deleted file mode 100644 index 33cd0d70..00000000 --- a/lib/src/main/java/com/auth0/jwt/interfaces/JWTPartsParser.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.auth0.jwt.interfaces; - -import com.auth0.jwt.exceptions.JWTDecodeException; - -/** - * The JWTPartsParser class defines which parts of the JWT should be converted - * to its specific Object representation instance. - */ -public interface JWTPartsParser { - - /** - * Parses the given JSON into a {@link Payload} instance. - * - * @param json the content of the Payload in a JSON representation. - * @return the Payload. - * @throws JWTDecodeException if the json doesn't have a proper JSON format. - */ - Payload parsePayload(String json) throws JWTDecodeException; - - /** - * Parses the given JSON into a {@link Header} instance. - * - * @param json the content of the Header in a JSON representation. - * @return the Header. - * @throws JWTDecodeException if the json doesn't have a proper JSON format. - */ - Header parseHeader(String json) throws JWTDecodeException; -} diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/interfaces/JWTVerifier.java deleted file mode 100644 index 2756ddd8..00000000 --- a/lib/src/main/java/com/auth0/jwt/interfaces/JWTVerifier.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.auth0.jwt.interfaces; - -import com.auth0.jwt.exceptions.JWTVerificationException; - - -/** - * Used to verify the JWT for its signature and claims. Implementations must be thread-safe. Instances are created - * using {@link Verification}. - * - *

- * try {
- *      JWTVerifier verifier = JWTVerifier.init(Algorithm.RSA256(publicKey, privateKey)
- *          .withIssuer("auth0")
- *          .build();
- *      DecodedJWT jwt = verifier.verify("token");
- * } catch (JWTVerificationException e) {
- *      // invalid signature or claims
- * }
- * 
- */ -public interface JWTVerifier { - - /** - * Performs the verification against the given Token. - * - * @param token to verify. - * @return a verified and decoded JWT. - * @throws JWTVerificationException if any of the verification steps fail - */ - DecodedJWT verify(String token) throws JWTVerificationException; - - /** - * Performs the verification against the given {@link DecodedJWT}. - * - * @param jwt to verify. - * @return a verified and decoded JWT. - * @throws JWTVerificationException if any of the verification steps fail - */ - DecodedJWT verify(DecodedJWT jwt) throws JWTVerificationException; -} diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/KeyProvider.java b/lib/src/main/java/com/auth0/jwt/interfaces/KeyProvider.java deleted file mode 100644 index 30a144a6..00000000 --- a/lib/src/main/java/com/auth0/jwt/interfaces/KeyProvider.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.auth0.jwt.interfaces; - -import java.security.PrivateKey; -import java.security.PublicKey; - -/** - * Generic Public/Private Key provider. - * While implementing, ensure the Private Key and Private Key ID doesn't change in between signing a token. - * - * @param the class that represents the Public Key - * @param the class that represents the Private Key - */ -interface KeyProvider { - - /** - * Getter for the Public Key instance with the given Id. Used to verify the signature on the JWT verification stage. - * - * @param keyId the Key Id specified in the Token's Header or null if none is available. - * Provides a hint on which Public Key to use to verify the token's signature. - * @return the Public Key instance - */ - U getPublicKeyById(String keyId); - - /** - * Getter for the Private Key instance. Used to sign the content on the JWT signing stage. - * - * @return the Private Key instance - */ - R getPrivateKey(); - - /** - * Getter for the Id of the Private Key used to sign the tokens. - * This represents the `kid` claim and will be placed in the Header. - * - * @return the Key Id that identifies the Private Key or null if it's not specified. - */ - String getPrivateKeyId(); -} diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Payload.java b/lib/src/main/java/com/auth0/jwt/interfaces/Payload.java deleted file mode 100644 index feb58c64..00000000 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Payload.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.auth0.jwt.interfaces; - -import java.time.Instant; -import java.util.Date; -import java.util.List; -import java.util.Map; - -/** - * The Payload class represents the 2nd part of the JWT, where the Payload value is held. - */ -public interface Payload { - - /** - * Get the value of the "iss" claim, or null if it's not available. - * - * @return the Issuer value or null. - */ - String getIssuer(); - - /** - * Get the value of the "sub" claim, or null if it's not available. - * - * @return the Subject value or null. - */ - String getSubject(); - - /** - * Get the value of the "aud" claim, or null if it's not available. - * - * @return the Audience value or null. - */ - List getAudience(); - - /** - * Get the value of the "exp" claim, or null if it's not available. - * - * @return the Expiration Time value or null. - */ - Date getExpiresAt(); - - /** - * Get the value of the "exp" claim as an {@linkplain Instant}, or null if it's not available. - * - * @return the Expiration Time value or null. - */ - default Instant getExpiresAtAsInstant() { - return getExpiresAt() != null ? getExpiresAt().toInstant() : null; - } - - /** - * Get the value of the "nbf" claim, or null if it's not available. - * - * @return the Not Before value or null. - */ - Date getNotBefore(); - - /** - * Get the value of the "nbf" claim as an {@linkplain Instant}, or null if it's not available. - * - * @return the Not Before value or null. - */ - default Instant getNotBeforeAsInstant() { - return getNotBefore() != null ? getNotBefore().toInstant() : null; - } - - /** - * Get the value of the "iat" claim, or null if it's not available. - * - * @return the Issued At value or null. - */ - Date getIssuedAt(); - - /** - * Get the value of the "iat" claim as an {@linkplain Instant}, or null if it's not available. - * - * @return the Issued At value or null. - */ - default Instant getIssuedAtAsInstant() { - return getIssuedAt() != null ? getIssuedAt().toInstant() : null; - } - - /** - * Get the value of the "jti" claim, or null if it's not available. - * - * @return the JWT ID value or null. - */ - String getId(); - - /** - * Get a Claim given its name. If the Claim wasn't specified in the Payload, a 'null claim' - * will be returned. All the methods of that claim will return {@code null}. - * - * @param name the name of the Claim to retrieve. - * @return a non-null Claim. - */ - Claim getClaim(String name); - - /** - * Get the Claims defined in the Token. - * - * @return a non-null Map containing the Claims defined in the Token. - */ - Map getClaims(); -} diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/RSAKeyProvider.java b/lib/src/main/java/com/auth0/jwt/interfaces/RSAKeyProvider.java deleted file mode 100644 index 55376f4d..00000000 --- a/lib/src/main/java/com/auth0/jwt/interfaces/RSAKeyProvider.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.auth0.jwt.interfaces; - -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; - -/** - * RSA Public/Private Key provider. - */ -public interface RSAKeyProvider extends KeyProvider { -} diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java b/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java deleted file mode 100644 index b4adcf5c..00000000 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java +++ /dev/null @@ -1,267 +0,0 @@ -package com.auth0.jwt.interfaces; - -import com.auth0.jwt.JWTVerifier; - -import java.time.Instant; -import java.util.Date; -import java.util.function.BiPredicate; - -/** - * Constructs and holds the checks required for a JWT to be considered valid. Note that implementations are - * not thread-safe. Once built by calling {@link #build()}, the resulting - * {@link com.auth0.jwt.interfaces.JWTVerifier} is thread-safe. - */ -public interface Verification { - - /** - * Verifies whether the JWT contains an Issuer ("iss") claim that equals to the value provided. - * This check is case-sensitive. - * - * @param issuer the required Issuer value. - * @return this same Verification instance. - */ - default Verification withIssuer(String issuer) { - return withIssuer(new String[]{issuer}); - } - - /** - * Verifies whether the JWT contains an Issuer ("iss") claim that contains all the values provided. - * This check is case-sensitive. An empty array is considered as a {@code null}. - * - * @param issuer the required Issuer value. If multiple values are given, the claim must at least match one of them - * @return this same Verification instance. - */ - Verification withIssuer(String... issuer); - - /** - * Verifies whether the JWT contains a Subject ("sub") claim that equals to the value provided. - * This check is case-sensitive. - * - * @param subject the required Subject value - * @return this same Verification instance. - */ - Verification withSubject(String subject); - - /** - * Verifies whether the JWT contains an Audience ("aud") claim that contains all the values provided. - * This check is case-sensitive. An empty array is considered as a {@code null}. - * - * @param audience the required Audience value - * @return this same Verification instance. - */ - Verification withAudience(String... audience); - - /** - * Verifies whether the JWT contains an Audience ("aud") claim contain at least one of the specified audiences. - * This check is case-sensitive. An empty array is considered as a {@code null}. - * - * @param audience the required Audience value for which the "aud" claim must contain at least one value. - * @return this same Verification instance. - */ - Verification withAnyOfAudience(String... audience); - - /** - * Define the default window in seconds in which the Not Before, Issued At and Expires At Claims - * will still be valid. Setting a specific leeway value on a given Claim will override this value for that Claim. - * - * @param leeway the window in seconds in which the Not Before, Issued At and Expires At Claims will still be valid. - * @return this same Verification instance. - * @throws IllegalArgumentException if leeway is negative. - */ - Verification acceptLeeway(long leeway) throws IllegalArgumentException; - - /** - * Set a specific leeway window in seconds in which the Expires At ("exp") Claim will still be valid. - * Expiration Date is always verified when the value is present. - * This method overrides the value set with acceptLeeway - * - * @param leeway the window in seconds in which the Expires At Claim will still be valid. - * @return this same Verification instance. - * @throws IllegalArgumentException if leeway is negative. - */ - Verification acceptExpiresAt(long leeway) throws IllegalArgumentException; - - /** - * Set a specific leeway window in seconds in which the Not Before ("nbf") Claim will still be valid. - * Not Before Date is always verified when the value is present. - * This method overrides the value set with acceptLeeway - * - * @param leeway the window in seconds in which the Not Before Claim will still be valid. - * @return this same Verification instance. - * @throws IllegalArgumentException if leeway is negative. - */ - Verification acceptNotBefore(long leeway) throws IllegalArgumentException; - - /** - * Set a specific leeway window in seconds in which the Issued At ("iat") Claim will still be valid. - * This method overrides the value set with {@link #acceptLeeway(long)}. - * By default, the Issued At claim is always verified when the value is present, - * unless disabled with {@link #ignoreIssuedAt()}. - * If Issued At verification has been disabled, no verification of the Issued At claim will be performed, - * and this method has no effect. - * - * @param leeway the window in seconds in which the Issued At Claim will still be valid. - * @return this same Verification instance. - * @throws IllegalArgumentException if leeway is negative. - */ - Verification acceptIssuedAt(long leeway) throws IllegalArgumentException; - - /** - * Verifies whether the JWT contains a JWT ID ("jti") claim that equals to the value provided. - * This check is case-sensitive. - * - * @param jwtId the required ID value - * @return this same Verification instance. - */ - Verification withJWTId(String jwtId); - - /** - * Verifies whether the claim is present in the JWT, with any value including {@code null}. - * - * @param name the Claim's name. - * @return this same Verification instance - * @throws IllegalArgumentException if the name is {@code null}. - */ - Verification withClaimPresence(String name) throws IllegalArgumentException; - - /** - * Verifies whether the claim is present with a {@code null} value. - * - * @param name the Claim's name. - * @return this same Verification instance. - * @throws IllegalArgumentException if the name is {@code null}. - */ - Verification withNullClaim(String name) throws IllegalArgumentException; - - /** - * Verifies whether the claim is equal to the given Boolean value. - * - * @param name the Claim's name. - * @param value the Claim's value. - * @return this same Verification instance. - * @throws IllegalArgumentException if the name is {@code null}. - */ - Verification withClaim(String name, Boolean value) throws IllegalArgumentException; - - /** - * Verifies whether the claim is equal to the given Integer value. - * - * @param name the Claim's name. - * @param value the Claim's value. - * @return this same Verification instance. - * @throws IllegalArgumentException if the name is {@code null}. - */ - Verification withClaim(String name, Integer value) throws IllegalArgumentException; - - /** - * Verifies whether the claim is equal to the given Long value. - * - * @param name the Claim's name. - * @param value the Claim's value. - * @return this same Verification instance. - * @throws IllegalArgumentException if the name is {@code null}. - */ - Verification withClaim(String name, Long value) throws IllegalArgumentException; - - /** - * Verifies whether the claim is equal to the given Integer value. - * - * @param name the Claim's name. - * @param value the Claim's value. - * @return this same Verification instance. - * @throws IllegalArgumentException if the name is {@code null}. - */ - Verification withClaim(String name, Double value) throws IllegalArgumentException; - - /** - * Verifies whether the claim is equal to the given String value. - * This check is case-sensitive. - * - * @param name the Claim's name. - * @param value the Claim's value. - * @return this same Verification instance. - * @throws IllegalArgumentException if the name is {@code null}. - */ - Verification withClaim(String name, String value) throws IllegalArgumentException; - - /** - * Verifies whether the claim is equal to the given Date value. - * Note that date-time claims are serialized as seconds since the epoch; - * when verifying date-time claim value, any time units more granular than seconds will not be considered. - * - * @param name the Claim's name. - * @param value the Claim's value. - * @return this same Verification instance. - * @throws IllegalArgumentException if the name is {@code null}. - */ - Verification withClaim(String name, Date value) throws IllegalArgumentException; - - /** - * Verifies whether the claim is equal to the given Instant value. - * Note that date-time claims are serialized as seconds since the epoch; - * when verifying a date-time claim value, any time units more granular than seconds will not be considered. - * - * @param name the Claim's name. - * @param value the Claim's value. - * @return this same Verification instance. - * @throws IllegalArgumentException if the name is {@code null}. - */ - default Verification withClaim(String name, Instant value) throws IllegalArgumentException { - return withClaim(name, value != null ? Date.from(value) : null); - } - - /** - * Executes the predicate provided and the validates the JWT if the predicate returns true. - * - * @param name the Claim's name - * @param predicate the predicate check to be done. - * @return this same Verification instance. - * @throws IllegalArgumentException if the name is {@code null}. - */ - Verification withClaim(String name, BiPredicate predicate) throws IllegalArgumentException; - - /** - * Verifies whether the claim contain at least the given String items. - * - * @param name the Claim's name. - * @param items the items the Claim must contain. - * @return this same Verification instance. - * @throws IllegalArgumentException if the name is {@code null}. - */ - Verification withArrayClaim(String name, String... items) throws IllegalArgumentException; - - /** - * Verifies whether the claim contain at least the given Integer items. - * - * @param name the Claim's name. - * @param items the items the Claim must contain. - * @return this same Verification instance. - * @throws IllegalArgumentException if the name is {@code null}. - */ - Verification withArrayClaim(String name, Integer... items) throws IllegalArgumentException; - - /** - * Verifies whether the claim contain at least the given Long items. - * - * @param name the Claim's name. - * @param items the items the Claim must contain. - * @return this same Verification instance. - * @throws IllegalArgumentException if the name is {@code null}. - */ - - Verification withArrayClaim(String name, Long ... items) throws IllegalArgumentException; - - /** - * Skip the Issued At ("iat") claim verification. By default, the verification is performed. - * - * @return this same Verification instance. - */ - Verification ignoreIssuedAt(); - - /** - * Creates a new and reusable instance of the JWTVerifier with the configuration already provided. - * - * @return a new {@link com.auth0.jwt.interfaces.JWTVerifier} instance. - */ - JWTVerifier build(); -} diff --git a/lib/src/main/java/module-info.java b/lib/src/main/java/module-info.java deleted file mode 100644 index a1e30e31..00000000 --- a/lib/src/main/java/module-info.java +++ /dev/null @@ -1,8 +0,0 @@ -module com.auth0.jwt { - requires com.fasterxml.jackson.databind; - - exports com.auth0.jwt; - exports com.auth0.jwt.algorithms; - exports com.auth0.jwt.exceptions; - exports com.auth0.jwt.interfaces; -} diff --git a/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java b/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java deleted file mode 100644 index 32ede1de..00000000 --- a/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java +++ /dev/null @@ -1,162 +0,0 @@ -package com.auth0.jwt; - -import com.auth0.jwt.algorithms.Algorithm; -import com.auth0.jwt.interfaces.DecodedJWT; -import net.jodah.concurrentunit.Waiter; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.security.interfaces.ECKey; -import java.security.interfaces.RSAKey; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.*; - -import static com.auth0.jwt.PemUtils.readPublicKeyFromFile; - -//@Ignore("Skipping concurrency tests") -public class ConcurrentVerifyTest { - - private static final long TIMEOUT = 10 * 1000 * 1000; //1 min - private static final int THREAD_COUNT = 100; - private static final int REPEAT_COUNT = 1000; - private static final String PUBLIC_KEY_FILE = "src/test/resources/rsa-public.pem"; - private static final String PUBLIC_KEY_FILE_256 = "src/test/resources/ec256-key-public.pem"; - private static final String PUBLIC_KEY_FILE_384 = "src/test/resources/ec384-key-public.pem"; - private static final String PUBLIC_KEY_FILE_512 = "src/test/resources/ec512-key-public.pem"; - - @Rule - public ExpectedException exception = ExpectedException.none(); - private static ExecutorService executor; - - @BeforeClass - public static void beforeAll() { - executor = Executors.newFixedThreadPool(THREAD_COUNT); - } - - @AfterClass - public static void afterAll() { - executor.shutdown(); - } - - @SuppressWarnings("Convert2Lambda") - private void concurrentVerify(final JWTVerifier verifier, final String token) throws TimeoutException, InterruptedException { - final Waiter waiter = new Waiter(); - List tasks = Collections.nCopies(REPEAT_COUNT, new VerifyTask(waiter, verifier, token)); - executor.invokeAll(tasks, TIMEOUT, TimeUnit.MILLISECONDS); - waiter.await(TIMEOUT, REPEAT_COUNT); - } - - private static class VerifyTask implements Callable { - - private final Waiter waiter; - private final JWTVerifier verifier; - private final String token; - - VerifyTask(Waiter waiter, final JWTVerifier verifier, final String token) { - this.waiter = waiter; - this.verifier = verifier; - this.token = token; - } - - @Override - public DecodedJWT call() { - DecodedJWT jwt = null; - try { - jwt = verifier.verify(token); - waiter.assertNotNull(jwt); - } catch (Exception e) { - waiter.fail(e); - } - waiter.resume(); - return jwt; - } - } - - @Test - public void shouldPassHMAC256Verification() throws Exception { - Algorithm algorithm = Algorithm.HMAC256("secret"); - JWTVerifier verifier = JWTVerifier.init(algorithm).withIssuer("auth0").build(); - String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; - - concurrentVerify(verifier, token); - } - - @Test - public void shouldPassHMAC384Verification() throws Exception { - String token = "eyJhbGciOiJIUzM4NCIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.uztpK_wUMYJhrRv8SV-1LU4aPnwl-EM1q-wJnqgyb5DHoDteP6lN_gE1xnZJH5vw"; - Algorithm algorithm = Algorithm.HMAC384("secret"); - JWTVerifier verifier = JWTVerifier.init(algorithm).withIssuer("auth0").build(); - - concurrentVerify(verifier, token); - } - - @Test - public void shouldPassHMAC512Verification() throws Exception { - String token = "eyJhbGciOiJIUzUxMiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.VUo2Z9SWDV-XcOc_Hr6Lff3vl7L9e5Vb8ThXpmGDFjHxe3Dr1ZBmUChYF-xVA7cAdX1P_D4ZCUcsv3IefpVaJw"; - Algorithm algorithm = Algorithm.HMAC512("secret"); - JWTVerifier verifier = JWTVerifier.init(algorithm).withIssuer("auth0").build(); - - concurrentVerify(verifier, token); - } - - @Test - public void shouldPassRSA256Verification() throws Exception { - String token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.dxXF3MdsyW-AuvwJpaQtrZ33fAde9xWxpLIg9cO2tMLH2GSRNuLAe61KsJusZhqZB9Iy7DvflcmRz-9OZndm6cj_ThGeJH2LLc90K83UEvvRPo8l85RrQb8PcanxCgIs2RcZOLygERizB3pr5icGkzR7R2y6zgNCjKJ5_NJ6EiZsGN6_nc2PRK_DbyY-Wn0QDxIxKoA5YgQJ9qafe7IN980pXvQv2Z62c3XR8dYuaXBqhthBj-AbaFHEpZapN-V-TmuLNzR2MCB6Xr7BYMuCaqWf_XU8og4XNe8f_8w9Wv5vvgqMM1KhqVpG5VdMJv4o_L4NoCROHhtUQSLRh2M9cA"; - Algorithm algorithm = Algorithm.RSA256((RSAKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA")); - JWTVerifier verifier = JWTVerifier.init(algorithm).withIssuer("auth0").build(); - - concurrentVerify(verifier, token); - } - - @Test - public void shouldPassRSA384Verification() throws Exception { - String token = "eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.TZlWjXObwGSQOiu2oMq8kiKz0_BR7bbBddNL6G8eZ_GoR82BXOZDqNrQr7lb_M-78XGBguWLWNIdYhzgxOUL9EoCJlrqVm9s9vo6G8T1sj1op-4TbjXZ61TwIvrJee9BvPLdKUJ9_fp1Js5kl6yXkst40Th8Auc5as4n49MLkipjpEhKDKaENKHpSubs1ripSz8SCQZSofeTM_EWVwSw7cpiM8Fy8jOPvWG8Xz4-e3ODFowvHVsDcONX_4FTMNbeRqDuHq2ZhCJnEfzcSJdrve_5VD5fM1LperBVslTrOxIgClOJ3RmM7-WnaizJrWP3D6Z9OLxPxLhM6-jx6tcxEw"; - Algorithm algorithm = Algorithm.RSA384((RSAKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA")); - JWTVerifier verifier = JWTVerifier.init(algorithm).withIssuer("auth0").build(); - - concurrentVerify(verifier, token); - } - - @Test - public void shouldPassRSA512Verification() throws Exception { - String token = "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mvL5LoMyIrWYjk5umEXZTmbyIrkbbcVPUkvdGZbu0qFBxGOf0nXP5PZBvPcOu084lvpwVox5n3VaD4iqzW-PsJyvKFgi5TnwmsbKchAp7JexQEsQOnTSGcfRqeUUiBZqRQdYsho71oAB3T4FnalDdFEpM-fztcZY9XqKyayqZLreTeBjqJm4jfOWH7KfGBHgZExQhe96NLq1UA9eUyQwdOA1Z0SgXe4Ja5PxZ6Fm37KnVDtDlNnY4JAAGFo6y74aGNnp_BKgpaVJCGFu1f1S5xCQ1HSvs8ZSdVWs5NgawW3wRd0kRt_GJ_Y3mIwiF4qUyHWGtsSHu_qjVdCTtbFyow"; - Algorithm algorithm = Algorithm.RSA512((RSAKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA")); - JWTVerifier verifier = JWTVerifier.init(algorithm).withIssuer("auth0").build(); - - concurrentVerify(verifier, token); - } - - @Test - public void shouldPassECDSA256VerificationWithJOSESignature() throws Exception { - String token = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g"; - ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - Algorithm algorithm = Algorithm.ECDSA256(key); - JWTVerifier verifier = JWTVerifier.init(algorithm).withIssuer("auth0").build(); - - concurrentVerify(verifier, token); - } - - @Test - public void shouldPassECDSA384VerificationWithJOSESignature() throws Exception { - String token = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.50UU5VKNdF1wfykY8jQBKpvuHZoe6IZBJm5NvoB8bR-hnRg6ti-CHbmvoRtlLfnHfwITa_8cJMy6TenMC2g63GQHytc8rYoXqbwtS4R0Ko_AXbLFUmfxnGnMC6v4MS_z"; - ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); - Algorithm algorithm = Algorithm.ECDSA384(key); - JWTVerifier verifier = JWTVerifier.init(algorithm).withIssuer("auth0").build(); - - concurrentVerify(verifier, token); - } - - @Test - public void shouldPassECDSA512VerificationWithJOSESignature() throws Exception { - String token = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.AeCJPDIsSHhwRSGZCY6rspi8zekOw0K9qYMNridP1Fu9uhrA1QrG-EUxXlE06yvmh2R7Rz0aE7kxBwrnq8L8aOBCAYAsqhzPeUvyp8fXjjgs0Eto5I0mndE2QHlgcMSFASyjHbU8wD2Rq7ZNzGQ5b2MZfpv030WGUajT-aZYWFUJHVg2"; - ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); - Algorithm algorithm = Algorithm.ECDSA512(key); - JWTVerifier verifier = JWTVerifier.init(algorithm).withIssuer("auth0").build(); - - concurrentVerify(verifier, token); - } -} diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java deleted file mode 100644 index 53cd267b..00000000 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ /dev/null @@ -1,1060 +0,0 @@ -package com.auth0.jwt; - -import com.auth0.jwt.algorithms.Algorithm; -import com.auth0.jwt.interfaces.ECDSAKeyProvider; -import com.auth0.jwt.interfaces.RSAKeyProvider; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.nio.charset.StandardCharsets; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.RSAPrivateKey; -import java.time.Instant; -import java.util.*; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class JWTCreatorTest { - - private static final String PRIVATE_KEY_FILE_RSA = "src/test/resources/rsa-private.pem"; - private static final String PRIVATE_KEY_FILE_EC_256 = "src/test/resources/ec256-key-private.pem"; - - @Rule - public ExpectedException exception = ExpectedException.none(); - - @Test - public void shouldThrowWhenRequestingSignWithoutAlgorithm() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("The Algorithm cannot be null"); - JWTCreator.init() - .sign(null); - } - - @Test - public void shouldAddHeaderClaim() { - Date date = new Date(123000); - Instant instant = date.toInstant(); - - List list = Arrays.asList(date, instant); - Map map = new HashMap<>(); - map.put("date", date); - map.put("instant", instant); - - List expectedSerializedList = Arrays.asList(date.getTime() / 1000, instant.getEpochSecond()); - Map expectedSerializedMap = new HashMap<>(); - expectedSerializedMap.put("date", date.getTime() / 1000); - expectedSerializedMap.put("instant", instant.getEpochSecond()); - - Map header = new HashMap<>(); - header.put("string", "string"); - header.put("int", 42); - header.put("long", 4200000000L); - header.put("double", 123.123); - header.put("bool", true); - header.put("date", date); - header.put("instant", instant); - header.put("list", list); - header.put("map", map); - - String signed = JWTCreator.init() - .withHeader(header) - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("string", "string")); - assertThat(headerJson, JsonMatcher.hasEntry("int", 42)); - assertThat(headerJson, JsonMatcher.hasEntry("long", 4200000000L)); - assertThat(headerJson, JsonMatcher.hasEntry("double", 123.123)); - assertThat(headerJson, JsonMatcher.hasEntry("bool", true)); - assertThat(headerJson, JsonMatcher.hasEntry("date", 123)); - assertThat(headerJson, JsonMatcher.hasEntry("instant", 123)); - assertThat(headerJson, JsonMatcher.hasEntry("list", expectedSerializedList)); - assertThat(headerJson, JsonMatcher.hasEntry("map", expectedSerializedMap)); - } - - @Test - public void shouldReturnBuilderIfNullMapIsProvided() { - Map nullMap = null; - String nullString = null; - String signed = JWTCreator.init() - .withHeader(nullMap) - .withHeader(nullString) - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - } - - @Test - public void shouldSupportJsonValueHeaderWithNestedDataStructure() { - String stringClaim = "someClaim"; - Integer intClaim = 1; - List nestedListClaims = Arrays.asList("1", "2"); - String claimsJson = "{\"stringClaim\": \"someClaim\", \"intClaim\": 1, \"nestedClaim\": { \"listClaim\": [ \"1\", \"2\" ]}}"; - - String jwt = JWTCreator.init() - .withHeader(claimsJson) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - - assertThat(headerJson, JsonMatcher.hasEntry("stringClaim", stringClaim)); - assertThat(headerJson, JsonMatcher.hasEntry("intClaim", intClaim)); - assertThat(headerJson, JsonMatcher.hasEntry("listClaim", nestedListClaims)); - } - - @Test - public void shouldFailWithIllegalArgumentExceptionForInvalidJsonForHeaderClaims() { - String invalidJson = "{ invalidJson }"; - - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Invalid header JSON"); - - JWTCreator.init() - .withHeader(invalidJson) - .sign(Algorithm.HMAC256("secret")); - } - - @Test - public void shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() { - Map header = new HashMap<>(); - header.put(HeaderParams.KEY_ID, "xyz"); - - String signed = JWTCreator.init() - .withKeyId("abc") - .withHeader(header) - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry(HeaderParams.KEY_ID, "xyz")); - } - - - @Test - public void shouldOverwriteExistingHeadersWhenSettingSameHeaderKey() { - Map header = new HashMap<>(); - header.put(HeaderParams.KEY_ID, "xyz"); - - String signed = JWTCreator.init() - .withHeader(header) - .withKeyId("abc") - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry(HeaderParams.KEY_ID, "abc")); - } - - @Test - public void shouldRemoveHeaderIfTheValueIsNull() { - Map header = new HashMap<>(); - header.put(HeaderParams.KEY_ID, null); - header.put("test2", "isSet"); - - String signed = JWTCreator.init() - .withKeyId("test") - .withHeader(header) - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.isNotPresent(HeaderParams.KEY_ID)); - assertThat(headerJson, JsonMatcher.hasEntry("test2", "isSet")); - } - - @Test - public void shouldAddKeyId() { - String signed = JWTCreator.init() - .withKeyId("56a8bd44da435300010000015f5ed") - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("kid", "56a8bd44da435300010000015f5ed")); - } - - @Test - public void shouldAddKeyIdIfAvailableFromRSAAlgorithms() throws Exception { - RSAPrivateKey privateKey = (RSAPrivateKey) PemUtils.readPrivateKeyFromFile(PRIVATE_KEY_FILE_RSA, "RSA"); - RSAKeyProvider provider = mock(RSAKeyProvider.class); - when(provider.getPrivateKeyId()).thenReturn("my-key-id"); - when(provider.getPrivateKey()).thenReturn(privateKey); - - String signed = JWTCreator.init() - .sign(Algorithm.RSA256(provider)); - - assertThat(signed, is(notNullValue())); - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("kid", "my-key-id")); - } - - @Test - public void shouldNotOverwriteKeyIdIfAddedFromRSAAlgorithms() throws Exception { - RSAPrivateKey privateKey = (RSAPrivateKey) PemUtils.readPrivateKeyFromFile(PRIVATE_KEY_FILE_RSA, "RSA"); - RSAKeyProvider provider = mock(RSAKeyProvider.class); - when(provider.getPrivateKeyId()).thenReturn("my-key-id"); - when(provider.getPrivateKey()).thenReturn(privateKey); - - String signed = JWTCreator.init() - .withKeyId("real-key-id") - .sign(Algorithm.RSA256(provider)); - - assertThat(signed, is(notNullValue())); - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("kid", "my-key-id")); - } - - @Test - public void shouldAddKeyIdIfAvailableFromECDSAAlgorithms() throws Exception { - ECPrivateKey privateKey = (ECPrivateKey) PemUtils.readPrivateKeyFromFile(PRIVATE_KEY_FILE_EC_256, "EC"); - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPrivateKeyId()).thenReturn("my-key-id"); - when(provider.getPrivateKey()).thenReturn(privateKey); - - String signed = JWTCreator.init() - .sign(Algorithm.ECDSA256(provider)); - - assertThat(signed, is(notNullValue())); - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("kid", "my-key-id")); - } - - @Test - public void shouldNotOverwriteKeyIdIfAddedFromECDSAAlgorithms() throws Exception { - ECPrivateKey privateKey = (ECPrivateKey) PemUtils.readPrivateKeyFromFile(PRIVATE_KEY_FILE_EC_256, "EC"); - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPrivateKeyId()).thenReturn("my-key-id"); - when(provider.getPrivateKey()).thenReturn(privateKey); - - String signed = JWTCreator.init() - .withKeyId("real-key-id") - .sign(Algorithm.ECDSA256(provider)); - - assertThat(signed, is(notNullValue())); - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("kid", "my-key-id")); - } - - @Test - public void shouldAddIssuer() { - String signed = JWTCreator.init() - .withIssuer("auth0") - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - assertThat(TokenUtils.splitToken(signed)[1], is("eyJpc3MiOiJhdXRoMCJ9")); - } - - @Test - public void shouldAddSubject() { - String signed = JWTCreator.init() - .withSubject("1234567890") - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - assertThat(TokenUtils.splitToken(signed)[1], is("eyJzdWIiOiIxMjM0NTY3ODkwIn0")); - } - - @Test - public void shouldAddAudience() { - String signed = JWTCreator.init() - .withAudience("Mark") - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - assertThat(TokenUtils.splitToken(signed)[1], is("eyJhdWQiOiJNYXJrIn0")); - - - String signedArr = JWTCreator.init() - .withAudience("Mark", "David") - .sign(Algorithm.HMAC256("secret")); - - assertThat(signedArr, is(notNullValue())); - assertThat(TokenUtils.splitToken(signedArr)[1], is("eyJhdWQiOlsiTWFyayIsIkRhdmlkIl19")); - } - - @Test - public void shouldAddExpiresAt() { - String signed = JWTCreator.init() - .withExpiresAt(new Date(1477592000)) - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - assertThat(TokenUtils.splitToken(signed)[1], is("eyJleHAiOjE0Nzc1OTJ9")); - } - - @Test - public void shouldAddExpiresAtInstant() { - String signed = JWTCreator.init() - .withExpiresAt(Instant.ofEpochSecond(1477592)) - .sign(Algorithm.HMAC256("secret")); - - System.out.println(signed); - assertThat(signed, is(notNullValue())); - assertThat(TokenUtils.splitToken(signed)[1], is("eyJleHAiOjE0Nzc1OTJ9")); - } - - @Test - public void shouldAddNotBefore() { - String signed = JWTCreator.init() - .withNotBefore(new Date(1477592000)) - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - assertThat(TokenUtils.splitToken(signed)[1], is("eyJuYmYiOjE0Nzc1OTJ9")); - } - - @Test - public void shouldAddNotBeforeInstant() { - String signed = JWTCreator.init() - .withNotBefore(Instant.ofEpochSecond(1477592)) - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - assertThat(TokenUtils.splitToken(signed)[1], is("eyJuYmYiOjE0Nzc1OTJ9")); - } - - @Test - public void shouldAddIssuedAt() { - String signed = JWTCreator.init() - .withIssuedAt(new Date(1477592000)) - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - assertThat(TokenUtils.splitToken(signed)[1], is("eyJpYXQiOjE0Nzc1OTJ9")); - } - - @Test - public void shouldAddIssuedAtInstant() { - String signed = JWTCreator.init() - .withIssuedAt(Instant.ofEpochSecond(1477592)) - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - assertThat(TokenUtils.splitToken(signed)[1], is("eyJpYXQiOjE0Nzc1OTJ9")); - } - - @Test - public void shouldAddJWTId() { - String signed = JWTCreator.init() - .withJWTId("jwt_id_123") - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - assertThat(TokenUtils.splitToken(signed)[1], is("eyJqdGkiOiJqd3RfaWRfMTIzIn0")); - } - - @Test - public void shouldSetCorrectAlgorithmInTheHeader() { - String signed = JWTCreator.init() - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("alg", "HS256")); - } - - @Test - public void shouldSetDefaultTypeInTheHeader() { - String signed = JWTCreator.init() - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); - } - - @Test - public void shouldSetCustomTypeInTheHeader() { - Map header = Collections.singletonMap("typ", "passport"); - String signed = JWTCreator.init() - .withHeader(header) - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("typ", "passport")); - } - - @Test - public void shouldSetEmptySignatureIfAlgorithmIsNone() { - String signed = JWTCreator.init() - .sign(Algorithm.none()); - assertThat(signed, is(notNullValue())); - assertThat(TokenUtils.splitToken(signed)[2], is("")); - } - - @Test - public void shouldThrowOnNullCustomClaimName() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("The Custom Claim's name can't be null."); - JWTCreator.init() - .withClaim(null, "value"); - } - - @Test - public void shouldAcceptCustomClaimOfTypeString() { - String jwt = JWTCreator.init() - .withClaim("name", "value") - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - assertThat(parts[1], is("eyJuYW1lIjoidmFsdWUifQ")); - } - - @Test - public void shouldAcceptCustomClaimOfTypeInteger() { - String jwt = JWTCreator.init() - .withClaim("name", 123) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - assertThat(parts[1], is("eyJuYW1lIjoxMjN9")); - } - - @Test - public void shouldAcceptCustomClaimOfTypeLong() { - String jwt = JWTCreator.init() - .withClaim("name", Long.MAX_VALUE) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - assertThat(parts[1], is("eyJuYW1lIjo5MjIzMzcyMDM2ODU0Nzc1ODA3fQ")); - } - - @Test - public void shouldAcceptCustomClaimOfTypeDouble() { - String jwt = JWTCreator.init() - .withClaim("name", 23.45) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - assertThat(parts[1], is("eyJuYW1lIjoyMy40NX0")); - } - - @Test - public void shouldAcceptCustomClaimOfTypeBoolean() { - String jwt = JWTCreator.init() - .withClaim("name", true) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - assertThat(parts[1], is("eyJuYW1lIjp0cnVlfQ")); - } - - @Test - public void shouldAcceptCustomClaimOfTypeDate() { - Date date = new Date(1478891521000L); - String jwt = JWTCreator.init() - .withClaim("name", date) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - assertThat(parts[1], is("eyJuYW1lIjoxNDc4ODkxNTIxfQ")); - } - - @Test - public void shouldAcceptCustomClaimOfTypeDateInstant() { - Instant instant = Instant.ofEpochSecond(1478891521); - String jwt = JWTCreator.init() - .withClaim("name", instant) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - assertThat(parts[1], is("eyJuYW1lIjoxNDc4ODkxNTIxfQ")); - } - - @Test - public void shouldAcceptCustomArrayClaimOfTypeString() { - String jwt = JWTCreator.init() - .withArrayClaim("name", new String[]{"text", "123", "true"}) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - assertThat(parts[1], is("eyJuYW1lIjpbInRleHQiLCIxMjMiLCJ0cnVlIl19")); - } - - @Test - public void shouldAcceptCustomArrayClaimOfTypeInteger() { - String jwt = JWTCreator.init() - .withArrayClaim("name", new Integer[]{1, 2, 3}) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - assertThat(parts[1], is("eyJuYW1lIjpbMSwyLDNdfQ")); - } - - @Test - public void shouldAcceptCustomArrayClaimOfTypeLong() { - String jwt = JWTCreator.init() - .withArrayClaim("name", new Long[]{1L, 2L, 3L}) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - assertThat(parts[1], is("eyJuYW1lIjpbMSwyLDNdfQ")); - } - - @Test - public void shouldAcceptCustomClaimOfTypeMap() { - Map data = new HashMap<>(); - data.put("test1", "abc"); - data.put("test2", "def"); - String jwt = JWTCreator.init() - .withClaim("data", data) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - assertThat(parts[1], is("eyJkYXRhIjp7InRlc3QyIjoiZGVmIiwidGVzdDEiOiJhYmMifX0")); - } - - @Test - public void shouldRefuseCustomClaimOfTypeUserPojo() { - Map data = new HashMap<>(); - data.put("test1", new UserPojo("Michael", 255)); - - exception.expect(IllegalArgumentException.class); - - JWTCreator.init() - .withClaim("pojo", data) - .sign(Algorithm.HMAC256("secret")); - } - - @SuppressWarnings("unchecked") - @Test - public void shouldAcceptCustomMapClaimOfBasicObjectTypes() throws Exception { - Map data = new HashMap<>(); - - // simple types - data.put("string", "abc"); - data.put("integer", 1); - data.put("long", Long.MAX_VALUE); - data.put("double", 123.456d); - data.put("date", new Date(123000L)); - data.put("instant", Instant.ofEpochSecond(123)); - data.put("boolean", true); - - // array types - data.put("intArray", new Integer[]{3, 5}); - data.put("longArray", new Long[]{Long.MAX_VALUE, Long.MIN_VALUE}); - data.put("stringArray", new String[]{"string"}); - - data.put("list", Arrays.asList("a", "b", "c")); - - Map sub = new HashMap<>(); - sub.put("subKey", "subValue"); - - data.put("map", sub); - - String jwt = JWTCreator.init() - .withClaim("data", data) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - - String body = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); - ObjectMapper mapper = new ObjectMapper(); - Map map = (Map) mapper.readValue(body, Map.class).get("data"); - - assertThat(map.get("string"), is("abc")); - assertThat(map.get("integer"), is(1)); - assertThat(map.get("long"), is(Long.MAX_VALUE)); - assertThat(map.get("double"), is(123.456d)); - - assertThat(map.get("date"), is(123)); - assertThat(map.get("instant"), is(123)); - assertThat(map.get("boolean"), is(true)); - - // array types - assertThat(map.get("intArray"), is(Arrays.asList(3, 5))); - assertThat(map.get("longArray"), is(Arrays.asList(Long.MAX_VALUE, Long.MIN_VALUE))); - assertThat(map.get("stringArray"), is(Collections.singletonList("string"))); - - // list - assertThat(map.get("list"), is(Arrays.asList("a", "b", "c"))); - assertThat(map.get("map"), is(sub)); - - } - - @SuppressWarnings("unchecked") - @Test - public void shouldAcceptCustomListClaimOfBasicObjectTypes() throws Exception { - List data = new ArrayList<>(); - - // simple types - data.add("abc"); - data.add(1); - data.add(Long.MAX_VALUE); - data.add(123.456d); - data.add(new Date(123000L)); - data.add(Instant.ofEpochSecond(123)); - data.add(true); - - // array types - data.add(new Integer[]{3, 5}); - data.add(new Long[]{Long.MAX_VALUE, Long.MIN_VALUE}); - data.add(new String[]{"string"}); - - data.add(Arrays.asList("a", "b", "c")); - - Map sub = new HashMap<>(); - sub.put("subKey", "subValue"); - - data.add(sub); - - String jwt = JWTCreator.init() - .withClaim("data", data) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - - String body = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); - ObjectMapper mapper = new ObjectMapper(); - List list = (List) mapper.readValue(body, Map.class).get("data"); - - assertThat(list.get(0), is("abc")); - assertThat(list.get(1), is(1)); - assertThat(list.get(2), is(Long.MAX_VALUE)); - assertThat(list.get(3), is(123.456d)); - assertThat(list.get(4), is(123)); - assertThat(list.get(5), is(123)); - assertThat(list.get(6), is(true)); - - // array types - assertThat(list.get(7), is(Arrays.asList(3, 5))); - assertThat(list.get(8), is(Arrays.asList(Long.MAX_VALUE, Long.MIN_VALUE))); - assertThat(list.get(9), is(Arrays.asList("string"))); - - // list - assertThat(list.get(10), is(Arrays.asList("a", "b", "c"))); - assertThat(list.get(11), is(sub)); - } - - @Test - public void shouldAcceptCustomClaimForNullListItem() { - Map data = new HashMap<>(); - data.put("test1", Arrays.asList("a", null, "c")); - - JWTCreator.init() - .withClaim("pojo", data) - .sign(Algorithm.HMAC256("secret")); - } - - @Test - public void shouldRefuseCustomClaimForNullMapKey() { - Map data = new HashMap<>(); - data.put(null, "subValue"); - - exception.expect(IllegalArgumentException.class); - - JWTCreator.init() - .withClaim("pojo", data) - .sign(Algorithm.HMAC256("secret")); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - @Test - public void shouldRefuseCustomMapClaimForNonStringKey() { - Map data = new HashMap<>(); - data.put(new Object(), "value"); - - exception.expect(IllegalArgumentException.class); - - JWTCreator.init() - .withClaim("pojo", (Map) data) - .sign(Algorithm.HMAC256("secret")); - } - - @Test - public void shouldRefuseCustomListClaimForUnknownListElement() { - List list = Collections.singletonList(new UserPojo("Michael", 255)); - - exception.expect(IllegalArgumentException.class); - - JWTCreator.init() - .withClaim("list", list) - .sign(Algorithm.HMAC256("secret")); - } - - @Test - public void shouldRefuseCustomListClaimForUnknownListElementWrappedInAMap() { - List list = Collections.singletonList(new UserPojo("Michael", 255)); - - Map data = new HashMap<>(); - data.put("someList", list); - - exception.expect(IllegalArgumentException.class); - - JWTCreator.init() - .withClaim("list", list) - .sign(Algorithm.HMAC256("secret")); - } - - @Test - public void shouldRefuseCustomListClaimForUnknownArrayType() { - List list = new ArrayList<>(); - list.add(new Object[]{"test"}); - - exception.expect(IllegalArgumentException.class); - - JWTCreator.init() - .withClaim("list", list) - .sign(Algorithm.HMAC256("secret")); - } - - @Test - public void withPayloadShouldAddBasicClaim() { - Map payload = new HashMap<>(); - payload.put("asd", 123); - String jwt = JWTCreator.init() - .withPayload(payload) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); - assertThat(payloadJson, JsonMatcher.hasEntry("asd", 123)); - } - - @Test - public void withPayloadShouldCreateJwtWithEmptyBodyIfPayloadNull() { - Map nullMap = null; - String nullString = null; - String jwt = JWTCreator.init() - .withPayload(nullMap) - .withPayload(nullString) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); - assertThat(payloadJson, is("{}")); - } - - @Test - public void withPayloadShouldOverwriteExistingClaimIfPayloadMapContainsTheSameKey() { - Map payload = new HashMap<>(); - payload.put(HeaderParams.KEY_ID, "xyz"); - - String jwt = JWTCreator.init() - .withKeyId("abc") - .withPayload(payload) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); - assertThat(payloadJson, JsonMatcher.hasEntry(HeaderParams.KEY_ID, "xyz")); - } - - @Test - public void shouldOverwriteExistingPayloadWhenSettingSamePayloadKey() { - Map payload = new HashMap<>(); - payload.put(RegisteredClaims.ISSUER, "xyz"); - - String jwt = JWTCreator.init() - .withPayload(payload) - .withIssuer("abc") - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); - assertThat(payloadJson, JsonMatcher.hasEntry(RegisteredClaims.ISSUER, "abc")); - } - - @Test - public void withPayloadShouldNotAllowCustomType() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String, Date, Instant, and Null"); - - Map payload = new HashMap<>(); - payload.put("entry", "value"); - payload.put("pojo", new UserPojo("name", 42)); - JWTCreator.init() - .withPayload(payload) - .sign(Algorithm.HMAC256("secret")); - } - - @Test - public void withPayloadShouldAllowNullListItems() { - Map payload = new HashMap<>(); - payload.put("list", Arrays.asList("item1", null, "item2")); - String jwt = JWTCreator.init() - .withPayload(payload) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); - assertThat(payloadJson, JsonMatcher.hasEntry("list", Arrays.asList("item1", null, "item2"))); - } - - @Test - public void withPayloadShouldNotAllowListWithCustomType() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String, Date, Instant, and Null"); - - Map payload = new HashMap<>(); - payload.put("list", Arrays.asList("item1", new UserPojo("name", 42))); - JWTCreator.init() - .withPayload(payload) - .sign(Algorithm.HMAC256("secret")); - } - - @Test - public void withPayloadShouldNotAllowMapWithCustomType() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String, Date, Instant, and Null"); - - Map payload = new HashMap<>(); - payload.put("entry", "value"); - payload.put("map", Collections.singletonMap("pojo", new UserPojo("name", 42))); - JWTCreator.init() - .withPayload(payload) - .sign(Algorithm.HMAC256("secret")); - } - - @Test - public void withPayloadShouldAllowNestedSupportedTypes() { - /* - JWT: - { - "stringClaim": "string", - "intClaim": 41, - "listClaim": [ - 1, 2, { - "nestedObjKey": true - } - ], - "objClaim": { - "objKey": ["nestedList1", "nestedList2"] - } - } - */ - - List listClaim = Arrays.asList(1, 2, Collections.singletonMap("nestedObjKey", "nestedObjValue")); - Map mapClaim = new HashMap<>(); - mapClaim.put("objKey", Arrays.asList("nestedList1", true)); - - Map payload = new HashMap<>(); - payload.put("stringClaim", "string"); - payload.put("intClaim", 41); - payload.put("listClaim", listClaim); - payload.put("objClaim", mapClaim); - - String jwt = JWTCreator.init() - .withPayload(payload) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); - assertThat(payloadJson, JsonMatcher.hasEntry("stringClaim", "string")); - assertThat(payloadJson, JsonMatcher.hasEntry("intClaim", 41)); - assertThat(payloadJson, JsonMatcher.hasEntry("listClaim", listClaim)); - assertThat(payloadJson, JsonMatcher.hasEntry("objClaim", mapClaim)); - } - - @Test - public void withPayloadShouldSupportNullValuesEverywhere() { - /* - JWT: - { - "listClaim": [ - "answer to ultimate question of life", - 42, - null - ], - "claim": null, - "listNestedClaim": [ - 1, - 2, - { - "nestedObjKey": null - } - ], - "objClaim": { - "nestedObjKey": null, - "objObjKey": { - "nestedObjKey": null, - "objListKey": [ - null, - "nestedList2" - ] - }, - "objListKey": [ - null, - "nestedList2" - ] - } - } - */ - - List listClaim = Arrays.asList("answer to ultimate question of life", 42, null); - List listNestedClaim = Arrays.asList(1, 2, Collections.singletonMap("nestedObjKey", null)); - List objListKey = Arrays.asList(null, "nestedList2"); - HashMap objClaim = new HashMap<>(); - objClaim.put("nestedObjKey", null); - objClaim.put("objListKey", objListKey); - objClaim.put("objObjKey", new HashMap<>(objClaim)); - - - Map payload = new HashMap<>(); - payload.put("claim", null); - payload.put("listClaim", listClaim); - payload.put("listNestedClaim", listNestedClaim); - payload.put("objClaim", objClaim); - - String jwt = JWTCreator.init() - .withPayload(payload) - .withHeader(payload) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - - assertThat(payloadJson, JsonMatcher.hasEntry("claim", null)); - assertThat(payloadJson, JsonMatcher.hasEntry("listClaim", listClaim)); - assertThat(payloadJson, JsonMatcher.hasEntry("listNestedClaim", listNestedClaim)); - assertThat(payloadJson, JsonMatcher.hasEntry("objClaim", objClaim)); - - assertThat(headerJson, JsonMatcher.hasEntry("claim", null)); - assertThat(headerJson, JsonMatcher.hasEntry("listClaim", listClaim)); - assertThat(headerJson, JsonMatcher.hasEntry("listNestedClaim", listNestedClaim)); - assertThat(headerJson, JsonMatcher.hasEntry("objClaim", objClaim)); - } - - @Test - public void withPayloadShouldSupportJsonValueWithNestedDataStructure() { - String stringClaim = "someClaim"; - Integer intClaim = 1; - List nestedListClaims = Arrays.asList("1", "2"); - String claimsJson = "{\"stringClaim\": \"someClaim\", \"intClaim\": 1, \"nestedClaim\": { \"listClaim\": [ \"1\", \"2\" ]}}"; - - String jwt = JWTCreator.init() - .withPayload(claimsJson) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); - - assertThat(payloadJson, JsonMatcher.hasEntry("stringClaim", stringClaim)); - assertThat(payloadJson, JsonMatcher.hasEntry("intClaim", intClaim)); - assertThat(payloadJson, JsonMatcher.hasEntry("listClaim", nestedListClaims)); - } - - @Test - public void shouldFailWithIllegalArgumentExceptionForInvalidJsonForPayloadClaims() { - String invalidJson = "{ invalidJson }"; - - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Invalid payload JSON"); - - JWTCreator.init() - .withPayload(invalidJson) - .sign(Algorithm.HMAC256("secret")); - } - - @Test - public void shouldCreatePayloadWithNullForMap() { - String jwt = JWTCreator.init() - .withClaim("name", (Map) null) - .sign(Algorithm.HMAC256("secret")); - assertThat(jwt, is(notNullValue())); - assertTrue(JWT.decode(jwt).getClaim("name").isNull()); - } - - @Test - public void shouldCreatePayloadWithNullForList() { - String jwt = JWTCreator.init() - .withClaim("name", (List) null) - .sign(Algorithm.HMAC256("secret")); - assertThat(jwt, is(notNullValue())); - assertTrue(JWT.decode(jwt).getClaim("name").isNull()); - } - - @Test - public void shouldPreserveInsertionOrder() throws Exception { - String taxonomyJson = "{\"class\": \"mammalia\", \"order\": \"carnivora\", \"family\": \"canidae\", \"genus\": \"vulpes\"}"; - List taxonomyClaims = Arrays.asList("class", "order", "family", "genus"); - List headerInsertionOrder = new ArrayList<>(taxonomyClaims); - Map header = new LinkedHashMap<>(); - for (int i = 0; i < 10; i++) { - String key = "h" + i; - header.put(key, "v" + 1); - headerInsertionOrder.add(key); - } - - List payloadInsertionOrder = new ArrayList<>(taxonomyClaims); - JWTCreator.Builder builder = JWTCreator.init() - .withHeader(taxonomyJson) - .withHeader(header) - .withPayload(taxonomyJson); - for (int i = 0; i < 10; i++) { - String name = "c" + i; - builder = builder.withClaim(name, "v" + i); - payloadInsertionOrder.add(name); - } - String signed = builder.sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - String[] parts = signed.split("\\."); - Base64.Decoder urlDecoder = Base64.getUrlDecoder(); - String headerJson = new String(urlDecoder.decode(parts[0]), StandardCharsets.UTF_8); - String payloadJson = new String(urlDecoder.decode(parts[1]), StandardCharsets.UTF_8); - - ObjectMapper objectMapper = new ObjectMapper(); - - List headerFields = new ArrayList<>(); - objectMapper.readValue(headerJson, ObjectNode.class) - .fieldNames().forEachRemaining(headerFields::add); - headerFields.retainAll(headerInsertionOrder); - assertThat("Header insertion order should be preserved", - headerFields, is(equalTo(headerInsertionOrder))); - - List payloadFields = new ArrayList<>(); - objectMapper.readValue(payloadJson, ObjectNode.class) - .fieldNames().forEachRemaining(payloadFields::add); - payloadFields.retainAll(payloadInsertionOrder); - assertThat("Claim insertion order should be preserved", - payloadFields, is(equalTo(payloadInsertionOrder))); - } -} diff --git a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java deleted file mode 100644 index cc427d60..00000000 --- a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java +++ /dev/null @@ -1,416 +0,0 @@ -package com.auth0.jwt; - -import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.interfaces.Claim; -import com.auth0.jwt.interfaces.DecodedJWT; -import org.hamcrest.collection.IsCollectionWithSize; -import org.hamcrest.core.IsIterableContaining; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.time.Instant; -import java.util.Base64; -import java.util.Date; -import java.util.List; -import java.util.Map; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; - -public class JWTDecoderTest { - @Rule - public ExpectedException exception = ExpectedException.none(); - - @Test - public void getSubject() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"); - assertThat(jwt.getSubject(), is(notNullValue())); - assertThat(jwt.getSubject(), is("1234567890")); - } - - // Exceptions - @Test - public void shouldThrowIfTheContentIsNotProperlyEncoded() { - exception.expect(JWTDecodeException.class); - exception.expectMessage(startsWith("The string '")); - exception.expectMessage(endsWith("' doesn't have a valid JSON format.")); - JWT.decode("eyJ0eXAiOiJKV1QiLCJhbGciO-corrupted.eyJ0ZXN0IjoxMjN9.sLtFC2rLAzN0-UJ13OLQX6ezNptAQzespaOGwCnpqk"); - } - - @Test - public void shouldThrowIfLessThan3Parts() { - exception.expect(JWTDecodeException.class); - exception.expectMessage("The token was expected to have 3 parts, but got 2."); - JWT.decode("two.parts"); - } - - @Test - public void shouldThrowIfMoreThan3Parts() { - exception.expect(JWTDecodeException.class); - exception.expectMessage("The token was expected to have 3 parts, but got > 3."); - JWT.decode("this.has.four.parts"); - } - - @Test - public void shouldThrowIfPayloadHasInvalidJSONFormat() { - String validJson = "{}"; - String invalidJson = "}{"; - exception.expect(JWTDecodeException.class); - exception.expectMessage(String.format("The string '%s' doesn't have a valid JSON format.", invalidJson)); - customJWT(validJson, invalidJson, "signature"); - } - - @Test - public void shouldThrowIfHeaderHasInvalidJSONFormat() { - String validJson = "{}"; - String invalidJson = "}{"; - exception.expect(JWTDecodeException.class); - exception.expectMessage(String.format("The string '%s' doesn't have a valid JSON format.", invalidJson)); - customJWT(invalidJson, validJson, "signature"); - } - - @Test - public void shouldThrowWhenHeaderNotValidBase64() { - exception.expect(JWTDecodeException.class); - exception.expectCause(isA(IllegalArgumentException.class)); - - String jwt = "eyJhbGciOiJub25l+IiwiY3R5IjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9.Ox-WRXRaGAuWt2KfPvWiGcCrPqZtbp_4OnQzZXaTfss"; - JWT.decode(jwt); - } - - @Test - public void shouldThrowWhenPayloadNotValidBase64() { - exception.expect(JWTDecodeException.class); - exception.expectCause(isA(IllegalArgumentException.class)); - - String jwt = "eyJhbGciOiJub25lIiwiY3R5IjoiSldUIn0.eyJpc3MiOiJhdXRo+MCJ9.Ox-WRXRaGAuWt2KfPvWiGcCrPqZtbp_4OnQzZXaTfss"; - JWT.decode(jwt); - } - - // Parts - - @Test - public void shouldGetStringToken() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getToken(), is(notNullValue())); - assertThat(jwt.getToken(), is("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ")); - } - - @Test - public void shouldGetHeader() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getHeader(), is("eyJhbGciOiJIUzI1NiJ9")); - } - - @Test - public void shouldGetPayload() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getPayload(), is("e30")); - } - - @Test - public void shouldGetSignature() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getSignature(), is("XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ")); - } - - // Standard Claims - - @Test - public void shouldGetIssuer() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJKb2huIERvZSJ9.SgXosfRR_IwCgHq5lF3tlM-JHtpucWCRSaVuoHTbWbQ"); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getIssuer(), is("John Doe")); - } - - @Test - public void shouldGetSubject() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJUb2szbnMifQ.RudAxkslimoOY3BLl2Ghny3BrUKu9I1ZrXzCZGDJtNs"); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getSubject(), is("Tok3ns")); - } - - @Test - public void shouldGetArrayAudience() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsiSG9wZSIsIlRyYXZpcyIsIlNvbG9tb24iXX0.Tm4W8WnfPjlmHSmKFakdij0on2rWPETpoM7Sh0u6-S4"); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getAudience(), is(IsCollectionWithSize.hasSize(3))); - assertThat(jwt.getAudience(), is(IsIterableContaining.hasItems("Hope", "Travis", "Solomon"))); - } - - @Test - public void shouldGetStringAudience() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJKYWNrIFJleWVzIn0.a4I9BBhPt1OB1GW67g2P1bEHgi6zgOjGUL4LvhE9Dgc"); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getAudience(), is(IsCollectionWithSize.hasSize(1))); - assertThat(jwt.getAudience(), is(IsIterableContaining.hasItems("Jack Reyes"))); - } - - @Test - public void shouldGetExpirationTime() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0NzY3MjcwODZ9.L9dcPHEDQew2u9MkDCORFkfDGcSOsgoPqNY-LUMLEHg"); - assertThat(jwt, is(notNullValue())); - long ms = 1476727086L * 1000; - assertThat(jwt.getExpiresAt(), is(equalTo(new Date(ms)))); - assertThat(jwt.getExpiresAtAsInstant(), is(equalTo(Instant.ofEpochMilli(ms)))); - } - - @Test - public void shouldGetNotBefore() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE0NzY3MjcwODZ9.tkpD3iCPQPVqjnjpDVp2bJMBAgpVCG9ZjlBuMitass0"); - assertThat(jwt, is(notNullValue())); - long ms = 1476727086L * 1000; - assertThat(jwt.getNotBefore(), is(equalTo(new Date(ms)))); - assertThat(jwt.getNotBeforeAsInstant(), is(equalTo(Instant.ofEpochMilli(ms)))); - } - - @Test - public void shouldGetIssuedAt() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0NzY3MjcwODZ9.KPjGoW665E8V5_27Jugab8qSTxLk2cgquhPCBfAP0_w"); - assertThat(jwt, is(notNullValue())); - long ms = 1476727086L * 1000; - assertThat(jwt.getIssuedAt(), is(equalTo(new Date(ms)))); - assertThat(jwt.getIssuedAtAsInstant(), is(equalTo(Instant.ofEpochMilli(ms)))); - } - - @Test - public void shouldGetId() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMjM0NTY3ODkwIn0.m3zgEfVUFOd-CvL3xG5BuOWLzb0zMQZCqiVNQQOPOvA"); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getId(), is("1234567890")); - } - - @Test - public void shouldGetContentType() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiIsImN0eSI6ImF3ZXNvbWUifQ.e30.AIm-pJDOaAyct9qKMlN-lQieqNDqc3d4erqUZc5SHAs"); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getContentType(), is("awesome")); - } - - @Test - public void shouldGetType() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.e30.WdFmrzx8b9v_a-r6EHC2PTAaWywgm_8LiP8RBRhYwkI"); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getType(), is("JWS")); - } - - @Test - public void shouldGetAlgorithm() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getAlgorithm(), is("HS256")); - } - - // Private Claims - - @Test - public void shouldGetMissingClaimIfClaimDoesNotExist() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.K17vlwhE8FCMShdl1_65jEYqsQqBOVMPUU9IgG-QlTM"); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getClaim("notExisting"), is(notNullValue())); - assertThat(jwt.getClaim("notExisting").isMissing(), is(true)); - assertThat(jwt.getClaim("notExisting").isNull(), is(false)); - } - - @Test - public void shouldGetValidClaim() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJvYmplY3QiOnsibmFtZSI6ImpvaG4ifX0.lrU1gZlOdlmTTeZwq0VI-pZx2iV46UWYd5-lCjy6-c4"); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getClaim("object"), is(notNullValue())); - assertThat(jwt.getClaim("object"), is(instanceOf(Claim.class))); - } - - @Test - public void shouldNotGetNullClaimIfClaimIsEmptyObject() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJvYmplY3QiOnt9fQ.d3nUeeL_69QsrHL0ZWij612LHEQxD8EZg1rNoY3a4aI"); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getClaim("object"), is(notNullValue())); - assertThat(jwt.getClaim("object").isNull(), is(false)); - } - - @Test - public void shouldGetCustomClaimOfTypeInteger() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxMjN9.XZAudnA7h3_Al5kJydzLjw6RzZC3Q6OvnLEYlhNW7HA"; - DecodedJWT jwt = JWT.decode(token); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getClaim("name").asInt(), is(123)); - } - - @Test - public void shouldGetCustomClaimOfTypeDouble() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoyMy40NX0.7pyX2OmEGaU9q15T8bGFqRm-d3RVTYnqmZNZtxMKSlA"; - DecodedJWT jwt = JWT.decode(token); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getClaim("name").asDouble(), is(23.45)); - } - - @Test - public void shouldGetCustomClaimOfTypeBoolean() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjp0cnVlfQ.FwQ8VfsZNRqBa9PXMinSIQplfLU4-rkCLfIlTLg_MV0"; - DecodedJWT jwt = JWT.decode(token); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getClaim("name").asBoolean(), is(true)); - } - - @Test - public void shouldGetCustomClaimOfTypeDate() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxNDc4ODkxNTIxfQ.mhioumeok8fghQEhTKF3QtQAksSvZ_9wIhJmgZLhJ6c"; - Date date = new Date(1478891521000L); - DecodedJWT jwt = JWT.decode(token); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getClaim("name").asDate().getTime(), is(date.getTime())); - } - - @Test - public void shouldGetCustomClaimOfTypeInstant() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxNDc4ODkxNTIxfQ.mhioumeok8fghQEhTKF3QtQAksSvZ_9wIhJmgZLhJ6c"; - Instant instant = Instant.ofEpochSecond(1478891521L); - DecodedJWT jwt = JWT.decode(token); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getClaim("name").asInstant(), is(equalTo(instant))); - } - - @Test - public void shouldGetCustomArrayClaimOfTypeString() { - String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbInRleHQiLCIxMjMiLCJ0cnVlIl19.lxM8EcmK1uSZRAPd0HUhXGZJdauRmZmLjoeqz4J9yAA"; - DecodedJWT jwt = JWT.decode(token); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getClaim("name").asArray(String.class), arrayContaining("text", "123", "true")); - } - - @Test - public void shouldGetCustomArrayClaimOfTypeInteger() { - String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbMSwyLDNdfQ.UEuMKRQYrzKAiPpPLhIVawWkKWA1zj0_GderrWUIyFE"; - DecodedJWT jwt = JWT.decode(token); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getClaim("name").asArray(Integer.class), arrayContaining(1, 2, 3)); - } - - @Test - public void shouldGetCustomMapClaim() { - String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjp7InN0cmluZyI6InZhbHVlIiwibnVtYmVyIjoxLCJib29sZWFuIjp0cnVlLCJlbXB0eSI6bnVsbH19.6xkCuYZnu4RA0xZSxlYSYAqzy9JDWsDtIWqSCUZlPt8"; - DecodedJWT jwt = JWT.decode(token); - assertThat(jwt, is(notNullValue())); - Map map = jwt.getClaim("name").asMap(); - assertThat(map, hasEntry("string", "value")); - assertThat(map, hasEntry("number", 1)); - assertThat(map, hasEntry("boolean", true)); - assertThat(map, hasEntry("empty", null)); - } - - @Test - public void shouldGetCustomNullClaim() { - String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpudWxsfQ.X4ALHe7uYqEcXWFBnwBUNRKwmwrtDEGZ2aynRYYUx8c"; - DecodedJWT jwt = JWT.decode(token); - assertThat(jwt.getClaim("name").isNull(), is(true)); - } - - @Test - public void shouldGetListClaim() { - String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbbnVsbCwiaGVsbG8iXX0.SpcuQRBGdTV0ofHdxBSnhWEUsQi89noZUXin2Thwb70"; - DecodedJWT jwt = JWT.decode(token); - assertThat(jwt.getClaim("name").asList(String.class), contains(null, "hello")); - } - - @Test - public void shouldGetAvailableClaims() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEyMzQ1Njc4OTAsImlhdCI6MTIzNDU2Nzg5MCwibmJmIjoxMjM0NTY3ODkwLCJqdGkiOiJodHRwczovL2p3dC5pby8iLCJhdWQiOiJodHRwczovL2RvbWFpbi5hdXRoMC5jb20iLCJzdWIiOiJsb2dpbiIsImlzcyI6ImF1dGgwIiwiZXh0cmFDbGFpbSI6IkpvaG4gRG9lIn0.2_0nxDPJwOk64U5V5V9pt8U92jTPJbGsHYQ35HYhbdE"); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getClaims(), is(notNullValue())); - assertThat(jwt.getClaims(), is(instanceOf(Map.class))); - assertThat(jwt.getClaims().get("exp"), is(notNullValue())); - assertThat(jwt.getClaims().get("iat"), is(notNullValue())); - assertThat(jwt.getClaims().get("nbf"), is(notNullValue())); - assertThat(jwt.getClaims().get("jti"), is(notNullValue())); - assertThat(jwt.getClaims().get("aud"), is(notNullValue())); - assertThat(jwt.getClaims().get("sub"), is(notNullValue())); - assertThat(jwt.getClaims().get("iss"), is(notNullValue())); - assertThat(jwt.getClaims().get("extraClaim"), is(notNullValue())); - } - - @Test - public void shouldSerializeAndDeserialize() throws Exception { - DecodedJWT originalJwt = JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEyMzQ1Njc4OTAsImlhdCI6MTIzNDU2Nzg5MCwibmJmIjoxMjM0NTY3ODkwLCJqdGkiOiJodHRwczovL2p3dC5pby8iLCJhdWQiOiJodHRwczovL2RvbWFpbi5hdXRoMC5jb20iLCJzdWIiOiJsb2dpbiIsImlzcyI6ImF1dGgwIiwiZXh0cmFDbGFpbSI6IkpvaG4gRG9lIn0.2_0nxDPJwOk64U5V5V9pt8U92jTPJbGsHYQ35HYhbdE"); - - assertThat(originalJwt, is(instanceOf(Serializable.class))); - - byte[] serialized = serialize(originalJwt); - DecodedJWT deserializedJwt = (DecodedJWT) deserialize(serialized); - - assertThat(originalJwt.getHeader(), is(equalTo(deserializedJwt.getHeader()))); - assertThat(originalJwt.getPayload(), is(equalTo(deserializedJwt.getPayload()))); - assertThat(originalJwt.getSignature(), is(equalTo(deserializedJwt.getSignature()))); - assertThat(originalJwt.getToken(), is(equalTo(deserializedJwt.getToken()))); - assertThat(originalJwt.getAlgorithm(), is(equalTo(deserializedJwt.getAlgorithm()))); - assertThat(originalJwt.getAudience(), is(equalTo(deserializedJwt.getAudience()))); - assertThat(originalJwt.getContentType(), is(equalTo(deserializedJwt.getContentType()))); - assertThat(originalJwt.getExpiresAt(), is(equalTo(deserializedJwt.getExpiresAt()))); - assertThat(originalJwt.getId(), is(equalTo(deserializedJwt.getId()))); - assertThat(originalJwt.getIssuedAt(), is(equalTo(deserializedJwt.getIssuedAt()))); - assertThat(originalJwt.getIssuer(), is(equalTo(deserializedJwt.getIssuer()))); - assertThat(originalJwt.getKeyId(), is(equalTo(deserializedJwt.getKeyId()))); - assertThat(originalJwt.getNotBefore(), is(equalTo(deserializedJwt.getNotBefore()))); - assertThat(originalJwt.getSubject(), is(equalTo(deserializedJwt.getSubject()))); - assertThat(originalJwt.getType(), is(equalTo(deserializedJwt.getType()))); - assertThat(originalJwt.getClaims().get("extraClaim").asString(), - is(equalTo(deserializedJwt.getClaims().get("extraClaim").asString()))); - } - - @Test - public void shouldDecodeHeaderClaims() { - String jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImRhdGUiOjE2NDczNTgzMjUsInN0cmluZyI6InN0cmluZyIsImJvb2wiOnRydWUsImRvdWJsZSI6MTIzLjEyMywibGlzdCI6WzE2NDczNTgzMjVdLCJtYXAiOnsiZGF0ZSI6MTY0NzM1ODMyNSwiaW5zdGFudCI6MTY0NzM1ODMyNX0sImludCI6NDIsImxvbmciOjQyMDAwMDAwMDAsImluc3RhbnQiOjE2NDczNTgzMjV9.eyJpYXQiOjE2NDczNjA4ODF9.S2nZDM03ZDvLMeJLWOIqWZ9kmYHZUueyQiIZCCjYNL8"; - - Instant expectedInstant = Instant.ofEpochSecond(1647358325); - Date expectedDate = Date.from(expectedInstant); - - DecodedJWT decoded = JWT.decode(jwt); - assertThat(decoded, is(notNullValue())); - assertThat(decoded.getHeaderClaim("date").asDate(), is(expectedDate)); - assertThat(decoded.getHeaderClaim("instant").asInstant(), is(expectedInstant)); - assertThat(decoded.getHeaderClaim("string").asString(), is("string")); - assertThat(decoded.getHeaderClaim("bool").asBoolean(), is(true)); - assertThat(decoded.getHeaderClaim("double").asDouble(), is(123.123)); - assertThat(decoded.getHeaderClaim("int").asInt(), is(42)); - assertThat(decoded.getHeaderClaim("long").asLong(), is(4200000000L)); - - Map headerMap = decoded.getHeaderClaim("map").asMap(); - assertThat(headerMap, is(notNullValue())); - assertThat(headerMap.size(), is(2)); - assertThat(headerMap, hasEntry("date", 1647358325)); - assertThat(headerMap, hasEntry("instant", 1647358325)); - - List headerList = decoded.getHeaderClaim("list").asList(Object.class); - assertThat(headerList, is(notNullValue())); - assertThat(headerList.size(), is(1)); - assertThat(headerList, contains(1647358325)); - } - - //Helper Methods - - private DecodedJWT customJWT(String jsonHeader, String jsonPayload, String signature) { - String header = Base64.getUrlEncoder().withoutPadding().encodeToString(jsonHeader.getBytes(StandardCharsets.UTF_8)); - String body = Base64.getUrlEncoder().withoutPadding().encodeToString(jsonPayload.getBytes(StandardCharsets.UTF_8)); - return JWT.decode(String.format("%s.%s.%s", header, body, signature)); - } - - private static byte[] serialize(Object obj) throws IOException { - ByteArrayOutputStream b = new ByteArrayOutputStream(); - ObjectOutputStream o = new ObjectOutputStream(b); - o.writeObject(obj); - return b.toByteArray(); - } - - private static Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException { - ByteArrayInputStream b = new ByteArrayInputStream(bytes); - ObjectInputStream o = new ObjectInputStream(b); - return o.readObject(); - } - -} \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/JWTTest.java b/lib/src/test/java/com/auth0/jwt/JWTTest.java deleted file mode 100644 index 087f1e9e..00000000 --- a/lib/src/test/java/com/auth0/jwt/JWTTest.java +++ /dev/null @@ -1,524 +0,0 @@ -package com.auth0.jwt; - -import com.auth0.jwt.algorithms.Algorithm; -import com.auth0.jwt.interfaces.DecodedJWT; -import org.hamcrest.collection.IsCollectionWithSize; -import org.hamcrest.core.IsIterableContaining; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.nio.charset.StandardCharsets; -import java.security.interfaces.ECKey; -import java.security.interfaces.RSAKey; -import java.time.Clock; -import java.time.Duration; -import java.time.Instant; -import java.time.ZoneId; -import java.util.Base64; -import java.util.Date; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; - -public class JWTTest { - - private static final String PUBLIC_KEY_FILE_RSA = "src/test/resources/rsa-public.pem"; - private static final String PRIVATE_KEY_FILE_RSA = "src/test/resources/rsa-private.pem"; - - private static final String PUBLIC_KEY_FILE_EC_256 = "src/test/resources/ec256-key-public.pem"; - private static final String PUBLIC_KEY_FILE_EC_384 = "src/test/resources/ec384-key-public.pem"; - private static final String PUBLIC_KEY_FILE_EC_512 = "src/test/resources/ec512-key-public.pem"; - private static final String PRIVATE_KEY_FILE_EC_256 = "src/test/resources/ec256-key-private.pem"; - private static final String PRIVATE_KEY_FILE_EC_384 = "src/test/resources/ec384-key-private.pem"; - private static final String PRIVATE_KEY_FILE_EC_512 = "src/test/resources/ec512-key-private.pem"; - - @Rule - public ExpectedException exception = ExpectedException.none(); - - // Decode - - @Test - public void shouldDecodeAStringToken() { - String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; - DecodedJWT jwt = JWT.decode(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldDecodeAStringTokenUsingInstance() { - String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; - JWT jwt = new JWT(); - DecodedJWT decodedJWT = jwt.decodeJwt(token); - - assertThat(decodedJWT, is(notNullValue())); - } - - // getToken - @Test - public void shouldGetStringToken() { - DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getToken(), is(notNullValue())); - assertThat(jwt.getToken(), is("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ")); - } - - // getToken - @Test - public void shouldGetStringTokenUsingInstance() { - JWT jwt = new JWT(); - DecodedJWT decodedJWT = jwt.decodeJwt("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); - assertThat(decodedJWT, is(notNullValue())); - assertThat(decodedJWT.getToken(), is(notNullValue())); - assertThat(decodedJWT.getToken(), is("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ")); - } - - // Verify - - @Test - public void shouldVerifyDecodedToken() throws Exception { - String token = "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mvL5LoMyIrWYjk5umEXZTmbyIrkbbcVPUkvdGZbu0qFBxGOf0nXP5PZBvPcOu084lvpwVox5n3VaD4iqzW-PsJyvKFgi5TnwmsbKchAp7JexQEsQOnTSGcfRqeUUiBZqRQdYsho71oAB3T4FnalDdFEpM-fztcZY9XqKyayqZLreTeBjqJm4jfOWH7KfGBHgZExQhe96NLq1UA9eUyQwdOA1Z0SgXe4Ja5PxZ6Fm37KnVDtDlNnY4JAAGFo6y74aGNnp_BKgpaVJCGFu1f1S5xCQ1HSvs8ZSdVWs5NgawW3wRd0kRt_GJ_Y3mIwiF4qUyHWGtsSHu_qjVdCTtbFyow"; - DecodedJWT decodedJWT = JWT.decode(token); - RSAKey key = (RSAKey) PemUtils.readPublicKeyFromFile(PUBLIC_KEY_FILE_RSA, "RSA"); - DecodedJWT jwt = JWT.require(Algorithm.RSA512(key)) - .build() - .verify(decodedJWT); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldAcceptNoneAlgorithm() { - String token = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9."; - DecodedJWT jwt = JWT.require(Algorithm.none()) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldAcceptHMAC256Algorithm() { - String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; - DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldAcceptHMAC384Algorithm() { - String token = "eyJhbGciOiJIUzM4NCIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.uztpK_wUMYJhrRv8SV-1LU4aPnwl-EM1q-wJnqgyb5DHoDteP6lN_gE1xnZJH5vw"; - DecodedJWT jwt = JWT.require(Algorithm.HMAC384("secret")) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldAcceptHMAC512Algorithm() { - String token = "eyJhbGciOiJIUzUxMiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.VUo2Z9SWDV-XcOc_Hr6Lff3vl7L9e5Vb8ThXpmGDFjHxe3Dr1ZBmUChYF-xVA7cAdX1P_D4ZCUcsv3IefpVaJw"; - DecodedJWT jwt = JWT.require(Algorithm.HMAC512("secret")) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - - @Test - public void shouldAcceptRSA256Algorithm() throws Exception { - String token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.dxXF3MdsyW-AuvwJpaQtrZ33fAde9xWxpLIg9cO2tMLH2GSRNuLAe61KsJusZhqZB9Iy7DvflcmRz-9OZndm6cj_ThGeJH2LLc90K83UEvvRPo8l85RrQb8PcanxCgIs2RcZOLygERizB3pr5icGkzR7R2y6zgNCjKJ5_NJ6EiZsGN6_nc2PRK_DbyY-Wn0QDxIxKoA5YgQJ9qafe7IN980pXvQv2Z62c3XR8dYuaXBqhthBj-AbaFHEpZapN-V-TmuLNzR2MCB6Xr7BYMuCaqWf_XU8og4XNe8f_8w9Wv5vvgqMM1KhqVpG5VdMJv4o_L4NoCROHhtUQSLRh2M9cA"; - RSAKey key = (RSAKey) PemUtils.readPublicKeyFromFile(PUBLIC_KEY_FILE_RSA, "RSA"); - DecodedJWT jwt = JWT.require(Algorithm.RSA256(key)) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - - @Test - public void shouldAcceptRSA384Algorithm() throws Exception { - String token = "eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.TZlWjXObwGSQOiu2oMq8kiKz0_BR7bbBddNL6G8eZ_GoR82BXOZDqNrQr7lb_M-78XGBguWLWNIdYhzgxOUL9EoCJlrqVm9s9vo6G8T1sj1op-4TbjXZ61TwIvrJee9BvPLdKUJ9_fp1Js5kl6yXkst40Th8Auc5as4n49MLkipjpEhKDKaENKHpSubs1ripSz8SCQZSofeTM_EWVwSw7cpiM8Fy8jOPvWG8Xz4-e3ODFowvHVsDcONX_4FTMNbeRqDuHq2ZhCJnEfzcSJdrve_5VD5fM1LperBVslTrOxIgClOJ3RmM7-WnaizJrWP3D6Z9OLxPxLhM6-jx6tcxEw"; - RSAKey key = (RSAKey) PemUtils.readPublicKeyFromFile(PUBLIC_KEY_FILE_RSA, "RSA"); - DecodedJWT jwt = JWT.require(Algorithm.RSA384(key)) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldAcceptRSA512Algorithm() throws Exception { - String token = "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mvL5LoMyIrWYjk5umEXZTmbyIrkbbcVPUkvdGZbu0qFBxGOf0nXP5PZBvPcOu084lvpwVox5n3VaD4iqzW-PsJyvKFgi5TnwmsbKchAp7JexQEsQOnTSGcfRqeUUiBZqRQdYsho71oAB3T4FnalDdFEpM-fztcZY9XqKyayqZLreTeBjqJm4jfOWH7KfGBHgZExQhe96NLq1UA9eUyQwdOA1Z0SgXe4Ja5PxZ6Fm37KnVDtDlNnY4JAAGFo6y74aGNnp_BKgpaVJCGFu1f1S5xCQ1HSvs8ZSdVWs5NgawW3wRd0kRt_GJ_Y3mIwiF4qUyHWGtsSHu_qjVdCTtbFyow"; - RSAKey key = (RSAKey) PemUtils.readPublicKeyFromFile(PUBLIC_KEY_FILE_RSA, "RSA"); - DecodedJWT jwt = JWT.require(Algorithm.RSA512(key)) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - - @Test - public void shouldAcceptECDSA256Algorithm() throws Exception { - String token = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g"; - ECKey key = (ECKey) PemUtils.readPublicKeyFromFile(PUBLIC_KEY_FILE_EC_256, "EC"); - DecodedJWT jwt = JWT.require(Algorithm.ECDSA256(key)) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldAcceptECDSA384Algorithm() throws Exception { - String token = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.50UU5VKNdF1wfykY8jQBKpvuHZoe6IZBJm5NvoB8bR-hnRg6ti-CHbmvoRtlLfnHfwITa_8cJMy6TenMC2g63GQHytc8rYoXqbwtS4R0Ko_AXbLFUmfxnGnMC6v4MS_z"; - ECKey key = (ECKey) PemUtils.readPublicKeyFromFile(PUBLIC_KEY_FILE_EC_384, "EC"); - DecodedJWT jwt = JWT.require(Algorithm.ECDSA384(key)) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldAcceptECDSA512Algorithm() throws Exception { - String token = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.AeCJPDIsSHhwRSGZCY6rspi8zekOw0K9qYMNridP1Fu9uhrA1QrG-EUxXlE06yvmh2R7Rz0aE7kxBwrnq8L8aOBCAYAsqhzPeUvyp8fXjjgs0Eto5I0mndE2QHlgcMSFASyjHbU8wD2Rq7ZNzGQ5b2MZfpv030WGUajT-aZYWFUJHVg2"; - ECKey key = (ECKey) PemUtils.readPublicKeyFromFile(PUBLIC_KEY_FILE_EC_512, "EC"); - DecodedJWT jwt = JWT.require(Algorithm.ECDSA512(key)) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - - // Standard Claims - - @Test - public void shouldGetAlgorithm() { - String token = "eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"; - DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getAlgorithm(), is("HS256")); - } - - @Test - public void shouldGetSignature() { - String token = "eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"; - DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getSignature(), is("XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ")); - } - - @Test - public void shouldGetIssuer() { - String token = "eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJKb2huIERvZSJ9.SgXosfRR_IwCgHq5lF3tlM-JHtpucWCRSaVuoHTbWbQ"; - DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getIssuer(), is("John Doe")); - } - - @Test - public void shouldGetSubject() { - String token = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJUb2szbnMifQ.RudAxkslimoOY3BLl2Ghny3BrUKu9I1ZrXzCZGDJtNs"; - DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getSubject(), is("Tok3ns")); - } - - @Test - public void shouldGetArrayAudience() { - String token = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsiSG9wZSIsIlRyYXZpcyIsIlNvbG9tb24iXX0.Tm4W8WnfPjlmHSmKFakdij0on2rWPETpoM7Sh0u6-S4"; - DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getAudience(), is(IsCollectionWithSize.hasSize(3))); - assertThat(jwt.getAudience(), is(IsIterableContaining.hasItems("Hope", "Travis", "Solomon"))); - } - - @Test - public void shouldGetStringAudience() { - String token = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJKYWNrIFJleWVzIn0.a4I9BBhPt1OB1GW67g2P1bEHgi6zgOjGUL4LvhE9Dgc"; - DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getAudience(), is(IsCollectionWithSize.hasSize(1))); - assertThat(jwt.getAudience(), is(IsIterableContaining.hasItems("Jack Reyes"))); - } - - @Test - public void shouldGetExpirationTime() { - long seconds = 1477592L; - Clock mockNow = Clock.fixed(Instant.ofEpochSecond(seconds - 1), ZoneId.of("UTC")); - - String token = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0Nzc1OTJ9.x_ZjkPkKYUV5tdvc0l8go6D_z2kez1MQcOxokXrDc3k"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWT.require(Algorithm.HMAC256("secret")); - DecodedJWT jwt = verification - .build(mockNow) - .verify(token); - - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getExpiresAt(), is(equalTo(new Date(seconds * 1000)))); - assertThat(jwt.getExpiresAtAsInstant(), is(equalTo(Instant.ofEpochSecond(seconds)))); - - } - - @Test - public void shouldGetNotBefore() { - long seconds = 1477592; - Clock clock = Clock.fixed(Instant.ofEpochSecond(seconds), ZoneId.of("UTC")); - - String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE0Nzc1OTJ9.mWYSOPoNXstjKbZkKrqgkwPOQWEx3F3gMm6PMcfuJd8"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWT.require(Algorithm.HMAC256("secret")); - DecodedJWT jwt = verification - .build(clock) - .verify(token); - - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getNotBefore(), is(equalTo(new Date(seconds * 1000)))); - assertThat(jwt.getNotBeforeAsInstant(), is(equalTo(Instant.ofEpochSecond(seconds)))); - } - - @Test - public void shouldGetIssuedAt() { - long seconds = 1477592; - Clock clock = Clock.fixed(Instant.ofEpochSecond(seconds), ZoneId.of("UTC")); - - String token = "eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0Nzc1OTJ9.5o1CKlLFjKKcddZzoarQ37pq7qZqNPav3sdZ_bsZaD4"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWT.require(Algorithm.HMAC256("secret")); - DecodedJWT jwt = verification - .build(clock) - .verify(token); - - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getIssuedAt(), is(equalTo(new Date(seconds * 1000)))); - assertThat(jwt.getIssuedAtAsInstant(), is(equalTo(Instant.ofEpochSecond(seconds)))); - } - - @Test - public void shouldGetId() { - String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMjM0NTY3ODkwIn0.m3zgEfVUFOd-CvL3xG5BuOWLzb0zMQZCqiVNQQOPOvA"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWT.require(Algorithm.HMAC256("secret")); - DecodedJWT jwt = verification - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getId(), is("1234567890")); - } - - @Test - public void shouldGetContentType() { - String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6ImF3ZXNvbWUifQ.e30.AIm-pJDOaAyct9qKMlN-lQieqNDqc3d4erqUZc5SHAs"; - DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getContentType(), is("awesome")); - } - - @Test - public void shouldGetType() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.e30.WdFmrzx8b9v_a-r6EHC2PTAaWywgm_8LiP8RBRhYwkI"; - DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getType(), is("JWS")); - } - - @Test - public void shouldGetKeyId() { - String token = "eyJhbGciOiJIUzI1NiIsImtpZCI6ImtleSJ9.e30.von1Vt9tq9cn5ZYdX1f4cf2EE7fUvb5BCBlKOTm9YWs"; - DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getKeyId(), is("key")); - } - - @Test - public void shouldGetCustomClaims() { - String token = "eyJhbGciOiJIUzI1NiIsImlzQWRtaW4iOnRydWV9.eyJpc0FkbWluIjoibm9wZSJ9.YDKBAgUDbh0PkhioDcLNzdQ8c2Gdf_yS6zdEtJQS3F0"; - DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - assertThat(jwt.getHeaderClaim("isAdmin"), notNullValue()); - assertThat(jwt.getHeaderClaim("isAdmin").asBoolean(), is(true)); - assertThat(jwt.getClaim("isAdmin"), notNullValue()); - assertThat(jwt.getClaim("isAdmin").asString(), is("nope")); - } - - // Sign - - @Test - public void shouldCreateAnEmptyHMAC256SignedToken() { - String signed = JWT.create().sign(Algorithm.HMAC256("secret")); - assertThat(signed, is(notNullValue())); - - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("alg", "HS256")); - assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); - assertThat(parts[1], is("e30")); - - JWTVerifier verified = JWT.require(Algorithm.HMAC256("secret")) - .build(); - assertThat(verified, is(notNullValue())); - } - - @Test - public void shouldCreateAnEmptyHMAC384SignedToken() { - String signed = JWT.create().sign(Algorithm.HMAC384("secret")); - assertThat(signed, is(notNullValue())); - - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("alg", "HS384")); - assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); - assertThat(parts[1], is("e30")); - - JWTVerifier verified = JWT.require(Algorithm.HMAC384("secret")) - .build(); - assertThat(verified, is(notNullValue())); - } - - @Test - public void shouldCreateAnEmptyHMAC512SignedToken() { - String signed = JWT.create().sign(Algorithm.HMAC512("secret")); - assertThat(signed, is(notNullValue())); - - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("alg", "HS512")); - assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); - assertThat(parts[1], is("e30")); - - JWTVerifier verified = JWT.require(Algorithm.HMAC512("secret")) - .build(); - assertThat(verified, is(notNullValue())); - } - - @Test - public void shouldCreateAnEmptyRSA256SignedToken() throws Exception { - String signed = JWT.create().sign(Algorithm.RSA256((RSAKey) PemUtils.readPrivateKeyFromFile(PRIVATE_KEY_FILE_RSA, "RSA"))); - assertThat(signed, is(notNullValue())); - - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("alg", "RS256")); - assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); - assertThat(parts[1], is("e30")); - - JWTVerifier verified = JWT.require(Algorithm.RSA256((RSAKey) PemUtils.readPublicKeyFromFile(PUBLIC_KEY_FILE_RSA, "RSA"))) - .build(); - assertThat(verified, is(notNullValue())); - } - - @Test - public void shouldCreateAnEmptyRSA384SignedToken() throws Exception { - String signed = JWT.create().sign(Algorithm.RSA384((RSAKey) PemUtils.readPrivateKeyFromFile(PRIVATE_KEY_FILE_RSA, "RSA"))); - assertThat(signed, is(notNullValue())); - - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("alg", "RS384")); - assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); - assertThat(parts[1], is("e30")); - - JWTVerifier verified = JWT.require(Algorithm.RSA384((RSAKey) PemUtils.readPublicKeyFromFile(PUBLIC_KEY_FILE_RSA, "RSA"))) - .build(); - assertThat(verified, is(notNullValue())); - } - - @Test - public void shouldCreateAnEmptyRSA512SignedToken() throws Exception { - String signed = JWT.create().sign(Algorithm.RSA512((RSAKey) PemUtils.readPrivateKeyFromFile(PRIVATE_KEY_FILE_RSA, "RSA"))); - assertThat(signed, is(notNullValue())); - - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("alg", "RS512")); - assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); - assertThat(parts[1], is("e30")); - - JWTVerifier verified = JWT.require(Algorithm.RSA512((RSAKey) PemUtils.readPublicKeyFromFile(PUBLIC_KEY_FILE_RSA, "RSA"))) - .build(); - assertThat(verified, is(notNullValue())); - } - - @Test - public void shouldCreateAnEmptyECDSA256SignedToken() throws Exception { - String signed = JWT.create().sign(Algorithm.ECDSA256((ECKey) PemUtils.readPrivateKeyFromFile(PRIVATE_KEY_FILE_EC_256, "EC"))); - assertThat(signed, is(notNullValue())); - - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("alg", "ES256")); - assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); - assertThat(parts[1], is("e30")); - - JWTVerifier verified = JWT.require(Algorithm.ECDSA256((ECKey) PemUtils.readPublicKeyFromFile(PUBLIC_KEY_FILE_EC_256, "EC"))) - .build(); - assertThat(verified, is(notNullValue())); - } - - @Test - public void shouldCreateAnEmptyECDSA384SignedToken() throws Exception { - String signed = JWT.create().sign(Algorithm.ECDSA384((ECKey) PemUtils.readPrivateKeyFromFile(PRIVATE_KEY_FILE_EC_384, "EC"))); - assertThat(signed, is(notNullValue())); - - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("alg", "ES384")); - assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); - assertThat(parts[1], is("e30")); - - JWTVerifier verified = JWT.require(Algorithm.ECDSA384((ECKey) PemUtils.readPublicKeyFromFile(PUBLIC_KEY_FILE_EC_384, "EC"))) - .build(); - assertThat(verified, is(notNullValue())); - } - - @Test - public void shouldCreateAnEmptyECDSA512SignedToken() throws Exception { - String signed = JWT.create().sign(Algorithm.ECDSA512((ECKey) PemUtils.readPrivateKeyFromFile(PRIVATE_KEY_FILE_EC_512, "EC"))); - assertThat(signed, is(notNullValue())); - - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("alg", "ES512")); - assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); - assertThat(parts[1], is("e30")); - - JWTVerifier verified = JWT.require(Algorithm.ECDSA512((ECKey) PemUtils.readPublicKeyFromFile(PUBLIC_KEY_FILE_EC_512, "EC"))) - .build(); - assertThat(verified, is(notNullValue())); - } -} diff --git a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java deleted file mode 100644 index 732d6365..00000000 --- a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java +++ /dev/null @@ -1,1317 +0,0 @@ -package com.auth0.jwt; - -import com.auth0.jwt.algorithms.Algorithm; -import com.auth0.jwt.exceptions.*; -import com.auth0.jwt.interfaces.Claim; -import com.auth0.jwt.interfaces.DecodedJWT; -import com.auth0.jwt.interfaces.Verification; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.time.Clock; -import java.time.Duration; -import java.time.Instant; -import java.time.ZoneId; -import java.util.Collections; -import java.util.Date; -import java.util.function.BiPredicate; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThrows; -import static org.mockito.Mockito.mock; - -public class JWTVerifierTest { - - private final Clock mockNow = Clock.fixed(Instant.ofEpochSecond(1477592), ZoneId.of("UTC")); - private final Clock mockOneSecondEarlier = Clock.offset(mockNow, Duration.ofSeconds(-1)); - private final Clock mockOneSecondLater = Clock.offset(mockNow, Duration.ofSeconds(1)); - - @Rule - public ExpectedException exception = ExpectedException.none(); - - @Test - public void shouldThrowWhenInitializedWithoutAlgorithm() { - IllegalArgumentException e = assertThrows(null, IllegalArgumentException.class, () -> - JWTVerifier.init(null)); - assertThat(e.getMessage(), is("The Algorithm cannot be null.")); - } - - @Test - public void shouldThrowWhenAlgorithmDoesntMatchTheTokensAlgorithm() { - AlgorithmMismatchException e = assertThrows(null, AlgorithmMismatchException.class, () -> { - JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC512("secret")).build(); - verifier.verify("eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.s69x7Mmu4JqwmdxiK6sesALO7tcedbFsKEEITUxw9ho"); - }); - assertThat(e.getMessage(), is("The provided Algorithm doesn't match the one defined in the JWT's Header.")); - } - - @Test - public void shouldValidateIssuer() { - String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withIssuer("auth0") - .build() - .verify(token); - assertThat(jwt, is(notNullValue())); - - // "iss": ["auth0", "okta"] - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, ()-> { - String token1 = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withIssuer((String[]) null) - .build() - .verify(token1); - }); - - assertThat(e.getClaimName(), is("iss")); - } - - @Test - public void shouldValidateMultipleIssuers() { - String auth0Token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; - String otherIssuertoken = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJvdGhlcklzc3VlciJ9.k4BCOJJl-c0_Y-49VD_mtt-u0QABKSV5i3W-RKc74co"; - JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withIssuer("otherIssuer", "auth0") - .build(); - - assertThat(verifier.verify(auth0Token), is(notNullValue())); - assertThat(verifier.verify(otherIssuertoken), is(notNullValue())); - } - - @Test - public void shouldThrowOnInvalidIssuer() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withIssuer("invalid") - .build() - .verify(token); - }); - assertThat(e.getMessage(), is("The Claim 'iss' value doesn't match the required issuer.")); - assertThat(e.getClaimName(), is(RegisteredClaims.ISSUER)); - assertThat(e.getClaimValue().asString(), is("auth0")); - } - - @Test - public void shouldThrowOnNullIssuer() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOm51bGx9.OoiCLipSfflWxkFX2rytvtwEiJ8eAL0opkdXY_ap0qA"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withIssuer("auth0") - .build() - .verify(token); - }); - assertThat(e.getMessage(), is("The Claim 'iss' value doesn't match the required issuer.")); - assertThat(e.getClaimName(), is(RegisteredClaims.ISSUER)); - assertThat(e.getClaimValue().isNull(), is(true)); - } - - @Test - public void shouldThrowOnMissingIssuer() { - MissingClaimException e = assertThrows(null, MissingClaimException.class, () -> { - String jwt = JWTCreator.init() - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withIssuer("nope") - .build() - .verify(jwt); - }); - assertThat(e.getMessage(), is("The Claim 'iss' is not present in the JWT.")); - assertThat(e.getClaimName(), is("iss")); - } - - @Test - public void shouldValidateSubject() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.Rq8IxqeX7eA6GgYxlcHdPFVRNFFZc5rEI3MQTZZbK3I"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withSubject("1234567890") - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldThrowOnInvalidSubject() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.Rq8IxqeX7eA6GgYxlcHdPFVRNFFZc5rEI3MQTZZbK3I"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withSubject("invalid") - .build() - .verify(token); - }); - assertThat(e.getMessage(), is("The Claim 'sub' value doesn't match the required one.")); - assertThat(e.getClaimName(), is(RegisteredClaims.SUBJECT)); - assertThat(e.getClaimValue().asString(), is("1234567890")); - } - - @Test - public void shouldAcceptAudienceWhenWithAudienceContainsAll() { - // Token 'aud': ["Mark"] - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJNYXJrIn0.xWB6czYI0XObbVhLAxe55TwChWZg7zO08RxONWU2iY4"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withAudience("Mark") - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - - // Token 'aud': ["Mark", "David"] - String tokenArr = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiTWFyayIsIkRhdmlkIl19.6WfbIt8m61f9WlCYIQn5CThvw4UNyC66qrPaoinfssw"; - DecodedJWT jwtArr = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withAudience("Mark", "David") - .build() - .verify(tokenArr); - - assertThat(jwtArr, is(notNullValue())); - } - - @Test - public void shouldAllowWithAnyOfAudienceVerificationToOverrideWithAudience() { - // Token 'aud' = ["Mark", "David", "John"] - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiTWFyayIsIkRhdmlkIiwiSm9obiJdfQ.DX5xXiCaYvr54x_iL0LZsJhK7O6HhAdHeDYkgDeb0Rw"; - Verification verification = JWTVerifier.init(Algorithm.HMAC256("secret")).withAudience("Mark", "Jim"); - - Exception exception = null; - try { - verification.build().verify(token); - } catch (Exception e) { - exception = e; - - } - - assertThat(exception, is(notNullValue())); - assertThat(exception, is(instanceOf(IncorrectClaimException.class))); - assertThat(exception.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); - - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")).withAnyOfAudience("Mark", "Jim").build().verify(token); - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldAllowWithAudienceVerificationToOverrideWithAnyOfAudience() { - // Token 'aud' = ["Mark", "David", "John"] - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiTWFyayIsIkRhdmlkIiwiSm9obiJdfQ.DX5xXiCaYvr54x_iL0LZsJhK7O6HhAdHeDYkgDeb0Rw"; - Verification verification = JWTVerifier.init(Algorithm.HMAC256("secret")).withAnyOfAudience("Jim"); - - Exception exception = null; - try { - verification.build().verify(token); - } catch (Exception e) { - exception = e; - - } - - assertThat(exception, is(notNullValue())); - assertThat(exception, is(instanceOf(IncorrectClaimException.class))); - assertThat(exception.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); - - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")).withAudience("Mark").build().verify(token); - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldAcceptAudienceWhenWithAudienceAndPartialExpected() { - // Token 'aud' = ["Mark", "David", "John"] - String tokenArr = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiTWFyayIsIkRhdmlkIiwiSm9obiJdfQ.DX5xXiCaYvr54x_iL0LZsJhK7O6HhAdHeDYkgDeb0Rw"; - DecodedJWT jwtArr = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withAudience("John") - .build() - .verify(tokenArr); - - assertThat(jwtArr, is(notNullValue())); - } - - @Test - public void shouldAcceptAudienceWhenAnyOfAudienceAndAllContained() { - // Token 'aud' = ["Mark", "David", "John"] - String tokenArr = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiTWFyayIsIkRhdmlkIiwiSm9obiJdfQ.DX5xXiCaYvr54x_iL0LZsJhK7O6HhAdHeDYkgDeb0Rw"; - DecodedJWT jwtArr = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withAnyOfAudience("Mark", "David", "John") - .build() - .verify(tokenArr); - - assertThat(jwtArr, is(notNullValue())); - } - - @Test - public void shouldThrowWhenAudienceHasNoneOfExpectedAnyOfAudience() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - // Token 'aud' = ["Mark", "David", "John"] - String tokenArr = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiTWFyayIsIkRhdmlkIiwiSm9obiJdfQ.DX5xXiCaYvr54x_iL0LZsJhK7O6HhAdHeDYkgDeb0Rw"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withAnyOfAudience("Joe", "Jim") - .build() - .verify(tokenArr); - }); - assertThat(e.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); - assertThat(e.getClaimName(), is(RegisteredClaims.AUDIENCE)); - assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"Mark","David","John"})); - } - - @Test - public void shouldThrowWhenAudienceClaimDoesNotContainAllExpected() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - // Token 'aud' = ["Mark", "David", "John"] - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiTWFyayIsIkRhdmlkIiwiSm9obiJdfQ.DX5xXiCaYvr54x_iL0LZsJhK7O6HhAdHeDYkgDeb0Rw"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withAudience("Mark", "Joe") - .build() - .verify(token); - }); - assertThat(e.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); - assertThat(e.getClaimName(), is(RegisteredClaims.AUDIENCE)); - assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"Mark","David","John"})); - } - - @Test - public void shouldThrowWhenAudienceClaimIsNull() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - // Token 'aud': null - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiYXVkIjpudWxsfQ.bpPyquk3b8KepErKgTidjJ1ZwiOGuoTxam2_x7cElKI"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withAudience("nope") - .build() - .verify(token); - }); - assertThat(e.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); - assertThat(e.getClaimName(), is(RegisteredClaims.AUDIENCE)); - assertThat(e.getClaimValue().isNull(), is(true)); - } - - @Test - public void shouldThrowWhenAudienceClaimIsMissing(){ - MissingClaimException e = assertThrows(null, MissingClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.Rq8IxqeX7eA6GgYxlcHdPFVRNFFZc5rEI3MQTZZbK3I"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withAudience("nope") - .build() - .verify(token); - }); - assertThat(e.getMessage(), is("The Claim 'aud' is not present in the JWT.")); - assertThat(e.getClaimName(), is("aud")); - } - - @Test - public void shouldThrowWhenAudienceClaimIsNullWithAnAudience() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - // Token 'aud': [null] - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiYXVkIjpbbnVsbF19.2cBf7FbkX52h8Vmjnl1DY1PYe_J_YP0KsyeoeYmuca8"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withAnyOfAudience("nope") - .build() - .verify(token); - }); - assertThat(e.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); - assertThat(e.getClaimName(), is(RegisteredClaims.AUDIENCE)); - assertThat(e.getClaimValue().asArray(String.class), is(new String[] {null})); - } - - @Test - public void shouldThrowWhenExpectedEmptyList() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - // Token 'aud': 'wide audience' - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ3aWRlIGF1ZGllbmNlIn0.c9anq03XepcuEKWEVsPk9cck0sIIfrT6hHbBsCar49o"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withAnyOfAudience(new String[0]) - .build() - .verify(token); - }); - assertThat(e.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); - assertThat(e.getClaimName(), is(RegisteredClaims.AUDIENCE)); - assertThat(e.getClaimValue().asString(), is("wide audience")); - } - - @Test - public void shouldNotReplaceWhenMultipleChecksAreAdded() { - JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withAudience((String[]) null) - .withAudience() - .withAnyOfAudience((String[]) null) - .withAnyOfAudience() - .build(); - - assertThat(verifier.expectedChecks.size(), is(7)); //3 extra mandatory checks exp, nbf, iat - } - - @Test - public void shouldThrowOnNullCustomClaimName() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("The Custom Claim's name can't be null."); - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim(null, "value"); - } - - @Test - public void shouldThrowWhenExpectedArrayClaimIsMissing() { - MissingClaimException e = assertThrows(null, MissingClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcnJheSI6WzEsMiwzXX0.wKNFBcMdwIpdF9rXRxvexrzSM6umgSFqRO1WZj992YM"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withArrayClaim("missing", 1, 2, 3) - .build() - .verify(token); - }); - assertThat(e.getMessage(), is("The Claim 'missing' is not present in the JWT.")); - assertThat(e.getClaimName(), is("missing")); - } - - @Test - public void shouldThrowWhenExpectedClaimIsMissing() { - MissingClaimException e = assertThrows(null, MissingClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGFpbSI6InRleHQifQ.aZ27Ze35VvTqxpaSIK5ZcnYHr4SrvANlUbDR8fw9qsQ"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("missing", "text") - .build() - .verify(token); - }); - assertThat(e.getMessage(), is("The Claim 'missing' is not present in the JWT.")); - assertThat(e.getClaimName(), is("missing")); - } - - @Test - public void shouldThrowOnInvalidCustomClaimValueOfTypeString() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", "value") - .build() - .verify(token); - }); - assertThat(e.getMessage(), is("The Claim 'name' value doesn't match the required one.")); - assertThat(e.getClaimName(), is("name")); - assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"something"})); - } - - @Test - public void shouldThrowOnInvalidCustomClaimValueOfTypeInteger() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", 123) - .build() - .verify(token); - }); - assertThat(e.getMessage(), is("The Claim 'name' value doesn't match the required one.")); - assertThat(e.getClaimName(), is("name")); - assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"something"})); - } - - @Test - public void shouldThrowOnInvalidCustomClaimValueOfTypeDouble() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", 23.45) - .build() - .verify(token); - }); - assertThat(e.getMessage(), is("The Claim 'name' value doesn't match the required one.")); - assertThat(e.getClaimName(), is("name")); - assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"something"})); - } - - @Test - public void shouldThrowOnInvalidCustomClaimValueOfTypeBoolean() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", true) - .build() - .verify(token); - }); - assertThat(e.getMessage(), is("The Claim 'name' value doesn't match the required one.")); - assertThat(e.getClaimName(), is("name")); - assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"something"})); - } - - - @Test - public void shouldThrowOnInvalidCustomClaimValueOfTypeDate() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", new Date()) - .build() - .verify(token); - }); - assertThat(e.getMessage(), is("The Claim 'name' value doesn't match the required one.")); - assertThat(e.getClaimName(), is("name")); - assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"something"})); - } - - @Test - public void shouldThrowOnInvalidCustomClaimValue() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", "check") - .build() - .verify(token); - }); - assertThat(e.getMessage(), is("The Claim 'name' value doesn't match the required one.")); - assertThat(e.getClaimName(), is("name")); - assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"something"})); - } - - @Test - public void shouldValidateCustomClaimOfTypeString() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidmFsdWUifQ.Jki8pvw6KGbxpMinufrgo6RDL1cu7AtNMJYVh6t-_cE"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", "value") - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldValidateCustomClaimOfTypeInteger() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxMjN9.XZAudnA7h3_Al5kJydzLjw6RzZC3Q6OvnLEYlhNW7HA"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", 123) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldValidateCustomClaimOfTypeLong() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjo5MjIzMzcyMDM2ODU0Nzc2MDB9.km-IwQ5IDnTZFmuJzhSgvjTzGkn_Z5X29g4nAuVC56I"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", 922337203685477600L) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldValidateCustomClaimOfTypeDouble() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoyMy40NX0.7pyX2OmEGaU9q15T8bGFqRm-d3RVTYnqmZNZtxMKSlA"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", 23.45) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldValidateCustomClaimOfTypeBoolean() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjp0cnVlfQ.FwQ8VfsZNRqBa9PXMinSIQplfLU4-rkCLfIlTLg_MV0"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", true) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldValidateCustomClaimOfTypeDate() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxNDc4ODkxNTIxfQ.mhioumeok8fghQEhTKF3QtQAksSvZ_9wIhJmgZLhJ6c"; - Date date = new Date(1478891521123L); - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", date) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldNotRemoveCustomClaimOfTypeDateWhenNull() { - JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", new Date()) - .withClaim("name", (Date) null) - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks.size(), is(5)); - } - - @Test - public void shouldValidateCustomArrayClaimOfTypeString() { - String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbInRleHQiLCIxMjMiLCJ0cnVlIl19.lxM8EcmK1uSZRAPd0HUhXGZJdauRmZmLjoeqz4J9yAA"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withArrayClaim("name", "text", "123", "true") - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldValidateCustomArrayClaimOfTypeInteger() { - String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbMSwyLDNdfQ.UEuMKRQYrzKAiPpPLhIVawWkKWA1zj0_GderrWUIyFE"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withArrayClaim("name", 1, 2, 3) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldValidateCustomArrayClaimOfTypeLong() { - String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbNTAwMDAwMDAwMDAxLDUwMDAwMDAwMDAwMiw1MDAwMDAwMDAwMDNdfQ.vzV7S0gbV9ZAVxChuIt4XZuSVTxMH536rFmoHzxmayM"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withArrayClaim("name", 500000000001L, 500000000002L, 500000000003L) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldValidateCustomArrayClaimOfTypeLongWhenValueIsInteger() { - String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbMSwyLDNdfQ.UEuMKRQYrzKAiPpPLhIVawWkKWA1zj0_GderrWUIyFE"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withArrayClaim("name", 1L, 2L, 3L) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldValidateCustomArrayClaimOfTypeLongWhenValueIsIntegerAndLong() { - String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbMSw1MDAwMDAwMDAwMDIsNTAwMDAwMDAwMDAzXX0.PQjb2rPPpYjM2sItZEzZcjS2YbfPCp6xksTSPjpjTQA"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withArrayClaim("name", 1L, 500000000002L, 500000000003L) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - // Generic Delta - @Test - public void shouldAddDefaultLeewayToDateClaims() { - Algorithm algorithm = mock(Algorithm.class); - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(algorithm); - JWTVerifier verifier = verification - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verification.getLeewayFor(RegisteredClaims.ISSUED_AT), is(0L)); - assertThat(verification.getLeewayFor(RegisteredClaims.EXPIRES_AT), is(0L)); - assertThat(verification.getLeewayFor(RegisteredClaims.NOT_BEFORE), is(0L)); - } - - @Test - public void shouldAddCustomLeewayToDateClaims() { - Algorithm algorithm = mock(Algorithm.class); - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(algorithm); - JWTVerifier verifier = verification - .acceptLeeway(1234L) - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verification.getLeewayFor(RegisteredClaims.ISSUED_AT), is(1234L)); - assertThat(verification.getLeewayFor(RegisteredClaims.EXPIRES_AT), is(1234L)); - assertThat(verification.getLeewayFor(RegisteredClaims.NOT_BEFORE), is(1234L)); - } - - @Test - public void shouldOverrideDefaultIssuedAtLeeway() { - Algorithm algorithm = mock(Algorithm.class); - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(algorithm); - JWTVerifier verifier = verification - .acceptLeeway(1234L) - .acceptIssuedAt(9999L) - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verification.getLeewayFor(RegisteredClaims.ISSUED_AT), is(9999L)); - assertThat(verification.getLeewayFor(RegisteredClaims.EXPIRES_AT), is(1234L)); - assertThat(verification.getLeewayFor(RegisteredClaims.NOT_BEFORE), is(1234L)); - } - - @Test - public void shouldOverrideDefaultExpiresAtLeeway() { - Algorithm algorithm = mock(Algorithm.class); - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(algorithm); - JWTVerifier verifier = verification - .acceptLeeway(1234L) - .acceptExpiresAt(9999L) - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verification.getLeewayFor(RegisteredClaims.ISSUED_AT), is(1234L)); - assertThat(verification.getLeewayFor(RegisteredClaims.EXPIRES_AT), is(9999L)); - assertThat(verification.getLeewayFor(RegisteredClaims.NOT_BEFORE), is(1234L)); - } - - @Test - public void shouldOverrideDefaultNotBeforeLeeway() { - Algorithm algorithm = mock(Algorithm.class); - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(algorithm); - JWTVerifier verifier = verification - .acceptLeeway(1234L) - .acceptNotBefore(9999L) - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verification.getLeewayFor(RegisteredClaims.ISSUED_AT), is(1234L)); - assertThat(verification.getLeewayFor(RegisteredClaims.EXPIRES_AT), is(1234L)); - assertThat(verification.getLeewayFor(RegisteredClaims.NOT_BEFORE), is(9999L)); - } - - @Test - public void shouldThrowOnNegativeCustomLeeway() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Leeway value can't be negative."); - Algorithm algorithm = mock(Algorithm.class); - JWTVerifier.init(algorithm) - .acceptLeeway(-1); - } - - // Expires At - - @Test - public void shouldValidateExpiresAtWithLeeway() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")) - .acceptExpiresAt(2); - DecodedJWT jwt = verification - .build(mockOneSecondLater) - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldValidateExpiresAtIfPresent() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); - DecodedJWT jwt = verification - .build(mockOneSecondEarlier) - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldThrowWhenExpiresAtIsNow() { - // exp must be > now - TokenExpiredException e = assertThrows(null, TokenExpiredException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); - verification - .build(mockNow) - .verify(token); - }); - assertThat(e.getMessage(), is("The Token has expired on 1970-01-18T02:26:32Z.")); - assertThat(e.getExpiredOn(), is(Instant.ofEpochSecond(1477592L))); - } - - @Test - public void shouldThrowOnInvalidExpiresAtIfPresent() { - TokenExpiredException e = assertThrows(null, TokenExpiredException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); - verification - .build(mockOneSecondLater) - .verify(token); - }); - assertThat(e.getMessage(), is("The Token has expired on 1970-01-18T02:26:32Z.")); - assertThat(e.getExpiredOn(), is(Instant.ofEpochSecond(1477592L))); - } - - @Test - public void shouldThrowOnNegativeExpiresAtLeeway() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Leeway value can't be negative."); - Algorithm algorithm = mock(Algorithm.class); - JWTVerifier.init(algorithm) - .acceptExpiresAt(-1); - } - - // Not before - @Test - public void shouldValidateNotBeforeWithLeeway() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0Nzc1OTJ9.wq4ZmnSF2VOxcQBxPLfeh1J2Ozy1Tj5iUaERm3FKaw8"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")) - .acceptNotBefore(2); - DecodedJWT jwt = verification - .build(mockOneSecondEarlier) - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldThrowOnInvalidNotBeforeIfPresent() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0Nzc1OTJ9.wq4ZmnSF2VOxcQBxPLfeh1J2Ozy1Tj5iUaERm3FKaw8"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); - verification - .build(mockOneSecondEarlier) - .verify(token); - }); - assertThat(e.getMessage(), is("The Token can't be used before 1970-01-18T02:26:32Z.")); - assertThat(e.getClaimName(), is(RegisteredClaims.NOT_BEFORE)); - assertThat(e.getClaimValue().asLong(), is(1477592L)); - } - - @Test - public void shouldValidateNotBeforeIfPresent() { - String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE0Nzc1OTN9.f4zVV0TbbTG5xxDjSoGZ320JIMchGoQCWrnT5MyQdT0"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); - DecodedJWT jwt = verification - .build(mockOneSecondLater) - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldAcceptNotBeforeEqualToNow() { - String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE0Nzc1OTJ9.71XBtRmkAa4iKnyhbS4NPW-Xr26eAVAdHZgmupS7a5o"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); - DecodedJWT jwt = verification - .build(mockNow) - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldThrowOnNegativeNotBeforeLeeway() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Leeway value can't be negative."); - Algorithm algorithm = mock(Algorithm.class); - JWTVerifier.init(algorithm) - .acceptNotBefore(-1); - } - - // Issued At with future date - @Test - public void shouldThrowOnFutureIssuedAt() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0Nzc1OTJ9.CWq-6pUXl1bFg81vqOUZbZrheO2kUBd2Xr3FUZmvudE"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); - - DecodedJWT jwt = verification.build(mockOneSecondEarlier).verify(token); - assertThat(jwt, is(notNullValue())); - }); - assertThat(e.getMessage(), is("The Token can't be used before 1970-01-18T02:26:32Z.")); - assertThat(e.getClaimName(), is(RegisteredClaims.ISSUED_AT)); - assertThat(e.getClaimValue().asLong(), is(1477592L)); - } - - // Issued At with future date and ignore flag - @Test - public void shouldSkipIssuedAtVerificationWhenFlagIsPassed() { - String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0Nzc1OTJ9.CWq-6pUXl1bFg81vqOUZbZrheO2kUBd2Xr3FUZmvudE"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); - verification.ignoreIssuedAt(); - - DecodedJWT jwt = verification.build(mockOneSecondEarlier).verify(token); - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldThrowOnInvalidIssuedAtIfPresent() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0Nzc1OTJ9.0WJky9eLN7kuxLyZlmbcXRL3Wy8hLoNCEk5CCl2M4lo"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); - verification - .build(mockOneSecondEarlier) - .verify(token); - }); - assertThat(e.getMessage(), is("The Token can't be used before 1970-01-18T02:26:32Z.")); - assertThat(e.getClaimName(), is(RegisteredClaims.ISSUED_AT)); - assertThat(e.getClaimValue().asLong(), is(1477592L)); - } - - @Test - public void shouldOverrideAcceptIssuedAtWhenIgnoreIssuedAtFlagPassedAndSkipTheVerification() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0Nzc1OTJ9.0WJky9eLN7kuxLyZlmbcXRL3Wy8hLoNCEk5CCl2M4lo"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")) - .acceptIssuedAt(1) - .ignoreIssuedAt(); - DecodedJWT jwt = verification - .build(mockOneSecondEarlier) - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldValidateIssuedAtIfPresent() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0Nzc1OTJ9.0WJky9eLN7kuxLyZlmbcXRL3Wy8hLoNCEk5CCl2M4lo"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); - DecodedJWT jwt = verification - .build(mockNow) - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldThrowOnNegativeIssuedAtLeeway() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Leeway value can't be negative."); - Algorithm algorithm = mock(Algorithm.class); - JWTVerifier.init(algorithm) - .acceptIssuedAt(-1); - } - - @Test - public void shouldValidateJWTId() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJqd3RfaWRfMTIzIn0.0kegfXUvwOYioP8PDaLMY1IlV8HOAzSVz3EGL7-jWF4"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withJWTId("jwt_id_123") - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldThrowOnInvalidJWTId() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJqd3RfaWRfMTIzIn0.0kegfXUvwOYioP8PDaLMY1IlV8HOAzSVz3EGL7-jWF4"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withJWTId("invalid") - .build() - .verify(token); - }); - assertThat(e.getMessage(), is("The Claim 'jti' value doesn't match the required one.")); - assertThat(e.getClaimName(), is("jti")); - assertThat(e.getClaimValue().asString(), is("jwt_id_123")); - } - - @Test - public void shouldNotRemoveClaimWhenPassingNull() { - Algorithm algorithm = mock(Algorithm.class); - JWTVerifier verifier = JWTVerifier.init(algorithm) - .withIssuer("iss") - .withIssuer((String) null) - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks.size(), is(5)); - - verifier = JWTVerifier.init(algorithm) - .withIssuer("iss") - .withIssuer((String[]) null) - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks.size(), is(5)); - } - - @Test - public void shouldNotRemoveIssuerWhenPassingNullReference() { - Algorithm algorithm = mock(Algorithm.class); - JWTVerifier verifier = JWTVerifier.init(algorithm) - .withIssuer((String) null) - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks.size(), is(4)); - - verifier = JWTVerifier.init(algorithm) - .withIssuer((String[]) null) - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks.size(), is(4)); - - verifier = JWTVerifier.init(algorithm) - .withIssuer() - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks.size(), is(4)); - - String emptyIss = " "; - verifier = JWTVerifier.init(algorithm) - .withIssuer(emptyIss) - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - } - - @Test - public void shouldSkipClaimValidationsIfNoClaimsRequired() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.t-IDcSemACt8x4iTMCda8Yhe3iZaWbvV5XKSTbuAn0M"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .build() - .verify(token); - - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldThrowWhenVerifyingClaimPresenceButClaimNotPresent() { - MissingClaimException e = assertThrows(null, MissingClaimException.class, () -> { - String jwt = JWTCreator.init() - .withClaim("custom", "") - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaimPresence("missing") - .build(); - - verifier.verify(jwt); - }); - assertThat(e.getMessage(), is("The Claim 'missing' is not present in the JWT.")); - assertThat(e.getClaimName(), is("missing")); - } - - @Test - public void shouldThrowWhenVerifyingClaimPresenceWhenClaimNameIsNull() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("The Custom Claim's name can't be null."); - - JWTCreator.init() - .withClaim("custom", "value") - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaimPresence(null); - } - - @Test - public void shouldVerifyStringClaimPresence() { - String jwt = JWTCreator.init() - .withClaim("custom", "") - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaimPresence("custom") - .build(); - - DecodedJWT decodedJWT = verifier.verify(jwt); - assertThat(decodedJWT, is(notNullValue())); - } - - @Test - public void shouldVerifyBooleanClaimPresence() { - String jwt = JWTCreator.init() - .withClaim("custom", true) - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaimPresence("custom") - .build(); - - DecodedJWT decodedJWT = verifier.verify(jwt); - assertThat(decodedJWT, is(notNullValue())); - } - - @Test - public void shouldVerifyIntegerClaimPresence() { - String jwt = JWTCreator.init() - .withClaim("custom", 123) - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaimPresence("custom") - .build(); - - DecodedJWT decodedJWT = verifier.verify(jwt); - assertThat(decodedJWT, is(notNullValue())); - } - - @Test - public void shouldVerifyLongClaimPresence() { - String jwt = JWTCreator.init() - .withClaim("custom", 922337203685477600L) - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaimPresence("custom") - .build(); - - DecodedJWT decodedJWT = verifier.verify(jwt); - assertThat(decodedJWT, is(notNullValue())); - } - - @Test - public void shouldVerifyDoubleClaimPresence() { - String jwt = JWTCreator.init() - .withClaim("custom", 12.34) - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaimPresence("custom") - .build(); - - DecodedJWT decodedJWT = verifier.verify(jwt); - assertThat(decodedJWT, is(notNullValue())); - } - - @Test - public void shouldVerifyListClaimPresence() { - String jwt = JWTCreator.init() - .withClaim("custom", Collections.singletonList("item")) - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaimPresence("custom") - .build(); - - DecodedJWT decodedJWT = verifier.verify(jwt); - assertThat(decodedJWT, is(notNullValue())); - } - - @Test - public void shouldVerifyMapClaimPresence() { - String jwt = JWTCreator.init() - .withClaim("custom", Collections.singletonMap("key", "value")) - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaimPresence("custom") - .build(); - - DecodedJWT decodedJWT = verifier.verify(jwt); - assertThat(decodedJWT, is(notNullValue())); - } - - @Test - public void shouldVerifyStandardClaimPresence() { - String jwt = JWTCreator.init() - .withClaim("aud", "any value") - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaimPresence("aud") - .build(); - - DecodedJWT decodedJWT = verifier.verify(jwt); - assertThat(decodedJWT, is(notNullValue())); - } - - @Test - public void shouldSuccessfullyVerifyClaimWithPredicate() { - String jwt = JWTCreator.init() - .withClaim("claimName", "claimValue") - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("claimName", (claim, decodedJWT) -> "claimValue".equals(claim.asString())) - .build(); - - DecodedJWT decodedJWT = verifier.verify(jwt); - assertThat(decodedJWT, is(notNullValue())); - } - - @Test - public void shouldThrowWhenPredicateReturnsFalse() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String jwt = JWTCreator.init() - .withClaim("claimName", "claimValue") - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("claimName", (claim, decodedJWT) -> "nope".equals(claim.asString())) - .build() - .verify(jwt); - }); - assertThat(e.getMessage(), is("The Claim 'claimName' value doesn't match the required one.")); - assertThat(e.getClaimName(), is("claimName")); - assertThat(e.getClaimValue().asString(), is("claimValue")); - } - - @Test - public void shouldNotRemovePredicateCheckForNull() { - JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("claimName", (claim, decodedJWT) -> "nope".equals(claim.asString())) - .withClaim("claimName", (BiPredicate) null) - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks.size(), is(5)); - } - - @Test - public void shouldSuccessfullyVerifyClaimWithNull() { - String jwt = JWTCreator.init() - .withNullClaim("claimName") - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withNullClaim("claimName") - .build(); - - DecodedJWT decodedJWT = verifier.verify(jwt); - assertThat(decodedJWT, is(notNullValue())); - } - - @Test - public void shouldThrowWhenNullClaimHasValue() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String jwt = JWTCreator.init() - .withClaim("claimName", "value") - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withNullClaim("claimName") - .build() - .verify(jwt); - }); - assertThat(e.getMessage(), is("The Claim 'claimName' value doesn't match the required one.")); - assertThat(e.getClaimName(), is("claimName")); - assertThat(e.getClaimValue().asString(), is("value")); - } - - @Test - public void shouldThrowWhenNullClaimIsMissing() { - MissingClaimException e = assertThrows(null, MissingClaimException.class, () -> { - String jwt = JWTCreator.init() - .withClaim("claimName", "value") - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withNullClaim("anotherClaimName") - .build() - .verify(jwt); - }); - assertThat(e.getMessage(), is("The Claim 'anotherClaimName' is not present in the JWT.")); - assertThat(e.getClaimName(), is("anotherClaimName")); - } - - @Test - public void shouldCheckForNullValuesForSubject() { - // sub = null - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOm51bGx9.y5brmQQ05OYwVvlTg83njUrz6tfpdyWNh17LHU6DxmI"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withSubject(null) - .build() - .verify(token); - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldCheckForNullValuesInIssuer() { - // iss = null - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOm51bGx9.OoiCLipSfflWxkFX2rytvtwEiJ8eAL0opkdXY_ap0qA"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withIssuer((String) null) - .withIssuer((String[]) null) - .withIssuer() - .build() - .verify(token); - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldCheckForNullValuesInJwtId() { - // jti = null - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOm51bGx9.z_MDyl8uPGH0q0jeB54wbYt3bwKXamU_3MO8LofGvZs"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withJWTId(null) - .build() - .verify(token); - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldCheckForNullValuesInCustomClaims() { - // jti = null - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b20iOm51bGx9.inAuN3Q9UZ6WgbB63O43B1ero2MTqnfzzumr_5qYIls"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("custom", (Boolean) null) - .withClaim("custom", (Integer) null) - .withClaim("custom", (Long) null) - .withClaim("custom", (Double) null) - .withClaim("custom", (String) null) - .withClaim("custom", (Date) null) - .withClaim("custom", (Instant) null) - .withClaim("custom", (BiPredicate) null) - .withArrayClaim("custom", (String[]) null) - .withArrayClaim("custom", (Integer[]) null) - .withArrayClaim("custom", (Long[]) null) - .build() - .verify(token); - assertThat(jwt, is(notNullValue())); - } - - - @Test - public void shouldCheckForNullValuesForAudience() { - // aud = null - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiYXVkIjpudWxsfQ.bpPyquk3b8KepErKgTidjJ1ZwiOGuoTxam2_x7cElKI"; - DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withAudience((String[]) null) - .withAudience((String) null) - .withAudience() - .withAnyOfAudience((String[]) null) - .withAnyOfAudience((String) null) - .withAnyOfAudience() - .build() - .verify(token); - assertThat(jwt, is(notNullValue())); - } - - @Test - public void shouldCheckForClaimPresenceEvenForNormalClaimChecks() { - MissingClaimException e = assertThrows(null, MissingClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiYXVkIjpudWxsfQ.bpPyquk3b8KepErKgTidjJ1ZwiOGuoTxam2_x7cElKI"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("custom", true) - .build() - .verify(token); - }); - assertThat(e.getClaimName(), is("custom")); - } - - @Test - public void shouldCheckForWrongLongClaim() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b20iOjF9.00btiK0sv8pQ2T-hOr9GC5x2osi7--Bsk4pS5cTikqQ"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("custom", 2L) - .build() - .verify(token); - }); - assertThat(e.getClaimName(), is("custom")); - assertThat(e.getClaimValue().asLong(), is(1L)); - } - - @Test - public void shouldCheckForWrongLongArrayClaim() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b20iOlsxXX0.R9ZSmgtJng062rcEc59u4VKCq89Yk5VlkN9BuMTMvr0"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withArrayClaim("custom", 2L) - .build() - .verify(token); - }); - assertThat(e.getClaimName(), is("custom")); - } - - @Test - public void shouldCheckForWrongStringArrayClaim() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b20iOlsxXX0.R9ZSmgtJng062rcEc59u4VKCq89Yk5VlkN9BuMTMvr0"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withArrayClaim("custom", "2L") - .build() - .verify(token); - }); - assertThat(e.getClaimName(), is("custom")); - } - - @Test - public void shouldCheckForWrongIntegerArrayClaim() { - IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b20iOlsxXX0.R9ZSmgtJng062rcEc59u4VKCq89Yk5VlkN9BuMTMvr0"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withArrayClaim("custom", 2) - .build() - .verify(token); - }); - assertThat(e.getClaimName(), is("custom")); - } -} diff --git a/lib/src/test/java/com/auth0/jwt/JsonMatcher.java b/lib/src/test/java/com/auth0/jwt/JsonMatcher.java deleted file mode 100644 index b09ab187..00000000 --- a/lib/src/test/java/com/auth0/jwt/JsonMatcher.java +++ /dev/null @@ -1,140 +0,0 @@ -package com.auth0.jwt; - -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeDiagnosingMatcher; - -import java.lang.reflect.Array; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -public class JsonMatcher extends TypeSafeDiagnosingMatcher { - - private final String entry; - private final String key; - private final Matcher matcher; - - private JsonMatcher(String key, Object value, Matcher valueMatcher) { - this.key = key; - this.matcher = valueMatcher; - if (value != null) { - String stringValue = objectToString(value); - entry = getStringKey(key) + stringValue; - } else { - entry = null; - } - } - - @Override - protected boolean matchesSafely(String item, Description mismatchDescription) { - if (item == null) { - mismatchDescription.appendText("JSON was null"); - return false; - } - if (matcher != null) { - if (!matcher.matches(item)) { - matcher.describeMismatch(item, mismatchDescription); - return false; - } - if (!item.contains(getStringKey(key))) { - mismatchDescription.appendText("JSON didn't contained the key ").appendValue(key); - return false; - } - } - if (entry != null && !item.contains(entry)) { - mismatchDescription.appendText("JSON was ").appendValue(item); - return false; - } - - return true; - } - - @Override - public void describeTo(Description description) { - if (matcher == null) { - description.appendText("A JSON with entry ") - .appendValue(entry); - } else { - matcher.describeTo(description); - } - } - - public static JsonMatcher hasEntry(String key, Object value) { - return new JsonMatcher(key, value, null); - } - - public static JsonMatcher hasEntry(String key, Matcher valueMatcher) { - return new JsonMatcher(key, null, valueMatcher); - } - - public static JsonMatcher isNotPresent(String key) { - return new JsonMatcher(key, null, null); - } - - private String getStringKey(String key) { - return "\"" + key + "\":"; - } - - private String objectToString(Object value) { - String stringValue; - if (value == null) { - stringValue = "null"; - } else if (value instanceof String) { - stringValue = "\"" + value + "\""; - } else if (value instanceof Map) { - stringValue = mapToString((Map) value); - } else if (value instanceof Array) { - stringValue = arrayToString((Object[]) value); - } else if (value instanceof List) { - stringValue = listToString((List) value); - } else { - stringValue = value.toString(); - } - return stringValue; - } - - private String arrayToString(Object[] array) { - StringBuilder sb = new StringBuilder(); - sb.append("["); - for (int i = 0; i < array.length; i++) { - Object o = array[i]; - sb.append(objectToString(o)); - if (i + 1 < array.length) { - sb.append(","); - } - } - sb.append("]"); - return sb.toString(); - } - - private String listToString(List list) { - StringBuilder sb = new StringBuilder(); - sb.append("["); - Iterator it = list.iterator(); - while (it.hasNext()) { - Object o = it.next(); - sb.append(objectToString(o)); - if (it.hasNext()) { - sb.append(","); - } - } - sb.append("]"); - return sb.toString(); - } - - private String mapToString(Map map) { - StringBuilder sb = new StringBuilder(); - sb.append("{"); - Iterator> it = map.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry e = it.next(); - sb.append("\"" + e.getKey() + "\":" + objectToString(e.getValue())); - if (it.hasNext()) { - sb.append(","); - } - } - sb.append("}"); - return sb.toString(); - } -} \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/PemUtils.java b/lib/src/test/java/com/auth0/jwt/PemUtils.java deleted file mode 100644 index 6c92e05e..00000000 --- a/lib/src/test/java/com/auth0/jwt/PemUtils.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.auth0.jwt; - -import org.bouncycastle.util.io.pem.PemObject; -import org.bouncycastle.util.io.pem.PemReader; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.spec.EncodedKeySpec; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; - -public class PemUtils { - - private static byte[] parsePEMFile(File pemFile) throws IOException { - if (!pemFile.isFile() || !pemFile.exists()) { - throw new FileNotFoundException(String.format("The file '%s' doesn't exist.", pemFile.getAbsolutePath())); - } - PemReader reader = new PemReader(new FileReader(pemFile)); - PemObject pemObject = reader.readPemObject(); - byte[] content = pemObject.getContent(); - reader.close(); - return content; - } - - private static PublicKey getPublicKey(byte[] keyBytes, String algorithm) { - PublicKey publicKey = null; - try { - KeyFactory kf = KeyFactory.getInstance(algorithm); - EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); - publicKey = kf.generatePublic(keySpec); - } catch (NoSuchAlgorithmException e) { - System.out.println("Could not reconstruct the public key, the given algorithm could not be found."); - } catch (InvalidKeySpecException e) { - System.out.println("Could not reconstruct the public key"); - } - - return publicKey; - } - - private static PrivateKey getPrivateKey(byte[] keyBytes, String algorithm) { - PrivateKey privateKey = null; - try { - KeyFactory kf = KeyFactory.getInstance(algorithm); - EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); - privateKey = kf.generatePrivate(keySpec); - } catch (NoSuchAlgorithmException e) { - System.out.println("Could not reconstruct the private key, the given algorithm could not be found."); - } catch (InvalidKeySpecException e) { - System.out.println("Could not reconstruct the private key"); - } - - return privateKey; - } - - public static PublicKey readPublicKeyFromFile(String filepath, String algorithm) throws IOException { - byte[] bytes = PemUtils.parsePEMFile(new File(filepath)); - return PemUtils.getPublicKey(bytes, algorithm); - } - - public static PrivateKey readPrivateKeyFromFile(String filepath, String algorithm) throws IOException { - byte[] bytes = PemUtils.parsePEMFile(new File(filepath)); - return PemUtils.getPrivateKey(bytes, algorithm); - } - -} diff --git a/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java b/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java deleted file mode 100644 index 01806ddc..00000000 --- a/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.auth0.jwt; - -import com.auth0.jwt.exceptions.JWTDecodeException; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import static org.hamcrest.Matchers.*; -import static org.hamcrest.MatcherAssert.assertThat; - -public class TokenUtilsTest { - - @Rule - public ExpectedException exception = ExpectedException.none(); - - @Test - public void toleratesEmptyFirstPart() { - String token = ".eyJpc3MiOiJhdXRoMCJ9.W1mx_Y0hbAMbPmfW9whT605AAcxB7REFuJiDAHk2Sdc"; - String[] parts = TokenUtils.splitToken(token); - - assertThat(parts, is(notNullValue())); - assertThat(parts, is(arrayWithSize(3))); - assertThat(parts[0], is("")); - assertThat(parts[1], is("eyJpc3MiOiJhdXRoMCJ9")); - assertThat(parts[2], is("W1mx_Y0hbAMbPmfW9whT605AAcxB7REFuJiDAHk2Sdc")); - } - - @Test - public void toleratesEmptySecondPart() { - String token = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0..W1mx_Y0hbAMbPmfW9whT605AAcxB7REFuJiDAHk2Sdc"; - String[] parts = TokenUtils.splitToken(token); - - assertThat(parts, is(notNullValue())); - assertThat(parts, is(arrayWithSize(3))); - assertThat(parts[0], is("eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0")); - assertThat(parts[1], is("")); - assertThat(parts[2], is("W1mx_Y0hbAMbPmfW9whT605AAcxB7REFuJiDAHk2Sdc")); - } - - @Test - public void shouldSplitToken() { - String token = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9.W1mx_Y0hbAMbPmfW9whT605AAcxB7REFuJiDAHk2Sdc"; - String[] parts = TokenUtils.splitToken(token); - - assertThat(parts, is(notNullValue())); - assertThat(parts, is(arrayWithSize(3))); - assertThat(parts[0], is("eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0")); - assertThat(parts[1], is("eyJpc3MiOiJhdXRoMCJ9")); - assertThat(parts[2], is("W1mx_Y0hbAMbPmfW9whT605AAcxB7REFuJiDAHk2Sdc")); - } - - @Test - public void shouldSplitTokenWithEmptySignature() { - String token = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9."; - String[] parts = TokenUtils.splitToken(token); - - assertThat(parts, is(notNullValue())); - assertThat(parts, is(arrayWithSize(3))); - assertThat(parts[0], is("eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0")); - assertThat(parts[1], is("eyJpc3MiOiJhdXRoMCJ9")); - assertThat(parts[2], is(emptyString())); - } - - @Test - public void shouldThrowOnSplitTokenWithMoreThan3Parts() { - exception.expect(JWTDecodeException.class); - exception.expectMessage("The token was expected to have 3 parts, but got > 3."); - String token = "this.has.four.parts"; - TokenUtils.splitToken(token); - } - - @Test - public void shouldThrowOnSplitTokenWithNoParts() { - exception.expect(JWTDecodeException.class); - exception.expectMessage("The token was expected to have 3 parts, but got 0."); - String token = "notajwt"; - TokenUtils.splitToken(token); - } - - @Test - public void shouldThrowOnSplitTokenWith2Parts() { - exception.expect(JWTDecodeException.class); - exception.expectMessage("The token was expected to have 3 parts, but got 2."); - String token = "two.parts"; - TokenUtils.splitToken(token); - } - - @Test - public void shouldThrowOnSplitTokenWithNullValue() { - exception.expect(JWTDecodeException.class); - exception.expectMessage("The token is null."); - TokenUtils.splitToken(null); - } -} \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/UserPojo.java b/lib/src/test/java/com/auth0/jwt/UserPojo.java deleted file mode 100644 index beb72b50..00000000 --- a/lib/src/test/java/com/auth0/jwt/UserPojo.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.auth0.jwt; - -public class UserPojo { - private String name; - private int id; - - @SuppressWarnings("unused") - public UserPojo() { - //Required Empty Constructor - } - - public UserPojo(String name, int id) { - this.name = name; - this.id = id; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - UserPojo userPojo = (UserPojo) o; - - return id == userPojo.id && (name != null ? name.equals(userPojo.name) : userPojo.name == null); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } -} \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java deleted file mode 100644 index e09661d3..00000000 --- a/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java +++ /dev/null @@ -1,576 +0,0 @@ -package com.auth0.jwt.algorithms; - -import com.auth0.jwt.interfaces.ECDSAKeyProvider; -import com.auth0.jwt.interfaces.RSAKeyProvider; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.ArgumentCaptor; - -import java.io.ByteArrayOutputStream; -import java.nio.charset.StandardCharsets; -import java.security.interfaces.*; - -import static org.hamcrest.Matchers.*; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.withSettings; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -public class AlgorithmTest { - - @Rule - public ExpectedException exception = ExpectedException.none(); - - - @Test - public void shouldThrowHMAC256InstanceWithNullSecretBytes() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("The Secret cannot be null"); - byte[] secret = null; - Algorithm.HMAC256(secret); - } - - @Test - public void shouldThrowHMAC384InstanceWithNullSecretBytes() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("The Secret cannot be null"); - byte[] secret = null; - Algorithm.HMAC384(secret); - } - - @Test - public void shouldThrowHMAC512InstanceWithNullSecretBytes() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("The Secret cannot be null"); - byte[] secret = null; - Algorithm.HMAC512(secret); - } - - @Test - public void shouldThrowHMAC256InstanceWithNullSecret() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("The Secret cannot be null"); - String secret = null; - Algorithm.HMAC256(secret); - } - - @Test - public void shouldThrowHMAC384InstanceWithNullSecret() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("The Secret cannot be null"); - String secret = null; - Algorithm.HMAC384(secret); - } - - @Test - public void shouldThrowHMAC512InstanceWithNullSecret() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("The Secret cannot be null"); - String secret = null; - Algorithm.HMAC512(secret); - } - - @Test - public void shouldThrowRSA256InstanceWithNullKey() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Both provided Keys cannot be null."); - RSAKey key = null; - Algorithm.RSA256(key); - } - - @Test - public void shouldThrowRSA256InstanceWithNullKeys() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Both provided Keys cannot be null."); - Algorithm.RSA256(null, null); - } - - @Test - public void shouldThrowRSA256InstanceWithNullKeyProvider() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("The Key Provider cannot be null."); - RSAKeyProvider provider = null; - Algorithm.RSA256(provider); - } - - @Test - public void shouldThrowRSA384InstanceWithNullKey() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Both provided Keys cannot be null."); - RSAKey key = null; - Algorithm.RSA384(key); - } - - @Test - public void shouldThrowRSA384InstanceWithNullKeys() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Both provided Keys cannot be null."); - Algorithm.RSA384(null, null); - } - - @Test - public void shouldThrowRSA384InstanceWithNullKeyProvider() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("The Key Provider cannot be null."); - RSAKeyProvider provider = null; - Algorithm.RSA384(provider); - } - - @Test - public void shouldThrowRSA512InstanceWithNullKey() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Both provided Keys cannot be null."); - RSAKey key = null; - Algorithm.RSA512(key); - } - - @Test - public void shouldThrowRSA512InstanceWithNullKeys() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Both provided Keys cannot be null."); - Algorithm.RSA512(null, null); - } - - @Test - public void shouldThrowRSA512InstanceWithNullKeyProvider() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("The Key Provider cannot be null."); - RSAKeyProvider provider = null; - Algorithm.RSA512(provider); - } - - @Test - public void shouldThrowECDSA256InstanceWithNullKey() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Both provided Keys cannot be null."); - ECKey key = null; - Algorithm.ECDSA256(key); - } - - @Test - public void shouldThrowECDSA256InstanceWithNullKeys() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Both provided Keys cannot be null."); - Algorithm.ECDSA256(null, null); - } - - @Test - public void shouldThrowECDSA256InstanceWithNullKeyProvider() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("The Key Provider cannot be null."); - ECDSAKeyProvider provider = null; - Algorithm.ECDSA256(provider); - } - - @Test - public void shouldThrowECDSA384InstanceWithNullKey() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Both provided Keys cannot be null."); - ECKey key = null; - Algorithm.ECDSA384(key); - } - - @Test - public void shouldThrowECDSA384InstanceWithNullKeys() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Both provided Keys cannot be null."); - Algorithm.ECDSA384(null, null); - } - - @Test - public void shouldThrowECDSA384InstanceWithNullKeyProvider() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("The Key Provider cannot be null."); - ECDSAKeyProvider provider = null; - Algorithm.ECDSA384(provider); - } - - @Test - public void shouldThrowECDSA512InstanceWithNullKey() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Both provided Keys cannot be null."); - ECKey key = null; - Algorithm.ECDSA512(key); - } - - @Test - public void shouldThrowECDSA512InstanceWithNullKeys() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Both provided Keys cannot be null."); - Algorithm.ECDSA512(null, null); - } - - @Test - public void shouldThrowECDSA512InstanceWithNullKeyProvider() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("The Key Provider cannot be null."); - ECDSAKeyProvider provider = null; - Algorithm.ECDSA512(provider); - } - - @Test - public void shouldCreateHMAC256AlgorithmWithBytes() { - Algorithm algorithm = Algorithm.HMAC256("secret".getBytes(StandardCharsets.UTF_8)); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(HMACAlgorithm.class))); - assertThat(algorithm.getDescription(), is("HmacSHA256")); - assertThat(algorithm.getName(), is("HS256")); - } - - @Test - public void shouldCreateHMAC384AlgorithmWithBytes() { - Algorithm algorithm = Algorithm.HMAC384("secret".getBytes(StandardCharsets.UTF_8)); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(HMACAlgorithm.class))); - assertThat(algorithm.getDescription(), is("HmacSHA384")); - assertThat(algorithm.getName(), is("HS384")); - } - - @Test - public void shouldCreateHMAC512AlgorithmWithBytes() { - Algorithm algorithm = Algorithm.HMAC512("secret".getBytes(StandardCharsets.UTF_8)); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(HMACAlgorithm.class))); - assertThat(algorithm.getDescription(), is("HmacSHA512")); - assertThat(algorithm.getName(), is("HS512")); - } - - @Test - public void shouldCreateHMAC256AlgorithmWithString() { - Algorithm algorithm = Algorithm.HMAC256("secret"); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(HMACAlgorithm.class))); - assertThat(algorithm.getDescription(), is("HmacSHA256")); - assertThat(algorithm.getName(), is("HS256")); - } - - @Test - public void shouldCreateHMAC384AlgorithmWithString() { - Algorithm algorithm = Algorithm.HMAC384("secret"); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(HMACAlgorithm.class))); - assertThat(algorithm.getDescription(), is("HmacSHA384")); - assertThat(algorithm.getName(), is("HS384")); - } - - @Test - public void shouldCreateHMAC512AlgorithmWithString() { - Algorithm algorithm = Algorithm.HMAC512("secret"); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(HMACAlgorithm.class))); - assertThat(algorithm.getDescription(), is("HmacSHA512")); - assertThat(algorithm.getName(), is("HS512")); - } - - @Test - public void shouldCreateRSA256AlgorithmWithPublicKey() { - RSAKey key = mock(RSAKey.class, withSettings().extraInterfaces(RSAPublicKey.class)); - Algorithm algorithm = Algorithm.RSA256(key); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(RSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA256withRSA")); - assertThat(algorithm.getName(), is("RS256")); - } - - @Test - public void shouldCreateRSA256AlgorithmWithPrivateKey() { - RSAKey key = mock(RSAKey.class, withSettings().extraInterfaces(RSAPrivateKey.class)); - Algorithm algorithm = Algorithm.RSA256(key); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(RSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA256withRSA")); - assertThat(algorithm.getName(), is("RS256")); - } - - @Test - public void shouldCreateRSA256AlgorithmWithBothKeys() { - RSAPublicKey publicKey = mock(RSAPublicKey.class); - RSAPrivateKey privateKey = mock(RSAPrivateKey.class); - Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(RSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA256withRSA")); - assertThat(algorithm.getName(), is("RS256")); - } - - @Test - public void shouldCreateRSA256AlgorithmWithProvider() { - RSAKeyProvider provider = mock(RSAKeyProvider.class); - Algorithm algorithm = Algorithm.RSA256(provider); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(RSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA256withRSA")); - assertThat(algorithm.getName(), is("RS256")); - } - - @Test - public void shouldCreateRSA384AlgorithmWithPublicKey() { - RSAKey key = mock(RSAKey.class, withSettings().extraInterfaces(RSAPublicKey.class)); - Algorithm algorithm = Algorithm.RSA384(key); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(RSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA384withRSA")); - assertThat(algorithm.getName(), is("RS384")); - } - - @Test - public void shouldCreateRSA384AlgorithmWithPrivateKey() { - RSAKey key = mock(RSAKey.class, withSettings().extraInterfaces(RSAPrivateKey.class)); - Algorithm algorithm = Algorithm.RSA384(key); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(RSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA384withRSA")); - assertThat(algorithm.getName(), is("RS384")); - } - - @Test - public void shouldCreateRSA384AlgorithmWithBothKeys() { - RSAPublicKey publicKey = mock(RSAPublicKey.class); - RSAPrivateKey privateKey = mock(RSAPrivateKey.class); - Algorithm algorithm = Algorithm.RSA384(publicKey, privateKey); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(RSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA384withRSA")); - assertThat(algorithm.getName(), is("RS384")); - } - - @Test - public void shouldCreateRSA384AlgorithmWithProvider() { - RSAKeyProvider provider = mock(RSAKeyProvider.class); - Algorithm algorithm = Algorithm.RSA384(provider); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(RSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA384withRSA")); - assertThat(algorithm.getName(), is("RS384")); - } - - @Test - public void shouldCreateRSA512AlgorithmWithPublicKey() { - RSAKey key = mock(RSAKey.class, withSettings().extraInterfaces(RSAPublicKey.class)); - Algorithm algorithm = Algorithm.RSA512(key); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(RSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA512withRSA")); - assertThat(algorithm.getName(), is("RS512")); - } - - @Test - public void shouldCreateRSA512AlgorithmWithPrivateKey() { - RSAKey key = mock(RSAKey.class, withSettings().extraInterfaces(RSAPrivateKey.class)); - Algorithm algorithm = Algorithm.RSA512(key); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(RSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA512withRSA")); - assertThat(algorithm.getName(), is("RS512")); - } - - @Test - public void shouldCreateRSA512AlgorithmWithBothKeys() { - RSAPublicKey publicKey = mock(RSAPublicKey.class); - RSAPrivateKey privateKey = mock(RSAPrivateKey.class); - Algorithm algorithm = Algorithm.RSA512(publicKey, privateKey); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(RSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA512withRSA")); - assertThat(algorithm.getName(), is("RS512")); - } - - @Test - public void shouldCreateRSA512AlgorithmWithProvider() { - RSAKeyProvider provider = mock(RSAKeyProvider.class); - Algorithm algorithm = Algorithm.RSA512(provider); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(RSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA512withRSA")); - assertThat(algorithm.getName(), is("RS512")); - } - - @Test - public void shouldCreateECDSA256AlgorithmWithPublicKey() { - ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPublicKey.class)); - Algorithm algorithm = Algorithm.ECDSA256(key); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(ECDSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA256withECDSA")); - assertThat(algorithm.getName(), is("ES256")); - } - - @Test - public void shouldCreateECDSA256AlgorithmWithPrivateKey() { - ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPrivateKey.class)); - Algorithm algorithm = Algorithm.ECDSA256(key); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(ECDSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA256withECDSA")); - assertThat(algorithm.getName(), is("ES256")); - } - - @Test - public void shouldCreateECDSA256AlgorithmWithBothKeys() { - ECPublicKey publicKey = mock(ECPublicKey.class); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - Algorithm algorithm = Algorithm.ECDSA256(publicKey, privateKey); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(ECDSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA256withECDSA")); - assertThat(algorithm.getName(), is("ES256")); - } - - @Test - public void shouldCreateECDSA256AlgorithmWithProvider() { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - Algorithm algorithm = Algorithm.ECDSA256(provider); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(ECDSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA256withECDSA")); - assertThat(algorithm.getName(), is("ES256")); - } - - @Test - public void shouldCreateECDSA384AlgorithmWithPublicKey() { - ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPublicKey.class)); - Algorithm algorithm = Algorithm.ECDSA384(key); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(ECDSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA384withECDSA")); - assertThat(algorithm.getName(), is("ES384")); - } - - @Test - public void shouldCreateECDSA384AlgorithmWithPrivateKey() { - ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPrivateKey.class)); - Algorithm algorithm = Algorithm.ECDSA384(key); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(ECDSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA384withECDSA")); - assertThat(algorithm.getName(), is("ES384")); - } - - @Test - public void shouldCreateECDSA384AlgorithmWithBothKeys() { - ECPublicKey publicKey = mock(ECPublicKey.class); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - Algorithm algorithm = Algorithm.ECDSA384(publicKey, privateKey); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(ECDSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA384withECDSA")); - assertThat(algorithm.getName(), is("ES384")); - } - - @Test - public void shouldCreateECDSA384AlgorithmWithProvider() { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - Algorithm algorithm = Algorithm.ECDSA384(provider); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(ECDSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA384withECDSA")); - assertThat(algorithm.getName(), is("ES384")); - } - - @Test - public void shouldCreateECDSA512AlgorithmWithPublicKey() { - ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPublicKey.class)); - Algorithm algorithm = Algorithm.ECDSA512(key); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(ECDSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA512withECDSA")); - assertThat(algorithm.getName(), is("ES512")); - } - - @Test - public void shouldCreateECDSA512AlgorithmWithPrivateKey() { - ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPrivateKey.class)); - Algorithm algorithm = Algorithm.ECDSA512(key); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(ECDSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA512withECDSA")); - assertThat(algorithm.getName(), is("ES512")); - } - - @Test - public void shouldCreateECDSA512AlgorithmWithBothKeys() { - ECPublicKey publicKey = mock(ECPublicKey.class); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - Algorithm algorithm = Algorithm.ECDSA512(publicKey, privateKey); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(ECDSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA512withECDSA")); - assertThat(algorithm.getName(), is("ES512")); - } - - @Test - public void shouldCreateECDSA512AlgorithmWithProvider() { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - Algorithm algorithm = Algorithm.ECDSA512(provider); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(ECDSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA512withECDSA")); - assertThat(algorithm.getName(), is("ES512")); - } - - @Test - public void shouldCreateNoneAlgorithm() { - Algorithm algorithm = Algorithm.none(); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(NoneAlgorithm.class))); - assertThat(algorithm.getDescription(), is("none")); - assertThat(algorithm.getName(), is("none")); - } - - @Test - public void shouldForwardHeaderPayloadSignatureToSiblingSignMethodForBackwardsCompatibility() throws Exception { - Algorithm algorithm = mock(Algorithm.class); - - ArgumentCaptor contentCaptor = ArgumentCaptor.forClass(byte[].class); - - byte[] header = new byte[]{0x00, 0x01, 0x02}; - byte[] payload = new byte[]{0x04, 0x05, 0x06}; - - byte[] signature = new byte[]{0x10, 0x11, 0x12}; - when(algorithm.sign(any(byte[].class), any(byte[].class))).thenCallRealMethod(); - when(algorithm.sign(contentCaptor.capture())).thenReturn(signature); - - byte[] sign = algorithm.sign(header, payload); - - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - bout.write(header); - bout.write('.'); - bout.write(payload); - - assertThat(sign, is(signature)); - assertThat(contentCaptor.getValue(), is(bout.toByteArray())); - } -} \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/CryptoTestHelper.java b/lib/src/test/java/com/auth0/jwt/algorithms/CryptoTestHelper.java deleted file mode 100644 index ef8e65e8..00000000 --- a/lib/src/test/java/com/auth0/jwt/algorithms/CryptoTestHelper.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.auth0.jwt.algorithms; - -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static org.hamcrest.Matchers.*; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.Assert.fail; - -public abstract class CryptoTestHelper { - - private static final Pattern authHeaderPattern = Pattern.compile("^([\\w-]+)\\.([\\w-]+)\\.([\\w-]+)"); - - public static String asJWT(Algorithm algorithm, String header, String payload) { - byte[] signatureBytes = algorithm.sign(header.getBytes(StandardCharsets.UTF_8), payload.getBytes(StandardCharsets.UTF_8)); - String jwtSignature = Base64.getUrlEncoder().withoutPadding().encodeToString(signatureBytes); - return String.format("%s.%s.%s", header, payload, jwtSignature); - } - - public static void assertSignatureValue(String jwt, String expectedSignature) { - String jwtSignature = jwt.substring(jwt.lastIndexOf('.') + 1); - assertThat(jwtSignature, is(expectedSignature)); - } - - public static void assertSignaturePresent(String jwt) { - Matcher matcher = authHeaderPattern.matcher(jwt); - if (!matcher.find() || matcher.groupCount() < 3) { - fail("No signature present in " + jwt); - } - - assertThat(matcher.group(3), not(is(emptyString()))); - } -} diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java deleted file mode 100644 index 2e636c71..00000000 --- a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java +++ /dev/null @@ -1,1352 +0,0 @@ -package com.auth0.jwt.algorithms; - -import com.auth0.jwt.JWT; -import com.auth0.jwt.exceptions.SignatureGenerationException; -import com.auth0.jwt.exceptions.SignatureVerificationException; -import com.auth0.jwt.interfaces.ECDSAKeyProvider; -import com.auth0.jwt.interfaces.JWTVerifier; -import org.hamcrest.Matchers; -import org.hamcrest.collection.IsIn; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.io.ByteArrayOutputStream; -import java.math.BigInteger; -import java.nio.charset.StandardCharsets; -import java.security.*; -import java.security.interfaces.ECKey; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.security.spec.ECParameterSpec; -import java.util.Arrays; -import java.util.Base64; - -import static com.auth0.jwt.PemUtils.readPrivateKeyFromFile; -import static com.auth0.jwt.PemUtils.readPublicKeyFromFile; -import static com.auth0.jwt.algorithms.CryptoTestHelper.asJWT; -import static com.auth0.jwt.algorithms.CryptoTestHelper.assertSignaturePresent; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.Matchers.isA; -import static org.hamcrest.Matchers.nullValue; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class ECDSAAlgorithmTest { - - private static final String PRIVATE_KEY_FILE_256 = "src/test/resources/ec256-key-private.pem"; - private static final String PUBLIC_KEY_FILE_256 = "src/test/resources/ec256-key-public.pem"; - private static final String INVALID_PUBLIC_KEY_FILE_256 = "src/test/resources/ec256-key-public-invalid.pem"; - - private static final String PRIVATE_KEY_FILE_384 = "src/test/resources/ec384-key-private.pem"; - private static final String PUBLIC_KEY_FILE_384 = "src/test/resources/ec384-key-public.pem"; - private static final String INVALID_PUBLIC_KEY_FILE_384 = "src/test/resources/ec384-key-public-invalid.pem"; - - private static final String PRIVATE_KEY_FILE_512 = "src/test/resources/ec512-key-private.pem"; - private static final String PUBLIC_KEY_FILE_512 = "src/test/resources/ec512-key-public.pem"; - private static final String INVALID_PUBLIC_KEY_FILE_512 = "src/test/resources/ec512-key-public-invalid.pem"; - - @Rule - public ExpectedException exception = ExpectedException.none(); - - //JOSE Signatures obtained using Node 'jwa' lib: https://github.com/brianloveswords/node-jwa - //DER Signatures obtained from source JOSE signature using 'ecdsa-sig-formatter' lib: https://github.com/Brightspace/node-ecdsa-sig-formatter - - //These tests use the default preferred SecurityProvider to handle ECDSA algorithms - - // Verify - - @Test - public void shouldPassECDSA256VerificationWithJOSESignature() throws Exception { - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g"; - ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - Algorithm algorithm = Algorithm.ECDSA256(key); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnECDSA256VerificationWithDERSignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.MEYCIQDiJWTf5jShFPj0hpCWn7x1nhxPMjKWCs9MMusS9AIhAMcFPJVLe2A9uvb8hl8sRO2IpGoKDRpDmyH14ixNPAHW"; - ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - Algorithm algorithm = Algorithm.ECDSA256(key); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassECDSA256VerificationWithJOSESignatureWithBothKeys() throws Exception { - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g"; - Algorithm algorithm = Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnECDSA256VerificationWithDERSignatureWithBothKeys() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.MEYCIQDiJWTf5jShFPj0hpCWn7x1nhxPMjKWCs9MMusS9AIhAMcFPJVLe2A9uvb8hl8sRO2IpGoKDRpDmyH14ixNPAHW"; - Algorithm algorithm = Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassECDSA256VerificationWithProvidedPublicKey() throws Exception { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - when(provider.getPublicKeyById("my-key-id")).thenReturn((ECPublicKey) publicKey); - String jwt = "eyJhbGciOiJFUzI1NiIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.D_oU4CB0ZEsxHOjcWnmS3ZJvlTzm6WcGFx-HASxnvcB2Xu2WjI-axqXH9xKq45aPBDs330JpRhJmqBSc2K8MXQ"; - Algorithm algorithm = Algorithm.ECDSA256(provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA256VerificationWhenProvidedPublicKeyIsNull() { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPublicKeyById("my-key-id")).thenReturn(null); - String jwt = "eyJhbGciOiJFUzI1NiIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.D_oU4CB0ZEsxHOjcWnmS3ZJvlTzm6WcGFx-HASxnvcB2Xu2WjI-axqXH9xKq45aPBDs330JpRhJmqBSc2K8MXQ"; - Algorithm algorithm = Algorithm.ECDSA256(provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA256VerificationWithInvalidPublicKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.W9qfN1b80B9hnMo49WL8THrOsf1vEjOhapeFemPMGySzxTcgfyudS5esgeBTO908X5SLdAr5jMwPUPBs9b6nNg"; - Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA256VerificationWhenUsingPrivateKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.W9qfN1b80B9hnMo49WL8THrOsf1vEjOhapeFemPMGySzxTcgfyudS5esgeBTO908X5SLdAr5jMwPUPBs9b6nNg"; - Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA256VerificationOnInvalidJOSESignatureLength() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - byte[] bytes = new byte[63]; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA256VerificationOnInvalidJOSESignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - - byte[] bytes = new byte[64]; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA256VerificationOnInvalidDERSignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - - byte[] bytes = new byte[64]; - bytes[0] = 0x30; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassECDSA384VerificationWithJOSESignature() throws Exception { - String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.50UU5VKNdF1wfykY8jQBKpvuHZoe6IZBJm5NvoB8bR-hnRg6ti-CHbmvoRtlLfnHfwITa_8cJMy6TenMC2g63GQHytc8rYoXqbwtS4R0Ko_AXbLFUmfxnGnMC6v4MS_z"; - ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); - Algorithm algorithm = Algorithm.ECDSA384(key); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnECDSA384VerificationWithDERSignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.MGUCMQDnRRTlUo10XXBKRjyNAEqm4dmh7ohkEmbk2gHxtH6GdGDq2L4IduahG2UtccCMH8CE2vHCTMuk3pzAtoOtxkB8rXPK2KF6m8LUuEdCqPwF2yxVJn8ZxpzAurDEv8w"; - ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); - Algorithm algorithm = Algorithm.ECDSA384(key); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassECDSA384VerificationWithJOSESignatureWithBothKeys() throws Exception { - String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.50UU5VKNdF1wfykY8jQBKpvuHZoe6IZBJm5NvoB8bR-hnRg6ti-CHbmvoRtlLfnHfwITa_8cJMy6TenMC2g63GQHytc8rYoXqbwtS4R0Ko_AXbLFUmfxnGnMC6v4MS_z"; - Algorithm algorithm = Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnECDSA384VerificationWithDERSignatureWithBothKeys() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.MGUCMQDnRRTlUo10XXBKRjyNAEqm4dmh7ohkEmbk2gHxtH6GdGDq2L4IduahG2UccCMH8CE2vHCTMuk3pzAtoOtxkB8rXPK2KF6m8LUuEdCqPwF2yxVJn8ZxpzAurDEv8w"; - Algorithm algorithm = Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassECDSA384VerificationWithProvidedPublicKey() throws Exception { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); - when(provider.getPublicKeyById("my-key-id")).thenReturn((ECPublicKey) publicKey); - String jwt = "eyJhbGciOiJFUzM4NCIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.9kjGuFTPx3ylfpqL0eY9H7TGmPepjQOBKI8UPoEvby6N7dDLF5HxLohosNxxFymNT7LzpeSgOPAB0wJEwG2Nl2ukgdUOpZOf492wog_i5ZcZmAykd3g1QH7onrzd69GU"; - Algorithm algorithm = Algorithm.ECDSA384(provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA384VerificationWhenProvidedPublicKeyIsNull() { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPublicKeyById("my-key-id")).thenReturn(null); - String jwt = "eyJhbGciOiJFUzM4NCIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.9kjGuFTPx3ylfpqL0eY9H7TGmPepjQOBKI8UPoEvby6N7dDLF5HxLohosNxxFymNT7LzpeSgOPAB0wJEwG2Nl2ukgdUOpZOf492wog_i5ZcZmAykd3g1QH7onrzd69GU"; - Algorithm algorithm = Algorithm.ECDSA384(provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA384VerificationWithInvalidPublicKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); - String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9._k5h1KyO-NE0R2_HAw0-XEc0bGT5atv29SxHhOGC9JDqUHeUdptfCK_ljQ01nLVt2OQWT2SwGs-TuyHDFmhPmPGFZ9wboxvq_ieopmYqhQilNAu-WF-frioiRz9733fU"; - Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_384, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA384VerificationWhenUsingPrivateKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9._k5h1KyO-NE0R2_HAw0-XEc0bGT5atv29SxHhOGC9JDqUHeUdptfCK_ljQ01nLVt2OQWT2SwGs-TuyHDFmhPmPGFZ9wboxvq_ieopmYqhQilNAu-WF-frioiRz9733fU"; - Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA384VerificationOnInvalidJOSESignatureLength() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - byte[] bytes = new byte[95]; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_384, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA384VerificationOnInvalidJOSESignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); - - byte[] bytes = new byte[96]; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_384, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA384VerificationOnInvalidDERSignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); - - byte[] bytes = new byte[96]; - new SecureRandom().nextBytes(bytes); - bytes[0] = 0x30; - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_384, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassECDSA512VerificationWithJOSESignature() throws Exception { - String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.AeCJPDIsSHhwRSGZCY6rspi8zekOw0K9qYMNridP1Fu9uhrA1QrG-EUxXlE06yvmh2R7Rz0aE7kxBwrnq8L8aOBCAYAsqhzPeUvyp8fXjjgs0Eto5I0mndE2QHlgcMSFASyjHbU8wD2Rq7ZNzGQ5b2MZfpv030WGUajT-aZYWFUJHVg2"; - ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); - Algorithm algorithm = Algorithm.ECDSA512(key); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnECDSA512VerificationWithDERSignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.MIGIAkIB4Ik8MixIeHBFIZkJjquymLzN6Q7DQr2pgw2uJ0UW726GsDVCsb4RTFeUTTrKaHZHtHPRoTuTEHCuerwvxo4EICQgGALKocz3lL8qfH1444LNBLaOSNJp3RNkB5YHDEhQEsox21PMA9kau2TcxkOW9jGX6b9N9FhlGo0mmWFhVCR1YNg"; - ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); - Algorithm algorithm = Algorithm.ECDSA512(key); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassECDSA512VerificationWithJOSESignatureWithBothKeys() throws Exception { - String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.AeCJPDIsSHhwRSGZCY6rspi8zekOw0K9qYMNridP1Fu9uhrA1QrG-EUxXlE06yvmh2R7Rz0aE7kxBwrnq8L8aOBCAYAsqhzPeUvyp8fXjjgs0Eto5I0mndE2QHlgcMSFASyjHbU8wD2Rq7ZNzGQ5b2MZfpv030WGUajT-aZYWFUJHVg2"; - Algorithm algorithm = Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowECDSA512VerificationWithDERSignatureWithBothKeys() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.MIGIAkIB4Ik8MixIeHBFIZkJjquymLzN6Q7DQr2pgw2uJ0UW726GsDVCsb4RTFeUTTrKaHZHtHPRoTuTEHCuerwvxo4EICQgGALKocz3lL8qfH1444LNBLaOSNJp3RNkB5YHDEhQEsox21PMA9kau2TcxkOW9jGX6b9N9FhlGo0mmWFhVCR1YNg"; - Algorithm algorithm = Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassECDSA512VerificationWithProvidedPublicKey() throws Exception { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); - when(provider.getPublicKeyById("my-key-id")).thenReturn((ECPublicKey) publicKey); - String jwt = "eyJhbGciOiJFUzUxMiIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.AGxEwbsYa2bQ7Y7DAcTQnVD8PmLSlhJ20jg2OfdyPnqdXI8SgBaG6lGciq3_pofFhs1HEoFoJ33Jcluha24oMHIvAfwu8qbv_Wq3L2eI9Q0L0p6ul8Pd_BS8adRa2PgLc36xXGcRc7ID5YH-CYaQfsTp5YIaF0Po3h0QyCoQ6ZiYQkqm"; - Algorithm algorithm = Algorithm.ECDSA512(provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA512VerificationWhenProvidedPublicKeyIsNull() { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPublicKeyById("my-key-id")).thenReturn(null); - String jwt = "eyJhbGciOiJFUzUxMiIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.AGxEwbsYa2bQ7Y7DAcTQnVD8PmLSlhJ20jg2OfdyPnqdXI8SgBaG6lGciq3_pofFhs1HEoFoJ33Jcluha24oMHIvAfwu8qbv_Wq3L2eI9Q0L0p6ul8Pd_BS8adRa2PgLc36xXGcRc7ID5YH-CYaQfsTp5YIaF0Po3h0QyCoQ6ZiYQkqm"; - Algorithm algorithm = Algorithm.ECDSA512(provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA512VerificationWithInvalidPublicKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); - String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.AZgdopFFsN0amCSs2kOucXdpylD31DEm5ChK1PG0_gq5Mf47MrvVph8zHSVuvcrXzcE1U3VxeCg89mYW1H33Y-8iAF0QFkdfTUQIWKNObH543WNMYYssv3OtOj0znPv8atDbaF8DMYAtcT1qdmaSJRhx-egRE9HGZkinPh9CfLLLt58X"; - Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_512, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA512VerificationWhenUsingPrivateKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.AZgdopFFsN0amCSs2kOucXdpylD31DEm5ChK1PG0_gq5Mf47MrvVph8zHSVuvcrXzcE1U3VxeCg89mYW1H33Y-8iAF0QFkdfTUQIWKNObH543WNMYYssv3OtOj0znPv8atDbaF8DMYAtcT1qdmaSJRhx-egRE9HGZkinPh9CfLLLt58X"; - Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA512VerificationOnInvalidJOSESignatureLength() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - byte[] bytes = new byte[131]; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_512, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA512VerificationOnInvalidJOSESignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); - - byte[] bytes = new byte[132]; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_512, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA512VerificationOnInvalidDERSignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); - - byte[] bytes = new byte[132]; - new SecureRandom().nextBytes(bytes); - bytes[0] = 0x30; - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_512, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailJOSEToDERConversionOnInvalidJOSESignatureLength() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - byte[] bytes = new byte[256]; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - - ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new ECDSAAlgorithm("ES256", "SHA256withECDSA", 128, provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnVerifyWhenSignatureAlgorithmDoesNotExists() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: some-alg"); - exception.expectCause(isA(NoSuchAlgorithmException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.verifySignatureFor(anyString(), any(PublicKey.class), any(String.class), any(String.class), any(byte[].class))) - .thenThrow(NoSuchAlgorithmException.class); - - ECPublicKey publicKey = mock(ECPublicKey.class); - when(publicKey.getParams()).thenReturn(mock(ECParameterSpec.class)); - byte[] a = new byte[64]; - Arrays.fill(a, Byte.MAX_VALUE); - when(publicKey.getParams().getOrder()).thenReturn(new BigInteger(a)); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g"; - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnVerifyWhenThePublicKeyIsInvalid() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: some-alg"); - exception.expectCause(isA(InvalidKeyException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.verifySignatureFor(anyString(), any(PublicKey.class), any(String.class), any(String.class), any(byte[].class))) - .thenThrow(InvalidKeyException.class); - - ECPublicKey publicKey = mock(ECPublicKey.class); - when(publicKey.getParams()).thenReturn(mock(ECParameterSpec.class)); - byte[] a = new byte[64]; - Arrays.fill(a, Byte.MAX_VALUE); - when(publicKey.getParams().getOrder()).thenReturn(new BigInteger(a)); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g"; - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnVerifyWhenTheSignatureIsNotPrepared() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: some-alg"); - exception.expectCause(isA(SignatureException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.verifySignatureFor(anyString(), any(PublicKey.class), any(String.class), any(String.class), any(byte[].class))) - .thenThrow(SignatureException.class); - - ECPublicKey publicKey = mock(ECPublicKey.class); - when(publicKey.getParams()).thenReturn(mock(ECParameterSpec.class)); - byte[] a = new byte[64]; - Arrays.fill(a, Byte.MAX_VALUE); - when(publicKey.getParams().getOrder()).thenReturn(new BigInteger(a)); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g"; - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowWhenSignatureNotValidBase64() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectCause(isA(IllegalArgumentException.class)); - - String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.MIGIAkIB4Ik8MixIeHBFIZkJjquymLzN6Q7DQr2pgw2uJ0UW726GsDVCsb4RTFeUTTrKaHZHtHPRoTuTEHCuerwvxo4+EICQgGALKocz3lL8qfH1444LNBLaOSNJp3RNkB5YHDEhQEsox21PMA9kau2TcxkOW9jGX6b9N9FhlGo0mmWFhVCR1YNg"; - ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); - Algorithm algorithm = Algorithm.ECDSA512(key); - algorithm.verify(JWT.decode(jwt)); - } - - //Sign - private static final String ES256Header = "eyJhbGciOiJFUzI1NiJ9"; - private static final String ES384Header = "eyJhbGciOiJFUzM4NCJ9"; - private static final String ES512Header = "eyJhbGciOiJFUzUxMiJ9"; - private static final String auth0IssPayload = "eyJpc3MiOiJhdXRoMCJ9"; - - private static final byte[] ES256HeaderBytes = ES256Header.getBytes(StandardCharsets.UTF_8); - private static final byte[] ES384HeaderBytes = ES384Header.getBytes(StandardCharsets.UTF_8); - private static final byte[] ES512HeaderBytes = ES512Header.getBytes(StandardCharsets.UTF_8); - private static final byte[] auth0IssPayloadBytes = auth0IssPayload.getBytes(StandardCharsets.UTF_8); - - - @Test - public void shouldDoECDSA256Signing() throws Exception { - Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - Algorithm algorithmVerify = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC")); - String jwt = asJWT(algorithm, ES256Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithmVerify.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoECDSA256SigningWithBothKeys() throws Exception { - Algorithm algorithm = Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - byte[] signatureBytes = algorithm.sign(ES256HeaderBytes, auth0IssPayloadBytes); - String jwtSignature = Base64.getUrlEncoder().withoutPadding().encodeToString(signatureBytes); - String jwt = String.format("%s.%s.%s", ES256Header, auth0IssPayload, jwtSignature); - - assertSignaturePresent(jwt); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoECDSA256SigningWithProvidedPrivateKey() throws Exception { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - PrivateKey privateKey = readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - when(provider.getPrivateKey()).thenReturn((ECPrivateKey) privateKey); - when(provider.getPublicKeyById(null)).thenReturn((ECPublicKey) publicKey); - Algorithm algorithm = Algorithm.ECDSA256(provider); - - String jwt = asJWT(algorithm, ES256Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailOnECDSA256SigningWhenProvidedPrivateKeyIsNull() { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPrivateKey()).thenReturn(null); - Algorithm algorithm = Algorithm.ECDSA256(provider); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldFailOnECDSA256SigningWhenUsingPublicKey() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC")); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldDoECDSA384Signing() throws Exception { - Algorithm algorithmSign = Algorithm.ECDSA384((ECKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); - Algorithm algorithmVerify = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC")); - String jwt = asJWT(algorithmSign, ES384Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithmVerify.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoECDSA384SigningWithBothKeys() throws Exception { - Algorithm algorithm = Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); - String jwt = asJWT(algorithm, ES384Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoECDSA384SigningWithProvidedPrivateKey() throws Exception { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - PrivateKey privateKey = readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC"); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); - when(provider.getPrivateKey()).thenReturn((ECPrivateKey) privateKey); - when(provider.getPublicKeyById(null)).thenReturn((ECPublicKey) publicKey); - Algorithm algorithm = Algorithm.ECDSA384(provider); - - String jwt = asJWT(algorithm, ES384Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailOnECDSA384SigningWhenProvidedPrivateKeyIsNull() { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA384withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPrivateKey()).thenReturn(null); - Algorithm algorithm = Algorithm.ECDSA384(provider); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldFailOnECDSA384SigningWhenUsingPublicKey() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA384withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC")); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldDoECDSA512Signing() throws Exception { - Algorithm algorithmSign = Algorithm.ECDSA512((ECKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); - Algorithm algorithmVerify = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC")); - - String jwt = asJWT(algorithmSign, ES512Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithmVerify.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoECDSA512SigningWithBothKeys() throws Exception { - Algorithm algorithm = Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); - - String jwt = asJWT(algorithm, ES512Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithm.verify(JWT.decode(jwt)); - } - - - @Test - public void shouldDoECDSA512SigningWithProvidedPrivateKey() throws Exception { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - PrivateKey privateKey = readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC"); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); - when(provider.getPrivateKey()).thenReturn((ECPrivateKey) privateKey); - when(provider.getPublicKeyById(null)).thenReturn((ECPublicKey) publicKey); - Algorithm algorithm = Algorithm.ECDSA512(provider); - - String jwt = asJWT(algorithm, ES512Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailOnECDSA512SigningWhenProvidedPrivateKeyIsNull() { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA512withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPrivateKey()).thenReturn(null); - Algorithm algorithm = Algorithm.ECDSA512(provider); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldFailOnECDSA512SigningWhenUsingPublicKey() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA512withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC")); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldThrowOnSignWhenSignatureAlgorithmDoesNotExists() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: some-algorithm"); - exception.expectCause(isA(NoSuchAlgorithmException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.createSignatureFor(anyString(), any(PrivateKey.class), any(byte[].class), any(byte[].class))) - .thenThrow(NoSuchAlgorithmException.class); - - ECPublicKey publicKey = mock(ECPublicKey.class); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); - algorithm.sign(ES256HeaderBytes, new byte[0]); - } - - @Test - public void shouldThrowOnSignWhenThePrivateKeyIsInvalid() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: some-algorithm"); - exception.expectCause(isA(InvalidKeyException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.createSignatureFor(anyString(), any(PrivateKey.class), any(byte[].class), any(byte[].class))) - .thenThrow(InvalidKeyException.class); - - ECPublicKey publicKey = mock(ECPublicKey.class); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); - algorithm.sign(ES256HeaderBytes, new byte[0]); - } - - @Test - public void shouldThrowOnSignWhenTheSignatureIsNotPrepared() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: some-algorithm"); - exception.expectCause(isA(SignatureException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.createSignatureFor(anyString(), any(PrivateKey.class), any(byte[].class), any(byte[].class))) - .thenThrow(SignatureException.class); - - ECPublicKey publicKey = mock(ECPublicKey.class); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); - algorithm.sign(ES256HeaderBytes, new byte[0]); - } - - @Test - public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() { - ECPublicKey publicKey = mock(ECPublicKey.class); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new ECDSAAlgorithm("some-alg", "some-algorithm", 32, provider); - - assertThat(algorithm.getSigningKeyId(), is(nullValue())); - } - - @Test - public void shouldReturnSigningKeyIdFromProvider() { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPrivateKeyId()).thenReturn("keyId"); - Algorithm algorithm = new ECDSAAlgorithm("some-alg", "some-algorithm", 32, provider); - - assertThat(algorithm.getSigningKeyId(), is("keyId")); - } - - @Test - public void shouldThrowOnDERSignatureConversionIfDoesNotStartWithCorrectSequenceByte() throws Exception { - exception.expect(SignatureException.class); - exception.expectMessage("Invalid DER signature format."); - - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - String content256 = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9"; - - byte[] signature = algorithm256.sign(content256.getBytes(), new byte[0]); - signature[0] = (byte) 0x02; - algorithm256.DERToJOSE(signature); - } - - @Test - public void shouldThrowOnDERSignatureConversionIfDoesNotHaveExpectedLength() throws Exception { - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - byte[] derSignature = createDERSignature(32, false, false); - int received = (int) derSignature[1]; - received--; - derSignature[1] = (byte) received; - exception.expect(SignatureException.class); - exception.expectMessage("Invalid DER signature format."); - - algorithm256.DERToJOSE(derSignature); - } - - @Test - public void shouldThrowOnDERSignatureConversionIfRNumberDoesNotHaveExpectedLength() throws Exception { - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - byte[] derSignature = createDERSignature(32, false, false); - derSignature[3] = (byte) 34; - exception.expect(SignatureException.class); - exception.expectMessage("Invalid DER signature format."); - - algorithm256.DERToJOSE(derSignature); - } - - @Test - public void shouldThrowOnDERSignatureConversionIfSNumberDoesNotHaveExpectedLength() throws Exception { - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - byte[] derSignature = createDERSignature(32, false, false); - derSignature[4 + 32 + 1] = (byte) 34; - exception.expect(SignatureException.class); - exception.expectMessage("Invalid DER signature format."); - - algorithm256.DERToJOSE(derSignature); - } - - @Test - public void shouldThrowOnJOSESignatureConversionIfDoesNotHaveExpectedLength() throws Exception { - ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256(publicKey, (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - byte[] joseSignature = new byte[32 * 2 - 1]; - exception.expect(SignatureException.class); - exception.expectMessage("Invalid JOSE signature format."); - - algorithm256.validateSignatureStructure(joseSignature, publicKey); - } - - @Test - public void shouldSignAndVerifyWithECDSA256() throws Exception { - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - String header256 = "eyJhbGciOiJFUzI1NiJ9"; - String body = "eyJpc3MiOiJhdXRoMCJ9"; - - for (int i = 0; i < 10; i++) { - String jwt = asJWT(algorithm256, header256, body); - algorithm256.verify(JWT.decode(jwt)); - } - } - - @Test - public void shouldSignAndVerifyWithECDSA384() throws Exception { - ECDSAAlgorithm algorithm384 = (ECDSAAlgorithm) Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); - String header384 = "eyJhbGciOiJFUzM4NCJ9"; - String body = "eyJpc3MiOiJhdXRoMCJ9"; - - for (int i = 0; i < 10; i++) { - String jwt = asJWT(algorithm384, header384, body); - algorithm384.verify(JWT.decode(jwt)); - } - } - - @Test - public void shouldSignAndVerifyWithECDSA512() throws Exception { - ECDSAAlgorithm algorithm512 = (ECDSAAlgorithm) Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); - String header512 = "eyJhbGciOiJFUzUxMiJ9"; - String body = "eyJpc3MiOiJhdXRoMCJ9"; - - for (int i = 0; i < 10; i++) { - String jwt = asJWT(algorithm512, header512, body); - algorithm512.verify(JWT.decode(jwt)); - } - } - - @Test - public void shouldDecodeECDSA256JOSE() throws Exception { - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - - //Without padding - byte[] joseSignature = createJOSESignature(32, false, false); - byte[] derSignature = algorithm256.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 32, false, false); - - //With R padding - joseSignature = createJOSESignature(32, true, false); - derSignature = algorithm256.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 32, true, false); - - //With S padding - joseSignature = createJOSESignature(32, false, true); - derSignature = algorithm256.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 32, false, true); - - //With both paddings - joseSignature = createJOSESignature(32, true, true); - derSignature = algorithm256.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 32, true, true); - } - - @Test - public void shouldDecodeECDSA256DER() throws Exception { - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - - //Without padding - byte[] derSignature = createDERSignature(32, false, false); - byte[] joseSignature = algorithm256.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 32, false, false); - - //With R padding - derSignature = createDERSignature(32, true, false); - joseSignature = algorithm256.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 32, true, false); - - //With S padding - derSignature = createDERSignature(32, false, true); - joseSignature = algorithm256.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 32, false, true); - - //With both paddings - derSignature = createDERSignature(32, true, true); - joseSignature = algorithm256.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 32, true, true); - } - - @Test - public void shouldDecodeECDSA384JOSE() throws Exception { - ECDSAAlgorithm algorithm384 = (ECDSAAlgorithm) Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); - - //Without padding - byte[] joseSignature = createJOSESignature(48, false, false); - byte[] derSignature = algorithm384.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 48, false, false); - - //With R padding - joseSignature = createJOSESignature(48, true, false); - derSignature = algorithm384.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 48, true, false); - - //With S padding - joseSignature = createJOSESignature(48, false, true); - derSignature = algorithm384.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 48, false, true); - - //With both paddings - joseSignature = createJOSESignature(48, true, true); - derSignature = algorithm384.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 48, true, true); - } - - @Test - public void shouldDecodeECDSA384DER() throws Exception { - ECDSAAlgorithm algorithm384 = (ECDSAAlgorithm) Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); - - //Without padding - byte[] derSignature = createDERSignature(48, false, false); - byte[] joseSignature = algorithm384.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 48, false, false); - - //With R padding - derSignature = createDERSignature(48, true, false); - joseSignature = algorithm384.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 48, true, false); - - //With S padding - derSignature = createDERSignature(48, false, true); - joseSignature = algorithm384.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 48, false, true); - - //With both paddings - derSignature = createDERSignature(48, true, true); - joseSignature = algorithm384.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 48, true, true); - } - - @Test - public void shouldDecodeECDSA512JOSE() throws Exception { - ECDSAAlgorithm algorithm512 = (ECDSAAlgorithm) Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); - - //Without padding - byte[] joseSignature = createJOSESignature(66, false, false); - byte[] derSignature = algorithm512.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 66, false, false); - - //With R padding - joseSignature = createJOSESignature(66, true, false); - derSignature = algorithm512.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 66, true, false); - - //With S padding - joseSignature = createJOSESignature(66, false, true); - derSignature = algorithm512.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 66, false, true); - - //With both paddings - joseSignature = createJOSESignature(66, true, true); - derSignature = algorithm512.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 66, true, true); - } - - @Test - public void shouldDecodeECDSA512DER() throws Exception { - ECDSAAlgorithm algorithm512 = (ECDSAAlgorithm) Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); - - //Without padding - byte[] derSignature = createDERSignature(66, false, false); - byte[] joseSignature = algorithm512.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 66, false, false); - - //With R padding - derSignature = createDERSignature(66, true, false); - joseSignature = algorithm512.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 66, true, false); - - //With S padding - derSignature = createDERSignature(66, false, true); - joseSignature = algorithm512.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 66, false, true); - - //With both paddings - derSignature = createDERSignature(66, true, true); - joseSignature = algorithm512.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 66, true, true); - } - - - //Test Helpers - static void assertValidJOSESignature(byte[] joseSignature, int numberSize, boolean withRPadding, boolean withSPadding) { - assertThat(joseSignature, is(Matchers.notNullValue())); - assertThat(numberSize, is(IsIn.oneOf(32, 48, 66))); - - assertThat(joseSignature.length, is(numberSize * 2)); - - byte[] rCopy = Arrays.copyOfRange(joseSignature, 0, numberSize); - byte[] sCopy = Arrays.copyOfRange(joseSignature, numberSize, numberSize * 2); - - byte[] rNumber = new byte[numberSize]; - byte[] sNumber = new byte[numberSize]; - Arrays.fill(rNumber, (byte) 0x11); - Arrays.fill(sNumber, (byte) 0x22); - if (withRPadding) { - rNumber[0] = (byte) 0; - } - if (withSPadding) { - sNumber[0] = (byte) 0; - } - assertThat(Arrays.equals(rNumber, rCopy), is(true)); - assertThat(Arrays.equals(sNumber, sCopy), is(true)); - } - - static byte[] createDERSignature(int numberSize, boolean withRPadding, boolean withSPadding) { - assertThat(numberSize, is(IsIn.oneOf(32, 48, 66))); - - int rLength = withRPadding ? numberSize - 1 : numberSize; - int sLength = withSPadding ? numberSize - 1 : numberSize; - int totalLength = 2 + (2 + rLength) + (2 + sLength); - - byte[] rNumber = new byte[rLength]; - byte[] sNumber = new byte[sLength]; - Arrays.fill(rNumber, (byte) 0x11); - Arrays.fill(sNumber, (byte) 0x22); - - byte[] derSignature; - int offset = 0; - if (totalLength > 0x7f) { - totalLength++; - derSignature = new byte[totalLength]; - //Start sequence and sign - derSignature[offset++] = (byte) 0x30; - derSignature[offset++] = (byte) 0x81; - } else { - derSignature = new byte[totalLength]; - //Start sequence - derSignature[offset++] = (byte) 0x30; - } - - //Sequence length - derSignature[offset++] = (byte) (totalLength - offset); - - //R number - derSignature[offset++] = (byte) 0x02; - derSignature[offset++] = (byte) rLength; - System.arraycopy(rNumber, 0, derSignature, offset, rLength); - offset += rLength; - - //S number - derSignature[offset++] = (byte) 0x02; - derSignature[offset++] = (byte) sLength; - System.arraycopy(sNumber, 0, derSignature, offset, sLength); - - return derSignature; - } - - static byte[] createJOSESignature(int numberSize, boolean withRPadding, boolean withSPadding) { - assertThat(numberSize, is(IsIn.oneOf(32, 48, 66))); - - byte[] rNumber = new byte[numberSize]; - byte[] sNumber = new byte[numberSize]; - Arrays.fill(rNumber, (byte) 0x11); - Arrays.fill(sNumber, (byte) 0x22); - if (withRPadding) { - rNumber[0] = (byte) 0; - } - if (withSPadding) { - sNumber[0] = (byte) 0; - } - byte[] joseSignature = new byte[numberSize * 2]; - System.arraycopy(rNumber, 0, joseSignature, 0, numberSize); - System.arraycopy(sNumber, 0, joseSignature, numberSize, numberSize); - return joseSignature; - } - - static void assertValidDERSignature(byte[] derSignature, int numberSize, boolean withRPadding, boolean withSPadding) { - assertThat(derSignature, is(Matchers.notNullValue())); - assertThat(numberSize, is(IsIn.oneOf(32, 48, 66))); - - int rLength = withRPadding ? numberSize - 1 : numberSize; - int sLength = withSPadding ? numberSize - 1 : numberSize; - int totalLength = 2 + (2 + rLength) + (2 + sLength); - int offset = 0; - - //Start sequence - assertThat(derSignature[offset++], is((byte) 0x30)); - if (totalLength > 0x7f) { - //Add sign before sequence length - totalLength++; - assertThat(derSignature[offset++], is((byte) 0x81)); - } - //Sequence length - assertThat(derSignature[offset++], is((byte) (totalLength - offset))); - - //R number - assertThat(derSignature[offset++], is((byte) 0x02)); - assertThat(derSignature[offset++], is((byte) rLength)); - byte[] rCopy = Arrays.copyOfRange(derSignature, offset, offset + rLength); - offset += rLength; - - //S number - assertThat(derSignature[offset++], is((byte) 0x02)); - assertThat(derSignature[offset++], is((byte) sLength)); - byte[] sCopy = Arrays.copyOfRange(derSignature, offset, offset + sLength); - - - byte[] rNumber = new byte[rLength]; - byte[] sNumber = new byte[sLength]; - Arrays.fill(rNumber, (byte) 0x11); - Arrays.fill(sNumber, (byte) 0x22); - assertThat(Arrays.equals(rNumber, rCopy), is(true)); - assertThat(Arrays.equals(sNumber, sCopy), is(true)); - assertThat(derSignature.length, is(totalLength)); - } - - @Test - public void shouldBeEqualSignatureMethodDecodeResults() throws Exception { - // signatures are not deterministic in value, so instead of directly comparing the signatures, - // check that both sign(..) methods can be used to create a jwt which can be - // verified - Algorithm algorithm = Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - - String header = "eyJhbGciOiJFUzI1NiJ9"; - String payload = "eyJpc3MiOiJhdXRoMCJ9"; - - byte[] headerBytes = header.getBytes(StandardCharsets.UTF_8); - byte[] payloadBytes = payload.getBytes(StandardCharsets.UTF_8); - - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - bout.write(headerBytes); - bout.write('.'); - bout.write(payloadBytes); - - String jwtSignature1 = Base64.getUrlEncoder().withoutPadding().encodeToString(algorithm.sign(bout.toByteArray())); - String jwt1 = String.format("%s.%s.%s", header, payload, jwtSignature1); - - algorithm.verify(JWT.decode(jwt1)); - - String jwtSignature2 = Base64.getUrlEncoder().withoutPadding().encodeToString(algorithm.sign(headerBytes, payloadBytes)); - String jwt2 = String.format("%s.%s.%s", header, payload, jwtSignature2); - - algorithm.verify(JWT.decode(jwt2)); - } - - /** - * Test deprecated signing method error handling. - * - * @see {@linkplain #shouldFailOnECDSA256SigningWhenProvidedPrivateKeyIsNull} - * @throws Exception expected exception - */ - - @Test - public void shouldFailOnECDSA256SigningWithDeprecatedMethodWhenProvidedPrivateKeyIsNull() { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPrivateKey()).thenReturn(null); - Algorithm algorithm = Algorithm.ECDSA256(provider); - algorithm.sign(new byte[0]); - } - - @Test - public void invalidECDSA256SignatureShouldFailTokenVerification() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectCause(isA(SignatureException.class)); - - String jwtWithInvalidSig = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0._____wAAAAD__________7zm-q2nF56E87nKwvxjJVH_____AAAAAP__________vOb6racXnoTzucrC_GMlUQ"; - - ECKey key256 = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - ECKey key384 = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); - ECKey key512 = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); - JWTVerifier verifier256 = JWT.require(Algorithm.ECDSA256(key256)).build(); - JWTVerifier verifier384 = JWT.require(Algorithm.ECDSA256(key384)).build(); - JWTVerifier verifier512 = JWT.require(Algorithm.ECDSA256(key512)).build(); - verifier256.verify(jwtWithInvalidSig); - verifier384.verify(jwtWithInvalidSig); - verifier512.verify(jwtWithInvalidSig); - } - - @Test - public void emptyECDSA256SignatureShouldFailTokenVerification() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectCause(isA(SignatureException.class)); - - String jwtWithInvalidSig = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - - ECKey key256 = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - ECKey key384 = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); - ECKey key512 = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); - JWTVerifier verifier256 = JWT.require(Algorithm.ECDSA256(key256)).build(); - JWTVerifier verifier384 = JWT.require(Algorithm.ECDSA256(key384)).build(); - JWTVerifier verifier512 = JWT.require(Algorithm.ECDSA256(key512)).build(); - verifier256.verify(jwtWithInvalidSig); - verifier384.verify(jwtWithInvalidSig); - verifier512.verify(jwtWithInvalidSig); - } - - @Test - public void signatureWithAllZerosShouldFail() throws Exception { - exception.expect(SignatureException.class); - exception.expectMessage("Invalid signature format."); - - ECPublicKey pubKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256(pubKey, (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - byte[] signatureBytes = new byte[64]; - algorithm256.validateSignatureStructure(signatureBytes, pubKey); - } - - @Test - public void signatureWithRZeroShouldFail() throws Exception { - exception.expect(SignatureException.class); - exception.expectMessage("Invalid signature format."); - - ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - ECPrivateKey privateKey = (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); - - String signedJwt = JWT.create().sign(Algorithm.ECDSA256(publicKey, privateKey)); - - String[] chunks = signedJwt.split("\\."); - byte[] signature = Base64.getUrlDecoder().decode(chunks[2]); - - byte[] sigWithBlankR = new byte[signature.length]; - for (int i = 0; i < signature.length; i++) { - if (i < signature.length / 2) { - sigWithBlankR[i] = 0; - } else { - sigWithBlankR[i] = signature[i]; - } - } - - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256(publicKey, privateKey); - algorithm256.validateSignatureStructure(sigWithBlankR, publicKey); - } - - @Test - public void signatureWithSZeroShouldFail() throws Exception { - exception.expect(SignatureException.class); - exception.expectMessage("Invalid signature format."); - - ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - ECPrivateKey privateKey = (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); - - String signedJwt = JWT.create().sign(Algorithm.ECDSA256(publicKey, privateKey)); - - String[] chunks = signedJwt.split("\\."); - byte[] signature = Base64.getUrlDecoder().decode(chunks[2]); - - byte[] sigWithBlankS = new byte[signature.length]; - for (int i = 0; i < signature.length; i++) { - if (i < signature.length / 2) { - sigWithBlankS[i] = signature[i]; - } else { - sigWithBlankS[i] = 0; - } - } - - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256(publicKey, privateKey); - algorithm256.validateSignatureStructure(sigWithBlankS, publicKey); - } - - @Test - public void signatureWithRValueNotLessThanOrderShouldFail() throws Exception { - exception.expect(SignatureException.class); - exception.expectMessage("Invalid signature format."); - - ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - ECPrivateKey privateKey = (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); - - String signedJwt = JWT.create().sign(Algorithm.ECDSA256(publicKey, privateKey)); - String jwtWithInvalidSig = signedJwt.substring(0, signedJwt.lastIndexOf('.') + 1) + "_____wAAAAD__________7zm-q2nF56E87nKwvxjJVH_____AAAAAP__________vOb6racXnoTzucrC_GMlUQ"; - - String[] chunks = jwtWithInvalidSig.split("\\."); - byte[] invalidSignature = Base64.getUrlDecoder().decode(chunks[2]); - - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256(publicKey, privateKey); - algorithm256.validateSignatureStructure(invalidSignature, publicKey); - } - - @Test - public void signatureWithSValueNotLessThanOrderShouldFail() throws Exception { - exception.expect(SignatureException.class); - exception.expectMessage("Invalid signature format."); - - ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - ECPrivateKey privateKey = (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); - - String signedJwt = JWT.create().sign(Algorithm.ECDSA256(publicKey, privateKey)); - String jwtWithInvalidSig = signedJwt.substring(0, signedJwt.lastIndexOf('.') + 1) + "_____wAAAAD__________7zm-q2nF56E87nKwvxjJVH_____AAAAAP__________vOb6racXnoTzucrC_GMlUQ"; - - String[] chunks = jwtWithInvalidSig.split("\\."); - byte[] invalidSignature = Base64.getUrlDecoder().decode(chunks[2]); - invalidSignature[0] = Byte.MAX_VALUE; - - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256(publicKey, privateKey); - algorithm256.validateSignatureStructure(invalidSignature, publicKey); - } -} \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java deleted file mode 100644 index 3925eef3..00000000 --- a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java +++ /dev/null @@ -1,1037 +0,0 @@ -package com.auth0.jwt.algorithms; - -import com.auth0.jwt.JWT; -import com.auth0.jwt.exceptions.SignatureGenerationException; -import com.auth0.jwt.exceptions.SignatureVerificationException; -import com.auth0.jwt.interfaces.ECDSAKeyProvider; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.math.BigInteger; -import java.nio.charset.StandardCharsets; -import java.security.*; -import java.security.interfaces.ECKey; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.security.spec.ECParameterSpec; -import java.util.Arrays; -import java.util.Base64; - -import static com.auth0.jwt.PemUtils.readPrivateKeyFromFile; -import static com.auth0.jwt.PemUtils.readPublicKeyFromFile; -import static com.auth0.jwt.algorithms.CryptoTestHelper.asJWT; -import static com.auth0.jwt.algorithms.CryptoTestHelper.assertSignaturePresent; -import static com.auth0.jwt.algorithms.ECDSAAlgorithmTest.*; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.Matchers.*; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class ECDSABouncyCastleProviderTests { - - private static final String PRIVATE_KEY_FILE_256 = "src/test/resources/ec256-key-private.pem"; - private static final String PUBLIC_KEY_FILE_256 = "src/test/resources/ec256-key-public.pem"; - private static final String INVALID_PUBLIC_KEY_FILE_256 = "src/test/resources/ec256-key-public-invalid.pem"; - - private static final String PRIVATE_KEY_FILE_384 = "src/test/resources/ec384-key-private.pem"; - private static final String PUBLIC_KEY_FILE_384 = "src/test/resources/ec384-key-public.pem"; - private static final String INVALID_PUBLIC_KEY_FILE_384 = "src/test/resources/ec384-key-public-invalid.pem"; - - private static final String PRIVATE_KEY_FILE_512 = "src/test/resources/ec512-key-private.pem"; - private static final String PUBLIC_KEY_FILE_512 = "src/test/resources/ec512-key-public.pem"; - private static final String INVALID_PUBLIC_KEY_FILE_512 = "src/test/resources/ec512-key-public-invalid.pem"; - - private static final String ES256K_JWT = "eyJraWQiOiJteS1rZXktaWQiLCJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.e30.2ggPsc4xwQhYcgJueo3uQ14MpaVJ3AbEE8UE-wA9fc8SMibeW54gjZbikL-JBHqhEwc22Cp8DNOtadXsM81RGQ"; - - @Rule - public ExpectedException exception = ExpectedException.none(); - private static final Provider bcProvider = new BouncyCastleProvider(); - - //JOSE Signatures obtained using Node 'jwa' lib: https://github.com/brianloveswords/node-jwa - //DER Signatures obtained from source JOSE signature using 'ecdsa-sig-formatter' lib: https://github.com/Brightspace/node-ecdsa-sig-formatter - - - //These tests add and use the BouncyCastle SecurityProvider to handle ECDSA algorithms - - @BeforeClass - public static void setUp() { - //Set BC as the preferred bcProvider - Security.insertProviderAt(bcProvider, 1); - } - - @AfterClass - public static void tearDown() { - Security.removeProvider(bcProvider.getName()); - } - - @Test - public void shouldPreferBouncyCastleProvider() { - assertThat(Security.getProviders()[0], is(equalTo(bcProvider))); - } - - @Test - public void shouldPassECDSA256VerificationWithJOSESignature() throws Exception { - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g"; - ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - Algorithm algorithm = Algorithm.ECDSA256(key); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnECDSA256VerificationWithDERSignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.MEYCIQDiJWTf5jShFPj0hpCWn7x1nhxPMjKWCs9MMusS9AIhAMcFPJVLe2A9uvb8hl8sRO2IpGoKDRpDmyH14ixNPAHW"; - ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - Algorithm algorithm = Algorithm.ECDSA256(key); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassECDSA256VerificationWithJOSESignatureWithBothKeys() throws Exception { - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g"; - Algorithm algorithm = Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnECDSA256VerificationWithDERSignatureWithBothKeys() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.MEYCIQDiJWTf5jShFPj0hpCWn7x1nhxPMjKWCs9MMusS9AIhAMcFPJVLe2A9uvb8hl8sRO2IpGoKDRpDmyH14ixNPAHW"; - Algorithm algorithm = Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassECDSA256VerificationWithProvidedPublicKey() throws Exception { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - when(provider.getPublicKeyById("my-key-id")).thenReturn((ECPublicKey) publicKey); - String jwt = "eyJhbGciOiJFUzI1NiIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.D_oU4CB0ZEsxHOjcWnmS3ZJvlTzm6WcGFx-HASxnvcB2Xu2WjI-axqXH9xKq45aPBDs330JpRhJmqBSc2K8MXQ"; - Algorithm algorithm = Algorithm.ECDSA256(provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA256VerificationWhenProvidedPublicKeyIsNull() { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPublicKeyById("my-key-id")).thenReturn(null); - String jwt = "eyJhbGciOiJFUzI1NiIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.D_oU4CB0ZEsxHOjcWnmS3ZJvlTzm6WcGFx-HASxnvcB2Xu2WjI-axqXH9xKq45aPBDs330JpRhJmqBSc2K8MXQ"; - Algorithm algorithm = Algorithm.ECDSA256(provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA256VerificationWithInvalidPublicKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.W9qfN1b80B9hnMo49WL8THrOsf1vEjOhapeFemPMGySzxTcgfyudS5esgeBTO908X5SLdAr5jMwPUPBs9b6nNg"; - Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA256VerificationWhenUsingPrivateKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.W9qfN1b80B9hnMo49WL8THrOsf1vEjOhapeFemPMGySzxTcgfyudS5esgeBTO908X5SLdAr5jMwPUPBs9b6nNg"; - Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA256VerificationOnInvalidJOSESignatureLength() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - byte[] bytes = new byte[63]; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA256VerificationOnInvalidJOSESignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - - byte[] bytes = new byte[64]; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA256VerificationOnInvalidDERSignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - - byte[] bytes = new byte[64]; - bytes[0] = 0x30; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassECDSA384VerificationWithJOSESignature() throws Exception { - String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.50UU5VKNdF1wfykY8jQBKpvuHZoe6IZBJm5NvoB8bR-hnRg6ti-CHbmvoRtlLfnHfwITa_8cJMy6TenMC2g63GQHytc8rYoXqbwtS4R0Ko_AXbLFUmfxnGnMC6v4MS_z"; - ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); - Algorithm algorithm = Algorithm.ECDSA384(key); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnECDSA384VerificationWithDERSignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.MGUCMQDnRRTlUo10XXBKRjyNAEqm4dmh7ohkEmbk2gHxtH6GdGDq2L4IduahG2UtccCMH8CE2vHCTMuk3pzAtoOtxkB8rXPK2KF6m8LUuEdCqPwF2yxVJn8ZxpzAurDEv8w"; - ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); - Algorithm algorithm = Algorithm.ECDSA384(key); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassECDSA384VerificationWithJOSESignatureWithBothKeys() throws Exception { - String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.50UU5VKNdF1wfykY8jQBKpvuHZoe6IZBJm5NvoB8bR-hnRg6ti-CHbmvoRtlLfnHfwITa_8cJMy6TenMC2g63GQHytc8rYoXqbwtS4R0Ko_AXbLFUmfxnGnMC6v4MS_z"; - Algorithm algorithm = Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnECDSA384VerificationWithDERSignatureWithBothKeys() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.MGUCMQDnRRTlUo10XXBKRjyNAEqm4dmh7ohkEmbk2gHxtH6GdGDq2L4IduahG2UtccCMH8CE2vHCTMuk3pzAtoOtxkB8rXPK2KF6m8LUuEdCqPwF2yxVJn8ZxpzAurDEv8w"; - Algorithm algorithm = Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassECDSA384VerificationWithProvidedPublicKey() throws Exception { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); - when(provider.getPublicKeyById("my-key-id")).thenReturn((ECPublicKey) publicKey); - String jwt = "eyJhbGciOiJFUzM4NCIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.9kjGuFTPx3ylfpqL0eY9H7TGmPepjQOBKI8UPoEvby6N7dDLF5HxLohosNxxFymNT7LzpeSgOPAB0wJEwG2Nl2ukgdUOpZOf492wog_i5ZcZmAykd3g1QH7onrzd69GU"; - Algorithm algorithm = Algorithm.ECDSA384(provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA384VerificationWhenProvidedPublicKeyIsNull() { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPublicKeyById("my-key-id")).thenReturn(null); - String jwt = "eyJhbGciOiJFUzM4NCIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.9kjGuFTPx3ylfpqL0eY9H7TGmPepjQOBKI8UPoEvby6N7dDLF5HxLohosNxxFymNT7LzpeSgOPAB0wJEwG2Nl2ukgdUOpZOf492wog_i5ZcZmAykd3g1QH7onrzd69GU"; - Algorithm algorithm = Algorithm.ECDSA384(provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA384VerificationWithInvalidPublicKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); - String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9._k5h1KyO-NE0R2_HAw0-XEc0bGT5atv29SxHhOGC9JDqUHeUdptfCK_ljQ01nLVt2OQWT2SwGs-TuyHDFmhPmPGFZ9wboxvq_ieopmYqhQilNAu-WF-frioiRz9733fU"; - Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_384, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA384VerificationWhenUsingPrivateKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9._k5h1KyO-NE0R2_HAw0-XEc0bGT5atv29SxHhOGC9JDqUHeUdptfCK_ljQ01nLVt2OQWT2SwGs-TuyHDFmhPmPGFZ9wboxvq_ieopmYqhQilNAu-WF-frioiRz9733fU"; - Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA384VerificationOnInvalidJOSESignatureLength() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - byte[] bytes = new byte[95]; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_384, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA384VerificationOnInvalidJOSESignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); - - byte[] bytes = new byte[96]; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_384, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA384VerificationOnInvalidDERSignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); - - byte[] bytes = new byte[96]; - new SecureRandom().nextBytes(bytes); - bytes[0] = 0x30; - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_384, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassECDSA512VerificationWithJOSESignature() throws Exception { - String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.AeCJPDIsSHhwRSGZCY6rspi8zekOw0K9qYMNridP1Fu9uhrA1QrG-EUxXlE06yvmh2R7Rz0aE7kxBwrnq8L8aOBCAYAsqhzPeUvyp8fXjjgs0Eto5I0mndE2QHlgcMSFASyjHbU8wD2Rq7ZNzGQ5b2MZfpv030WGUajT-aZYWFUJHVg2"; - ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); - Algorithm algorithm = Algorithm.ECDSA512(key); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnECDSA512VerificationWithDERSignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.MIGIAkIB4Ik8MixIeHBFIZkJjquymLzN6Q7DQr2pgw2uJ0UW726GsDVCsb4RTFeUTTrKaHZHtHPRoTuTEHCuerwvxo4EICQgGALKocz3lL8qfH1444LNBLaOSNJp3RNkB5YHDEhQEsox21PMA9kau2TcxkOW9jGX6b9N9FhlGo0mmWFhVCR1YNg"; - ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); - Algorithm algorithm = Algorithm.ECDSA512(key); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassECDSA512VerificationWithJOSESignatureWithBothKeys() throws Exception { - String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.AeCJPDIsSHhwRSGZCY6rspi8zekOw0K9qYMNridP1Fu9uhrA1QrG-EUxXlE06yvmh2R7Rz0aE7kxBwrnq8L8aOBCAYAsqhzPeUvyp8fXjjgs0Eto5I0mndE2QHlgcMSFASyjHbU8wD2Rq7ZNzGQ5b2MZfpv030WGUajT-aZYWFUJHVg2"; - Algorithm algorithm = Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowECDSA512VerificationWithDERSignatureWithBothKeys() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.MIGIAkIB4Ik8MixIeHBFIZkJjquymLzN6Q7DQr2pgw2uJ0UW726GsDVCsb4RTFeUTTrKaHZHtHPRoTuTEHCuerwvxo4EICQgGALKocz3lL8qfH1444LNBLaOSNJp3RNkB5YHDEhQEsox21PMA9kau2TcxkOW9jGX6b9N9FhlGo0mmWFhVCR1YNg"; - Algorithm algorithm = Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassECDSA512VerificationWithProvidedPublicKey() throws Exception { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); - when(provider.getPublicKeyById("my-key-id")).thenReturn((ECPublicKey) publicKey); - String jwt = "eyJhbGciOiJFUzUxMiIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.AGxEwbsYa2bQ7Y7DAcTQnVD8PmLSlhJ20jg2OfdyPnqdXI8SgBaG6lGciq3_pofFhs1HEoFoJ33Jcluha24oMHIvAfwu8qbv_Wq3L2eI9Q0L0p6ul8Pd_BS8adRa2PgLc36xXGcRc7ID5YH-CYaQfsTp5YIaF0Po3h0QyCoQ6ZiYQkqm"; - Algorithm algorithm = Algorithm.ECDSA512(provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA512VerificationWhenProvidedPublicKeyIsNull() { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPublicKeyById("my-key-id")).thenReturn(null); - String jwt = "eyJhbGciOiJFUzUxMiIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.AGxEwbsYa2bQ7Y7DAcTQnVD8PmLSlhJ20jg2OfdyPnqdXI8SgBaG6lGciq3_pofFhs1HEoFoJ33Jcluha24oMHIvAfwu8qbv_Wq3L2eI9Q0L0p6ul8Pd_BS8adRa2PgLc36xXGcRc7ID5YH-CYaQfsTp5YIaF0Po3h0QyCoQ6ZiYQkqm"; - Algorithm algorithm = Algorithm.ECDSA512(provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA512VerificationWithInvalidPublicKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); - String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.AZgdopFFsN0amCSs2kOucXdpylD31DEm5ChK1PG0_gq5Mf47MrvVph8zHSVuvcrXzcE1U3VxeCg89mYW1H33Y-8iAF0QFkdfTUQIWKNObH543WNMYYssv3OtOj0znPv8atDbaF8DMYAtcT1qdmaSJRhx-egRE9HGZkinPh9CfLLLt58X"; - Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_512, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA512VerificationWhenUsingPrivateKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.AZgdopFFsN0amCSs2kOucXdpylD31DEm5ChK1PG0_gq5Mf47MrvVph8zHSVuvcrXzcE1U3VxeCg89mYW1H33Y-8iAF0QFkdfTUQIWKNObH543WNMYYssv3OtOj0znPv8atDbaF8DMYAtcT1qdmaSJRhx-egRE9HGZkinPh9CfLLLt58X"; - Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA512VerificationOnInvalidJOSESignatureLength() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - byte[] bytes = new byte[131]; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_512, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA512VerificationOnInvalidJOSESignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); - - byte[] bytes = new byte[132]; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_512, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA512VerificationOnInvalidDERSignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); - - byte[] bytes = new byte[132]; - new SecureRandom().nextBytes(bytes); - bytes[0] = 0x30; - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_512, "EC")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailJOSEToDERConversionOnInvalidJOSESignatureLength() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - byte[] bytes = new byte[256]; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; - - ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new ECDSAAlgorithm("ES256", "SHA256withECDSA", 128, provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnVerifyWhenSignatureAlgorithmDoesNotExists() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: some-alg"); - exception.expectCause(isA(NoSuchAlgorithmException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.verifySignatureFor(anyString(), any(PublicKey.class), any(String.class), any(String.class), any(byte[].class))) - .thenThrow(NoSuchAlgorithmException.class); - - ECPublicKey publicKey = mock(ECPublicKey.class); - when(publicKey.getParams()).thenReturn(mock(ECParameterSpec.class)); - byte[] a = new byte[64]; - Arrays.fill(a, Byte.MAX_VALUE); - when(publicKey.getParams().getOrder()).thenReturn(new BigInteger(a)); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g"; - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnVerifyWhenThePublicKeyIsInvalid() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: some-alg"); - exception.expectCause(isA(InvalidKeyException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.verifySignatureFor(anyString(), any(PublicKey.class), any(String.class), any(String.class), any(byte[].class))) - .thenThrow(InvalidKeyException.class); - - ECPublicKey publicKey = mock(ECPublicKey.class); - when(publicKey.getParams()).thenReturn(mock(ECParameterSpec.class)); - byte[] a = new byte[64]; - Arrays.fill(a, Byte.MAX_VALUE); - when(publicKey.getParams().getOrder()).thenReturn(new BigInteger(a)); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g"; - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnVerifyWhenTheSignatureIsNotPrepared() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: some-alg"); - exception.expectCause(isA(SignatureException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.verifySignatureFor(anyString(), any(PublicKey.class), any(String.class), any(String.class), any(byte[].class))) - .thenThrow(SignatureException.class); - - ECPublicKey publicKey = mock(ECPublicKey.class); - when(publicKey.getParams()).thenReturn(mock(ECParameterSpec.class)); - byte[] a = new byte[64]; - Arrays.fill(a, Byte.MAX_VALUE); - when(publicKey.getParams().getOrder()).thenReturn(new BigInteger(a)); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g"; - algorithm.verify(JWT.decode(jwt)); - } - - //Sign - private static final String ES256Header = "eyJhbGciOiJFUzI1NiJ9"; - private static final String ES384Header = "eyJhbGciOiJFUzM4NCJ9"; - private static final String ES512Header = "eyJhbGciOiJFUzUxMiJ9"; - private static final String auth0IssPayload = "eyJpc3MiOiJhdXRoMCJ9"; - - @Test - public void shouldDoECDSA256Signing() throws Exception { - Algorithm algorithmSign = Algorithm.ECDSA256((ECKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - Algorithm algorithmVerify = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC")); - String jwt = asJWT(algorithmSign, ES256Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithmVerify.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoECDSA256SigningWithBothKeys() throws Exception { - Algorithm algorithm = Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - String jwt = asJWT(algorithm, ES256Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoECDSA256SigningWithProvidedPrivateKey() throws Exception { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - PrivateKey privateKey = readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - when(provider.getPrivateKey()).thenReturn((ECPrivateKey) privateKey); - when(provider.getPublicKeyById(null)).thenReturn((ECPublicKey) publicKey); - Algorithm algorithm = Algorithm.ECDSA256(provider); - - String jwt = asJWT(algorithm, ES256Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailOnECDSA256SigningWhenProvidedPrivateKeyIsNull() { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPrivateKey()).thenReturn(null); - Algorithm algorithm = Algorithm.ECDSA256(provider); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldFailOnECDSA256SigningWhenUsingPublicKey() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC")); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldDoECDSA384Signing() throws Exception { - Algorithm algorithmSign = Algorithm.ECDSA384((ECKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); - Algorithm algorithmVerify = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC")); - String jwt = asJWT(algorithmSign, ES384Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithmVerify.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoECDSA384SigningWithBothKeys() throws Exception { - Algorithm algorithm = Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); - String jwt = asJWT(algorithm, ES384Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoECDSA384SigningWithProvidedPrivateKey() throws Exception { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - PrivateKey privateKey = readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC"); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); - when(provider.getPrivateKey()).thenReturn((ECPrivateKey) privateKey); - when(provider.getPublicKeyById(null)).thenReturn((ECPublicKey) publicKey); - Algorithm algorithm = Algorithm.ECDSA384(provider); - - String jwt = asJWT(algorithm, ES384Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailOnECDSA384SigningWhenProvidedPrivateKeyIsNull() { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA384withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPrivateKey()).thenReturn(null); - Algorithm algorithm = Algorithm.ECDSA384(provider); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldFailOnECDSA384SigningWhenUsingPublicKey() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA384withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC")); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldDoECDSA512Signing() throws Exception { - Algorithm algorithmSign = Algorithm.ECDSA512((ECKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); - Algorithm algorithmVerify = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC")); - - String jwt = asJWT(algorithmSign, ES512Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithmVerify.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoECDSA512SigningWithBothKeys() throws Exception { - Algorithm algorithm = Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); - String jwt = asJWT(algorithm, ES512Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithm.verify(JWT.decode(jwt)); - } - - - @Test - public void shouldDoECDSA512SigningWithProvidedPrivateKey() throws Exception { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - PrivateKey privateKey = readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC"); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); - when(provider.getPrivateKey()).thenReturn((ECPrivateKey) privateKey); - when(provider.getPublicKeyById(null)).thenReturn((ECPublicKey) publicKey); - Algorithm algorithm = Algorithm.ECDSA512(provider); - String jwt = asJWT(algorithm, ES512Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailOnECDSA512SigningWhenProvidedPrivateKeyIsNull() { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA512withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPrivateKey()).thenReturn(null); - Algorithm algorithm = Algorithm.ECDSA512(provider); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldFailOnECDSA512SigningWhenUsingPublicKey() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA512withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC")); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldThrowOnSignWhenSignatureAlgorithmDoesNotExists() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: some-algorithm"); - exception.expectCause(isA(NoSuchAlgorithmException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.createSignatureFor(anyString(), any(PrivateKey.class), any(byte[].class), any(byte[].class))) - .thenThrow(NoSuchAlgorithmException.class); - - ECPublicKey publicKey = mock(ECPublicKey.class); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); - algorithm.sign(ES256Header.getBytes(StandardCharsets.UTF_8), new byte[0]); - } - - @Test - public void shouldThrowOnSignWhenThePrivateKeyIsInvalid() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: some-algorithm"); - exception.expectCause(isA(InvalidKeyException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.createSignatureFor(anyString(), any(PrivateKey.class), any(byte[].class), any(byte[].class))) - .thenThrow(InvalidKeyException.class); - - ECPublicKey publicKey = mock(ECPublicKey.class); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); - algorithm.sign(ES256Header.getBytes(StandardCharsets.UTF_8), new byte[0]); - } - - @Test - public void shouldThrowOnSignWhenTheSignatureIsNotPrepared() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: some-algorithm"); - exception.expectCause(isA(SignatureException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.createSignatureFor(anyString(), any(PrivateKey.class), any(byte[].class), any(byte[].class))) - .thenThrow(SignatureException.class); - - ECPublicKey publicKey = mock(ECPublicKey.class); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); - algorithm.sign(ES256Header.getBytes(StandardCharsets.UTF_8), new byte[0]); - } - - @Test - public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() { - ECPublicKey publicKey = mock(ECPublicKey.class); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new ECDSAAlgorithm("some-alg", "some-algorithm", 32, provider); - - assertThat(algorithm.getSigningKeyId(), is(nullValue())); - } - - @Test - public void shouldReturnSigningKeyIdFromProvider() { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPrivateKeyId()).thenReturn("keyId"); - Algorithm algorithm = new ECDSAAlgorithm("some-alg", "some-algorithm", 32, provider); - - assertThat(algorithm.getSigningKeyId(), is("keyId")); - } - - @Test - public void shouldThrowOnDERSignatureConversionIfDoesNotStartWithCorrectSequenceByte() throws Exception { - exception.expect(SignatureException.class); - exception.expectMessage("Invalid DER signature format."); - - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - String content256 = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9"; - - byte[] signature = algorithm256.sign(content256.getBytes(), new byte[0]); - signature[0] = (byte) 0x02; - algorithm256.DERToJOSE(signature); - } - - @Test - public void shouldThrowOnDERSignatureConversionIfDoesNotHaveExpectedLength() throws Exception { - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - byte[] derSignature = createDERSignature(32, false, false); - int received = (int) derSignature[1]; - received--; - derSignature[1] = (byte) received; - exception.expect(SignatureException.class); - exception.expectMessage("Invalid DER signature format."); - - algorithm256.DERToJOSE(derSignature); - } - - @Test - public void shouldThrowOnDERSignatureConversionIfRNumberDoesNotHaveExpectedLength() throws Exception { - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - byte[] derSignature = createDERSignature(32, false, false); - derSignature[3] = (byte) 34; - exception.expect(SignatureException.class); - exception.expectMessage("Invalid DER signature format."); - - algorithm256.DERToJOSE(derSignature); - } - - @Test - public void shouldThrowOnDERSignatureConversionIfSNumberDoesNotHaveExpectedLength() throws Exception { - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - byte[] derSignature = createDERSignature(32, false, false); - derSignature[4 + 32 + 1] = (byte) 34; - exception.expect(SignatureException.class); - exception.expectMessage("Invalid DER signature format."); - - algorithm256.DERToJOSE(derSignature); - } - - @Test - public void shouldThrowOnJOSESignatureConversionIfDoesNotHaveExpectedLength() throws Exception { - ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256(publicKey, (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - byte[] joseSignature = new byte[32 * 2 - 1]; - exception.expect(SignatureException.class); - exception.expectMessage("Invalid JOSE signature format."); - - algorithm256.validateSignatureStructure(joseSignature, publicKey); - } - - @Test - public void shouldSignAndVerifyWithECDSA256() throws Exception { - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - String header256 = "eyJhbGciOiJFUzI1NiJ9"; - String body = "eyJpc3MiOiJhdXRoMCJ9"; - - for (int i = 0; i < 10; i++) { - String jwt = asJWT(algorithm256, header256, body); - algorithm256.verify(JWT.decode(jwt)); - } - } - - @Test - public void shouldSignAndVerifyWithECDSA384() throws Exception { - ECDSAAlgorithm algorithm384 = (ECDSAAlgorithm) Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); - String header384 = "eyJhbGciOiJFUzM4NCJ9"; - String body = "eyJpc3MiOiJhdXRoMCJ9"; - - for (int i = 0; i < 10; i++) { - String jwt = asJWT(algorithm384, header384, body); - algorithm384.verify(JWT.decode(jwt)); - } - } - - @Test - public void shouldSignAndVerifyWithECDSA512() throws Exception { - ECDSAAlgorithm algorithm512 = (ECDSAAlgorithm) Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); - String header512 = "eyJhbGciOiJFUzUxMiJ9"; - String body = "eyJpc3MiOiJhdXRoMCJ9"; - - for (int i = 0; i < 10; i++) { - String jwt = asJWT(algorithm512, header512, body); - algorithm512.verify(JWT.decode(jwt)); - } - } - - @Test - public void shouldDecodeECDSA256JOSE() throws Exception { - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - - //Without padding - byte[] joseSignature = createJOSESignature(32, false, false); - byte[] derSignature = algorithm256.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 32, false, false); - - //With R padding - joseSignature = createJOSESignature(32, true, false); - derSignature = algorithm256.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 32, true, false); - - //With S padding - joseSignature = createJOSESignature(32, false, true); - derSignature = algorithm256.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 32, false, true); - - //With both paddings - joseSignature = createJOSESignature(32, true, true); - derSignature = algorithm256.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 32, true, true); - } - - @Test - public void shouldDecodeECDSA256DER() throws Exception { - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); - - //Without padding - byte[] derSignature = createDERSignature(32, false, false); - byte[] joseSignature = algorithm256.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 32, false, false); - - //With R padding - derSignature = createDERSignature(32, true, false); - joseSignature = algorithm256.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 32, true, false); - - //With S padding - derSignature = createDERSignature(32, false, true); - joseSignature = algorithm256.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 32, false, true); - - //With both paddings - derSignature = createDERSignature(32, true, true); - joseSignature = algorithm256.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 32, true, true); - } - - @Test - public void shouldDecodeECDSA384JOSE() throws Exception { - ECDSAAlgorithm algorithm384 = (ECDSAAlgorithm) Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); - - //Without padding - byte[] joseSignature = createJOSESignature(48, false, false); - byte[] derSignature = algorithm384.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 48, false, false); - - //With R padding - joseSignature = createJOSESignature(48, true, false); - derSignature = algorithm384.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 48, true, false); - - //With S padding - joseSignature = createJOSESignature(48, false, true); - derSignature = algorithm384.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 48, false, true); - - //With both paddings - joseSignature = createJOSESignature(48, true, true); - derSignature = algorithm384.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 48, true, true); - } - - @Test - public void shouldDecodeECDSA384DER() throws Exception { - ECDSAAlgorithm algorithm384 = (ECDSAAlgorithm) Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); - - //Without padding - byte[] derSignature = createDERSignature(48, false, false); - byte[] joseSignature = algorithm384.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 48, false, false); - - //With R padding - derSignature = createDERSignature(48, true, false); - joseSignature = algorithm384.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 48, true, false); - - //With S padding - derSignature = createDERSignature(48, false, true); - joseSignature = algorithm384.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 48, false, true); - - //With both paddings - derSignature = createDERSignature(48, true, true); - joseSignature = algorithm384.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 48, true, true); - } - - @Test - public void shouldDecodeECDSA512JOSE() throws Exception { - ECDSAAlgorithm algorithm512 = (ECDSAAlgorithm) Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); - - //Without padding - byte[] joseSignature = createJOSESignature(66, false, false); - byte[] derSignature = algorithm512.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 66, false, false); - - //With R padding - joseSignature = createJOSESignature(66, true, false); - derSignature = algorithm512.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 66, true, false); - - //With S padding - joseSignature = createJOSESignature(66, false, true); - derSignature = algorithm512.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 66, false, true); - - //With both paddings - joseSignature = createJOSESignature(66, true, true); - derSignature = algorithm512.JOSEToDER(joseSignature); - assertValidDERSignature(derSignature, 66, true, true); - } - - @Test - public void shouldDecodeECDSA512DER() throws Exception { - ECDSAAlgorithm algorithm512 = (ECDSAAlgorithm) Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); - - //Without padding - byte[] derSignature = createDERSignature(66, false, false); - byte[] joseSignature = algorithm512.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 66, false, false); - - //With R padding - derSignature = createDERSignature(66, true, false); - joseSignature = algorithm512.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 66, true, false); - - //With S padding - derSignature = createDERSignature(66, false, true); - joseSignature = algorithm512.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 66, false, true); - - //With both paddings - derSignature = createDERSignature(66, true, true); - joseSignature = algorithm512.DERToJOSE(derSignature); - assertValidJOSESignature(joseSignature, 66, true, true); - } - - -} diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java deleted file mode 100644 index 9b6ac0c0..00000000 --- a/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java +++ /dev/null @@ -1,309 +0,0 @@ -package com.auth0.jwt.algorithms; - -import com.auth0.jwt.JWT; -import com.auth0.jwt.exceptions.SignatureGenerationException; -import com.auth0.jwt.exceptions.SignatureVerificationException; -import com.auth0.jwt.interfaces.DecodedJWT; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.io.ByteArrayOutputStream; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; - -import static com.auth0.jwt.algorithms.CryptoTestHelper.asJWT; -import static com.auth0.jwt.algorithms.CryptoTestHelper.assertSignaturePresent; -import static com.auth0.jwt.algorithms.CryptoTestHelper.assertSignatureValue; -import static org.hamcrest.Matchers.*; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.Assert.assertArrayEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class HMACAlgorithmTest { - - @Rule - public ExpectedException exception = ExpectedException.none(); - - // Verify - - @Test - public void shouldGetStringBytes() { - String text = "abcdef123456!@#$%^"; - byte[] expectedBytes = text.getBytes(StandardCharsets.UTF_8); - assertArrayEquals(expectedBytes, HMACAlgorithm.getSecretBytes(text)); - } - - @Test - public void shouldCopyTheReceivedSecretArray() { - String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; - byte[] secretArray = "secret".getBytes(Charset.defaultCharset()); - Algorithm algorithmString = Algorithm.HMAC256(secretArray); - - DecodedJWT decoded = JWT.decode(jwt); - algorithmString.verify(decoded); - secretArray[0] = secretArray[1]; - algorithmString.verify(decoded); - } - - @Test - public void shouldPassHMAC256Verification() { - String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; - Algorithm algorithmString = Algorithm.HMAC256("secret"); - Algorithm algorithmBytes = Algorithm.HMAC256("secret".getBytes(StandardCharsets.UTF_8)); - DecodedJWT decoded = JWT.decode(jwt); - algorithmString.verify(decoded); - algorithmBytes.verify(decoded); - } - - @Test - public void shouldFailHMAC256VerificationWithInvalidSecretString() { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA256"); - String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; - Algorithm algorithm = Algorithm.HMAC256("not_real_secret"); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailHMAC256VerificationWithInvalidSecretBytes() { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA256"); - String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; - Algorithm algorithm = Algorithm.HMAC256("not_real_secret".getBytes(StandardCharsets.UTF_8)); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassHMAC384Verification() { - String jwt = "eyJhbGciOiJIUzM4NCIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.uztpK_wUMYJhrRv8SV-1LU4aPnwl-EM1q-wJnqgyb5DHoDteP6lN_gE1xnZJH5vw"; - Algorithm algorithmString = Algorithm.HMAC384("secret"); - Algorithm algorithmBytes = Algorithm.HMAC384("secret".getBytes(StandardCharsets.UTF_8)); - DecodedJWT decoded = JWT.decode(jwt); - algorithmString.verify(decoded); - algorithmBytes.verify(decoded); - } - - @Test - public void shouldFailHMAC384VerificationWithInvalidSecretString() { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA384"); - String jwt = "eyJhbGciOiJIUzM4NCIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.uztpK_wUMYJhrRv8SV-1LU4aPnwl-EM1q-wJnqgyb5DHoDteP6lN_gE1xnZJH5vw"; - Algorithm algorithm = Algorithm.HMAC384("not_real_secret"); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailHMAC384VerificationWithInvalidSecretBytes() { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA384"); - String jwt = "eyJhbGciOiJIUzM4NCIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.uztpK_wUMYJhrRv8SV-1LU4aPnwl-EM1q-wJnqgyb5DHoDteP6lN_gE1xnZJH5vw"; - Algorithm algorithm = Algorithm.HMAC384("not_real_secret".getBytes(StandardCharsets.UTF_8)); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassHMAC512Verification() { - String jwt = "eyJhbGciOiJIUzUxMiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.VUo2Z9SWDV-XcOc_Hr6Lff3vl7L9e5Vb8ThXpmGDFjHxe3Dr1ZBmUChYF-xVA7cAdX1P_D4ZCUcsv3IefpVaJw"; - Algorithm algorithmString = Algorithm.HMAC512("secret"); - Algorithm algorithmBytes = Algorithm.HMAC512("secret".getBytes(StandardCharsets.UTF_8)); - DecodedJWT decoded = JWT.decode(jwt); - algorithmString.verify(decoded); - algorithmBytes.verify(decoded); - } - - @Test - public void shouldFailHMAC512VerificationWithInvalidSecretString() { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA512"); - String jwt = "eyJhbGciOiJIUzUxMiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.VUo2Z9SWDV-XcOc_Hr6Lff3vl7L9e5Vb8ThXpmGDFjHxe3Dr1ZBmUChYF-xVA7cAdX1P_D4ZCUcsv3IefpVaJw"; - Algorithm algorithm = Algorithm.HMAC512("not_real_secret"); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailHMAC512VerificationWithInvalidSecretBytes() { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA512"); - String jwt = "eyJhbGciOiJIUzUxMiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.VUo2Z9SWDV-XcOc_Hr6Lff3vl7L9e5Vb8ThXpmGDFjHxe3Dr1ZBmUChYF-xVA7cAdX1P_D4ZCUcsv3IefpVaJw"; - Algorithm algorithm = Algorithm.HMAC512("not_real_secret".getBytes(StandardCharsets.UTF_8)); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnVerifyWhenSignatureAlgorithmDoesNotExists() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: some-alg"); - exception.expectCause(isA(NoSuchAlgorithmException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.verifySignatureFor(anyString(), any(byte[].class), any(String.class), any(String.class), any(byte[].class))) - .thenThrow(NoSuchAlgorithmException.class); - - Algorithm algorithm = new HMACAlgorithm(crypto, "some-alg", "some-algorithm", "secret".getBytes(StandardCharsets.UTF_8)); - String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnVerifyWhenTheSecretIsInvalid() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: some-alg"); - exception.expectCause(isA(InvalidKeyException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.verifySignatureFor(anyString(), any(byte[].class), any(String.class), any(String.class), any(byte[].class))) - .thenThrow(InvalidKeyException.class); - - Algorithm algorithm = new HMACAlgorithm(crypto, "some-alg", "some-algorithm", "secret".getBytes(StandardCharsets.UTF_8)); - String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; - algorithm.verify(JWT.decode(jwt)); - } - - // Sign - - private static final String HS256Header = "eyJhbGciOiJIUzI1NiJ9"; - private static final String HS384Header = "eyJhbGciOiJIUzM4NCJ9"; - private static final String HS512Header = "eyJhbGciOiJIUzUxMiJ9"; - private static final String auth0IssPayload = "eyJpc3MiOiJhdXRoMCJ9"; - - @Test - public void shouldDoHMAC256SigningWithBytes() { - Algorithm algorithm = Algorithm.HMAC256("secret".getBytes(StandardCharsets.UTF_8)); - - String jwt = asJWT(algorithm, HS256Header, auth0IssPayload); - String expectedSignature = "s69x7Mmu4JqwmdxiK6sesALO7tcedbFsKEEITUxw9ho"; - - assertSignaturePresent(jwt); - assertSignatureValue(jwt, expectedSignature); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoHMAC384SigningWithBytes() { - Algorithm algorithm = Algorithm.HMAC384("secret".getBytes(StandardCharsets.UTF_8)); - - String jwt = asJWT(algorithm, HS384Header, auth0IssPayload); - String expectedSignature = "4-y2Gxz_foN0jAOFimmBPF7DWxf4AsjM20zxNkHg8Zah5Q64G42P9GfjmUp4Hldt"; - - assertSignaturePresent(jwt); - assertSignatureValue(jwt, expectedSignature); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoHMAC512SigningWithBytes() { - Algorithm algorithm = Algorithm.HMAC512("secret".getBytes(StandardCharsets.UTF_8)); - - String jwt = asJWT(algorithm, HS512Header, auth0IssPayload); - String expectedSignature = "OXWyxmf-VcVo8viOiTFfLaEy6mrQqLEos5R82Xsx8mtFxQadJAQ1aVniIWN8qT2GNE_pMQPcdzk4x7Cqxsp1dw"; - - assertSignaturePresent(jwt); - assertSignatureValue(jwt, expectedSignature); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoHMAC256SigningWithString() { - Algorithm algorithm = Algorithm.HMAC256("secret"); - - String jwt = asJWT(algorithm, HS256Header, auth0IssPayload); - String expectedSignature = "s69x7Mmu4JqwmdxiK6sesALO7tcedbFsKEEITUxw9ho"; - - assertSignaturePresent(jwt); - assertSignatureValue(jwt, expectedSignature); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoHMAC384SigningWithString() { - Algorithm algorithm = Algorithm.HMAC384("secret"); - - String jwt = asJWT(algorithm, HS384Header, auth0IssPayload); - String expectedSignature = "4-y2Gxz_foN0jAOFimmBPF7DWxf4AsjM20zxNkHg8Zah5Q64G42P9GfjmUp4Hldt"; - - assertSignaturePresent(jwt); - assertSignatureValue(jwt, expectedSignature); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoHMAC512SigningWithString() { - Algorithm algorithm = Algorithm.HMAC512("secret"); - - String jwt = asJWT(algorithm ,HS512Header, auth0IssPayload); - String expectedSignature = "OXWyxmf-VcVo8viOiTFfLaEy6mrQqLEos5R82Xsx8mtFxQadJAQ1aVniIWN8qT2GNE_pMQPcdzk4x7Cqxsp1dw"; - - assertSignaturePresent(jwt); - assertSignatureValue(jwt, expectedSignature); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowOnSignWhenSignatureAlgorithmDoesNotExists() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: some-algorithm"); - exception.expectCause(isA(NoSuchAlgorithmException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.createSignatureFor(anyString(), any(byte[].class), any(byte[].class), any(byte[].class))) - .thenThrow(NoSuchAlgorithmException.class); - - Algorithm algorithm = new HMACAlgorithm(crypto, "some-alg", "some-algorithm", "secret".getBytes(StandardCharsets.UTF_8)); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldThrowOnSignWhenTheSecretIsInvalid() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: some-algorithm"); - exception.expectCause(isA(InvalidKeyException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.createSignatureFor(anyString(), any(byte[].class), any(byte[].class), any(byte[].class))) - .thenThrow(InvalidKeyException.class); - - Algorithm algorithm = new HMACAlgorithm(crypto, "some-alg", "some-algorithm", "secret".getBytes(StandardCharsets.UTF_8)); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldReturnNullSigningKeyId() { - assertThat(Algorithm.HMAC256("secret").getSigningKeyId(), is(nullValue())); - } - - @Test - public void shouldBeEqualSignatureMethodResults() throws Exception { - Algorithm algorithm = Algorithm.HMAC256("secret"); - - byte[] header = new byte[]{0x00, 0x01, 0x02}; - byte[] payload = new byte[]{0x04, 0x05, 0x06}; - - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - bout.write(header); - bout.write('.'); - bout.write(payload); - - assertThat(algorithm.sign(bout.toByteArray()), is(algorithm.sign(header, payload))); - } - - - @Test - public void shouldThrowWhenSignatureNotValidBase64() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectCause(isA(IllegalArgumentException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.verifySignatureFor(anyString(), any(byte[].class), any(String.class), any(String.class), any(byte[].class))) - .thenThrow(NoSuchAlgorithmException.class); - - Algorithm algorithm = new HMACAlgorithm(crypto, "some-alg", "some-algorithm", "secret".getBytes(StandardCharsets.UTF_8)); - String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWm+i903JuUoDRZDBPB7HwkS4nVyWH1M"; - algorithm.verify(JWT.decode(jwt)); - } -} \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/NoneAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/NoneAlgorithmTest.java deleted file mode 100644 index 263dc249..00000000 --- a/lib/src/test/java/com/auth0/jwt/algorithms/NoneAlgorithmTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.auth0.jwt.algorithms; - -import com.auth0.jwt.JWT; -import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.exceptions.SignatureVerificationException; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import static org.hamcrest.Matchers.*; -import static org.hamcrest.MatcherAssert.assertThat; - -public class NoneAlgorithmTest { - - @Rule - public ExpectedException exception = ExpectedException.none(); - - @Test - public void shouldPassNoneVerification() { - Algorithm algorithm = Algorithm.none(); - String jwt = "eyJhbGciOiJub25lIiwiY3R5IjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9."; - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailNoneVerificationWhenTokenHasTwoParts() { - exception.expect(JWTDecodeException.class); - exception.expectMessage("The token was expected to have 3 parts, but got 2."); - String jwt = "eyJhbGciOiJub25lIiwiY3R5IjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9"; - Algorithm algorithm = Algorithm.none(); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailNoneVerificationWhenSignatureIsPresent() { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: none"); - String jwt = "eyJhbGciOiJub25lIiwiY3R5IjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9.Ox-WRXRaGAuWt2KfPvWiGcCrPqZtbp_4OnQzZXaTfss"; - Algorithm algorithm = Algorithm.none(); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldReturnNullSigningKeyId() { - assertThat(Algorithm.none().getSigningKeyId(), is(nullValue())); - } - - @Test - public void shouldThrowWhenSignatureNotValidBase64() { - exception.expect(SignatureVerificationException.class); - exception.expectCause(isA(IllegalArgumentException.class)); - - String jwt = "eyJhbGciOiJub25lIiwiY3R5IjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9.Ox-WRXRaGAuWt2KfPvW+iGcCrPqZtbp_4OnQzZXaTfss"; - Algorithm algorithm = Algorithm.none(); - algorithm.verify(JWT.decode(jwt)); - } -} \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/RSAAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/RSAAlgorithmTest.java deleted file mode 100644 index 115de64c..00000000 --- a/lib/src/test/java/com/auth0/jwt/algorithms/RSAAlgorithmTest.java +++ /dev/null @@ -1,579 +0,0 @@ -package com.auth0.jwt.algorithms; - -import com.auth0.jwt.JWT; -import com.auth0.jwt.exceptions.SignatureGenerationException; -import com.auth0.jwt.exceptions.SignatureVerificationException; -import com.auth0.jwt.interfaces.RSAKeyProvider; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.io.ByteArrayOutputStream; -import java.security.*; -import java.security.interfaces.RSAKey; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; - -import static com.auth0.jwt.PemUtils.readPrivateKeyFromFile; -import static com.auth0.jwt.PemUtils.readPublicKeyFromFile; -import static org.hamcrest.Matchers.*; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static com.auth0.jwt.algorithms.CryptoTestHelper.*; - -public class RSAAlgorithmTest { - - private static final String PRIVATE_KEY_FILE = "src/test/resources/rsa-private.pem"; - private static final String PUBLIC_KEY_FILE = "src/test/resources/rsa-public.pem"; - private static final String INVALID_PUBLIC_KEY_FILE = "src/test/resources/rsa-public_invalid.pem"; - - @Rule - public ExpectedException exception = ExpectedException.none(); - - //Verify - - @Test - public void shouldPassRSA256Verification() throws Exception { - String jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.dxXF3MdsyW-AuvwJpaQtrZ33fAde9xWxpLIg9cO2tMLH2GSRNuLAe61KsJusZhqZB9Iy7DvflcmRz-9OZndm6cj_ThGeJH2LLc90K83UEvvRPo8l85RrQb8PcanxCgIs2RcZOLygERizB3pr5icGkzR7R2y6zgNCjKJ5_NJ6EiZsGN6_nc2PRK_DbyY-Wn0QDxIxKoA5YgQJ9qafe7IN980pXvQv2Z62c3XR8dYuaXBqhthBj-AbaFHEpZapN-V-TmuLNzR2MCB6Xr7BYMuCaqWf_XU8og4XNe8f_8w9Wv5vvgqMM1KhqVpG5VdMJv4o_L4NoCROHhtUQSLRh2M9cA"; - Algorithm algorithm = Algorithm.RSA256((RSAKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassRSA256VerificationWithBothKeys() throws Exception { - String jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.dxXF3MdsyW-AuvwJpaQtrZ33fAde9xWxpLIg9cO2tMLH2GSRNuLAe61KsJusZhqZB9Iy7DvflcmRz-9OZndm6cj_ThGeJH2LLc90K83UEvvRPo8l85RrQb8PcanxCgIs2RcZOLygERizB3pr5icGkzR7R2y6zgNCjKJ5_NJ6EiZsGN6_nc2PRK_DbyY-Wn0QDxIxKoA5YgQJ9qafe7IN980pXvQv2Z62c3XR8dYuaXBqhthBj-AbaFHEpZapN-V-TmuLNzR2MCB6Xr7BYMuCaqWf_XU8og4XNe8f_8w9Wv5vvgqMM1KhqVpG5VdMJv4o_L4NoCROHhtUQSLRh2M9cA"; - Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA"), (RSAPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE, "RSA")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassRSA256VerificationWithProvidedPublicKey() throws Exception { - RSAKeyProvider provider = mock(RSAKeyProvider.class); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA"); - when(provider.getPublicKeyById("my-key-id")).thenReturn((RSAPublicKey) publicKey); - String jwt = "eyJhbGciOiJSUzI1NiIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.jXrbue3xJmnzWH9kU-uGeCTtgbQEKbch8uHd4Z52t86ncNyepfusl_bsyLJIcxMwK7odRzKiSE9efV9JaRSEDODDBdMeCzODFx82uBM7e46T1NLVSmjYIM7Hcfh81ZeTIk-hITvgtL6hvTdeJWOCZAB0bs18qSVW5SvursRUhY38xnhuNI6HOHCtqp7etxWAu6670L53I3GtXsmi6bXIzv_0v1xZcAFg4HTvXxfhfj3oCqkSs2nC27mHxBmQtmZKWmXk5HzVUyPRwTUWx5wHPT_hCsGer-CMCAyGsmOg466y1KDqf7ogpMYojfVZGWBsyA39LO1oWZ4Ryomkn8t5Vg"; - Algorithm algorithm = Algorithm.RSA256(provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailRSA256VerificationWhenProvidedPublicKeyIsNull() { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withRSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - RSAKeyProvider provider = mock(RSAKeyProvider.class); - when(provider.getPublicKeyById("my-key-id")).thenReturn(null); - String jwt = "eyJhbGciOiJSUzI1NiIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.jXrbue3xJmnzWH9kU-uGeCTtgbQEKbch8uHd4Z52t86ncNyepfusl_bsyLJIcxMwK7odRzKiSE9efV9JaRSEDODDBdMeCzODFx82uBM7e46T1NLVSmjYIM7Hcfh81ZeTIk-hITvgtL6hvTdeJWOCZAB0bs18qSVW5SvursRUhY38xnhuNI6HOHCtqp7etxWAu6670L53I3GtXsmi6bXIzv_0v1xZcAFg4HTvXxfhfj3oCqkSs2nC27mHxBmQtmZKWmXk5HzVUyPRwTUWx5wHPT_hCsGer-CMCAyGsmOg466y1KDqf7ogpMYojfVZGWBsyA39LO1oWZ4Ryomkn8t5Vg"; - Algorithm algorithm = Algorithm.RSA256(provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailRSA256VerificationWithInvalidPublicKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withRSA"); - String jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.dxXF3MdsyW-AuvwJpaQtrZ33fAde9xWxpLIg9cO2tMLH2GSRNuLAe61KsJusZhqZB9Iy7DvflcmRz-9OZndm6cj_ThGeJH2LLc90K83UEvvRPo8l85RrQb8PcanxCgIs2RcZOLygERizB3pr5icGkzR7R2y6zgNCjKJ5_NJ6EiZsGN6_nc2PRK_DbyY-Wn0QDxIxKoA5YgQJ9qafe7IN980pXvQv2Z62c3XR8dYuaXBqhthBj-AbaFHEpZapN-V-TmuLNzR2MCB6Xr7BYMuCaqWf_XU8og4XNe8f_8w9Wv5vvgqMM1KhqVpG5VdMJv4o_L4NoCROHhtUQSLRh2M9cA"; - Algorithm algorithm = Algorithm.RSA256((RSAKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE, "RSA")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailRSA256VerificationWhenUsingPrivateKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withRSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - String jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.dxXF3MdsyW-AuvwJpaQtrZ33fAde9xWxpLIg9cO2tMLH2GSRNuLAe61KsJusZhqZB9Iy7DvflcmRz-9OZndm6cj_ThGeJH2LLc90K83UEvvRPo8l85RrQb8PcanxCgIs2RcZOLygERizB3pr5icGkzR7R2y6zgNCjKJ5_NJ6EiZsGN6_nc2PRK_DbyY-Wn0QDxIxKoA5YgQJ9qafe7IN980pXvQv2Z62c3XR8dYuaXBqhthBj-AbaFHEpZapN-V-TmuLNzR2MCB6Xr7BYMuCaqWf_XU8og4XNe8f_8w9Wv5vvgqMM1KhqVpG5VdMJv4o_L4NoCROHhtUQSLRh2M9cA"; - Algorithm algorithm = Algorithm.RSA256((RSAKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE, "RSA")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassRSA384Verification() throws Exception { - String jwt = "eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.TZlWjXObwGSQOiu2oMq8kiKz0_BR7bbBddNL6G8eZ_GoR82BXOZDqNrQr7lb_M-78XGBguWLWNIdYhzgxOUL9EoCJlrqVm9s9vo6G8T1sj1op-4TbjXZ61TwIvrJee9BvPLdKUJ9_fp1Js5kl6yXkst40Th8Auc5as4n49MLkipjpEhKDKaENKHpSubs1ripSz8SCQZSofeTM_EWVwSw7cpiM8Fy8jOPvWG8Xz4-e3ODFowvHVsDcONX_4FTMNbeRqDuHq2ZhCJnEfzcSJdrve_5VD5fM1LperBVslTrOxIgClOJ3RmM7-WnaizJrWP3D6Z9OLxPxLhM6-jx6tcxEw"; - Algorithm algorithm = Algorithm.RSA384((RSAKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassRSA384VerificationWithBothKeys() throws Exception { - String jwt = "eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.TZlWjXObwGSQOiu2oMq8kiKz0_BR7bbBddNL6G8eZ_GoR82BXOZDqNrQr7lb_M-78XGBguWLWNIdYhzgxOUL9EoCJlrqVm9s9vo6G8T1sj1op-4TbjXZ61TwIvrJee9BvPLdKUJ9_fp1Js5kl6yXkst40Th8Auc5as4n49MLkipjpEhKDKaENKHpSubs1ripSz8SCQZSofeTM_EWVwSw7cpiM8Fy8jOPvWG8Xz4-e3ODFowvHVsDcONX_4FTMNbeRqDuHq2ZhCJnEfzcSJdrve_5VD5fM1LperBVslTrOxIgClOJ3RmM7-WnaizJrWP3D6Z9OLxPxLhM6-jx6tcxEw"; - Algorithm algorithm = Algorithm.RSA384((RSAPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA"), (RSAPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE, "RSA")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassRSA384VerificationWithProvidedPublicKey() throws Exception { - RSAKeyProvider provider = mock(RSAKeyProvider.class); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA"); - when(provider.getPublicKeyById("my-key-id")).thenReturn((RSAPublicKey) publicKey); - String jwt = "eyJhbGciOiJSUzM4NCIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.ITNTVCT7ercumZKHV4-BXGkJwwa7fyF3CnSfEvm09fDFSkaseDxNo_75WLDmK9WM8RMHTPvkpHcTKm4guYEbC_la7RzFIKpU72bppzQojggSmWWXt_6zq50QP2t5HFMebote1zxhp8ccEdSCX5pyY6J2sm9kJ__HKK32KxIVCTjVCz-bFBS60oG35aYEySdKsxuUdWbD5FQ9I16Ony2x0EPvmlL3GPiAPmgjSFp3LtcBIbCDaoonM7iuDRGIQiDN_n2FKKb1Bt4_38uWPtTkwRpNalt6l53Y3JDdzGI5fMrMo3RQnQlAJxUJKD0eL6dRAA645IVIIXucHwuhgGGIVw"; - Algorithm algorithm = Algorithm.RSA384(provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailRSA384VerificationWhenProvidedPublicKeyIsNull() { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withRSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - RSAKeyProvider provider = mock(RSAKeyProvider.class); - when(provider.getPublicKeyById("my-key-id")).thenReturn(null); - String jwt = "eyJhbGciOiJSUzM4NCIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.ITNTVCT7ercumZKHV4-BXGkJwwa7fyF3CnSfEvm09fDFSkaseDxNo_75WLDmK9WM8RMHTPvkpHcTKm4guYEbC_la7RzFIKpU72bppzQojggSmWWXt_6zq50QP2t5HFMebote1zxhp8ccEdSCX5pyY6J2sm9kJ__HKK32KxIVCTjVCz-bFBS60oG35aYEySdKsxuUdWbD5FQ9I16Ony2x0EPvmlL3GPiAPmgjSFp3LtcBIbCDaoonM7iuDRGIQiDN_n2FKKb1Bt4_38uWPtTkwRpNalt6l53Y3JDdzGI5fMrMo3RQnQlAJxUJKD0eL6dRAA645IVIIXucHwuhgGGIVw"; - Algorithm algorithm = Algorithm.RSA384(provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailRSA384VerificationWithInvalidPublicKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withRSA"); - String jwt = "eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.TZlWjXObwGSQOiu2oMq8kiKz0_BR7bbBddNL6G8eZ_GoR82BXOZDqNrQr7lb_M-78XGBguWLWNIdYhzgxOUL9EoCJlrqVm9s9vo6G8T1sj1op-4TbjXZ61TwIvrJee9BvPLdKUJ9_fp1Js5kl6yXkst40Th8Auc5as4n49MLkipjpEhKDKaENKHpSubs1ripSz8SCQZSofeTM_EWVwSw7cpiM8Fy8jOPvWG8Xz4-e3ODFowvHVsDcONX_4FTMNbeRqDuHq2ZhCJnEfzcSJdrve_5VD5fM1LperBVslTrOxIgClOJ3RmM7-WnaizJrWP3D6Z9OLxPxLhM6-jx6tcxEw"; - Algorithm algorithm = Algorithm.RSA384((RSAKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE, "RSA")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailRSA384VerificationWhenUsingPrivateKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withRSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - String jwt = "eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.TZlWjXObwGSQOiu2oMq8kiKz0_BR7bbBddNL6G8eZ_GoR82BXOZDqNrQr7lb_M-78XGBguWLWNIdYhzgxOUL9EoCJlrqVm9s9vo6G8T1sj1op-4TbjXZ61TwIvrJee9BvPLdKUJ9_fp1Js5kl6yXkst40Th8Auc5as4n49MLkipjpEhKDKaENKHpSubs1ripSz8SCQZSofeTM_EWVwSw7cpiM8Fy8jOPvWG8Xz4-e3ODFowvHVsDcONX_4FTMNbeRqDuHq2ZhCJnEfzcSJdrve_5VD5fM1LperBVslTrOxIgClOJ3RmM7-WnaizJrWP3D6Z9OLxPxLhM6-jx6tcxEw"; - Algorithm algorithm = Algorithm.RSA384((RSAKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE, "RSA")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassRSA512Verification() throws Exception { - String jwt = "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mvL5LoMyIrWYjk5umEXZTmbyIrkbbcVPUkvdGZbu0qFBxGOf0nXP5PZBvPcOu084lvpwVox5n3VaD4iqzW-PsJyvKFgi5TnwmsbKchAp7JexQEsQOnTSGcfRqeUUiBZqRQdYsho71oAB3T4FnalDdFEpM-fztcZY9XqKyayqZLreTeBjqJm4jfOWH7KfGBHgZExQhe96NLq1UA9eUyQwdOA1Z0SgXe4Ja5PxZ6Fm37KnVDtDlNnY4JAAGFo6y74aGNnp_BKgpaVJCGFu1f1S5xCQ1HSvs8ZSdVWs5NgawW3wRd0kRt_GJ_Y3mIwiF4qUyHWGtsSHu_qjVdCTtbFyow"; - Algorithm algorithm = Algorithm.RSA512((RSAKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassRSA512VerificationWithBothKeys() throws Exception { - String jwt = "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mvL5LoMyIrWYjk5umEXZTmbyIrkbbcVPUkvdGZbu0qFBxGOf0nXP5PZBvPcOu084lvpwVox5n3VaD4iqzW-PsJyvKFgi5TnwmsbKchAp7JexQEsQOnTSGcfRqeUUiBZqRQdYsho71oAB3T4FnalDdFEpM-fztcZY9XqKyayqZLreTeBjqJm4jfOWH7KfGBHgZExQhe96NLq1UA9eUyQwdOA1Z0SgXe4Ja5PxZ6Fm37KnVDtDlNnY4JAAGFo6y74aGNnp_BKgpaVJCGFu1f1S5xCQ1HSvs8ZSdVWs5NgawW3wRd0kRt_GJ_Y3mIwiF4qUyHWGtsSHu_qjVdCTtbFyow"; - Algorithm algorithm = Algorithm.RSA512((RSAPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA"), (RSAPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE, "RSA")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassRSA512VerificationWithProvidedPublicKey() throws Exception { - RSAKeyProvider provider = mock(RSAKeyProvider.class); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA"); - when(provider.getPublicKeyById("my-key-id")).thenReturn((RSAPublicKey) publicKey); - String jwt = "eyJhbGciOiJSUzUxMiIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.GpHv85Q8tAU_6hNWsmO0GEpO1qz9lmK3NKeAcemysz9MGo4FXWn8xbD8NjCfzZ8EWphm65M0NArKSjpKHO5-gcNsQxLBVfSED1vzcoaZH_Vy5Rp1M76dGH7JghB_66KrpfyMxer_yRJb-KXesNvIroDGilLQF2ENG-IfLF5nBKlDiVHmPaqr3pm1q20fNLhegkSRca4BJ5VdIlT6kOqE_ykVyCBqzD_oXp3LKO_ARnxoeB9SegIW1fy_3tuxSTKYsCZiOfiyVEXXblAuY3pSLZnGvgeBRnfvmWXDWhP0vVUFtYJBF09eULvvUMVqWcrjUG9gDzzzT7veiY_fHd_x8g"; - Algorithm algorithm = Algorithm.RSA512(provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailRSA512VerificationWhenProvidedPublicKeyIsNull() { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withRSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - RSAKeyProvider provider = mock(RSAKeyProvider.class); - when(provider.getPublicKeyById("my-key-id")).thenReturn(null); - String jwt = "eyJhbGciOiJSUzUxMiIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.GpHv85Q8tAU_6hNWsmO0GEpO1qz9lmK3NKeAcemysz9MGo4FXWn8xbD8NjCfzZ8EWphm65M0NArKSjpKHO5-gcNsQxLBVfSED1vzcoaZH_Vy5Rp1M76dGH7JghB_66KrpfyMxer_yRJb-KXesNvIroDGilLQF2ENG-IfLF5nBKlDiVHmPaqr3pm1q20fNLhegkSRca4BJ5VdIlT6kOqE_ykVyCBqzD_oXp3LKO_ARnxoeB9SegIW1fy_3tuxSTKYsCZiOfiyVEXXblAuY3pSLZnGvgeBRnfvmWXDWhP0vVUFtYJBF09eULvvUMVqWcrjUG9gDzzzT7veiY_fHd_x8g"; - Algorithm algorithm = Algorithm.RSA512(provider); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailRSA512VerificationWithInvalidPublicKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withRSA"); - String jwt = "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mvL5LoMyIrWYjk5umEXZTmbyIrkbbcVPUkvdGZbu0qFBxGOf0nXP5PZBvPcOu084lvpwVox5n3VaD4iqzW-PsJyvKFgi5TnwmsbKchAp7JexQEsQOnTSGcfRqeUUiBZqRQdYsho71oAB3T4FnalDdFEpM-fztcZY9XqKyayqZLreTeBjqJm4jfOWH7KfGBHgZExQhe96NLq1UA9eUyQwdOA1Z0SgXe4Ja5PxZ6Fm37KnVDtDlNnY4JAAGFo6y74aGNnp_BKgpaVJCGFu1f1S5xCQ1HSvs8ZSdVWs5NgawW3wRd0kRt_GJ_Y3mIwiF4qUyHWGtsSHu_qjVdCTtbFyow"; - Algorithm algorithm = Algorithm.RSA512((RSAKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE, "RSA")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailRSA512VerificationWhenUsingPrivateKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withRSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - String jwt = "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mvL5LoMyIrWYjk5umEXZTmbyIrkbbcVPUkvdGZbu0qFBxGOf0nXP5PZBvPcOu084lvpwVox5n3VaD4iqzW-PsJyvKFgi5TnwmsbKchAp7JexQEsQOnTSGcfRqeUUiBZqRQdYsho71oAB3T4FnalDdFEpM-fztcZY9XqKyayqZLreTeBjqJm4jfOWH7KfGBHgZExQhe96NLq1UA9eUyQwdOA1Z0SgXe4Ja5PxZ6Fm37KnVDtDlNnY4JAAGFo6y74aGNnp_BKgpaVJCGFu1f1S5xCQ1HSvs8ZSdVWs5NgawW3wRd0kRt_GJ_Y3mIwiF4qUyHWGtsSHu_qjVdCTtbFyow"; - Algorithm algorithm = Algorithm.RSA512((RSAKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE, "RSA")); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowWhenMacAlgorithmDoesNotExists() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: some-alg"); - exception.expectCause(isA(NoSuchAlgorithmException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.verifySignatureFor(anyString(), any(PublicKey.class), any(String.class), any(String.class), any(byte[].class))) - .thenThrow(NoSuchAlgorithmException.class); - - RSAPublicKey publicKey = mock(RSAPublicKey.class); - RSAPrivateKey privateKey = mock(RSAPrivateKey.class); - RSAKeyProvider provider = RSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new RSAAlgorithm(crypto, "some-alg", "some-algorithm", provider); - String jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.dxXF3MdsyW-AuvwJpaQtrZ33fAde9xWxpLIg9cO2tMLH2GSRNuLAe61KsJusZhqZB9Iy7DvflcmRz-9OZndm6cj_ThGeJH2LLc90K83UEvvRPo8l85RrQb8PcanxCgIs2RcZOLygERizB3pr5icGkzR7R2y6zgNCjKJ5_NJ6EiZsGN6_nc2PRK_DbyY-Wn0QDxIxKoA5YgQJ9qafe7IN980pXvQv2Z62c3XR8dYuaXBqhthBj-AbaFHEpZapN-V-TmuLNzR2MCB6Xr7BYMuCaqWf_XU8og4XNe8f_8w9Wv5vvgqMM1KhqVpG5VdMJv4o_L4NoCROHhtUQSLRh2M9cA"; - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowWhenThePublicKeyIsInvalid() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: some-alg"); - exception.expectCause(isA(InvalidKeyException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.verifySignatureFor(anyString(), any(PublicKey.class), any(String.class), any(String.class), any(byte[].class))) - .thenThrow(InvalidKeyException.class); - - RSAPublicKey publicKey = mock(RSAPublicKey.class); - RSAPrivateKey privateKey = mock(RSAPrivateKey.class); - RSAKeyProvider provider = RSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new RSAAlgorithm(crypto, "some-alg", "some-algorithm", provider); - String jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.dxXF3MdsyW-AuvwJpaQtrZ33fAde9xWxpLIg9cO2tMLH2GSRNuLAe61KsJusZhqZB9Iy7DvflcmRz-9OZndm6cj_ThGeJH2LLc90K83UEvvRPo8l85RrQb8PcanxCgIs2RcZOLygERizB3pr5icGkzR7R2y6zgNCjKJ5_NJ6EiZsGN6_nc2PRK_DbyY-Wn0QDxIxKoA5YgQJ9qafe7IN980pXvQv2Z62c3XR8dYuaXBqhthBj-AbaFHEpZapN-V-TmuLNzR2MCB6Xr7BYMuCaqWf_XU8og4XNe8f_8w9Wv5vvgqMM1KhqVpG5VdMJv4o_L4NoCROHhtUQSLRh2M9cA"; - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldThrowWhenTheSignatureIsNotPrepared() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: some-alg"); - exception.expectCause(isA(SignatureException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.verifySignatureFor(anyString(), any(PublicKey.class), any(String.class), any(String.class), any(byte[].class))) - .thenThrow(SignatureException.class); - - RSAPublicKey publicKey = mock(RSAPublicKey.class); - RSAPrivateKey privateKey = mock(RSAPrivateKey.class); - RSAKeyProvider provider = RSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new RSAAlgorithm(crypto, "some-alg", "some-algorithm", provider); - String jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.dxXF3MdsyW-AuvwJpaQtrZ33fAde9xWxpLIg9cO2tMLH2GSRNuLAe61KsJusZhqZB9Iy7DvflcmRz-9OZndm6cj_ThGeJH2LLc90K83UEvvRPo8l85RrQb8PcanxCgIs2RcZOLygERizB3pr5icGkzR7R2y6zgNCjKJ5_NJ6EiZsGN6_nc2PRK_DbyY-Wn0QDxIxKoA5YgQJ9qafe7IN980pXvQv2Z62c3XR8dYuaXBqhthBj-AbaFHEpZapN-V-TmuLNzR2MCB6Xr7BYMuCaqWf_XU8og4XNe8f_8w9Wv5vvgqMM1KhqVpG5VdMJv4o_L4NoCROHhtUQSLRh2M9cA"; - algorithm.verify(JWT.decode(jwt)); - } - - - //Sign - private static final String RS256Header = "eyJhbGciOiJSUzI1NiJ9"; - private static final String RS384Header = "eyJhbGciOiJSUzM4NCJ9"; - private static final String RS512Header = "eyJhbGciOiJSUzUxMiJ9"; - private static final String auth0IssPayload = "eyJpc3MiOiJhdXRoMCJ9"; - - @Test - public void shouldDoRSA256Signing() throws Exception { - Algorithm algorithmSign = Algorithm.RSA256((RSAKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE, "RSA")); - Algorithm algorithmVerify = Algorithm.RSA256((RSAKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA")); - - String jwt = asJWT(algorithmSign, RS256Header, auth0IssPayload); - String expectedSignature = "ZB-Tr0vLtnf8I9fhSdSjU6HZei5xLYZQ6nZqM5O6Va0W9PgAqgRT7ShI9CjeYulRXPHvVmSl5EQuYuXdBzM0-H_3p_Nsl6tSMy4EyX2kkhEm6T0HhvarTh8CG0PCjn5p6FP5ZxWwhLcmRN70ItP6Z5MMO4CcJh1JrNxR4Fi4xQgt-CK2aVDMFXd-Br5yQiLVx1CX83w28OD9wssW3Rdltl5e66vCef0Ql6Q5I5e5F0nqGYT989a9fkNgLIx2F8k_az5x07BY59FV2SZg59nSiY7TZNjP8ot11Ew7HKRfPXOdh9eKRUVdhcxzqDePhyzKabU8TG5FP0SiWH5qVPfAgw"; - - assertSignaturePresent(jwt); - assertSignatureValue(jwt, expectedSignature); - algorithmVerify.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoRSA256SigningWithBothKeys() throws Exception { - Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA"), (RSAPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE, "RSA")); - - String jwt = asJWT(algorithm, RS256Header, auth0IssPayload); - String expectedSignature = "ZB-Tr0vLtnf8I9fhSdSjU6HZei5xLYZQ6nZqM5O6Va0W9PgAqgRT7ShI9CjeYulRXPHvVmSl5EQuYuXdBzM0-H_3p_Nsl6tSMy4EyX2kkhEm6T0HhvarTh8CG0PCjn5p6FP5ZxWwhLcmRN70ItP6Z5MMO4CcJh1JrNxR4Fi4xQgt-CK2aVDMFXd-Br5yQiLVx1CX83w28OD9wssW3Rdltl5e66vCef0Ql6Q5I5e5F0nqGYT989a9fkNgLIx2F8k_az5x07BY59FV2SZg59nSiY7TZNjP8ot11Ew7HKRfPXOdh9eKRUVdhcxzqDePhyzKabU8TG5FP0SiWH5qVPfAgw"; - - assertSignaturePresent(jwt); - assertSignatureValue(jwt, expectedSignature); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoRSA256SigningWithProvidedPrivateKey() throws Exception { - RSAKeyProvider provider = mock(RSAKeyProvider.class); - PrivateKey privateKey = readPrivateKeyFromFile(PRIVATE_KEY_FILE, "RSA"); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA"); - when(provider.getPrivateKey()).thenReturn((RSAPrivateKey) privateKey); - when(provider.getPublicKeyById(null)).thenReturn((RSAPublicKey) publicKey); - Algorithm algorithm = Algorithm.RSA256(provider); - - String jwt = asJWT(algorithm, RS256Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailOnRSA256SigningWhenProvidedPrivateKeyIsNull() { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withRSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - RSAKeyProvider provider = mock(RSAKeyProvider.class); - when(provider.getPrivateKey()).thenReturn(null); - Algorithm algorithm = Algorithm.RSA256(provider); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldFailOnRSA256SigningWhenUsingPublicKey() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withRSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - Algorithm algorithm = Algorithm.RSA256((RSAKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA")); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldDoRSA384Signing() throws Exception { - Algorithm algorithmSign = Algorithm.RSA384((RSAKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE, "RSA")); - Algorithm algorithmVerify = Algorithm.RSA384((RSAKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA")); - - String jwt = asJWT(algorithmSign, RS384Header, auth0IssPayload); - String expectedSignature = "Jx1PaTBnjd_U56MNjifFcY7w9ImDbseg0y8Ijr2pSiA1_wzQb_wy9undaWfzR5YqdIAXvjS8AGuZUAzIoTG4KMgOgdVyYDz3l2jzj6wI-lgqfR5hTy1w1ruMUQ4_wobpdxAiJ4fEbg8Mi_GljOiCO-P1HilxKnpiOJZidR8MQGwTInsf71tOUkK4x5UsdmUueuZbaU-CL5kPnRfXmJj9CcdxZbD9oMlbo23dwkP5BNMrS2LwGGzc9C_-ypxrBIOVilG3WZxcSmuG86LjcZbnL6LBEfph5NmKBgQav147uipb_7umBEr1m2dYiB_9u606n3bcoo3rnsYYK_Xfi1GAEQ"; - - assertSignaturePresent(jwt); - assertSignatureValue(jwt, expectedSignature); - algorithmVerify.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoRSA384SigningWithBothKeys() throws Exception { - Algorithm algorithm = Algorithm.RSA384((RSAPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA"), (RSAPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE, "RSA")); - - String jwt = asJWT(algorithm, RS384Header, auth0IssPayload); - String expectedSignature = "Jx1PaTBnjd_U56MNjifFcY7w9ImDbseg0y8Ijr2pSiA1_wzQb_wy9undaWfzR5YqdIAXvjS8AGuZUAzIoTG4KMgOgdVyYDz3l2jzj6wI-lgqfR5hTy1w1ruMUQ4_wobpdxAiJ4fEbg8Mi_GljOiCO-P1HilxKnpiOJZidR8MQGwTInsf71tOUkK4x5UsdmUueuZbaU-CL5kPnRfXmJj9CcdxZbD9oMlbo23dwkP5BNMrS2LwGGzc9C_-ypxrBIOVilG3WZxcSmuG86LjcZbnL6LBEfph5NmKBgQav147uipb_7umBEr1m2dYiB_9u606n3bcoo3rnsYYK_Xfi1GAEQ"; - - assertSignaturePresent(jwt); - assertSignatureValue(jwt, expectedSignature); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoRSA384SigningWithProvidedPrivateKey() throws Exception { - RSAKeyProvider provider = mock(RSAKeyProvider.class); - PrivateKey privateKey = readPrivateKeyFromFile(PRIVATE_KEY_FILE, "RSA"); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA"); - when(provider.getPrivateKey()).thenReturn((RSAPrivateKey) privateKey); - when(provider.getPublicKeyById(null)).thenReturn((RSAPublicKey) publicKey); - Algorithm algorithm = Algorithm.RSA384(provider); - - String jwt = asJWT(algorithm, RS384Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailOnRSA384SigningWhenProvidedPrivateKeyIsNull() { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA384withRSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - RSAKeyProvider provider = mock(RSAKeyProvider.class); - when(provider.getPrivateKey()).thenReturn(null); - Algorithm algorithm = Algorithm.RSA384(provider); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldFailOnRSA384SigningWhenUsingPublicKey() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA384withRSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - Algorithm algorithm = Algorithm.RSA384((RSAKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA")); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldDoRSA512Signing() throws Exception { - Algorithm algorithmSign = Algorithm.RSA512((RSAKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE, "RSA")); - Algorithm algorithmVerify = Algorithm.RSA512((RSAKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA")); - - String jwt = asJWT(algorithmSign, RS512Header, auth0IssPayload); - String expectedSignature = "THIPVYzNZ1Yo_dm0k1UELqV0txs3SzyMopCyHcLXOOdgYXF4MlGvBqu0CFvgSga72Sp5LpuC1Oesj40v_QDsp2GTGDeWnvvcv_eo-b0LPSpmT2h1Ibrmu-z70u2rKf28pkN-AJiMFqi8sit2kMIp1bwIVOovPvMTQKGFmova4Xwb3G526y_PeLlflW1h69hQTIVcI67ACEkAC-byjDnnYIklA-B4GWcggEoFwQRTdRjAUpifA6HOlvnBbZZlUd6KXwEydxVS-eh1odwPjB2_sfbyy5HnLsvNdaniiZQwX7QbwLNT4F72LctYdHHM1QCrID6bgfgYp9Ij9CRX__XDEA"; - - assertSignaturePresent(jwt); - assertSignatureValue(jwt, expectedSignature); - algorithmVerify.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoRSA512SigningWithBothKeys() throws Exception { - Algorithm algorithm = Algorithm.RSA512((RSAPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA"), (RSAPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE, "RSA")); - - String jwt = asJWT(algorithm, RS512Header, auth0IssPayload); - String expectedSignature = "THIPVYzNZ1Yo_dm0k1UELqV0txs3SzyMopCyHcLXOOdgYXF4MlGvBqu0CFvgSga72Sp5LpuC1Oesj40v_QDsp2GTGDeWnvvcv_eo-b0LPSpmT2h1Ibrmu-z70u2rKf28pkN-AJiMFqi8sit2kMIp1bwIVOovPvMTQKGFmova4Xwb3G526y_PeLlflW1h69hQTIVcI67ACEkAC-byjDnnYIklA-B4GWcggEoFwQRTdRjAUpifA6HOlvnBbZZlUd6KXwEydxVS-eh1odwPjB2_sfbyy5HnLsvNdaniiZQwX7QbwLNT4F72LctYdHHM1QCrID6bgfgYp9Ij9CRX__XDEA"; - - assertSignaturePresent(jwt); - assertSignatureValue(jwt, expectedSignature); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldDoRSA512SigningWithProvidedPrivateKey() throws Exception { - RSAKeyProvider provider = mock(RSAKeyProvider.class); - PrivateKey privateKey = readPrivateKeyFromFile(PRIVATE_KEY_FILE, "RSA"); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA"); - when(provider.getPrivateKey()).thenReturn((RSAPrivateKey) privateKey); - when(provider.getPublicKeyById(null)).thenReturn((RSAPublicKey) publicKey); - Algorithm algorithm = Algorithm.RSA512(provider); - - String jwt = asJWT(algorithm, RS512Header, auth0IssPayload); - - assertSignaturePresent(jwt); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailOnRSA512SigningWhenProvidedPrivateKeyIsNull() { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA512withRSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - RSAKeyProvider provider = mock(RSAKeyProvider.class); - when(provider.getPrivateKey()).thenReturn(null); - Algorithm algorithm = Algorithm.RSA512(provider); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldFailOnRSA512SigningWhenUsingPublicKey() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA512withRSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - Algorithm algorithm = Algorithm.RSA512((RSAKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA")); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldThrowOnSignWhenSignatureAlgorithmDoesNotExists() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: some-algorithm"); - exception.expectCause(isA(NoSuchAlgorithmException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.createSignatureFor(anyString(), any(PrivateKey.class), any(byte[].class), any(byte[].class))) - .thenThrow(NoSuchAlgorithmException.class); - - RSAPublicKey publicKey = mock(RSAPublicKey.class); - RSAPrivateKey privateKey = mock(RSAPrivateKey.class); - RSAKeyProvider provider = RSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new RSAAlgorithm(crypto, "some-alg", "some-algorithm", provider); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldThrowOnSignWhenThePrivateKeyIsInvalid() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: some-algorithm"); - exception.expectCause(isA(InvalidKeyException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.createSignatureFor(anyString(), any(PrivateKey.class), any(byte[].class), any(byte[].class))) - .thenThrow(InvalidKeyException.class); - - RSAPublicKey publicKey = mock(RSAPublicKey.class); - RSAPrivateKey privateKey = mock(RSAPrivateKey.class); - RSAKeyProvider provider = RSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new RSAAlgorithm(crypto, "some-alg", "some-algorithm", provider); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldThrowOnSignWhenTheSignatureIsNotPrepared() throws Exception { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: some-algorithm"); - exception.expectCause(isA(SignatureException.class)); - - CryptoHelper crypto = mock(CryptoHelper.class); - when(crypto.createSignatureFor(anyString(), any(PrivateKey.class), any(byte[].class), any(byte[].class))) - .thenThrow(SignatureException.class); - - RSAPublicKey publicKey = mock(RSAPublicKey.class); - RSAPrivateKey privateKey = mock(RSAPrivateKey.class); - RSAKeyProvider provider = RSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new RSAAlgorithm(crypto, "some-alg", "some-algorithm", provider); - algorithm.sign(new byte[0], new byte[0]); - } - - @Test - public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() { - RSAPublicKey publicKey = mock(RSAPublicKey.class); - RSAPrivateKey privateKey = mock(RSAPrivateKey.class); - RSAKeyProvider provider = RSAAlgorithm.providerForKeys(publicKey, privateKey); - Algorithm algorithm = new RSAAlgorithm("some-alg", "some-algorithm", provider); - - assertThat(algorithm.getSigningKeyId(), is(nullValue())); - } - - @Test - public void shouldReturnSigningKeyIdFromProvider() { - RSAKeyProvider provider = mock(RSAKeyProvider.class); - when(provider.getPrivateKeyId()).thenReturn("keyId"); - Algorithm algorithm = new RSAAlgorithm("some-alg", "some-algorithm", provider); - - assertThat(algorithm.getSigningKeyId(), is("keyId")); - } - - @Test - public void shouldBeEqualSignatureMethodResults() throws Exception { - RSAPrivateKey privateKey = (RSAPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE, "RSA"); - RSAPublicKey publicKey = (RSAPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE, "RSA"); - - Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey); - - byte[] header = new byte[]{0x00, 0x01, 0x02}; - byte[] payload = new byte[]{0x04, 0x05, 0x06}; - - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - bout.write(header); - bout.write('.'); - bout.write(payload); - - assertThat(algorithm.sign(bout.toByteArray()), is(algorithm.sign(header, payload))); - } - - /** - * Test deprecated signing method error handling. - * - * @see {@linkplain #shouldFailOnRSA256SigningWhenProvidedPrivateKeyIsNull} - */ - - @Test - public void shouldFailOnRSA256SigningWithDeprecatedMethodWhenProvidedPrivateKeyIsNull() { - exception.expect(SignatureGenerationException.class); - exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withRSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Private Key is null."))); - - RSAKeyProvider provider = mock(RSAKeyProvider.class); - when(provider.getPrivateKey()).thenReturn(null); - Algorithm algorithm = Algorithm.RSA256(provider); - algorithm.sign(new byte[0]); - } - - @Test - public void shouldThrowWhenSignatureNotValidBase64() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectCause(isA(IllegalArgumentException.class)); - - String jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.dxXF3MdsyW-AuvwJpaQtrZ33fAde9xWxpLIg9cO2tMLH2GSRNu+LAe61KsJusZhqZB9Iy7DvflcmRz-9OZndm6cj_ThGeJH2LLc90K83UEvvRPo8l85RrQb8PcanxCgIs2RcZOLygERizB3pr5icGkzR7R2y6zgNCjKJ5_NJ6EiZsGN6_nc2PRK_DbyY-Wn0QDxIxKoA5YgQJ9qafe7IN980pXvQv2Z62c3XR8dYuaXBqhthBj-AbaFHEpZapN-V-TmuLNzR2MCB6Xr7BYMuCaqWf_XU8og4XNe8f_8w9Wv5vvgqMM1KhqVpG5VdMJv4o_L4NoCROHhtUQSLRh2M9cA"; - Algorithm algorithm = Algorithm.RSA256((RSAKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE, "RSA")); - algorithm.verify(JWT.decode(jwt)); - } -} \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/impl/BasicHeaderTest.java b/lib/src/test/java/com/auth0/jwt/impl/BasicHeaderTest.java deleted file mode 100644 index c4a04d81..00000000 --- a/lib/src/test/java/com/auth0/jwt/impl/BasicHeaderTest.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.auth0.jwt.impl; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectReader; -import com.fasterxml.jackson.databind.node.NullNode; -import com.fasterxml.jackson.databind.node.TextNode; -import org.hamcrest.collection.IsMapContaining; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.util.HashMap; -import java.util.Map; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; - -public class BasicHeaderTest { - - @Rule - public ExpectedException exception = ExpectedException.none(); - - private ObjectReader objectReader = new ObjectMapper().reader(); - - @SuppressWarnings("Convert2Diamond") - @Test - public void shouldHaveUnmodifiableTreeWhenInstantiatedWithNonNullTree() { - exception.expect(UnsupportedOperationException.class); - BasicHeader header = new BasicHeader(null, null, null, null, new HashMap(), objectReader); - header.getTree().put("something", null); - } - - @Test - public void shouldHaveUnmodifiableTreeWhenInstantiatedWithNullTree() { - exception.expect(UnsupportedOperationException.class); - BasicHeader header = new BasicHeader(null, null, null, null, null, objectReader); - header.getTree().put("something", null); - } - - @Test - public void shouldHaveTree() { - HashMap map = new HashMap<>(); - JsonNode node = NullNode.getInstance(); - map.put("key", node); - BasicHeader header = new BasicHeader(null, null, null, null, map, objectReader); - - assertThat(header.getTree(), is(notNullValue())); - assertThat(header.getTree(), is(IsMapContaining.hasEntry("key", node))); - } - - @Test - public void shouldGetAlgorithm() { - BasicHeader header = new BasicHeader("HS256", null, null, null, null, objectReader); - - assertThat(header, is(notNullValue())); - assertThat(header.getAlgorithm(), is(notNullValue())); - assertThat(header.getAlgorithm(), is("HS256")); - } - - @Test - public void shouldGetNullAlgorithmIfMissing() { - BasicHeader header = new BasicHeader(null, null, null, null, null, objectReader); - - assertThat(header, is(notNullValue())); - assertThat(header.getAlgorithm(), is(nullValue())); - } - - @Test - public void shouldGetType() { - BasicHeader header = new BasicHeader(null, "jwt", null, null, null, objectReader); - - assertThat(header, is(notNullValue())); - assertThat(header.getType(), is(notNullValue())); - assertThat(header.getType(), is("jwt")); - } - - @Test - public void shouldGetNullTypeIfMissing() { - BasicHeader header = new BasicHeader(null, null, null, null, null, objectReader); - - assertThat(header, is(notNullValue())); - assertThat(header.getType(), is(nullValue())); - } - - @Test - public void shouldGetContentType() { - BasicHeader header = new BasicHeader(null, null, "content", null, null, objectReader); - - assertThat(header, is(notNullValue())); - assertThat(header.getContentType(), is(notNullValue())); - assertThat(header.getContentType(), is("content")); - } - - @Test - public void shouldGetNullContentTypeIfMissing() { - BasicHeader header = new BasicHeader(null, null, null, null, null, objectReader); - - assertThat(header, is(notNullValue())); - assertThat(header.getContentType(), is(nullValue())); - } - - @Test - public void shouldGetKeyId() { - BasicHeader header = new BasicHeader(null, null, null, "key", null, objectReader); - - assertThat(header, is(notNullValue())); - assertThat(header.getKeyId(), is(notNullValue())); - assertThat(header.getKeyId(), is("key")); - } - - @Test - public void shouldGetNullKeyIdIfMissing() { - BasicHeader header = new BasicHeader(null, null, null, null, null, objectReader); - - assertThat(header, is(notNullValue())); - assertThat(header.getKeyId(), is(nullValue())); - } - - @Test - public void shouldGetExtraClaim() { - Map tree = new HashMap<>(); - tree.put("extraClaim", new TextNode("extraValue")); - BasicHeader header = new BasicHeader(null, null, null, null, tree, objectReader); - - assertThat(header, is(notNullValue())); - assertThat(header.getHeaderClaim("extraClaim"), is(instanceOf(JsonNodeClaim.class))); - assertThat(header.getHeaderClaim("extraClaim").asString(), is("extraValue")); - } - - @Test - public void shouldGetNotNullExtraClaimIfMissing() { - Map tree = new HashMap<>(); - BasicHeader header = new BasicHeader(null, null, null, null, tree, objectReader); - - assertThat(header, is(notNullValue())); - assertThat(header.getHeaderClaim("missing"), is(notNullValue())); - assertThat(header.getHeaderClaim("missing").isMissing(), is(true)); - assertThat(header.getHeaderClaim("missing").isNull(), is(false)); - } -} \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java b/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java deleted file mode 100644 index 02d782a7..00000000 --- a/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.auth0.jwt.impl; - -import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.interfaces.Header; -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.ObjectCodec; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.NullNode; -import com.fasterxml.jackson.databind.node.TextNode; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.io.StringReader; -import java.util.HashMap; -import java.util.Map; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class HeaderDeserializerTest { - - @Rule - public ExpectedException exception = ExpectedException.none(); - private HeaderDeserializer deserializer; - - @Before - public void setUp() { - deserializer = new HeaderDeserializer(); - } - - @Test - public void shouldThrowOnNullTree() throws Exception { - exception.expect(JWTDecodeException.class); - exception.expectMessage("Parsing the Header's JSON resulted on a Null map"); - - JsonDeserializer deserializer = new HeaderDeserializer(); - JsonParser parser = mock(JsonParser.class); - ObjectCodec codec = mock(ObjectCodec.class); - DeserializationContext context = mock(DeserializationContext.class); - - when(codec.readValue(eq(parser), any(TypeReference.class))).thenReturn(null); - when(parser.getCodec()).thenReturn(codec); - - deserializer.deserialize(parser, context); - } - - - @Test - public void shouldNotRemoveKnownPublicClaimsFromTree() throws Exception { - String headerJSON = "{\n" + - " \"alg\": \"HS256\",\n" + - " \"typ\": \"jws\",\n" + - " \"cty\": \"content\",\n" + - " \"kid\": \"key\",\n" + - " \"roles\": \"admin\"\n" + - "}"; - StringReader reader = new StringReader(headerJSON); - JsonParser jsonParser = new JsonFactory().createParser(reader); - ObjectMapper mapper = new ObjectMapper(); - jsonParser.setCodec(mapper); - - Header header = deserializer.deserialize(jsonParser, mapper.getDeserializationContext()); - - assertThat(header, is(notNullValue())); - assertThat(header.getAlgorithm(), is("HS256")); - assertThat(header.getType(), is("jws")); - assertThat(header.getContentType(), is("content")); - assertThat(header.getKeyId(), is("key")); - - assertThat(header.getHeaderClaim("roles").asString(), is("admin")); - assertThat(header.getHeaderClaim("alg").asString(), is("HS256")); - assertThat(header.getHeaderClaim("typ").asString(), is("jws")); - assertThat(header.getHeaderClaim("cty").asString(), is("content")); - assertThat(header.getHeaderClaim("kid").asString(), is("key")); - } - - @Test - public void shouldGetNullStringWhenParsingNullNode() { - Map tree = new HashMap<>(); - NullNode node = NullNode.getInstance(); - tree.put("key", node); - - String text = deserializer.getString(tree, "key"); - assertThat(text, is(nullValue())); - } - - @Test - public void shouldGetNullStringWhenParsingNull() { - Map tree = new HashMap<>(); - tree.put("key", null); - - String text = deserializer.getString(tree, "key"); - assertThat(text, is(nullValue())); - } - - @Test - public void shouldGetStringWhenParsingTextNode() { - Map tree = new HashMap<>(); - TextNode node = new TextNode("something here"); - tree.put("key", node); - - String text = deserializer.getString(tree, "key"); - assertThat(text, is(notNullValue())); - assertThat(text, is("something here")); - } -} \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/impl/JWTParserTest.java b/lib/src/test/java/com/auth0/jwt/impl/JWTParserTest.java deleted file mode 100644 index da62131a..00000000 --- a/lib/src/test/java/com/auth0/jwt/impl/JWTParserTest.java +++ /dev/null @@ -1,116 +0,0 @@ -package com.auth0.jwt.impl; - -import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.interfaces.Header; -import com.auth0.jwt.interfaces.Payload; -import com.fasterxml.jackson.databind.Module; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectReader; -import com.fasterxml.jackson.databind.SerializationFeature; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import static com.auth0.jwt.impl.JWTParser.getDefaultObjectMapper; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class JWTParserTest { - - @Rule - public ExpectedException exception = ExpectedException.none(); - private JWTParser parser; - - @Before - public void setUp() { - parser = new JWTParser(); - } - - @Test - public void shouldGetDefaultObjectMapper() { - ObjectMapper mapper = getDefaultObjectMapper(); - assertThat(mapper, is(notNullValue())); - assertThat(mapper, is(instanceOf(ObjectMapper.class))); - assertThat(mapper.isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS), is(false)); - } - - @Test - public void shouldAddDeserializers() { - ObjectMapper mapper = mock(ObjectMapper.class); - JWTParser.addDeserializers(mapper); - verify(mapper).registerModule(any(Module.class)); - } - - @Test - public void shouldParsePayload() throws Exception { - ObjectMapper mapper = mock(ObjectMapper.class); - ObjectReader reader = mock(ObjectReader.class); - when(mapper.readerFor(Payload.class)).thenReturn(reader); - JWTParser parser = new JWTParser(mapper); - parser.parsePayload("{}"); - - verify(reader).readValue("{}"); - } - - @Test - public void shouldThrowOnInvalidPayload() { - String jsonPayload = "{{"; - exception.expect(JWTDecodeException.class); - exception.expectMessage(String.format("The string '%s' doesn't have a valid JSON format.", jsonPayload)); - Payload payload = parser.parsePayload(jsonPayload); - assertThat(payload, is(nullValue())); - } - - @Test - public void shouldParseHeader() throws Exception { - ObjectMapper mapper = mock(ObjectMapper.class); - ObjectReader reader = mock(ObjectReader.class); - when(mapper.readerFor(Header.class)).thenReturn(reader); - JWTParser parser = new JWTParser(mapper); - parser.parseHeader("{}"); - - verify(reader).readValue("{}"); - } - - @Test - public void shouldThrowOnInvalidHeader() { - String jsonHeader = "}}"; - exception.expect(JWTDecodeException.class); - exception.expectMessage(String.format("The string '%s' doesn't have a valid JSON format.", jsonHeader)); - Header header = parser.parseHeader(jsonHeader); - assertThat(header, is(nullValue())); - } - - @Test - public void shouldThrowWhenConvertingHeaderIfNullJson() { - exception.expect(JWTDecodeException.class); - exception.expectMessage("The string 'null' doesn't have a valid JSON format."); - parser.parseHeader(null); - } - - @Test - public void shouldThrowWhenConvertingHeaderFromInvalidJson() { - exception.expect(JWTDecodeException.class); - exception.expectMessage("The string '}{' doesn't have a valid JSON format."); - parser.parseHeader("}{"); - } - - @Test - public void shouldThrowWhenConvertingPayloadIfNullJson() { - exception.expect(JWTDecodeException.class); - exception.expectMessage("The string 'null' doesn't have a valid JSON format."); - parser.parsePayload(null); - } - - @Test - public void shouldThrowWhenConvertingPayloadFromInvalidJson() { - exception.expect(JWTDecodeException.class); - exception.expectMessage("The string '}{' doesn't have a valid JSON format."); - parser.parsePayload("}{"); - } -} diff --git a/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java b/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java deleted file mode 100644 index a0364953..00000000 --- a/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java +++ /dev/null @@ -1,533 +0,0 @@ -package com.auth0.jwt.impl; - -import com.auth0.jwt.UserPojo; -import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.interfaces.Claim; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.JsonNodeType; -import com.fasterxml.jackson.databind.node.MissingNode; -import com.fasterxml.jackson.databind.node.NullNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import org.hamcrest.collection.IsMapContaining; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.ArgumentMatchers; - -import java.io.IOException; -import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -import static com.auth0.jwt.impl.JWTParser.getDefaultObjectMapper; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.arrayContaining; -import static org.hamcrest.Matchers.hasEntry; -import static org.hamcrest.Matchers.hasItems; -import static org.hamcrest.Matchers.hasKey; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.core.IsNull.notNullValue; -import static org.hamcrest.core.IsNull.nullValue; -import static org.junit.Assert.assertNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - -public class JsonNodeClaimTest { - - private ObjectMapper mapper; - - @Rule - public ExpectedException exception = ExpectedException.none(); - - @Before - public void setUp() { - mapper = getDefaultObjectMapper(); - } - - @Test - public void shouldGetBooleanValue() { - JsonNode value = mapper.valueToTree(true); - Claim claim = claimFromNode(value); - - assertThat(claim.asBoolean(), is(notNullValue())); - assertThat(claim.asBoolean(), is(true)); - } - - private Claim claimFromNode(JsonNode value) { - return JsonNodeClaim.claimFromNode(value, mapper); - } - - @Test - public void shouldGetNullBooleanIfNotBooleanValue() { - JsonNode objectValue = mapper.valueToTree(new Object()); - assertThat(claimFromNode(objectValue).asBoolean(), is(nullValue())); - JsonNode stringValue = mapper.valueToTree("boolean"); - assertThat(claimFromNode(stringValue).asBoolean(), is(nullValue())); - } - - @Test - public void shouldGetIntValue() { - JsonNode value = mapper.valueToTree(123); - Claim claim = claimFromNode(value); - - assertThat(claim.asInt(), is(notNullValue())); - assertThat(claim.asInt(), is(123)); - } - - @Test - public void shouldGetNullIntIfNotIntValue() { - JsonNode objectValue = mapper.valueToTree(new Object()); - assertThat(claimFromNode(objectValue).asInt(), is(nullValue())); - JsonNode stringValue = mapper.valueToTree("123"); - assertThat(claimFromNode(stringValue).asInt(), is(nullValue())); - } - - @Test - public void shouldGetLongValue() { - JsonNode value = mapper.valueToTree(Long.MAX_VALUE); - Claim claim = claimFromNode(value); - - assertThat(claim.asLong(), is(notNullValue())); - assertThat(claim.asLong(), is(Long.MAX_VALUE)); - } - - @Test - public void shouldGetNullLongIfNotIntValue() { - JsonNode objectValue = mapper.valueToTree(new Object()); - assertThat(claimFromNode(objectValue).asLong(), is(nullValue())); - JsonNode stringValue = mapper.valueToTree("" + Long.MAX_VALUE); - assertThat(claimFromNode(stringValue).asLong(), is(nullValue())); - } - - @Test - public void shouldGetDoubleValue() { - JsonNode value = mapper.valueToTree(1.5); - Claim claim = claimFromNode(value); - - assertThat(claim.asDouble(), is(notNullValue())); - assertThat(claim.asDouble(), is(1.5)); - } - - @Test - public void shouldGetNullDoubleIfNotDoubleValue() { - JsonNode objectValue = mapper.valueToTree(new Object()); - assertThat(claimFromNode(objectValue).asDouble(), is(nullValue())); - JsonNode stringValue = mapper.valueToTree("123.23"); - assertThat(claimFromNode(stringValue).asDouble(), is(nullValue())); - } - - @Test - public void shouldGetNumericDateValue() { - long seconds = 1476824844L; - JsonNode value = mapper.valueToTree(seconds); - Claim claim = claimFromNode(value); - - assertThat(claim.asDate(), is(new Date(seconds * 1000))); - assertThat(claim.asInstant(), is(Instant.ofEpochSecond(seconds))); - } - - @Test - public void shouldGetNullIfNotNumericDateValue() { - JsonNode objectValue = mapper.valueToTree(new Object()); - assertThat(claimFromNode(objectValue).asDate(), is(nullValue())); - assertThat(claimFromNode(objectValue).asInstant(), is(nullValue())); - JsonNode stringValue = mapper.valueToTree("1476824844"); - assertThat(claimFromNode(stringValue).asDate(), is(nullValue())); - assertThat(claimFromNode(stringValue).asInstant(), is(nullValue())); - } - - @Test - public void shouldGetStringValue() { - JsonNode value = mapper.valueToTree("string"); - Claim claim = claimFromNode(value); - - assertThat(claim.asString(), is(notNullValue())); - assertThat(claim.asString(), is("string")); - } - - @Test - public void shouldGetNullStringIfNotStringValue() { - JsonNode objectValue = mapper.valueToTree(new Object()); - assertThat(claimFromNode(objectValue).asString(), is(nullValue())); - JsonNode intValue = mapper.valueToTree(12345); - assertThat(claimFromNode(intValue).asString(), is(nullValue())); - } - - @Test - public void shouldGetArrayValueOfCustomClass() { - JsonNode value = mapper.valueToTree(new UserPojo[]{new UserPojo("George", 1), new UserPojo("Mark", 2)}); - Claim claim = claimFromNode(value); - - assertThat(claim.asArray(UserPojo.class), is(notNullValue())); - assertThat(claim.asArray(UserPojo.class), is(arrayContaining(new UserPojo("George", 1), new UserPojo("Mark", 2)))); - } - - @Test - public void shouldGetArrayValue() { - JsonNode value = mapper.valueToTree(new String[]{"string1", "string2"}); - Claim claim = claimFromNode(value); - - assertThat(claim.asArray(String.class), is(notNullValue())); - assertThat(claim.asArray(String.class), is(arrayContaining("string1", "string2"))); - } - - @Test - public void shouldGetNullArrayIfNullValue() { - JsonNode value = mapper.valueToTree(null); - Claim claim = claimFromNode(value); - - assertThat(claim.asArray(String.class), is(nullValue())); - } - - @Test - public void shouldGetNullArrayIfNonArrayValue() { - JsonNode value = mapper.valueToTree(1); - Claim claim = claimFromNode(value); - - assertThat(claim.asArray(String.class), is(nullValue())); - } - - @Test - public void shouldThrowIfArrayClassMismatch() { - JsonNode value = mapper.valueToTree(new String[]{"keys", "values"}); - Claim claim = claimFromNode(value); - - exception.expect(JWTDecodeException.class); - claim.asArray(UserPojo.class); - } - - @Test - public void shouldGetListValueOfCustomClass() { - JsonNode value = mapper.valueToTree(Arrays.asList(new UserPojo("George", 1), new UserPojo("Mark", 2))); - Claim claim = claimFromNode(value); - - assertThat(claim.asList(UserPojo.class), is(notNullValue())); - assertThat(claim.asList(UserPojo.class), is(hasItems(new UserPojo("George", 1), new UserPojo("Mark", 2)))); - } - - @Test - public void shouldGetListValue() { - JsonNode value = mapper.valueToTree(Arrays.asList("string1", "string2")); - Claim claim = claimFromNode(value); - - assertThat(claim.asList(String.class), is(notNullValue())); - assertThat(claim.asList(String.class), is(hasItems("string1", "string2"))); - } - - @Test - public void shouldGetNullListIfNullValue() { - JsonNode value = mapper.valueToTree(null); - Claim claim = claimFromNode(value); - - assertThat(claim.asList(String.class), is(nullValue())); - } - - @Test - public void shouldGetNullListIfNonArrayValue() { - JsonNode value = mapper.valueToTree(1); - Claim claim = claimFromNode(value); - - assertThat(claim.asList(String.class), is(nullValue())); - } - - @Test - public void shouldThrowIfListClassMismatch() { - JsonNode value = mapper.valueToTree(new String[]{"keys", "values"}); - Claim claim = claimFromNode(value); - - exception.expect(JWTDecodeException.class); - claim.asList(UserPojo.class); - } - - @Test - public void shouldGetNullMapIfNullValue() { - JsonNode value = mapper.valueToTree(null); - Claim claim = claimFromNode(value); - - assertThat(claim.asMap(), is(nullValue())); - } - - @Test - public void shouldGetNullMapIfNonArrayValue() { - JsonNode value = mapper.valueToTree(1); - Claim claim = claimFromNode(value); - - assertThat(claim.asMap(), is(nullValue())); - } - - @Test - public void shouldGetMapValue() { - Map map = new HashMap<>(); - map.put("text", "extraValue"); - map.put("number", 12); - map.put("boolean", true); - map.put("object", Collections.singletonMap("something", "else")); - - JsonNode value = mapper.valueToTree(map); - Claim claim = claimFromNode(value); - - assertThat(claim, is(notNullValue())); - Map backMap = claim.asMap(); - assertThat(backMap, is(notNullValue())); - assertThat(backMap, hasEntry("text", (Object) "extraValue")); - assertThat(backMap, hasEntry("number", (Object) 12)); - assertThat(backMap, hasEntry("boolean", (Object) true)); - assertThat(backMap, hasKey("object")); - assertThat((Map) backMap.get("object"), IsMapContaining.hasEntry("something", (Object) "else")); - } - - @Test - public void shouldThrowIfAnExtraordinaryExceptionHappensWhenParsingAsGenericMap() throws Exception { - JsonNode value = mock(ObjectNode.class); - when(value.getNodeType()).thenReturn(JsonNodeType.OBJECT); - - ObjectMapper mockedMapper = mock(ObjectMapper.class); - - JsonNodeClaim claim = (JsonNodeClaim) JsonNodeClaim.claimFromNode(value, mockedMapper); - JsonNodeClaim spiedClaim = spy(claim); - - JsonParser mockedParser = mock(JsonParser.class); - when(mockedMapper.treeAsTokens(value)).thenReturn(mockedParser); - when(mockedParser.readValueAs(ArgumentMatchers.any(TypeReference.class))).thenThrow(IOException.class); - - exception.expect(JWTDecodeException.class); - spiedClaim.asMap(); - } - - @Test - public void shouldGetCustomClassValue() { - JsonNode value = mapper.valueToTree(new UserPojo("john", 123)); - Claim claim = claimFromNode(value); - - assertThat(claim, is(notNullValue())); - assertThat(claim.as(UserPojo.class).getName(), is("john")); - assertThat(claim.as(UserPojo.class).getId(), is(123)); - } - - @Test - public void shouldThrowIfCustomClassMismatch() { - JsonNode value = mapper.valueToTree(new UserPojo("john", 123)); - Claim claim = claimFromNode(value); - - exception.expect(JWTDecodeException.class); - claim.as(String.class); - } - - @Test - public void shouldReturnNullForMissingAndNullClaims() { - JsonNode missingValue = MissingNode.getInstance(); - Claim missingClaim = claimFromNode(missingValue); - assertThat(missingClaim.isMissing(), is(true)); - assertThat(missingClaim.isNull(), is(false)); - assertNull(missingClaim.as(String.class)); - assertNull(missingClaim.asString()); - assertNull(missingClaim.asBoolean()); - assertNull(missingClaim.asDate()); - assertNull(missingClaim.asDouble()); - assertNull(missingClaim.asLong()); - assertNull(missingClaim.asInt()); - assertNull(missingClaim.asInstant()); - assertNull(missingClaim.asMap()); - assertNull(missingClaim.asList(String.class)); - assertNull(missingClaim.asArray(String.class)); - - JsonNode nullValue = mapper.valueToTree(null); - Claim nullClaim = claimFromNode(nullValue); - assertThat(nullClaim.isMissing(), is(false)); - assertThat(nullClaim.isNull(), is(true)); - assertNull(nullClaim.as(String.class)); - assertNull(nullClaim.asString()); - assertNull(nullClaim.asBoolean()); - assertNull(nullClaim.asDate()); - assertNull(nullClaim.asDouble()); - assertNull(nullClaim.asLong()); - assertNull(nullClaim.asInt()); - assertNull(nullClaim.asInstant()); - assertNull(nullClaim.asMap()); - assertNull(nullClaim.asList(String.class)); - assertNull(nullClaim.asArray(String.class)); - } - - @Test - public void shouldReturnNullForInvalidArrayValue() { - JsonNode value = mapper.valueToTree(new UserPojo("john", 123)); - Claim claim = claimFromNode(value); - assertNull(claim.asArray(String.class)); - } - - @SuppressWarnings({"unchecked", "RedundantCast"}) - @Test - public void shouldGetAsMapValue() { - JsonNode value = mapper.valueToTree(Collections.singletonMap("key", new UserPojo("john", 123))); - Claim claim = claimFromNode(value); - - assertThat(claim, is(notNullValue())); - Map map = claim.as(Map.class); - assertThat(((Map) map.get("key")), hasEntry("name", (Object) "john")); - assertThat(((Map) map.get("key")), hasEntry("id", (Object) 123)); - } - - @Test - public void shouldReturnBaseClaimWhenParsingMissingNode() { - JsonNode value = MissingNode.getInstance(); - Claim claim = claimFromNode(value); - - assertThat(claim, is(notNullValue())); - assertThat(claim.isMissing(), is(true)); - assertThat(claim.isNull(), is(false)); - } - - @Test - public void shouldReturnBaseClaimWhenParsingNullNode() { - JsonNode value = NullNode.getInstance(); - Claim claim = claimFromNode(value); - - assertThat(claim, is(notNullValue())); - assertThat(claim.isNull(), is(true)); - assertThat(claim.isMissing(), is(false)); - } - - @Test - public void shouldReturnBaseClaimWhenParsingNullValue() { - JsonNode value = mapper.valueToTree(null); - Claim claim = claimFromNode(value); - - assertThat(claim, is(notNullValue())); - assertThat(claim.isNull(), is(true)); - assertThat(claim.isMissing(), is(false)); - } - - @Test - public void shouldReturnNonNullClaimWhenParsingObject() { - JsonNode value = mapper.valueToTree(new Object()); - Claim claim = claimFromNode(value); - - assertThat(claim, is(notNullValue())); - assertThat(claim, is(instanceOf(JsonNodeClaim.class))); - assertThat(claim.isNull(), is(false)); - assertThat(claim.isMissing(), is(false)); - } - - @Test - public void shouldReturnNonNullClaimWhenParsingArray() { - JsonNode value = mapper.valueToTree(new String[]{}); - Claim claim = claimFromNode(value); - - assertThat(claim, is(notNullValue())); - assertThat(claim, is(instanceOf(JsonNodeClaim.class))); - assertThat(claim.isNull(), is(false)); - assertThat(claim.isMissing(), is(false)); - } - - @Test - public void shouldReturnNonNullClaimWhenParsingList() { - JsonNode value = mapper.valueToTree(new ArrayList()); - Claim claim = claimFromNode(value); - - assertThat(claim, is(notNullValue())); - assertThat(claim, is(instanceOf(JsonNodeClaim.class))); - assertThat(claim.isNull(), is(false)); - assertThat(claim.isMissing(), is(false)); - } - - @Test - public void shouldReturnNonNullClaimWhenParsingStringValue() { - JsonNode value = mapper.valueToTree(""); - Claim claim = claimFromNode(value); - - assertThat(claim, is(notNullValue())); - assertThat(claim, is(instanceOf(JsonNodeClaim.class))); - assertThat(claim.isNull(), is(false)); - assertThat(claim.isMissing(), is(false)); - } - - @Test - public void shouldReturnNonNullClaimWhenParsingIntValue() { - JsonNode value = mapper.valueToTree(Integer.MAX_VALUE); - Claim claim = claimFromNode(value); - - assertThat(claim, is(notNullValue())); - assertThat(claim, is(instanceOf(JsonNodeClaim.class))); - assertThat(claim.isNull(), is(false)); - assertThat(claim.isMissing(), is(false)); - } - - @Test - public void shouldReturnNonNullClaimWhenParsingDoubleValue() { - JsonNode value = mapper.valueToTree(Double.MAX_VALUE); - Claim claim = claimFromNode(value); - - assertThat(claim, is(notNullValue())); - assertThat(claim, is(instanceOf(JsonNodeClaim.class))); - assertThat(claim.isNull(), is(false)); - assertThat(claim.isMissing(), is(false)); - } - - @Test - public void shouldReturnNonNullClaimWhenParsingDateValue() { - JsonNode value = mapper.valueToTree(new Date()); - Claim claim = claimFromNode(value); - - assertThat(claim, is(notNullValue())); - assertThat(claim, is(instanceOf(JsonNodeClaim.class))); - assertThat(claim.isNull(), is(false)); - assertThat(claim.isMissing(), is(false)); - } - - @Test - public void shouldReturnNonNullClaimWhenParsingBooleanValue() { - JsonNode value = mapper.valueToTree(Boolean.TRUE); - Claim claim = claimFromNode(value); - - assertThat(claim, is(notNullValue())); - assertThat(claim, is(instanceOf(JsonNodeClaim.class))); - assertThat(claim.isNull(), is(false)); - assertThat(claim.isMissing(), is(false)); - } - - @Test - public void shouldReturnNullIsTrue() { - JsonNode value = mapper.valueToTree(null); - Claim claim = claimFromNode(value); - - assertThat(claim, is(notNullValue())); - assertThat(claim, is(instanceOf(JsonNodeClaim.class))); - assertThat(claim.isNull(), is(true)); - assertThat(claim.isMissing(), is(false)); - } - - @Test - public void shouldDelegateToJsonNodeToString() { - JsonNode value = mapper.valueToTree(new UserPojo("john", 123)); - Claim claim = claimFromNode(value); - assertThat(claim.toString(), is(value.toString())); - } - - @Test - public void shouldConvertToString() { - JsonNode value = mapper.valueToTree(new UserPojo("john", 123)); - JsonNode nullValue = mapper.valueToTree(null); - JsonNode missingValue = MissingNode.getInstance(); - - Claim claim = claimFromNode(value); - Claim nullClaim = claimFromNode(nullValue); - Claim missingClaim = claimFromNode(missingValue); - - assertThat(claim.toString(), is("{\"name\":\"john\",\"id\":123}")); - assertThat(nullClaim.isNull(), is(true)); - assertThat(nullClaim.toString(), is("Null claim")); - assertThat(missingClaim.isMissing(), is(true)); - assertThat(missingClaim.toString(), is("Missing claim")); - - } -} \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadClaimsHolderTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadClaimsHolderTest.java deleted file mode 100644 index 2f053830..00000000 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadClaimsHolderTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.auth0.jwt.impl; - -import org.hamcrest.collection.IsMapContaining; -import org.junit.Test; - -import java.util.HashMap; -import java.util.Map; - -import static org.hamcrest.Matchers.*; -import static org.hamcrest.MatcherAssert.assertThat; - -public class PayloadClaimsHolderTest { - - @Test - public void shouldGetClaims() { - HashMap claims = new HashMap<>(); - claims.put("iss", "auth0"); - ClaimsHolder holder = new PayloadClaimsHolder(claims); - assertThat(holder, is(notNullValue())); - assertThat(holder.getClaims(), is(notNullValue())); - assertThat(holder.getClaims(), is(instanceOf(Map.class))); - assertThat(holder.getClaims(), is(IsMapContaining.hasEntry("iss", "auth0"))); - } - - @Test - public void shouldGetNotNullClaims() { - ClaimsHolder holder = new PayloadClaimsHolder(null); - assertThat(holder, is(notNullValue())); - assertThat(holder.getClaims(), is(notNullValue())); - assertThat(holder.getClaims(), is(instanceOf(Map.class))); - } -} \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java deleted file mode 100644 index c3e04013..00000000 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java +++ /dev/null @@ -1,274 +0,0 @@ -package com.auth0.jwt.impl; - -import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.interfaces.Payload; -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.ObjectCodec; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.*; -import org.hamcrest.collection.IsCollectionWithSize; -import org.hamcrest.collection.IsEmptyCollection; -import org.hamcrest.core.IsIterableContaining; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.io.StringReader; -import java.time.Instant; -import java.util.*; - -import static org.hamcrest.Matchers.*; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class PayloadDeserializerTest { - - @Rule - public ExpectedException exception = ExpectedException.none(); - private PayloadDeserializer deserializer; - - private ObjectMapper objectMapper; - - @Before - public void setUp() { - objectMapper = new ObjectMapper(); - deserializer = new PayloadDeserializer(); - } - - @Test - public void shouldThrowOnNullTree() throws Exception { - exception.expect(JWTDecodeException.class); - exception.expectMessage("Parsing the Payload's JSON resulted on a Null map"); - - JsonParser parser = mock(JsonParser.class); - ObjectCodec codec = mock(ObjectCodec.class); - DeserializationContext context = mock(DeserializationContext.class); - - when(codec.readValue(eq(parser), any(TypeReference.class))).thenReturn(null); - when(parser.getCodec()).thenReturn(codec); - - deserializer.deserialize(parser, context); - } - - @Test - public void shouldThrowWhenParsingArrayWithObjectValue() throws Exception { - exception.expect(JWTDecodeException.class); - exception.expectMessage("Couldn't map the Claim's array contents to String"); - - ObjectMapper mapper = new ObjectMapper(); - JsonNode jsonNode = mapper.readTree("{\"some\" : \"random\", \"properties\" : \"inside\"}"); - Map tree = new HashMap<>(); - List subNodes = new ArrayList<>(); - subNodes.add(jsonNode); - ArrayNode arrNode = new ArrayNode(JsonNodeFactory.instance, subNodes); - tree.put("key", arrNode); - - deserializer.getStringOrArray(objectMapper, tree, "key"); - } - - @Test - public void shouldNotRemoveKnownPublicClaimsFromTree() throws Exception { - String payloadJSON = "{\n" + - " \"iss\": \"auth0\",\n" + - " \"sub\": \"emails\",\n" + - " \"aud\": \"users\",\n" + - " \"iat\": 10101010,\n" + - " \"exp\": 11111111,\n" + - " \"nbf\": 10101011,\n" + - " \"jti\": \"idid\",\n" + - " \"roles\":\"admin\" \n" + - "}"; - StringReader reader = new StringReader(payloadJSON); - JsonParser jsonParser = new JsonFactory().createParser(reader); - ObjectMapper mapper = new ObjectMapper(); - jsonParser.setCodec(mapper); - - Payload payload = deserializer.deserialize(jsonParser, mapper.getDeserializationContext()); - - assertThat(payload, is(notNullValue())); - assertThat(payload.getIssuer(), is("auth0")); - assertThat(payload.getSubject(), is("emails")); - assertThat(payload.getAudience(), is(IsIterableContaining.hasItem("users"))); - assertThat(payload.getIssuedAt().getTime(), is(10101010L * 1000)); - assertThat(payload.getExpiresAt().getTime(), is(11111111L * 1000)); - assertThat(payload.getNotBefore().getTime(), is(10101011L * 1000)); - assertThat(payload.getIssuedAtAsInstant().getEpochSecond(), is(10101010L)); - assertThat(payload.getExpiresAtAsInstant().getEpochSecond(), is(11111111L)); - assertThat(payload.getNotBeforeAsInstant().getEpochSecond(), is(10101011L)); - assertThat(payload.getId(), is("idid")); - - assertThat(payload.getClaim("roles").asString(), is("admin")); - assertThat(payload.getClaim("iss").asString(), is("auth0")); - assertThat(payload.getClaim("sub").asString(), is("emails")); - assertThat(payload.getClaim("aud").asString(), is("users")); - assertThat(payload.getClaim("iat").asDouble(), is(10101010D)); - assertThat(payload.getClaim("exp").asDouble(), is(11111111D)); - assertThat(payload.getClaim("nbf").asDouble(), is(10101011D)); - assertThat(payload.getClaim("jti").asString(), is("idid")); - } - - @Test - public void shouldGetStringArrayWhenParsingArrayNode() { - Map tree = new HashMap<>(); - List subNodes = new ArrayList<>(); - TextNode textNode1 = new TextNode("one"); - TextNode textNode2 = new TextNode("two"); - subNodes.add(textNode1); - subNodes.add(textNode2); - ArrayNode arrNode = new ArrayNode(JsonNodeFactory.instance, subNodes); - tree.put("key", arrNode); - - List values = deserializer.getStringOrArray(objectMapper, tree, "key"); - assertThat(values, is(notNullValue())); - assertThat(values, is(IsCollectionWithSize.hasSize(2))); - assertThat(values, is(IsIterableContaining.hasItems("one", "two"))); - } - - @Test - public void shouldGetStringArrayWhenParsingTextNode() { - Map tree = new HashMap<>(); - TextNode textNode = new TextNode("something"); - tree.put("key", textNode); - - List values = deserializer.getStringOrArray(objectMapper, tree, "key"); - assertThat(values, is(notNullValue())); - assertThat(values, is(IsCollectionWithSize.hasSize(1))); - assertThat(values, is(IsIterableContaining.hasItems("something"))); - } - - @Test - public void shouldGetEmptyStringInArrayWhenParsingEmptyTextNode() { - Map tree = new HashMap<>(); - TextNode textNode = new TextNode(""); - tree.put("key", textNode); - - List values = deserializer.getStringOrArray(objectMapper, tree, "key"); - assertThat(values, is(notNullValue())); - assertThat(values, is(IsIterableContaining.hasItem(""))); - } - - @Test - public void shouldGetNullArrayWhenParsingNullNode() { - Map tree = new HashMap<>(); - NullNode node = NullNode.getInstance(); - tree.put("key", node); - - List values = deserializer.getStringOrArray(objectMapper, tree, "key"); - assertThat(values, is(nullValue())); - } - - @Test - public void shouldGetNullArrayWhenParsingNullNodeValue() { - Map tree = new HashMap<>(); - tree.put("key", null); - - List values = deserializer.getStringOrArray(objectMapper, tree, "key"); - assertThat(values, is(nullValue())); - } - - @Test - public void shouldGetNullArrayWhenParsingNonArrayOrTextNode() { - Map tree = new HashMap<>(); - IntNode node = new IntNode(456789); - tree.put("key", node); - - List values = deserializer.getStringOrArray(objectMapper, tree, "key"); - assertThat(values, is(nullValue())); - } - - @Test - public void shouldGetNullInstantWhenParsingNullNode() { - Map tree = new HashMap<>(); - NullNode node = NullNode.getInstance(); - tree.put("key", node); - - Instant instant = deserializer.getInstantFromSeconds(tree, "key"); - assertThat(instant, is(nullValue())); - } - - @Test - public void shouldGetNullInstantWhenParsingNull() { - Map tree = new HashMap<>(); - tree.put("key", null); - - Instant instant = deserializer.getInstantFromSeconds(tree, "key"); - assertThat(instant, is(nullValue())); - } - - @Test - public void shouldThrowWhenParsingNonNumericNode() { - exception.expect(JWTDecodeException.class); - exception.expectMessage("The claim 'key' contained a non-numeric date value."); - - Map tree = new HashMap<>(); - TextNode node = new TextNode("123456789"); - tree.put("key", node); - - deserializer.getInstantFromSeconds(tree, "key"); - } - - @Test - public void shouldGetInstantWhenParsingNumericNode() { - Map tree = new HashMap<>(); - long seconds = 1478627949 / 1000; - LongNode node = new LongNode(seconds); - tree.put("key", node); - - Instant instant = deserializer.getInstantFromSeconds(tree, "key"); - assertThat(instant, is(notNullValue())); - assertThat(instant.toEpochMilli(), is(seconds * 1000)); - } - - - @Test - public void shouldGetLargeInstantWhenParsingNumericNode() { - Map tree = new HashMap<>(); - long seconds = Integer.MAX_VALUE + 10000L; - LongNode node = new LongNode(seconds); - tree.put("key", node); - - Instant instant = deserializer.getInstantFromSeconds(tree, "key"); - assertThat(instant, is(notNullValue())); - assertThat(instant.toEpochMilli(), is(seconds * 1000)); - assertThat(instant.toEpochMilli(), is(2147493647L * 1000)); - } - - @Test - public void shouldGetNullStringWhenParsingNullNode() { - Map tree = new HashMap<>(); - NullNode node = NullNode.getInstance(); - tree.put("key", node); - - String text = deserializer.getString(tree, "key"); - assertThat(text, is(nullValue())); - } - - @Test - public void shouldGetNullStringWhenParsingNull() { - Map tree = new HashMap<>(); - tree.put("key", null); - - String text = deserializer.getString(tree, "key"); - assertThat(text, is(nullValue())); - } - - @Test - public void shouldGetStringWhenParsingTextNode() { - Map tree = new HashMap<>(); - TextNode node = new TextNode("something here"); - tree.put("key", node); - - String text = deserializer.getString(tree, "key"); - assertThat(text, is(notNullValue())); - assertThat(text, is("something here")); - } - -} \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java deleted file mode 100644 index 5ad7ac68..00000000 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java +++ /dev/null @@ -1,194 +0,0 @@ -package com.auth0.jwt.impl; - -import com.auth0.jwt.interfaces.Claim; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectReader; -import com.fasterxml.jackson.databind.node.TextNode; -import org.hamcrest.collection.IsCollectionWithSize; -import org.hamcrest.core.IsIterableContaining; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.time.Instant; -import java.util.*; - -import static com.auth0.jwt.impl.JWTParser.getDefaultObjectMapper; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; - -public class PayloadImplTest { - - @Rule - public ExpectedException exception = ExpectedException.none(); - - private PayloadImpl payload; - private final Instant expiresAt = Instant.now().plusSeconds(10); - private final Instant notBefore = Instant.now(); - private final Instant issuedAt = Instant.now(); - - private ObjectMapper objectMapper; - - @Before - public void setUp() { - objectMapper = getDefaultObjectMapper(); - - Map tree = new HashMap<>(); - tree.put("extraClaim", new TextNode("extraValue")); - payload = new PayloadImpl("issuer", "subject", Collections.singletonList("audience"), expiresAt, notBefore, issuedAt, "jwtId", tree, objectMapper); - } - - @Test - public void shouldHaveUnmodifiableTree() { - exception.expect(UnsupportedOperationException.class); - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, new HashMap<>(), objectMapper); - payload.getTree().put("something", null); - } - - @Test - public void shouldHaveUnmodifiableAudience() { - exception.expect(UnsupportedOperationException.class); - PayloadImpl payload = new PayloadImpl(null, null, new ArrayList<>(), null, null, null, null, null, objectMapper); - payload.getAudience().add("something"); - } - - @Test - public void shouldGetIssuer() { - assertThat(payload, is(notNullValue())); - assertThat(payload.getIssuer(), is("issuer")); - } - - @Test - public void shouldGetNullIssuerIfMissing() { - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectMapper); - assertThat(payload, is(notNullValue())); - assertThat(payload.getIssuer(), is(nullValue())); - } - - @Test - public void shouldGetSubject() { - assertThat(payload, is(notNullValue())); - assertThat(payload.getSubject(), is("subject")); - } - - @Test - public void shouldGetNullSubjectIfMissing() { - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectMapper); - assertThat(payload, is(notNullValue())); - assertThat(payload.getSubject(), is(nullValue())); - } - - @Test - public void shouldGetAudience() { - assertThat(payload, is(notNullValue())); - - assertThat(payload.getAudience(), is(IsCollectionWithSize.hasSize(1))); - assertThat(payload.getAudience(), is(IsIterableContaining.hasItems("audience"))); - } - - @Test - public void shouldGetNullAudienceIfMissing() { - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectMapper); - assertThat(payload, is(notNullValue())); - assertThat(payload.getAudience(), is(nullValue())); - } - - @Test - public void shouldGetExpiresAt() { - assertThat(payload, is(notNullValue())); - assertThat(payload.getExpiresAt(), is(Date.from(expiresAt))); - assertThat(payload.getExpiresAtAsInstant(), is(expiresAt)); - } - - @Test - public void shouldGetNullExpiresAtIfMissing() { - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectMapper); - assertThat(payload, is(notNullValue())); - assertThat(payload.getExpiresAt(), is(nullValue())); - assertThat(payload.getExpiresAtAsInstant(), is(nullValue())); - } - - @Test - public void shouldGetNotBefore() { - assertThat(payload, is(notNullValue())); - assertThat(payload.getNotBefore(), is(Date.from(notBefore))); - assertThat(payload.getNotBeforeAsInstant(), is(notBefore)); - } - - @Test - public void shouldGetNullNotBeforeIfMissing() { - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectMapper); - assertThat(payload, is(notNullValue())); - assertThat(payload.getNotBefore(), is(nullValue())); - assertThat(payload.getNotBeforeAsInstant(), is(nullValue())); - } - - @Test - public void shouldGetIssuedAt() { - assertThat(payload, is(notNullValue())); - assertThat(payload.getIssuedAt(), is(Date.from(issuedAt))); - assertThat(payload.getIssuedAtAsInstant(), is(issuedAt)); - } - - @Test - public void shouldGetNullIssuedAtIfMissing() { - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectMapper); - assertThat(payload, is(notNullValue())); - assertThat(payload.getIssuedAt(), is(nullValue())); - assertThat(payload.getIssuedAtAsInstant(), is(nullValue())); - } - - @Test - public void shouldGetJWTId() { - assertThat(payload, is(notNullValue())); - assertThat(payload.getId(), is("jwtId")); - } - - @Test - public void shouldGetNullJWTIdIfMissing() { - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectMapper); - assertThat(payload, is(notNullValue())); - assertThat(payload.getId(), is(nullValue())); - } - - @Test - public void shouldGetExtraClaim() { - assertThat(payload, is(notNullValue())); - assertThat(payload.getClaim("extraClaim"), is(instanceOf(JsonNodeClaim.class))); - assertThat(payload.getClaim("extraClaim").asString(), is("extraValue")); - } - - @Test - public void shouldGetNotNullExtraClaimIfMissing() { - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectMapper); - assertThat(payload, is(notNullValue())); - assertThat(payload.getClaim("missing"), is(notNullValue())); - assertThat(payload.getClaim("missing").isMissing(), is(true)); - assertThat(payload.getClaim("missing").isNull(), is(false)); - } - - @Test - public void shouldGetClaims() { - Map tree = new HashMap<>(); - tree.put("extraClaim", new TextNode("extraValue")); - tree.put("sub", new TextNode("auth0")); - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, tree, objectMapper); - assertThat(payload, is(notNullValue())); - Map claims = payload.getClaims(); - assertThat(claims, is(notNullValue())); - - assertThat(claims.get("extraClaim"), is(notNullValue())); - assertThat(claims.get("sub"), is(notNullValue())); - } - - @Test - public void shouldNotAllowToModifyClaimsMap() { - assertThat(payload, is(notNullValue())); - Map claims = payload.getClaims(); - assertThat(claims, is(notNullValue())); - exception.expect(UnsupportedOperationException.class); - claims.put("name", null); - } -} \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java deleted file mode 100644 index 45761de0..00000000 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java +++ /dev/null @@ -1,289 +0,0 @@ -package com.auth0.jwt.impl; - -import com.auth0.jwt.UserPojo; -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializerProvider; -import org.junit.Before; -import org.junit.Test; - -import java.io.StringWriter; -import java.util.*; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; - -public class PayloadSerializerTest { - - private StringWriter writer; - private PayloadSerializer serializer; - private JsonGenerator jsonGenerator; - private SerializerProvider serializerProvider; - - @Before - public void setUp() throws Exception { - writer = new StringWriter(); - serializer = new PayloadSerializer(); - jsonGenerator = new JsonFactory().createGenerator(writer); - ObjectMapper mapper = new ObjectMapper(); - jsonGenerator.setCodec(mapper); - serializerProvider = mapper.getSerializerProvider(); - } - - @Test - public void shouldSerializeEmptyMap() throws Exception { - PayloadClaimsHolder holder = new PayloadClaimsHolder(new HashMap<>()); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{}"))); - } - - @Test - public void shouldSerializeStringAudienceAsString() throws Exception { - PayloadClaimsHolder holder = holderFor("aud", "auth0"); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{\"aud\":\"auth0\"}"))); - } - - @Test - public void shouldSerializeSingleItemAudienceAsArray() throws Exception { - PayloadClaimsHolder holder = holderFor("aud", new String[]{"auth0"}); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{\"aud\":\"auth0\"}"))); - } - - @Test - public void shouldSerializeMultipleItemsAudienceAsArray() throws Exception { - PayloadClaimsHolder holder = holderFor("aud", new String[]{"auth0", "auth10"}); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{\"aud\":[\"auth0\",\"auth10\"]}"))); - } - - @Test - public void shouldSkipSerializationOnEmptyAudience() throws Exception { - PayloadClaimsHolder holder = holderFor("aud", new String[0]); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{}"))); - } - - @Test - public void shouldSerializeSingleItemAudienceAsArrayWhenAList() throws Exception { - PayloadClaimsHolder holder = holderFor("aud", Collections.singletonList("auth0")); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{\"aud\":\"auth0\"}"))); - } - - @Test - public void shouldSerializeMultipleItemsAudienceAsArrayWhenAList() throws Exception { - PayloadClaimsHolder holder = holderFor("aud", Arrays.asList("auth0", "auth10")); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{\"aud\":[\"auth0\",\"auth10\"]}"))); - } - - @Test - public void shouldSkipSerializationOnEmptyAudienceWhenList() throws Exception { - PayloadClaimsHolder holder = holderFor("aud", new ArrayList<>()); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{}"))); - } - - @Test - public void shouldSkipNonStringsOnAudienceWhenSingleItemList() throws Exception { - PayloadClaimsHolder holder = holderFor("aud", Collections.singletonList(2)); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{}"))); - } - - @Test - public void shouldSkipNonStringsOnAudienceWhenList() throws Exception { - PayloadClaimsHolder holder = holderFor("aud", Arrays.asList("auth0", 2, "auth10")); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{\"aud\":[\"auth0\",\"auth10\"]}"))); - } - - @Test - public void shouldSkipNonStringsOnAudience() throws Exception { - PayloadClaimsHolder holder = holderFor("aud", 4); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{}"))); - } - - @Test - public void shouldSerializeNotBeforeDateInSeconds() throws Exception { - PayloadClaimsHolder holder = holderFor("nbf", new Date(1478874000)); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{\"nbf\":1478874}"))); - } - - @Test - public void shouldSerializeIssuedAtDateInSeconds() throws Exception { - PayloadClaimsHolder holder = holderFor("iat", new Date(1478874000)); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{\"iat\":1478874}"))); - } - - @Test - public void shouldSerializeExpiresAtDateInSeconds() throws Exception { - PayloadClaimsHolder holder = holderFor("exp", new Date(1478874000)); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{\"exp\":1478874}"))); - } - - @Test - public void shouldSerializeCustomDateInSeconds() throws Exception { - PayloadClaimsHolder holder = holderFor("birthdate", new Date(1478874000)); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{\"birthdate\":1478874}"))); - } - - @Test - public void shouldSerializeDatesUsingLong() throws Exception { - long secs = Integer.MAX_VALUE + 10000L; - Date date = new Date(secs * 1000L); - Map claims = new HashMap<>(); - claims.put("iat", date); - claims.put("nbf", date); - claims.put("exp", date); - claims.put("ctm", date); - claims.put("map", Collections.singletonMap("date", date)); - claims.put("list", Collections.singletonList(date)); - - Map nestedInMap = new HashMap<>(); - nestedInMap.put("list", Collections.singletonList(date)); - claims.put("nestedInMap", nestedInMap); - - List nestedInList = new ArrayList<>(); - nestedInList.add(Collections.singletonMap("nested", date)); - claims.put("nestedInList", nestedInList); - - PayloadClaimsHolder holder = new PayloadClaimsHolder(claims); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - String json = writer.toString(); - System.out.println(json); - - assertThat(json, containsString("\"iat\":2147493647")); - assertThat(json, containsString("\"nbf\":2147493647")); - assertThat(json, containsString("\"exp\":2147493647")); - assertThat(json, containsString("\"ctm\":2147493647")); - assertThat(json, containsString("\"map\":{\"date\":2147493647")); - assertThat(json, containsString("\"list\":[2147493647]")); - assertThat(json, containsString("\"nestedInMap\":{\"list\":[2147493647]}")); - assertThat(json, containsString("\"nestedInList\":[{\"nested\":2147493647}]")); - } - - @Test - public void shouldSerializeStrings() throws Exception { - PayloadClaimsHolder holder = holderFor("name", "Auth0 Inc"); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{\"name\":\"Auth0 Inc\"}"))); - } - - @Test - public void shouldSerializeIntegers() throws Exception { - PayloadClaimsHolder holder = holderFor("number", 12345); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{\"number\":12345}"))); - } - - @Test - public void shouldSerializeDoubles() throws Exception { - PayloadClaimsHolder holder = holderFor("fraction", 23.45); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{\"fraction\":23.45}"))); - } - - @Test - public void shouldSerializeBooleans() throws Exception { - PayloadClaimsHolder holder = holderFor("pro", true); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{\"pro\":true}"))); - } - - @Test - public void shouldSerializeNulls() throws Exception { - PayloadClaimsHolder holder = holderFor("id", null); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{\"id\":null}"))); - } - - @Test - public void shouldSerializeCustomArrayOfObject() throws Exception { - UserPojo user1 = new UserPojo("Michael", 1); - UserPojo user2 = new UserPojo("Lucas", 2); - PayloadClaimsHolder holder = holderFor("users", new UserPojo[]{user1, user2}); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{\"users\":[{\"name\":\"Michael\",\"id\":1},{\"name\":\"Lucas\",\"id\":2}]}"))); - } - - @Test - public void shouldSerializeCustomListOfObject() throws Exception { - UserPojo user1 = new UserPojo("Michael", 1); - UserPojo user2 = new UserPojo("Lucas", 2); - PayloadClaimsHolder holder = holderFor("users", Arrays.asList(user1, user2)); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{\"users\":[{\"name\":\"Michael\",\"id\":1},{\"name\":\"Lucas\",\"id\":2}]}"))); - } - - @Test - public void shouldSerializeCustomObject() throws Exception { - UserPojo user = new UserPojo("Michael", 1); - PayloadClaimsHolder holder = holderFor("users", user); - serializer.serialize(holder, jsonGenerator, serializerProvider); - jsonGenerator.flush(); - - assertThat(writer.toString(), is(equalTo("{\"users\":{\"name\":\"Michael\",\"id\":1}}"))); - } - - private PayloadClaimsHolder holderFor(String key, Object value) { - Map map = new HashMap<>(); - map.put(key, value); - return new PayloadClaimsHolder(map); - } - -} \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/interfaces/ClaimTest.java b/lib/src/test/java/com/auth0/jwt/interfaces/ClaimTest.java deleted file mode 100644 index 61541ccf..00000000 --- a/lib/src/test/java/com/auth0/jwt/interfaces/ClaimTest.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.auth0.jwt.interfaces; - -import com.auth0.jwt.exceptions.JWTDecodeException; -import org.junit.Test; - -import java.util.Date; -import java.util.List; -import java.util.Map; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; - -public class ClaimTest { - - @Test - public void shouldGetInstantUsingDefault() { - Date date = new Date(1646667492000L); - Claim claim = new ClaimImplForTest(date); - assertThat(claim.asInstant(), is(date.toInstant())); - } - - @Test - public void shouldGetNullInstantUsingDefault() { - Claim claim = new ClaimImplForTest(null); - assertThat(claim.asInstant(), is(nullValue())); - } - - /** - * Implementation that does not override {@code asInstant()} - */ - static class ClaimImplForTest implements Claim { - private final Date date; - - ClaimImplForTest(Date date) { - this.date = date; - } - - @Override - public boolean isNull() { - return false; - } - - @Override - public boolean isMissing() { - return false; - } - - @Override - public Boolean asBoolean() { - return null; - } - - @Override - public Integer asInt() { - return null; - } - - @Override - public Long asLong() { - return null; - } - - @Override - public Double asDouble() { - return null; - } - - @Override - public String asString() { - return null; - } - - @Override - public Date asDate() { - return date; - } - - @Override - public T[] asArray(Class clazz) throws JWTDecodeException { - return null; - } - - @Override - public List asList(Class clazz) throws JWTDecodeException { - return null; - } - - @Override - public Map asMap() throws JWTDecodeException { - return null; - } - - @Override - public T as(Class tClazz) throws JWTDecodeException { - return null; - } - } -} diff --git a/lib/src/test/java/com/auth0/jwt/interfaces/PayloadTest.java b/lib/src/test/java/com/auth0/jwt/interfaces/PayloadTest.java deleted file mode 100644 index c5d2bd00..00000000 --- a/lib/src/test/java/com/auth0/jwt/interfaces/PayloadTest.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.auth0.jwt.interfaces; - -import org.junit.Test; - -import java.util.Date; -import java.util.List; -import java.util.Map; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; - -public class PayloadTest { - - @Test - public void shouldGetInstantFromDefault() { - Date date = new Date(1646667492000L); - Payload payload = new PayloadImplForTest(date); - assertThat(payload.getExpiresAtAsInstant(), is(date.toInstant())); - assertThat(payload.getIssuedAtAsInstant(), is(date.toInstant())); - assertThat(payload.getNotBeforeAsInstant(), is(date.toInstant())); - } - - @Test - public void shouldGetInstantFromDefaultAsNu() { - Payload payload = new PayloadImplForTest(null); - assertThat(payload.getExpiresAtAsInstant(), is(nullValue())); - assertThat(payload.getIssuedAtAsInstant(), is(nullValue())); - assertThat(payload.getNotBeforeAsInstant(), is(nullValue())); - } - - static class PayloadImplForTest implements Payload { - private final Date date; - - PayloadImplForTest(Date date) { - this.date = date; - } - - @Override - public String getIssuer() { - return null; - } - - @Override - public String getSubject() { - return null; - } - - @Override - public List getAudience() { - return null; - } - - @Override - public Date getExpiresAt() { - return date; - } - - @Override - public Date getNotBefore() { - return date; - } - - @Override - public Date getIssuedAt() { - return date; - } - - @Override - public String getId() { - return null; - } - - @Override - public Claim getClaim(String name) { - return null; - } - - @Override - public Map getClaims() { - return null; - } - } -} diff --git a/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java b/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java deleted file mode 100644 index 11acb029..00000000 --- a/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java +++ /dev/null @@ -1,171 +0,0 @@ -package com.auth0.jwt.interfaces; - -import com.auth0.jwt.JWTVerifier; -import org.junit.Test; - -import java.time.Instant; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.function.BiPredicate; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.hasEntry; -import static org.hamcrest.Matchers.instanceOf; -import static org.junit.Assert.assertThrows; - -/** - * Tests for any default method implementations in the {@link Verification} interface. - */ -public class VerificationTest { - - @Test - public void withInstantClaimShouldUseDefaultImpl() { - Instant instant = Instant.ofEpochSecond(1478891521); - Verification verification = new VerificationImplForTest() - .withClaim("name", instant); - - assertThat(verification, instanceOf(VerificationImplForTest.class)); - assertThat(((VerificationImplForTest)verification).expectedClaims, hasEntry("name", Date.from(instant))); - } - - @Test - public void withInstantClaimShouldUseDefaultImplAndHandleNull() { - Verification verification = new VerificationImplForTest() - .withClaim("name", (Instant) null); - - assertThat(verification, instanceOf(VerificationImplForTest.class)); - assertThat(((VerificationImplForTest)verification).expectedClaims, hasEntry("name", null)); - } - - @Test - public void withIssuerStringDefaultImplShouldDelegate() { - Verification verification = new VerificationImplForTest() - .withIssuer("string"); - - assertThat(verification, instanceOf(VerificationImplForTest.class)); - assertThat(((VerificationImplForTest)verification).expectedClaims, hasEntry("iss", new String[]{"string"})); - } - - static class VerificationImplForTest implements Verification { - - private final Map expectedClaims = new HashMap<>(); - - @Override - public Verification withIssuer(String... issuer) { - expectedClaims.put("iss", issuer); - return this; - } - - @Override - public Verification withSubject(String subject) { - return null; - } - - @Override - public Verification withAudience(String... audience) { - return null; - } - - @Override - public Verification withAnyOfAudience(String... audience) { - return null; - } - - @Override - public Verification acceptLeeway(long leeway) throws IllegalArgumentException { - return null; - } - - @Override - public Verification acceptExpiresAt(long leeway) throws IllegalArgumentException { - return null; - } - - @Override - public Verification acceptNotBefore(long leeway) throws IllegalArgumentException { - return null; - } - - @Override - public Verification acceptIssuedAt(long leeway) throws IllegalArgumentException { - return null; - } - - @Override - public Verification withJWTId(String jwtId) { - return null; - } - - @Override - public Verification withClaimPresence(String name) throws IllegalArgumentException { - return null; - } - - @Override - public Verification withNullClaim(String name) throws IllegalArgumentException { - return null; - } - - @Override - public Verification withClaim(String name, Boolean value) throws IllegalArgumentException { - return null; - } - - @Override - public Verification withClaim(String name, Integer value) throws IllegalArgumentException { - return null; - } - - @Override - public Verification withClaim(String name, Long value) throws IllegalArgumentException { - return null; - } - - @Override - public Verification withClaim(String name, Double value) throws IllegalArgumentException { - return null; - } - - @Override - public Verification withClaim(String name, String value) throws IllegalArgumentException { - return null; - } - - @Override - public Verification withClaim(String name, Date value) throws IllegalArgumentException { - this.expectedClaims.put(name, value); - return this; - } - - @Override - public Verification withArrayClaim(String name, String... items) throws IllegalArgumentException { - return null; - } - - @Override - public Verification withArrayClaim(String name, Integer... items) throws IllegalArgumentException { - return null; - } - - @Override - public Verification withArrayClaim(String name, Long... items) throws IllegalArgumentException { - return null; - } - - @Override - public Verification withClaim(String name, BiPredicate predicate) throws IllegalArgumentException { - return null; - } - - @Override - public Verification ignoreIssuedAt() { - return null; - } - - @Override - public JWTVerifier build() { - return null; - } - } -} diff --git a/lib/src/test/resources/ec256-key-pair.pem b/lib/src/test/resources/ec256-key-pair.pem deleted file mode 100644 index 63e8673f..00000000 --- a/lib/src/test/resources/ec256-key-pair.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MHcCAQEEIDxiRgJuF9X7wbgtc0qTv+CM8ej13zTGoimkuUVJBahBoAoGCCqGSM49 -AwEHoUQDQgAEQgb5npLHd0Bk61bNnjK632uwmBfrF7I8hoPgaOZjyhh+BrPDO6CL -6D/aW/yPObXXm7SpZogmRwGROcOA3yUleg== ------END EC PRIVATE KEY----- diff --git a/lib/src/test/resources/ec256-key-private.pem b/lib/src/test/resources/ec256-key-private.pem deleted file mode 100644 index 756361a1..00000000 --- a/lib/src/test/resources/ec256-key-private.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgPGJGAm4X1fvBuC1z -SpO/4Izx6PXfNMaiKaS5RUkFqEGhRANCAARCBvmeksd3QGTrVs2eMrrfa7CYF+sX -sjyGg+Bo5mPKGH4Gs8M7oIvoP9pb/I85tdebtKlmiCZHAZE5w4DfJSV6 ------END PRIVATE KEY----- diff --git a/lib/src/test/resources/ec256-key-public-invalid.pem b/lib/src/test/resources/ec256-key-public-invalid.pem deleted file mode 100644 index 8e4f6a97..00000000 --- a/lib/src/test/resources/ec256-key-public-invalid.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoBUyo8CQAFPeYPvv78ylh5MwFZjT -CLQeb042TjiMJxG+9DLFmRSMlBQ9T/RsLLc+PmpB1+7yPAR+oR5gZn3kJQ== ------END PUBLIC KEY----- diff --git a/lib/src/test/resources/ec256-key-public.pem b/lib/src/test/resources/ec256-key-public.pem deleted file mode 100644 index 34401f77..00000000 --- a/lib/src/test/resources/ec256-key-public.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEQgb5npLHd0Bk61bNnjK632uwmBfr -F7I8hoPgaOZjyhh+BrPDO6CL6D/aW/yPObXXm7SpZogmRwGROcOA3yUleg== ------END PUBLIC KEY----- diff --git a/lib/src/test/resources/ec384-key-pair.pem b/lib/src/test/resources/ec384-key-pair.pem deleted file mode 100644 index 8c124080..00000000 --- a/lib/src/test/resources/ec384-key-pair.pem +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MIGkAgEBBDCVWQsOJHjKD0I4cXOYJm4G8i5c7IMhFbxFq57OUlrTVmND43dvvNW1 -oQ6i6NiXEQWgBwYFK4EEACKhZANiAASezSGlAu4wAaJe4676mQM0F/5slI+Ekdpt -RJdfsQP9mNxe7RdzHgcSw7j/Wxa45nlnFnFrPPL4viJKOBRxMB1jjVA9my9PixxJ -GoB22qDQwFbP8ldmEp6abwdBsXNaePM= ------END EC PRIVATE KEY----- diff --git a/lib/src/test/resources/ec384-key-private.pem b/lib/src/test/resources/ec384-key-private.pem deleted file mode 100644 index 9482bfa8..00000000 --- a/lib/src/test/resources/ec384-key-private.pem +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCVWQsOJHjKD0I4cXOY -Jm4G8i5c7IMhFbxFq57OUlrTVmND43dvvNW1oQ6i6NiXEQWhZANiAASezSGlAu4w -AaJe4676mQM0F/5slI+EkdptRJdfsQP9mNxe7RdzHgcSw7j/Wxa45nlnFnFrPPL4 -viJKOBRxMB1jjVA9my9PixxJGoB22qDQwFbP8ldmEp6abwdBsXNaePM= ------END PRIVATE KEY----- diff --git a/lib/src/test/resources/ec384-key-public-invalid.pem b/lib/src/test/resources/ec384-key-public-invalid.pem deleted file mode 100644 index 1f4b6853..00000000 --- a/lib/src/test/resources/ec384-key-public-invalid.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEJ0tamPyAJVUhDO1DlceSYCdA9WKVX6nO -K4VYetXvqmMKdyVkaoA4Gl02KoVLujiSSSAE6oK/Hf7x2fagaE9LgJdJxg07Ip+T -C6cgFi2HHDeXG7djB5Zl1TKA9/w/8iW5 ------END PUBLIC KEY----- diff --git a/lib/src/test/resources/ec384-key-public.pem b/lib/src/test/resources/ec384-key-public.pem deleted file mode 100644 index 511596e7..00000000 --- a/lib/src/test/resources/ec384-key-public.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEns0hpQLuMAGiXuOu+pkDNBf+bJSPhJHa -bUSXX7ED/ZjcXu0Xcx4HEsO4/1sWuOZ5ZxZxazzy+L4iSjgUcTAdY41QPZsvT4sc -SRqAdtqg0MBWz/JXZhKemm8HQbFzWnjz ------END PUBLIC KEY----- diff --git a/lib/src/test/resources/ec512-key-pair.pem b/lib/src/test/resources/ec512-key-pair.pem deleted file mode 100644 index 1428daae..00000000 --- a/lib/src/test/resources/ec512-key-pair.pem +++ /dev/null @@ -1,7 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MIHbAgEBBEHzl1DpZSQJ8YhCbN/uvo5SOu0BjDDX9Gub6zsBW6B2TxRzb5sBeQaW -VscDUZha4Xr1HEWpVtua9+nEQU/9Aq9Pl6AHBgUrgQQAI6GBiQOBhgAEAJhvCa6S -89ePqlLO6MRV9KQqHvdAITDAf/WRDcvCmfrrNuov+j4gQXO12ohIukPCHM9rYms8 -Eqciz3gaxVTxZD4CAA8i2k9H6ew9iSh1qXa1kLxiyzMBqmAmmg4u/SroD6OleG56 -SwZVbWx+KIINB6r/PQVciGX8FjwgR/mbLHotVZYD ------END EC PRIVATE KEY----- diff --git a/lib/src/test/resources/ec512-key-private.pem b/lib/src/test/resources/ec512-key-private.pem deleted file mode 100644 index bde90986..00000000 --- a/lib/src/test/resources/ec512-key-private.pem +++ /dev/null @@ -1,7 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIHtAgEAMBAGByqGSM49AgEGBSuBBAAjBIHVMIHSAgEBBEHzl1DpZSQJ8YhCbN/u -vo5SOu0BjDDX9Gub6zsBW6B2TxRzb5sBeQaWVscDUZha4Xr1HEWpVtua9+nEQU/9 -Aq9Pl6GBiQOBhgAEAJhvCa6S89ePqlLO6MRV9KQqHvdAITDAf/WRDcvCmfrrNuov -+j4gQXO12ohIukPCHM9rYms8Eqciz3gaxVTxZD4CAA8i2k9H6ew9iSh1qXa1kLxi -yzMBqmAmmg4u/SroD6OleG56SwZVbWx+KIINB6r/PQVciGX8FjwgR/mbLHotVZYD ------END PRIVATE KEY----- diff --git a/lib/src/test/resources/ec512-key-public-invalid.pem b/lib/src/test/resources/ec512-key-public-invalid.pem deleted file mode 100644 index f976d7f5..00000000 --- a/lib/src/test/resources/ec512-key-public-invalid.pem +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBgtBWt9rVtdQPdeoChvCXnXHvkg/F -41AAubIVd+3yTvLFmxuHuaor9CHl7FlT3532mUG+GG0EEw5UuYkFrg/ABBgAfuVf -wO1u0V0wJPkmpxcnZoojFaAOKcsBvUvDulbBh0HhAyd+nlfZquvV43uwFVpn2Cjb -Lx+/AT1PE6Muqy4JkGU= ------END PUBLIC KEY----- diff --git a/lib/src/test/resources/ec512-key-public.pem b/lib/src/test/resources/ec512-key-public.pem deleted file mode 100644 index 360209ae..00000000 --- a/lib/src/test/resources/ec512-key-public.pem +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAmG8JrpLz14+qUs7oxFX0pCoe90Ah -MMB/9ZENy8KZ+us26i/6PiBBc7XaiEi6Q8Icz2tiazwSpyLPeBrFVPFkPgIADyLa -T0fp7D2JKHWpdrWQvGLLMwGqYCaaDi79KugPo6V4bnpLBlVtbH4ogg0Hqv89BVyI -ZfwWPCBH+Zssei1VlgM= ------END PUBLIC KEY----- diff --git a/lib/src/test/resources/rsa-private.pem b/lib/src/test/resources/rsa-private.pem deleted file mode 100644 index e4519683..00000000 --- a/lib/src/test/resources/rsa-private.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC4ZtdaIrd1BPIJ -tfnF0TjIK5inQAXZ3XlCrUlJdP+XHwIRxdv1FsN12XyMYO/6ymLmo9ryoQeIrsXB -XYqlET3zfAY+diwCb0HEsVvhisthwMU4gZQu6TYW2s9LnXZB5rVtcBK69hcSlA2k -ZudMZWxZcj0L7KMfO2rIvaHw/qaVOE9j0T257Z8Kp2CLF9MUgX0ObhIsdumFRLaL -DvDUmBPr2zuh/34j2XmWwn1yjN/WvGtdfhXW79Ki1S40HcWnygHgLV8sESFKUxxQ -mKvPUTwDOIwLFL5WtE8Mz7N++kgmDcmWMCHc8kcOIu73Ta/3D4imW7VbKgHZo9+K -3ESFE3RjAgMBAAECggEBAJTEIyjMqUT24G2FKiS1TiHvShBkTlQdoR5xvpZMlYbN -tVWxUmrAGqCQ/TIjYnfpnzCDMLhdwT48Ab6mQJw69MfiXwc1PvwX1e9hRscGul36 -ryGPKIVQEBsQG/zc4/L2tZe8ut+qeaK7XuYrPp8bk/X1e9qK5m7j+JpKosNSLgJj -NIbYsBkG2Mlq671irKYj2hVZeaBQmWmZxK4fw0Istz2WfN5nUKUeJhTwpR+JLUg4 -ELYYoB7EO0Cej9UBG30hbgu4RyXA+VbptJ+H042K5QJROUbtnLWuuWosZ5ATldwO -u03dIXL0SH0ao5NcWBzxU4F2sBXZRGP2x/jiSLHcqoECgYEA4qD7mXQpu1b8XO8U -6abpKloJCatSAHzjgdR2eRDRx5PMvloipfwqA77pnbjTUFajqWQgOXsDTCjcdQui -wf5XAaWu+TeAVTytLQbSiTsBhrnoqVrr3RoyDQmdnwHT8aCMouOgcC5thP9vQ8Us -rVdjvRRbnJpg3BeSNimH+u9AHgsCgYEA0EzcbOltCWPHRAY7B3Ge/AKBjBQr86Kv -TdpTlxePBDVIlH+BM6oct2gaSZZoHbqPjbq5v7yf0fKVcXE4bSVgqfDJ/sZQu9Lp -PTeV7wkk0OsAMKk7QukEpPno5q6tOTNnFecpUhVLLlqbfqkB2baYYwLJR3IRzboJ -FQbLY93E8gkCgYB+zlC5VlQbbNqcLXJoImqItgQkkuW5PCgYdwcrSov2ve5r/Acz -FNt1aRdSlx4176R3nXyibQA1Vw+ztiUFowiP9WLoM3PtPZwwe4bGHmwGNHPIfwVG -m+exf9XgKKespYbLhc45tuC08DATnXoYK7O1EnUINSFJRS8cezSI5eHcbQKBgQDC -PgqHXZ2aVftqCc1eAaxaIRQhRmY+CgUjumaczRFGwVFveP9I6Gdi+Kca3DE3F9Pq -PKgejo0SwP5vDT+rOGHN14bmGJUMsX9i4MTmZUZ5s8s3lXh3ysfT+GAhTd6nKrIE -kM3Nh6HWFhROptfc6BNusRh1kX/cspDplK5x8EpJ0QKBgQDWFg6S2je0KtbV5PYe -RultUEe2C0jYMDQx+JYxbPmtcopvZQrFEur3WKVuLy5UAy7EBvwMnZwIG7OOohJb -vkSpADK6VPn9lbqq7O8cTedEHttm6otmLt8ZyEl3hZMaL3hbuRj6ysjmoFKx6CrX -rK0/Ikt5ybqUzKCMJZg2VKGTxg== ------END PRIVATE KEY----- \ No newline at end of file diff --git a/lib/src/test/resources/rsa-public.pem b/lib/src/test/resources/rsa-public.pem deleted file mode 100644 index e8d62885..00000000 --- a/lib/src/test/resources/rsa-public.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuGbXWiK3dQTyCbX5xdE4 -yCuYp0AF2d15Qq1JSXT/lx8CEcXb9RbDddl8jGDv+spi5qPa8qEHiK7FwV2KpRE9 -83wGPnYsAm9BxLFb4YrLYcDFOIGULuk2FtrPS512Qea1bXASuvYXEpQNpGbnTGVs -WXI9C+yjHztqyL2h8P6mlThPY9E9ue2fCqdgixfTFIF9Dm4SLHbphUS2iw7w1JgT -69s7of9+I9l5lsJ9cozf1rxrXX4V1u/SotUuNB3Fp8oB4C1fLBEhSlMcUJirz1E8 -AziMCxS+VrRPDM+zfvpIJg3JljAh3PJHDiLu902v9w+Iplu1WyoB2aPfitxEhRN0 -YwIDAQAB ------END PUBLIC KEY----- diff --git a/lib/src/test/resources/rsa-public_invalid.pem b/lib/src/test/resources/rsa-public_invalid.pem deleted file mode 100644 index eab17cf7..00000000 --- a/lib/src/test/resources/rsa-public_invalid.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxzYuc22QSst/dS7geYYK -5l5kLxU0tayNdixkEQ17ix+CUcUbKIsnyftZxaCYT46rQtXgCaYRdJcbB3hmyrOa -vkhTpX79xJZnQmfuamMbZBqitvscxW9zRR9tBUL6vdi/0rpoUwPMEh8+Bw7CgYR0 -FK0DhWYBNDfe9HKcyZEv3max8Cdq18htxjEsdYO0iwzhtKRXomBWTdhD5ykd/fAC -VTr4+KEY+IeLvubHVmLUhbE5NgWXxrRpGasDqzKhCTmsa2Ysf712rl57SlH0Wz/M -r3F7aM9YpErzeYLrl0GhQr9BVJxOvXcVd4kmY+XkiCcrkyS1cnghnllh+LCwQu1s -YwIDAQAB ------END PUBLIC KEY----- diff --git a/opslevel.yml b/opslevel.yml deleted file mode 100644 index 009a5ec0..00000000 --- a/opslevel.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -version: 1 -repository: - owner: dx_sdks - tier: - tags: diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..b1c69ea2 --- /dev/null +++ b/pom.xml @@ -0,0 +1,158 @@ + + 4.0.0 + + + org.sonatype.oss + oss-parent + 9 + + + com.auth0 + java-jwt + 2.3.1-SNAPSHOT + + Java JWT + Java implementation of JSON Web Token developed against draft-ietf-oauth-json-web-token-08. + + http://www.jwt.io + + + 1.7 + 1.7 + com.auth0.jwt.internal + + + + + The MIT License + http://www.opensource.org/licenses/mit-license.php + repo + + + + + https://github.com/auth0/java-jwt + scm:git:git@github.com:auth0/java-jwt.git + scm:git:git@github.com:auth0/java-jwt.git + + + + + + com.fasterxml.jackson.core + jackson-databind + 2.0.1 + + + + org.bouncycastle + bcprov-jdk15on + 1.52 + + + + commons-codec + commons-codec + 1.10 + + + + org.apache.commons + commons-lang3 + 3.4 + + + + + + junit + junit + 4.12 + test + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + ${java.source.version} + ${java.target.version} + UTF-8 + + + + org.jacoco + jacoco-maven-plugin + 0.7.7.201606060606 + + + + prepare-agent + + + + report + test + + report + + + + + + org.apache.maven.plugins + maven-shade-plugin + 2.2 + + + package + + shade + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + false + true + + + com.fasterxml.jackson + ${repackage.base}.com.fasterxml.jackson + + + org.apache.commons.codec + ${repackage.base}.org.apache.commons.codec + + + org.apache.commons.io + ${repackage.base}.org.apache.commons.io + + + org.apache.commons.lang3 + ${repackage.base}.org.apache.commons.lang3 + + + org.bouncycastle + ${repackage.base}.org.bouncycastle + + + + + + + + + diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index d3c4c85b..00000000 --- a/settings.gradle +++ /dev/null @@ -1,8 +0,0 @@ -pluginManagement { - repositories { - gradlePluginPortal() - } -} - -include ':java-jwt' -project(':java-jwt').projectDir = new File(rootProject.projectDir, '/lib') diff --git a/src/main/java/com/auth0/jwt/Algorithm.java b/src/main/java/com/auth0/jwt/Algorithm.java new file mode 100644 index 00000000..b3009a73 --- /dev/null +++ b/src/main/java/com/auth0/jwt/Algorithm.java @@ -0,0 +1,33 @@ +package com.auth0.jwt; + +import org.apache.commons.lang3.Validate; + +/** + * Supported Library Algorithms + * + * https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyPairGenerator + */ +public enum Algorithm { + + HS256("HmacSHA256"), HS384("HmacSHA384"), HS512("HmacSHA512"), RS256("SHA256withRSA"), RS384("SHA384withRSA"), RS512("SHA512withRSA"); + + private Algorithm(final String value) { + this.value = value; + } + + private String value; + + public String getValue() { + return value; + } + + public static Algorithm findByName(final String name) throws JWTAlgorithmException { + Validate.notNull(name); + try { + return Algorithm.valueOf(name); + } catch (IllegalArgumentException e) { + throw new JWTAlgorithmException("Unsupported algorithm: " + name); + } + } + +} diff --git a/src/main/java/com/auth0/jwt/JWTAlgorithmException.java b/src/main/java/com/auth0/jwt/JWTAlgorithmException.java new file mode 100644 index 00000000..fec47b3e --- /dev/null +++ b/src/main/java/com/auth0/jwt/JWTAlgorithmException.java @@ -0,0 +1,20 @@ +package com.auth0.jwt; + +/** + * Represents Exception related to Algorithm - for example JWT header algorithm is unsupported / missing + */ +public class JWTAlgorithmException extends JWTVerifyException { + + + public JWTAlgorithmException() {} + + public JWTAlgorithmException(final String message, final Throwable cause) { + super(message, cause); + } + + public JWTAlgorithmException(final String message) { + super(message); + } + +} + diff --git a/src/main/java/com/auth0/jwt/JWTAudienceException.java b/src/main/java/com/auth0/jwt/JWTAudienceException.java new file mode 100644 index 00000000..622d73b7 --- /dev/null +++ b/src/main/java/com/auth0/jwt/JWTAudienceException.java @@ -0,0 +1,36 @@ +package com.auth0.jwt; + +import com.fasterxml.jackson.databind.JsonNode; +import org.apache.commons.lang3.Validate; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents Exception related to Audience - for example illegal audience on JWT Verification + */ +public class JWTAudienceException extends JWTVerifyException { + + private JsonNode audienceNode; + + public JWTAudienceException(final JsonNode audienceNode) { + this.audienceNode = audienceNode; + } + + public JWTAudienceException(final String message, final JsonNode audienceNode) { + super(message); + this.audienceNode = audienceNode; + } + + public List getAudience() { + final ArrayList audience = new ArrayList<>(); + if (audienceNode.isArray()) { + for (final JsonNode jsonNode : audienceNode) { + audience.add(jsonNode.textValue()); + } + } else if (audienceNode.isTextual()) { + audience.add(audienceNode.textValue()); + } + return audience; + } +} diff --git a/src/main/java/com/auth0/jwt/JWTExpiredException.java b/src/main/java/com/auth0/jwt/JWTExpiredException.java new file mode 100644 index 00000000..41086eef --- /dev/null +++ b/src/main/java/com/auth0/jwt/JWTExpiredException.java @@ -0,0 +1,23 @@ +package com.auth0.jwt; + + +/** + * Represents Exception related to Expiration - for example JWT token has expired + */ +public class JWTExpiredException extends JWTVerifyException { + + private long expiration; + + public JWTExpiredException(final long expiration) { + this.expiration = expiration; + } + + public JWTExpiredException(final String message, final long expiration) { + super(message); + this.expiration = expiration; + } + + public long getExpiration() { + return expiration; + }; +} diff --git a/src/main/java/com/auth0/jwt/JWTIssuerException.java b/src/main/java/com/auth0/jwt/JWTIssuerException.java new file mode 100644 index 00000000..13463ddc --- /dev/null +++ b/src/main/java/com/auth0/jwt/JWTIssuerException.java @@ -0,0 +1,22 @@ +package com.auth0.jwt; + +/** + * Represents Exception related to Issuer - for example issuer mismatch / missing upon verification + */ +public class JWTIssuerException extends JWTVerifyException { + + private final String issuer; + + public JWTIssuerException(final String issuer) { + this.issuer = issuer; + } + + public JWTIssuerException(final String message, final String issuer) { + super(message); + this.issuer = issuer; + } + + public String getIssuer() { + return issuer; + } +} diff --git a/src/main/java/com/auth0/jwt/JWTSigner.java b/src/main/java/com/auth0/jwt/JWTSigner.java new file mode 100644 index 00000000..828128ad --- /dev/null +++ b/src/main/java/com/auth0/jwt/JWTSigner.java @@ -0,0 +1,362 @@ +package com.auth0.jwt; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.*; +import java.util.*; + +/** + * Handles JWT Sign Operation + * + * Default algorithm when none provided is HMAC SHA-256 ("HS256") + * + * See associated library test cases for clear examples on usage + * + */ +public class JWTSigner { + + static { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { + Security.addProvider(new BouncyCastleProvider()); + } + } + + private byte[] secret; + private PrivateKey privateKey; + + // Default algorithm HMAC SHA-256 ("HS256") + protected final static Algorithm DEFAULT_ALGORITHM = Algorithm.HS256; + + public JWTSigner(final String secret) { + this(secret.getBytes()); + } + + public JWTSigner(final byte[] secret) { + Validate.notNull(secret); + this.secret = secret; + } + + public JWTSigner(final PrivateKey privateKey) { + this.privateKey = privateKey; + } + + /** + * Generate a JSON Web Token. + * + * @param claims A map of the JWT claims that form the payload. Registered claims + * must be of appropriate Java datatype as following: + *
    + *
  • iss, sub: String + *
  • exp, nbf, iat, jti: numeric, eg. Long + *
  • aud: String, or Collection<String> + *
+ * All claims with a null value are left out the JWT. + * Any claims set automatically as specified in + * the "options" parameter override claims in this map. + * @param options Allow choosing the signing algorithm, and automatic setting of some registered claims. + */ + public String sign(final Map claims, final Options options) { + Validate.notNull(claims); + final Algorithm algorithm = (options != null && options.algorithm != null) ? options.algorithm : DEFAULT_ALGORITHM; + final List segments = new ArrayList<>(); + try { + segments.add(encodedHeader(algorithm)); + segments.add(encodedPayload(claims, options)); + segments.add(encodedSignature(join(segments, "."), algorithm)); + return join(segments, "."); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Generate a JSON Web Token using the default algorithm HMAC SHA-256 ("HS256") + * and no claims automatically set. + */ + public String sign(final Map claims) { + Validate.notNull(claims); + return sign(claims, null); + } + + /** + * Generate the header part of a JSON web token. + */ + private String encodedHeader(final Algorithm algorithm) throws UnsupportedEncodingException { + Validate.notNull(algorithm); + // create the header + final ObjectNode header = JsonNodeFactory.instance.objectNode(); + header.put("typ", "JWT"); + header.put("alg", algorithm.name()); + return base64UrlEncode(header.toString().getBytes("UTF-8")); + } + + /** + * Generate the JSON web token payload string from the claims. + * + * @param options + */ + private String encodedPayload(final Map _claims, final Options options) throws IOException { + final Map claims = new HashMap<>(_claims); + enforceStringOrURI(claims, "iss"); + enforceStringOrURI(claims, "sub"); + enforceStringOrURICollection(claims, "aud"); + enforceIntDate(claims, "exp"); + enforceIntDate(claims, "nbf"); + enforceIntDate(claims, "iat"); + enforceString(claims, "jti"); + if (options != null) { + processPayloadOptions(claims, options); + } + final String payload = new ObjectMapper().writeValueAsString(claims); + return base64UrlEncode(payload.getBytes("UTF-8")); + } + + private void processPayloadOptions(final Map claims, final Options options) { + Validate.notNull(claims); + Validate.notNull(options); + final long now = System.currentTimeMillis() / 1000l; + if (options.expirySeconds != null) + claims.put("exp", now + options.expirySeconds); + if (options.notValidBeforeLeeway != null) + claims.put("nbf", now - options.notValidBeforeLeeway); + if (options.isIssuedAt()) + claims.put("iat", now); + if (options.isJwtId()) + claims.put("jti", UUID.randomUUID().toString()); + } + + // consider cleanup + private void enforceIntDate(final Map claims, final String claimName) { + Validate.notNull(claims); + Validate.notNull(claimName); + final Object value = handleNullValue(claims, claimName); + if (value == null) + return; + if (!(value instanceof Number)) { + throw new IllegalStateException(String.format("Claim '%s' is invalid: must be an instance of Number", claimName)); + } + final long longValue = ((Number) value).longValue(); + if (longValue < 0) + throw new IllegalStateException(String.format("Claim '%s' is invalid: must be non-negative", claimName)); + claims.put(claimName, longValue); + } + + // consider cleanup + private void enforceStringOrURICollection(final Map claims, final String claimName) { + final Object values = handleNullValue(claims, claimName); + if (values == null) + return; + if (values instanceof Collection) { + @SuppressWarnings({"unchecked"}) + final Iterator iterator = ((Collection) values).iterator(); + while (iterator.hasNext()) { + Object value = iterator.next(); + String error = checkStringOrURI(value); + if (error != null) + throw new IllegalStateException(String.format("Claim 'aud' element is invalid: %s", error)); + } + } else { + enforceStringOrURI(claims, "aud"); + } + } + + // consider cleanup + private void enforceStringOrURI(final Map claims, final String claimName) { + final Object value = handleNullValue(claims, claimName); + if (value == null) + return; + final String error = checkStringOrURI(value); + if (error != null) + throw new IllegalStateException(String.format("Claim '%s' is invalid: %s", claimName, error)); + } + + // consider cleanup + private void enforceString(final Map claims, final String claimName) { + final Object value = handleNullValue(claims, claimName); + if (value == null) + return; + if (!(value instanceof String)) + throw new IllegalStateException(String.format("Claim '%s' is invalid: not a string", claimName)); + } + + // consider cleanup + private Object handleNullValue(final Map claims, final String claimName) { + if (!claims.containsKey(claimName)) + return null; + final Object value = claims.get(claimName); + if (value == null) { + claims.remove(claimName); + return null; + } + return value; + } + + // consider cleanup + private String checkStringOrURI(final Object value) { + if (!(value instanceof String)) + return "not a string"; + final String stringOrUri = (String) value; + if (!stringOrUri.contains(":")) + return null; + try { + new URI(stringOrUri); + } catch (URISyntaxException e) { + return "not a valid URI"; + } + return null; + } + + /** + * Sign the header and payload + */ + private String encodedSignature(final String signingInput, final Algorithm algorithm) throws NoSuchAlgorithmException, InvalidKeyException, + NoSuchProviderException, SignatureException, JWTAlgorithmException { + Validate.notNull(signingInput); + Validate.notNull(algorithm); + switch (algorithm) { + case HS256: + case HS384: + case HS512: + return base64UrlEncode(signHmac(algorithm, signingInput, secret)); + case RS256: + case RS384: + case RS512: + return base64UrlEncode(signRs(algorithm, signingInput, privateKey)); + default: + throw new JWTAlgorithmException("Unsupported signing method"); + } + } + + /** + * Safe URL encode a byte array to a String + */ + private String base64UrlEncode(final byte[] str) { + Validate.notNull(str); + return new String(Base64.encodeBase64URLSafe(str)); + } + + /** + * Sign an input string using HMAC and return the encrypted bytes + */ + private static byte[] signHmac(final Algorithm algorithm, final String msg, final byte[] secret) throws NoSuchAlgorithmException, InvalidKeyException { + Validate.notNull(algorithm); + Validate.notNull(msg); + Validate.notNull(secret); + final Mac mac = Mac.getInstance(algorithm.getValue()); + mac.init(new SecretKeySpec(secret, algorithm.getValue())); + return mac.doFinal(msg.getBytes()); + } + + /** + * Sign an input string using RSA and return the encrypted bytes + */ + private static byte[] signRs(final Algorithm algorithm, final String msg, final PrivateKey privateKey) throws NoSuchProviderException, + NoSuchAlgorithmException, InvalidKeyException, SignatureException { + Validate.notNull(algorithm); + Validate.notNull(msg); + Validate.notNull(privateKey); + final byte[] messageBytes = msg.getBytes(); + final Signature signature = Signature.getInstance(algorithm.getValue(), "BC"); + signature.initSign(privateKey); + signature.update(messageBytes); + return signature.sign(); + } + + private String join(final List input, final String separator) { + Validate.notNull(input); + Validate.notNull(separator); + return StringUtils.join(input.iterator(), separator); + } + + /** + * An option object for JWT signing operation. Allow choosing the algorithm, and/or specifying + * claims to be automatically set. + */ + public static class Options { + + private Algorithm algorithm; + private Integer expirySeconds; + private Integer notValidBeforeLeeway; + private boolean issuedAt; + private boolean jwtId; + + public Algorithm getAlgorithm() { + return algorithm; + } + + /** + * Algorithm to sign JWT with. + */ + public Options setAlgorithm(final Algorithm algorithm) { + this.algorithm = algorithm; + return this; + } + + + public Integer getExpirySeconds() { + return expirySeconds; + } + + /** + * Set JWT claim "exp" to current timestamp plus this value. + * Overrides content of claims in sign(). + */ + public Options setExpirySeconds(final Integer expirySeconds) { + this.expirySeconds = expirySeconds; + return this; + } + + public Integer getNotValidBeforeLeeway() { + return notValidBeforeLeeway; + } + + /** + * Set JWT claim "nbf" to current timestamp minus this value. + * Overrides content of claims in sign(). + */ + public Options setNotValidBeforeLeeway(final Integer notValidBeforeLeeway) { + this.notValidBeforeLeeway = notValidBeforeLeeway; + return this; + } + + public boolean isIssuedAt() { + return issuedAt; + } + + /** + * Set JWT claim "iat" to current timestamp. Defaults to false. + * Overrides content of claims in sign(). + */ + public Options setIssuedAt(final boolean issuedAt) { + this.issuedAt = issuedAt; + return this; + } + + public boolean isJwtId() { + return jwtId; + } + + /** + * Set JWT claim "jti" to a pseudo random unique value (type 4 UUID). Defaults to false. + * Overrides content of claims in sign(). + */ + public Options setJwtId(final boolean jwtId) { + this.jwtId = jwtId; + return this; + } + + } + +} diff --git a/src/main/java/com/auth0/jwt/JWTVerifier.java b/src/main/java/com/auth0/jwt/JWTVerifier.java new file mode 100644 index 00000000..0e0199fa --- /dev/null +++ b/src/main/java/com/auth0/jwt/JWTVerifier.java @@ -0,0 +1,239 @@ +package com.auth0.jwt; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.Validate; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.IOException; +import java.nio.charset.Charset; +import java.security.*; +import java.util.Map; + +/** + * Handles JWT Verification Operations + * + * Validates claims and signature + * + * See associated library test cases for clear examples on usage + * + */ +public class JWTVerifier { + + static { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { + Security.addProvider(new BouncyCastleProvider()); + } + } + + private byte[] secret; + private PublicKey publicKey; + private final String audience; + private final String issuer; + private final Base64 decoder = new Base64(true); + + private final ObjectMapper mapper; + + + public JWTVerifier(final String secret, final String audience, final String issuer) { + this(secret.getBytes(Charset.forName("UTF-8")), audience, issuer); + } + + public JWTVerifier(final String secret, final String audience) { + this(secret, audience, null); + } + + public JWTVerifier(final String secret) { + this(secret, null, null); + } + + public JWTVerifier(final byte[] secret, final String audience) { + this(secret, audience, null); + } + + public JWTVerifier(final byte[] secret) { + this(secret, null, null); + } + + public JWTVerifier(final byte[] secret, final String audience, final String issuer) { + if (secret == null || secret.length == 0) { + throw new IllegalArgumentException("Secret cannot be null or empty"); + } + mapper = new ObjectMapper(); + this.secret = secret; + this.audience = audience; + this.issuer = issuer; + } + + public JWTVerifier(final PublicKey publicKey, final String audience, final String issuer) { + Validate.notNull(publicKey); + mapper = new ObjectMapper(); + this.publicKey = publicKey; + this.audience = audience; + this.issuer = issuer; + } + + public JWTVerifier(final PublicKey publicKey, final String audience) { + this(publicKey, audience, null); + } + + public JWTVerifier(final PublicKey publicKey) { + this(publicKey, null, null); + } + + + /** + * Performs JWT validation + * + * @param token token to verify + * @throws SignatureException when signature is invalid + * @throws JWTVerifyException when expiration, issuer or audience are invalid + * @throws JWTAlgorithmException when the algorithm is missing or unsupported + * @throws IllegalStateException when token's structure is invalid or secret / public key does not match algorithm of token + */ + @SuppressWarnings("WeakerAccess") + public Map verify(final String token) throws NoSuchAlgorithmException, InvalidKeyException, IllegalStateException, + IOException, SignatureException, JWTVerifyException { + if (token == null || "".equals(token)) { + throw new IllegalStateException("token not set"); + } + final String[] pieces = token.split("\\."); + if (pieces.length != 3) { + throw new IllegalStateException("Wrong number of segments: " + pieces.length); + } + final JsonNode jwtHeader = decodeAndParse(pieces[0]); + final Algorithm algorithm = getAlgorithm(jwtHeader); + final JsonNode jwtPayload = decodeAndParse(pieces[1]); + verifySignature(pieces, algorithm); + verifyExpiration(jwtPayload); + verifyIssuer(jwtPayload); + verifyAudience(jwtPayload); + return mapper.treeToValue(jwtPayload, Map.class); + } + + void verifySignature(final String[] pieces, final Algorithm algorithm) throws NoSuchAlgorithmException, + InvalidKeyException, SignatureException, JWTAlgorithmException, IllegalStateException { + Validate.notNull(pieces); + Validate.notNull(algorithm); + if (pieces.length != 3) { + throw new IllegalStateException("Wrong number of segments: " + pieces.length); + } + switch (algorithm) { + case HS256: + case HS384: + case HS512: + verifyHmac(algorithm, pieces, secret); + return; + case RS256: + case RS384: + case RS512: + verifyRs(algorithm, pieces, publicKey); + return; + default: + throw new JWTAlgorithmException("Unsupported signing method"); + } + } + + private void verifyHmac(final Algorithm algorithm, final String[] pieces, final byte[] secret) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException { + if (secret == null || secret.length == 0) { + throw new IllegalStateException("Secret cannot be null or empty when using algorithm: " + algorithm.getValue()); + } + final Mac hmac = Mac.getInstance(algorithm.getValue()); + hmac.init(new SecretKeySpec(secret, algorithm.getValue())); + final byte[] sig = hmac.doFinal((pieces[0] + "." + pieces[1]).getBytes()); + if (!MessageDigest.isEqual(sig, decoder.decode(pieces[2]))) { + throw new SignatureException("signature verification failed"); + } + } + + private void verifyRs(final Algorithm algorithm, final String[] pieces, final PublicKey publicKey) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException, JWTAlgorithmException { + if (publicKey == null) { + throw new IllegalStateException("PublicKey cannot be null when using algorithm: " + algorithm.getValue()); + } + final byte[] decodedSignatureBytes = new Base64(true).decode(pieces[2]); + final byte[] headerPayloadBytes = (pieces[0] + "." + pieces[1]).getBytes(); + final boolean verified = verifySignatureWithPublicKey(this.publicKey, headerPayloadBytes, decodedSignatureBytes, algorithm); + if (!verified) { + throw new SignatureException("signature verification failed"); + } + } + + private boolean verifySignatureWithPublicKey(final PublicKey publicKey, final byte[] messageBytes, final byte[] signatureBytes, final Algorithm algorithm) throws InvalidKeyException, SignatureException, NoSuchAlgorithmException, JWTAlgorithmException { + Validate.notNull(publicKey); + Validate.notNull(messageBytes); + Validate.notNull(signatureBytes); + Validate.notNull(algorithm); + try { + final Signature signature = Signature.getInstance(algorithm.getValue(), "BC"); + signature.initVerify(publicKey); + signature.update(messageBytes); + return signature.verify(signatureBytes); + } catch (NoSuchProviderException e) { + throw new JWTAlgorithmException(e.getMessage(), e.getCause()); + } + } + + void verifyExpiration(final JsonNode jwtClaims) throws JWTExpiredException { + Validate.notNull(jwtClaims); + final long expiration = jwtClaims.has("exp") ? jwtClaims.get("exp").asLong(0) : 0; + if (expiration != 0 && System.currentTimeMillis() / 1000L >= expiration) { + throw new JWTExpiredException("jwt expired", expiration); + } + } + + void verifyIssuer(final JsonNode jwtClaims) throws JWTIssuerException { + Validate.notNull(jwtClaims); + + if (this.issuer == null ) { + return; + } + + final String issuerFromToken = jwtClaims.has("iss") ? jwtClaims.get("iss").asText() : null; + + if (issuerFromToken == null || !issuer.equals(issuerFromToken)) { + throw new JWTIssuerException("jwt issuer invalid", issuerFromToken); + } + } + + void verifyAudience(final JsonNode jwtClaims) throws JWTAudienceException { + Validate.notNull(jwtClaims); + if (audience == null) { + return; + } + final JsonNode audNode = jwtClaims.get("aud"); + if (audNode == null) { + throw new JWTAudienceException("jwt audience invalid", null); + } + if (audNode.isArray()) { + for (final JsonNode jsonNode : audNode) { + if (audience.equals(jsonNode.textValue())) { + return; + } + } + } else if (audNode.isTextual()) { + if (audience.equals(audNode.textValue())) { + return; + } + } + throw new JWTAudienceException("jwt audience invalid", audNode); + } + + Algorithm getAlgorithm(final JsonNode jwtHeader) throws JWTAlgorithmException { + Validate.notNull(jwtHeader); + final String algorithmName = jwtHeader.has("alg") ? jwtHeader.get("alg").asText() : null; + if (jwtHeader.get("alg") == null) { + throw new IllegalStateException("algorithm not set"); + } + return Algorithm.findByName(algorithmName); + } + + JsonNode decodeAndParse(final String b64String) throws IOException { + Validate.notNull(b64String); + final String jsonString = new String(decoder.decode(b64String), "UTF-8"); + return mapper.readValue(jsonString, JsonNode.class); + } + +} diff --git a/src/main/java/com/auth0/jwt/JWTVerifyException.java b/src/main/java/com/auth0/jwt/JWTVerifyException.java new file mode 100644 index 00000000..9e18d6b8 --- /dev/null +++ b/src/main/java/com/auth0/jwt/JWTVerifyException.java @@ -0,0 +1,18 @@ +package com.auth0.jwt; + +/** + * Represents General Exception related to Verification + */ +public class JWTVerifyException extends Exception { + + public JWTVerifyException() {} + + public JWTVerifyException(final String message, final Throwable cause) { + super(message, cause); + } + + public JWTVerifyException(final String message) { + super(message); + } + +} diff --git a/src/main/java/com/auth0/jwt/pem/PemFileReader.java b/src/main/java/com/auth0/jwt/pem/PemFileReader.java new file mode 100644 index 00000000..60eb9f33 --- /dev/null +++ b/src/main/java/com/auth0/jwt/pem/PemFileReader.java @@ -0,0 +1,38 @@ +package com.auth0.jwt.pem; + +import org.bouncycastle.util.io.pem.PemObject; +import org.bouncycastle.util.io.pem.PemReader; +import org.bouncycastle.util.io.pem.PemWriter; + +import java.io.*; + +/** + * Can read PEM from disk - depends on BouncyCastle PemReader + */ +class PemFileReader { + + private PemObject pemObject; + + public PemFileReader(final String filename) throws IOException { + final PemReader pemReader = new PemReader(new InputStreamReader(new FileInputStream(filename))); + try { + this.pemObject = pemReader.readPemObject(); + } finally { + pemReader.close(); + } + } + + public void write(final String filename) throws IOException { + final PemWriter pemWriter = new PemWriter(new OutputStreamWriter(new FileOutputStream(filename))); + try { + pemWriter.writeObject(this.pemObject); + } finally { + pemWriter.close(); + } + } + + public PemObject getPemObject() { + return pemObject; + } + +} diff --git a/src/main/java/com/auth0/jwt/pem/PemFileWriter.java b/src/main/java/com/auth0/jwt/pem/PemFileWriter.java new file mode 100644 index 00000000..8b23df10 --- /dev/null +++ b/src/main/java/com/auth0/jwt/pem/PemFileWriter.java @@ -0,0 +1,31 @@ +package com.auth0.jwt.pem; + +import org.bouncycastle.util.io.pem.PemObject; +import org.bouncycastle.util.io.pem.PemWriter; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.security.Key; + +/** + * Can write PEM to disk - depends on BouncyCastle PemWriter + */ +class PemFileWriter { + + private PemObject pemObject; + + public PemFileWriter(final Key key, final String description) { + this.pemObject = new PemObject(description, key.getEncoded()); + } + + public void write(final String filename) throws IOException { + final PemWriter pemWriter = new PemWriter(new OutputStreamWriter(new FileOutputStream(filename))); + try { + pemWriter.writeObject(this.pemObject); + } finally { + pemWriter.close(); + } + } + +} diff --git a/src/main/java/com/auth0/jwt/pem/PemReader.java b/src/main/java/com/auth0/jwt/pem/PemReader.java new file mode 100644 index 00000000..90ca0486 --- /dev/null +++ b/src/main/java/com/auth0/jwt/pem/PemReader.java @@ -0,0 +1,68 @@ +package com.auth0.jwt.pem; + +import org.apache.commons.lang3.Validate; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.security.*; +import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +/** + * Read operations for PEM files + */ +public class PemReader { + + static { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { + Security.addProvider(new BouncyCastleProvider()); + } + } + + public static PrivateKey readPrivateKey(final String filePath) throws NoSuchProviderException, NoSuchAlgorithmException, IOException, InvalidKeySpecException { + Validate.notNull(filePath); + final KeyFactory factory = KeyFactory.getInstance("RSA", "BC"); + final PrivateKey privateKey = readPrivateKeyFromFile(factory, filePath); + return privateKey; + } + + public static PublicKey readPublicKey(final String filePath) throws NoSuchProviderException, NoSuchAlgorithmException, IOException, InvalidKeySpecException { + Validate.notNull(filePath); + final KeyFactory factory = KeyFactory.getInstance("RSA", "BC"); + final PublicKey publicKey = readPublicKeyFromFile(factory, filePath); + return publicKey; + } + + private static PrivateKey readPrivateKeyFromFile(final KeyFactory factory, final String filename) throws InvalidKeySpecException, IOException { + Validate.notNull(factory); + Validate.notNull(filename); + final PemFileReader pemFileReader = new PemFileReader(filename); + final byte[] content = pemFileReader.getPemObject().getContent(); + final PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content); + return factory.generatePrivate(privKeySpec); + } + + private static PublicKey readPublicKeyFromFile(final KeyFactory factory, final String filename) throws InvalidKeySpecException, IOException { + Validate.notNull(factory); + Validate.notNull(filename); + final File file = new File(filename); + final byte[] data = Files.readAllBytes(file.toPath()); + final X509Certificate cert = X509CertUtils.parse(new String(data)); + if (cert != null) { + java.security.PublicKey publicKey = cert.getPublicKey(); + return publicKey; + } else { + final PemFileReader pemFileReader = new PemFileReader(filename); + final byte[] content = pemFileReader.getPemObject().getContent(); + final X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content); + return factory.generatePublic(pubKeySpec); + } + + + } + +} diff --git a/src/main/java/com/auth0/jwt/pem/PemWriter.java b/src/main/java/com/auth0/jwt/pem/PemWriter.java new file mode 100644 index 00000000..55856ce4 --- /dev/null +++ b/src/main/java/com/auth0/jwt/pem/PemWriter.java @@ -0,0 +1,34 @@ +package com.auth0.jwt.pem; + +import org.apache.commons.lang3.Validate; + +import java.io.IOException; +import java.security.Key; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +/** + * Write operations for PEM files + */ +public class PemWriter { + + public static void writePrivateKey(final RSAPrivateKey privateKey, final String description, final String filename) throws IOException { + Validate.notNull(privateKey); + Validate.notNull(filename); + writePemFile(privateKey, description, filename); + } + + public static void writePublicKey(final RSAPublicKey publicKey, final String description, final String filename) throws IOException { + Validate.notNull(publicKey); + Validate.notNull(filename); + writePemFile(publicKey, description, filename); + } + + public static void writePemFile(final Key key, final String description, final String filename) throws IOException { + Validate.notNull(key); + Validate.notNull(filename); + final PemFileWriter pemFileWriter = new PemFileWriter(key, description); + pemFileWriter.write(filename); + } + +} diff --git a/src/main/java/com/auth0/jwt/pem/X509CertUtils.java b/src/main/java/com/auth0/jwt/pem/X509CertUtils.java new file mode 100644 index 00000000..ef65e476 --- /dev/null +++ b/src/main/java/com/auth0/jwt/pem/X509CertUtils.java @@ -0,0 +1,61 @@ +package com.auth0.jwt.pem; + +import org.apache.commons.codec.binary.Base64; + +import java.io.ByteArrayInputStream; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + + +/** + * X.509 certificate utilities. + */ +public class X509CertUtils { + + private static final String PEM_BEGIN_MARKER = "-----BEGIN CERTIFICATE-----"; + private static final String PEM_END_MARKER = "-----END CERTIFICATE-----"; + + /** + * Parses a DER-encoded X.509 certificate. + */ + public static X509Certificate parse(final byte[] derEncodedCert) { + if (derEncodedCert == null || derEncodedCert.length == 0) { + return null; + } + try { + final CertificateFactory cf = CertificateFactory.getInstance("X.509"); + final Certificate cert = cf.generateCertificate(new ByteArrayInputStream(derEncodedCert)); + if (!(cert instanceof X509Certificate)) { + return null; + } + return (X509Certificate) cert; + } catch (CertificateException e) { + return null; + } + } + + /** + * Parses a PEM-encoded X.509 certificate. + */ + public static X509Certificate parse(final String pemEncodedCert) { + if (pemEncodedCert == null || pemEncodedCert.isEmpty()) { + return null; + } + final int markerStart = pemEncodedCert.indexOf(PEM_BEGIN_MARKER); + if (markerStart < 0) { + return null; + } + String buf = pemEncodedCert.substring(markerStart + PEM_BEGIN_MARKER.length()); + final int markerEnd = buf.indexOf(PEM_END_MARKER); + if (markerEnd < 0) { + return null; + } + buf = buf.substring(0, markerEnd); + buf = buf.replaceAll("\\s", ""); + return parse(new Base64(true).decodeBase64(buf)); + } + +} + diff --git a/src/test/java/com/auth0/jwt/JWTRoundTripRsa256Test.java b/src/test/java/com/auth0/jwt/JWTRoundTripRsa256Test.java new file mode 100644 index 00000000..722de2a4 --- /dev/null +++ b/src/test/java/com/auth0/jwt/JWTRoundTripRsa256Test.java @@ -0,0 +1,100 @@ +package com.auth0.jwt; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.security.*; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.util.*; + +import static com.auth0.jwt.pem.PemReader.readPrivateKey; +import static com.auth0.jwt.pem.PemReader.readPublicKey; +import static com.auth0.jwt.pem.PemWriter.writePrivateKey; +import static com.auth0.jwt.pem.PemWriter.writePublicKey; +import static junit.framework.TestCase.*; + +/** + * Test that generates KeyPair - writes PEM files (private and public) to disk, + * then reads in those PEM files (private and public) and uses them to Sign a JWT + * and subsequently verify its correctness - hence "RoundTrip" + */ +public class JWTRoundTripRsa256Test { + + private static final int KEY_SIZE = 2048; + + static { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { + Security.addProvider(new BouncyCastleProvider()); + } + } + + private File privateKeyPem; + private File publicKeyPem; + + @Before + public void createPemFiles() throws NoSuchAlgorithmException, NoSuchProviderException, IOException { + // create key pair + final KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC"); + generator.initialize(KEY_SIZE); + final KeyPair keyPair = generator.generateKeyPair(); + // write private key + final RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); + privateKeyPem = File.createTempFile("id_rsa", ""); + writePrivateKey(privateKey, "RSA PRIVATE KEY", privateKeyPem.getAbsolutePath()); + // write public key + publicKeyPem = File.createTempFile("id_rsa", ".pub"); + final RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); + writePublicKey(publicKey, "RSA PUBLIC KEY", publicKeyPem.getAbsolutePath()); + } + + @Test + public void roundTripCreatingSignedTokenAndVerifyingUsingRs256Algo() throws NoSuchProviderException, NoSuchAlgorithmException, IOException, InvalidKeySpecException, SignatureException, InvalidKeyException, JWTAlgorithmException, JWTVerifyException { + // read pem files + final PrivateKey privateKey = readPrivateKey(privateKeyPem.getAbsolutePath()); + assertNotNull(privateKey); + final PublicKey publicKey = readPublicKey(publicKeyPem.getAbsolutePath()); + assertNotNull(publicKey); + // create and sign a JWT + final String issuer = "https://arcseldon.auth0.com/"; + final String clientId = "xGXMKfEdcOcacZEU7Uq1mgWOtpUxBlL4"; // this is the audience + final String name = "arcseldon"; + final String email = "arcseldon+test@gmail.com"; + final String subject = "auth0|576be978a93121cc48c7487d"; + final List roles = new ArrayList<>(); + roles.add("ROLE_ADMIN"); + final long iat = System.currentTimeMillis() / 1000l; + final long exp = iat + 3600L; + final HashMap claims = new HashMap<>(); + claims.put("name", name); + claims.put("email", email); + claims.put("email_verified", "true"); + claims.put("iss", issuer); + claims.put("roles", roles.toArray(new String[0])); + claims.put("sub", subject); + claims.put("aud", clientId); + claims.put("exp", exp); + claims.put("iat", iat); + final JWTSigner jwtSigner = new JWTSigner(privateKey); + final JWTSigner.Options options = new JWTSigner.Options(); + options.setAlgorithm(Algorithm.RS256); + final String token = jwtSigner.sign(claims, options); + assertNotNull(token); + final JWTVerifier jwtVerifier = new JWTVerifier(publicKey); + final Map verifiedClaims = jwtVerifier.verify(token); + assertEquals(name, verifiedClaims.get("name")); + assertEquals(email, verifiedClaims.get("email")); + assertEquals("true", verifiedClaims.get("email_verified")); + assertTrue(roles.equals((List) verifiedClaims.get("roles"))); + assertEquals(issuer, verifiedClaims.get("iss")); + assertEquals(subject, verifiedClaims.get("sub")); + assertEquals(clientId, verifiedClaims.get("aud")); + assertTrue(exp == (Integer) verifiedClaims.get("exp")); + assertTrue(iat == (Integer) verifiedClaims.get("iat")); + } + +} diff --git a/src/test/java/com/auth0/jwt/JWTRoundTripTest.java b/src/test/java/com/auth0/jwt/JWTRoundTripTest.java new file mode 100644 index 00000000..3fca12a9 --- /dev/null +++ b/src/test/java/com/auth0/jwt/JWTRoundTripTest.java @@ -0,0 +1,162 @@ +package com.auth0.jwt; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Test things that are difficult using signer or verifier alone. In particular, setting + * claims via Options produces output dependent on current time. + * + */ +public class JWTRoundTripTest { + private static final String SECRET; + static { + SECRET = "my secret"; + } + private static JWTSigner signer = new JWTSigner(SECRET); + private static JWTVerifier verifier = new JWTVerifier(SECRET); + + /* + * Roundtrip of different datatypes. + */ + @Test + public void shouldEmpty() throws Exception { + HashMap claims = new HashMap(); + String token = signer.sign(claims); + Map decoded = verifier.verify(token); + assertEquals(claims, decoded); + } + + @Test + public void shouldString() throws Exception { + HashMap claims = new HashMap(); + claims.put("foo", "bar"); + String token = signer.sign(claims); + Map decoded = verifier.verify(token); + assertEquals(claims, decoded); + } + + @Test + public void shouldShort() throws Exception { + HashMap claims = new HashMap(); + claims.put("foo", (short) -10); + String token = signer.sign(claims); + Map decoded = verifier.verify(token); + Number fooValue = (Number) decoded.get("foo"); + decoded.put("foo", fooValue.shortValue()); + assertEquals(claims, decoded); + } + + @Test + public void shouldLong() throws Exception { + HashMap claims = new HashMap(); + claims.put("foo", Long.MAX_VALUE); + String token = signer.sign(claims); + Map decoded = verifier.verify(token); + assertEquals(claims, decoded); + } + + @Test + public void shouldObject() throws Exception { + HashMap claims = new HashMap(); + User user = new User(); + user.setUsername("foo"); + user.setPassword("bar"); + claims.put("user", user); + String token = signer.sign(claims); + Map decoded = verifier.verify(token); + HashMap expectedUser = new HashMap(); + expectedUser.put("username", "foo"); + expectedUser.put("password", "bar"); + HashMap expected = new HashMap(); + expected.put("user", expectedUser); + assertEquals(expected, decoded); + } + + @Test + public void shouldBoolean() throws Exception { + HashMap claims = new HashMap(); + claims.put("foo", true); + claims.put("bar", false); + String token = signer.sign(claims); + Map decoded = verifier.verify(token); + assertEquals(claims, decoded); + } + + /* + * Setting claims via Options + */ + + @Test + public void shouldOptionsIat() throws Exception { + HashMap claims = new HashMap(); + long before = System.currentTimeMillis(); + String token = signer.sign(claims, new JWTSigner.Options().setIssuedAt(true)); + long after = System.currentTimeMillis(); + Map decoded = verifier.verify(token); + + assertEquals(decoded.size(), 1); + long iat = ((Number) decoded.get("iat")).longValue(); + assertTrue(iat >= before / 1000l); + assertTrue(iat <= after / 1000l); + } + + @Test + public void shouldOptionsTimestamps() throws Exception { + HashMap claims = new HashMap(); + String token = signer.sign(claims, + new JWTSigner.Options() + .setExpirySeconds(50).setNotValidBeforeLeeway(10).setIssuedAt(true)); + Map decoded = verifier.verify(token); + assertEquals(decoded.size(), 3); + long iat = ((Number) decoded.get("iat")).longValue(); + long exp = ((Number) decoded.get("exp")).longValue(); + long nbf = ((Number) decoded.get("nbf")).longValue(); + assertEquals(exp, iat + 50); + assertEquals(nbf, iat - 10); + } + + @Test + public void shouldOptionsJti() throws Exception { + HashMap claims = new HashMap(); + String token = signer.sign(claims, + new JWTSigner.Options().setJwtId(true)); + Map decoded = verifier.verify(token); + assertEquals(decoded.size(), 1); + assertEquals(((String) decoded.get("jti")).length(), 36); + } + + + public static class User { + + private String username; + private String password; + + public User() { + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + } +} + + + diff --git a/src/test/java/com/auth0/jwt/JWTSignerBytesTest.java b/src/test/java/com/auth0/jwt/JWTSignerBytesTest.java new file mode 100644 index 00000000..2d5d06a4 --- /dev/null +++ b/src/test/java/com/auth0/jwt/JWTSignerBytesTest.java @@ -0,0 +1,205 @@ +package com.auth0.jwt; + +import com.auth0.jwt.Algorithm; +import com.auth0.jwt.JWTSigner; +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; + +import static org.junit.Assert.assertEquals; + +/** + * General library JwtSigner unit tests using byte constructor alternative for secret + */ +public class JWTSignerBytesTest { + private static JWTSigner signer = new JWTSigner(new byte[] { 109, 121, 32, 115, 101, 99, 114, 101, 116}); + + @Test + public void shouldSignEmpty() throws Exception { + HashMap claims = new HashMap(); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e30.86pkOAQxvnSDd91EThNNpOTbO-hbvxdssnFjQqT04NU", token); + } + + @Test + public void shouldSignEmptyTwoParams() throws Exception { + HashMap claims = new HashMap(); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e30.86pkOAQxvnSDd91EThNNpOTbO-hbvxdssnFjQqT04NU", token); + } + + @Test + public void shouldSignStringOrURI1() throws Exception { + HashMap claims = new HashMap(); + claims.put("iss", "foo"); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmb28ifQ.UbvkKJx4ubG9SQYs3Hpe6FJl1ix89jSLw0I9GNTnLgY", token); + } + + @Test + public void shouldSignStringOrURI2() throws Exception { + HashMap claims = new HashMap(); + claims.put("sub", "http://foo"); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJodHRwOi8vZm9vIn0.EaYoTXJWUNd_1tWfZo4EZoKUP8hVMJm1LHBQNo4Xfwg", token); + } + + @Test + public void shouldSignStringOrURI3() throws Exception { + HashMap claims = new HashMap(); + claims.put("aud", ""); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIifQ.T2EKheH_WVVwybctic8Sqk89miYVKADW0AeXOicDbz8", token); + } + + @Test + public void shouldSignStringOrURICollection() throws Exception { + HashMap claims = new HashMap(); + LinkedList aud = new LinkedList(); + aud.add("xyz"); + aud.add("ftp://foo"); + claims.put("aud", aud); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsieHl6IiwiZnRwOi8vZm9vIl19.WGpsdOnLJ2k7Rr4WeEuabHO4wNQIhJfPMZot1DrTUgA", token); + } + + @Test + public void shouldSignIntDate1() throws Exception { + HashMap claims = new HashMap(); + claims.put("exp", 123); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjEyM30.FzAXEHf0LVQPOyRQFftA1VBAj8RmZGEfwQIPSfg_DUg", token); + } + + @Test + public void bytes_shouldSignIntDate1() throws Exception { + HashMap claims = new HashMap(); + claims.put("exp", 123); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjEyM30.FzAXEHf0LVQPOyRQFftA1VBAj8RmZGEfwQIPSfg_DUg", token); + } + + @Test + public void shouldSignIntDate2() throws Exception { + HashMap claims = new HashMap(); + claims.put("nbf", 0); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYmYiOjB9.ChHEHjtyr4qOUMu6KDsa2BjGXtkGurboD5ljr99gVzw", token); + } + + @Test + public void shouldSignIntDate3() throws Exception { + HashMap claims = new HashMap(); + claims.put("iat", Long.MAX_VALUE); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjkyMjMzNzIwMzY4NTQ3NzU4MDd9.7yrsheXoAuqk5hDcbKmT3l6aDNNr7RMnbVe6kVkvv4M", token); + } + + @Test + public void bytes_shouldSignIntDate2() throws Exception { + HashMap claims = new HashMap(); + claims.put("nbf", 0); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYmYiOjB9.ChHEHjtyr4qOUMu6KDsa2BjGXtkGurboD5ljr99gVzw", token); + } + + @Test + public void shouldSignString() throws Exception { + HashMap claims = new HashMap(); + claims.put("jti", "foo"); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJmb28ifQ.CriA-W8LKO4bCxy3e2Nu7kx2MxgcHGyFu_GVLMX3bko", token); + } + + @Test + public void shouldSignNullEqualsMissing() throws Exception { + HashMap claims = new HashMap(); + for (String claimName : Arrays.asList("iss", "sub", "aud", "exp", "nbf", "iat", "jti")) { + claims.put(claimName, null); + } + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e30.86pkOAQxvnSDd91EThNNpOTbO-hbvxdssnFjQqT04NU", token); + } + + @Test(expected = Exception.class) + public void shouldFailExpectStringOrURI1() throws Exception { + HashMap claims = new HashMap(); + claims.put("iss", 0); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectStringOrURI2() throws Exception { + HashMap claims = new HashMap(); + claims.put("sub", ":"); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectStringOrURICollection1() throws Exception { + HashMap claims = new HashMap(); + claims.put("aud", 0); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectStringOrURICollection2() throws Exception { + HashMap claims = new HashMap(); + claims.put("aud", Arrays.asList(0)); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectStringOrURICollection3() throws Exception { + HashMap claims = new HashMap(); + claims.put("aud", Arrays.asList(":")); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectIntDate1() throws Exception { + HashMap claims = new HashMap(); + claims.put("exp", -1); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectIntDate2() throws Exception { + HashMap claims = new HashMap(); + claims.put("nbf", "100"); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectString() throws Exception { + HashMap claims = new HashMap(); + claims.put("jti", 100); + signer.sign(claims); + } + + @Test + public void shouldOptionsNone() throws Exception { + HashMap claims = new HashMap(); + String token = signer.sign(claims, new JWTSigner.Options()); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e30.86pkOAQxvnSDd91EThNNpOTbO-hbvxdssnFjQqT04NU", token); + } + + @Test + public void shouldOptionsAll() throws Exception { + HashMap claims = new HashMap(); + signer.sign(claims, new JWTSigner.Options() + .setExpirySeconds(1000).setNotValidBeforeLeeway(5) + .setIssuedAt(true).setJwtId(true)); + } + + @Test + public void shouldOptionsAlgorithm() throws Exception { + HashMap claims = new HashMap(); + String token = signer.sign(claims, + new JWTSigner.Options().setAlgorithm(Algorithm.HS512)); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.e30.11MgCe-_uiheyy_kARCwhSZbeq3IkMn40GLQkczQ4Bjn_lkCYfSeqz0HeeYpitksiQ2bW47N0oGKCOYOlmQPyg", token); + } + +} diff --git a/src/test/java/com/auth0/jwt/JWTSignerTest.java b/src/test/java/com/auth0/jwt/JWTSignerTest.java new file mode 100644 index 00000000..099e5c12 --- /dev/null +++ b/src/test/java/com/auth0/jwt/JWTSignerTest.java @@ -0,0 +1,188 @@ +package com.auth0.jwt; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; + +import static org.junit.Assert.assertEquals; + + +/** + * General library JwtSigner related unit tests + */ +public class JWTSignerTest { + private static JWTSigner signer = new JWTSigner("my secret"); + + @Test + public void shouldSignEmpty() throws Exception { + HashMap claims = new HashMap(); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e30.86pkOAQxvnSDd91EThNNpOTbO-hbvxdssnFjQqT04NU", token); + } + + @Test + public void shouldSignEmptyTwoParams() throws Exception { + HashMap claims = new HashMap(); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e30.86pkOAQxvnSDd91EThNNpOTbO-hbvxdssnFjQqT04NU", token); + } + + @Test + public void shouldSignStringOrURI1() throws Exception { + HashMap claims = new HashMap(); + claims.put("iss", "foo"); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmb28ifQ.UbvkKJx4ubG9SQYs3Hpe6FJl1ix89jSLw0I9GNTnLgY", token); + } + + @Test + public void shouldSignStringOrURI2() throws Exception { + HashMap claims = new HashMap(); + claims.put("sub", "http://foo"); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJodHRwOi8vZm9vIn0.EaYoTXJWUNd_1tWfZo4EZoKUP8hVMJm1LHBQNo4Xfwg", token); + } + + @Test + public void shouldSignStringOrURI3() throws Exception { + HashMap claims = new HashMap(); + claims.put("aud", ""); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIifQ.T2EKheH_WVVwybctic8Sqk89miYVKADW0AeXOicDbz8", token); + } + + @Test + public void shouldSignStringOrURICollection() throws Exception { + HashMap claims = new HashMap(); + LinkedList aud = new LinkedList(); + aud.add("xyz"); + aud.add("ftp://foo"); + claims.put("aud", aud); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsieHl6IiwiZnRwOi8vZm9vIl19.WGpsdOnLJ2k7Rr4WeEuabHO4wNQIhJfPMZot1DrTUgA", token); + } + + @Test + public void shouldSignIntDate1() throws Exception { + HashMap claims = new HashMap(); + claims.put("exp", 123); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjEyM30.FzAXEHf0LVQPOyRQFftA1VBAj8RmZGEfwQIPSfg_DUg", token); + } + + @Test + public void shouldSignIntDate2() throws Exception { + HashMap claims = new HashMap(); + claims.put("nbf", 0); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYmYiOjB9.ChHEHjtyr4qOUMu6KDsa2BjGXtkGurboD5ljr99gVzw", token); + } + + @Test + public void shouldSignIntDate3() throws Exception { + HashMap claims = new HashMap(); + claims.put("iat", Long.MAX_VALUE); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjkyMjMzNzIwMzY4NTQ3NzU4MDd9.7yrsheXoAuqk5hDcbKmT3l6aDNNr7RMnbVe6kVkvv4M", token); + } + + @Test + public void shouldSignString() throws Exception { + HashMap claims = new HashMap(); + claims.put("jti", "foo"); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJmb28ifQ.CriA-W8LKO4bCxy3e2Nu7kx2MxgcHGyFu_GVLMX3bko", token); + } + + @Test + public void shouldSignNullEqualsMissing() throws Exception { + HashMap claims = new HashMap(); + for (String claimName : Arrays.asList("iss", "sub", "aud", "exp", "nbf", "iat", "jti")) { + claims.put(claimName, null); + } + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e30.86pkOAQxvnSDd91EThNNpOTbO-hbvxdssnFjQqT04NU", token); + } + + @Test(expected = Exception.class) + public void shouldFailExpectStringOrURI1() throws Exception { + HashMap claims = new HashMap(); + claims.put("iss", 0); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectStringOrURI2() throws Exception { + HashMap claims = new HashMap(); + claims.put("sub", ":"); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectStringOrURICollection1() throws Exception { + HashMap claims = new HashMap(); + claims.put("aud", 0); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectStringOrURICollection2() throws Exception { + HashMap claims = new HashMap(); + claims.put("aud", Arrays.asList(0)); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectStringOrURICollection3() throws Exception { + HashMap claims = new HashMap(); + claims.put("aud", Arrays.asList(":")); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectIntDate1() throws Exception { + HashMap claims = new HashMap(); + claims.put("exp", -1); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectIntDate2() throws Exception { + HashMap claims = new HashMap(); + claims.put("nbf", "100"); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectString() throws Exception { + HashMap claims = new HashMap(); + claims.put("jti", 100); + signer.sign(claims); + } + + @Test + public void shouldOptionsNone() throws Exception { + HashMap claims = new HashMap(); + String token = signer.sign(claims, new JWTSigner.Options()); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e30.86pkOAQxvnSDd91EThNNpOTbO-hbvxdssnFjQqT04NU", token); + } + + @Test + public void shouldOptionsAll() throws Exception { + HashMap claims = new HashMap(); + signer.sign(claims, new JWTSigner.Options() + .setExpirySeconds(1000).setNotValidBeforeLeeway(5) + .setIssuedAt(true).setJwtId(true)); + } + + @Test + public void shouldOptionsAlgorithm() throws Exception { + HashMap claims = new HashMap(); + String token = signer.sign(claims, + new JWTSigner.Options().setAlgorithm(Algorithm.HS512)); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.e30.11MgCe-_uiheyy_kARCwhSZbeq3IkMn40GLQkczQ4Bjn_lkCYfSeqz0HeeYpitksiQ2bW47N0oGKCOYOlmQPyg", token); + } + +} diff --git a/src/test/java/com/auth0/jwt/JWTSignerTest_Bytes.java b/src/test/java/com/auth0/jwt/JWTSignerTest_Bytes.java new file mode 100644 index 00000000..93cffda4 --- /dev/null +++ b/src/test/java/com/auth0/jwt/JWTSignerTest_Bytes.java @@ -0,0 +1,200 @@ +package com.auth0.jwt; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; + +import static org.junit.Assert.assertEquals; + +public class JWTSignerTest_Bytes { + private static JWTSigner signer = new JWTSigner(new byte[] { 109, 121, 32, 115, 101, 99, 114, 101, 116}); + + @Test + public void shouldSignEmpty() throws Exception { + HashMap claims = new HashMap(); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e30.86pkOAQxvnSDd91EThNNpOTbO-hbvxdssnFjQqT04NU", token); + } + + @Test + public void shouldSignEmptyTwoParams() throws Exception { + HashMap claims = new HashMap(); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e30.86pkOAQxvnSDd91EThNNpOTbO-hbvxdssnFjQqT04NU", token); + } + + @Test + public void shouldSignStringOrURI1() throws Exception { + HashMap claims = new HashMap(); + claims.put("iss", "foo"); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmb28ifQ.UbvkKJx4ubG9SQYs3Hpe6FJl1ix89jSLw0I9GNTnLgY", token); + } + + @Test + public void shouldSignStringOrURI2() throws Exception { + HashMap claims = new HashMap(); + claims.put("sub", "http://foo"); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJodHRwOi8vZm9vIn0.EaYoTXJWUNd_1tWfZo4EZoKUP8hVMJm1LHBQNo4Xfwg", token); + } + + @Test + public void shouldSignStringOrURI3() throws Exception { + HashMap claims = new HashMap(); + claims.put("aud", ""); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIifQ.T2EKheH_WVVwybctic8Sqk89miYVKADW0AeXOicDbz8", token); + } + + @Test + public void shouldSignStringOrURICollection() throws Exception { + HashMap claims = new HashMap(); + LinkedList aud = new LinkedList(); + aud.add("xyz"); + aud.add("ftp://foo"); + claims.put("aud", aud); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsieHl6IiwiZnRwOi8vZm9vIl19.WGpsdOnLJ2k7Rr4WeEuabHO4wNQIhJfPMZot1DrTUgA", token); + } + + @Test + public void shouldSignIntDate1() throws Exception { + HashMap claims = new HashMap(); + claims.put("exp", 123); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjEyM30.FzAXEHf0LVQPOyRQFftA1VBAj8RmZGEfwQIPSfg_DUg", token); + } + + @Test + public void bytes_shouldSignIntDate1() throws Exception { + HashMap claims = new HashMap(); + claims.put("exp", 123); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjEyM30.FzAXEHf0LVQPOyRQFftA1VBAj8RmZGEfwQIPSfg_DUg", token); + } + + @Test + public void shouldSignIntDate2() throws Exception { + HashMap claims = new HashMap(); + claims.put("nbf", 0); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYmYiOjB9.ChHEHjtyr4qOUMu6KDsa2BjGXtkGurboD5ljr99gVzw", token); + } + + @Test + public void shouldSignIntDate3() throws Exception { + HashMap claims = new HashMap(); + claims.put("iat", Long.MAX_VALUE); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjkyMjMzNzIwMzY4NTQ3NzU4MDd9.7yrsheXoAuqk5hDcbKmT3l6aDNNr7RMnbVe6kVkvv4M", token); + } + + @Test + public void bytes_shouldSignIntDate2() throws Exception { + HashMap claims = new HashMap(); + claims.put("nbf", 0); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYmYiOjB9.ChHEHjtyr4qOUMu6KDsa2BjGXtkGurboD5ljr99gVzw", token); + } + + @Test + public void shouldSignString() throws Exception { + HashMap claims = new HashMap(); + claims.put("jti", "foo"); + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJmb28ifQ.CriA-W8LKO4bCxy3e2Nu7kx2MxgcHGyFu_GVLMX3bko", token); + } + + @Test + public void shouldSignNullEqualsMissing() throws Exception { + HashMap claims = new HashMap(); + for (String claimName : Arrays.asList("iss", "sub", "aud", "exp", "nbf", "iat", "jti")) { + claims.put(claimName, null); + } + String token = signer.sign(claims); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e30.86pkOAQxvnSDd91EThNNpOTbO-hbvxdssnFjQqT04NU", token); + } + + @Test(expected = Exception.class) + public void shouldFailExpectStringOrURI1() throws Exception { + HashMap claims = new HashMap(); + claims.put("iss", 0); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectStringOrURI2() throws Exception { + HashMap claims = new HashMap(); + claims.put("sub", ":"); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectStringOrURICollection1() throws Exception { + HashMap claims = new HashMap(); + claims.put("aud", 0); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectStringOrURICollection2() throws Exception { + HashMap claims = new HashMap(); + claims.put("aud", Arrays.asList(0)); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectStringOrURICollection3() throws Exception { + HashMap claims = new HashMap(); + claims.put("aud", Arrays.asList(":")); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectIntDate1() throws Exception { + HashMap claims = new HashMap(); + claims.put("exp", -1); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectIntDate2() throws Exception { + HashMap claims = new HashMap(); + claims.put("nbf", "100"); + signer.sign(claims); + } + + @Test(expected = Exception.class) + public void shouldFailExpectString() throws Exception { + HashMap claims = new HashMap(); + claims.put("jti", 100); + signer.sign(claims); + } + + @Test + public void shouldOptionsNone() throws Exception { + HashMap claims = new HashMap(); + String token = signer.sign(claims, new JWTSigner.Options()); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e30.86pkOAQxvnSDd91EThNNpOTbO-hbvxdssnFjQqT04NU", token); + } + + @Test + public void shouldOptionsAll() throws Exception { + HashMap claims = new HashMap(); + signer.sign(claims, new JWTSigner.Options() + .setExpirySeconds(1000).setNotValidBeforeLeeway(5) + .setIssuedAt(true).setJwtId(true)); + } + + @Test + public void shouldOptionsAlgorithm() throws Exception { + HashMap claims = new HashMap(); + String token = signer.sign(claims, + new JWTSigner.Options().setAlgorithm(Algorithm.HS512)); + assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.e30.11MgCe-_uiheyy_kARCwhSZbeq3IkMn40GLQkczQ4Bjn_lkCYfSeqz0HeeYpitksiQ2bW47N0oGKCOYOlmQPyg", token); + } + +} diff --git a/src/test/java/com/auth0/jwt/JWTVerifierRsa256Test.java b/src/test/java/com/auth0/jwt/JWTVerifierRsa256Test.java new file mode 100644 index 00000000..485954ce --- /dev/null +++ b/src/test/java/com/auth0/jwt/JWTVerifierRsa256Test.java @@ -0,0 +1,106 @@ +package com.auth0.jwt; + +import com.auth0.jwt.pem.X509CertUtils; +import org.apache.commons.codec.binary.Base64; +import org.junit.Test; + +import java.io.File; +import java.nio.file.Files; +import java.security.PublicKey; +import java.security.SignatureException; +import java.security.cert.X509Certificate; +import java.util.HashMap; +import java.util.Map; + +import static com.auth0.jwt.pem.PemReader.readPublicKey; +import static junit.framework.TestCase.assertNotNull; + +/** + * RS256 Verification Checks + */ +public class JWTVerifierRsa256Test { + + private final static String RESOURCES_DIR = "src/test/resources/auth0-pem/"; + private final static String MISMATCHED_RESOURCES_DIR = "src/test/resources/test-pem/"; + private final static String PUBLIC_KEY_PEM_FILENAME = "key.pem"; + private final static String MISMATCHED_PUBLIC_KEY_PEM_FILENAME = "test-auth0.pem"; + + + + /** + * Here we pass in a public key that does not correspond to the private key that was used to sign the JWT Token + */ + @Test(expected = SignatureException.class) + public void shouldFailOnInvalidSignature() throws Exception { + final String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlFVTkVRelZCTXpoRk1FVTNRMFZGTURJNFFqYzROakJDTkRSQ1JFRkNSalkzUWpnMFJEVXlOZyJ9" + + "." + + "eyJyb2xlcyI6WyJST0xFX0FETUlOIl0sInVzZXJfaWQiOiJhdXRoMHw1NzcxMGU5ZDE0MWIwN2YyMmU3NDNhYzciLCJlbWFpbCI6ImFyY3NlbGRvbit0cm5AZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYWppbG9uMS5hdXRoMC5jb20vIiwic3ViIjoiYXV0aDB8NTc3MTBlOWQxNDFiMDdmMjJlNzQzYWM3IiwiYXVkIjoibm5ld1NobHBHVDFBbkZpY1ExUGlKWXdheENuejE4eUIiLCJleHAiOjE0Njc3MDk5OTMsImlhdCI6MTQ2NzY3Mzk5M30" + + "." + + "gQML78V8H6WN3MSN1QhrFG4AxNTdFChPBQxrnuqPF0iBvf35v_z9oDzTERaPBDWFHzWT17h0ADxpl7tCIo43k0FoFie6RHa5j82iHnOKPhcqM5hArfKDYk3G5gc30lVmFiMm8PX8WKzDExygLqXZVnIzfB-EmcJWW_2fLiFEMpNC8KDTBVAiyds_n5kiGmW6F_QpLt11af3BDy71tg2fuqkyJE6pEHd1HsTHNCFQzWt7GevVB0HouJS099p6GphsH3kIhmAvHp5j267uYv49sndiUaLq7bL6GZnzv8dhzgQlucHvNaIZ6m6m6n4t43cjUxSrO0ZP9Crv9NBDJme0cA"; + final PublicKey publicKey = readPublicKey(MISMATCHED_RESOURCES_DIR + MISMATCHED_PUBLIC_KEY_PEM_FILENAME); + assertNotNull(publicKey); + new JWTVerifier(publicKey, "audience").verifySignature(token.split("\\."), Algorithm.RS256); + } + + /** + * Here we pass in a public key that correctly corresponds to the private key that was used to sign the JWT Token + */ + @Test + public void shouldVerifySignature() throws Exception { + final String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlFVTkVRelZCTXpoRk1FVTNRMFZGTURJNFFqYzROakJDTkRSQ1JFRkNSalkzUWpnMFJEVXlOZyJ9" + + "." + + "eyJyb2xlcyI6WyJST0xFX0FETUlOIl0sInVzZXJfaWQiOiJhdXRoMHw1NzcxMGU5ZDE0MWIwN2YyMmU3NDNhYzciLCJlbWFpbCI6ImFyY3NlbGRvbit0cm5AZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYWppbG9uMS5hdXRoMC5jb20vIiwic3ViIjoiYXV0aDB8NTc3MTBlOWQxNDFiMDdmMjJlNzQzYWM3IiwiYXVkIjoibm5ld1NobHBHVDFBbkZpY1ExUGlKWXdheENuejE4eUIiLCJleHAiOjE0Njc3MDk5OTMsImlhdCI6MTQ2NzY3Mzk5M30" + + "." + + "gQML78V8H6WN3MSN1QhrFG4AxNTdFChPBQxrnuqPF0iBvf35v_z9oDzTERaPBDWFHzWT17h0ADxpl7tCIo43k0FoFie6RHa5j82iHnOKPhcqM5hArfKDYk3G5gc30lVmFiMm8PX8WKzDExygLqXZVnIzfB-EmcJWW_2fLiFEMpNC8KDTBVAiyds_n5kiGmW6F_QpLt11af3BDy71tg2fuqkyJE6pEHd1HsTHNCFQzWt7GevVB0HouJS099p6GphsH3kIhmAvHp5j267uYv49sndiUaLq7bL6GZnzv8dhzgQlucHvNaIZ6m6m6n4t43cjUxSrO0ZP9Crv9NBDJme0cA"; + final PublicKey publicKey = readPublicKey(RESOURCES_DIR + PUBLIC_KEY_PEM_FILENAME); + assertNotNull(publicKey); + new JWTVerifier(publicKey, "audience").verifySignature(token.split("\\."), Algorithm.RS256); + } + + /** + * Here we modify the signature on an otherwise legal JWT Token and check verification using the correct Public Key fails + */ + @Test(expected = SignatureException.class) + public void shouldFailOnInvalidJWTTokenSignature() throws Exception { + final String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlFVTkVRelZCTXpoRk1FVTNRMFZGTURJNFFqYzROakJDTkRSQ1JFRkNSalkzUWpnMFJEVXlOZyJ9" + + "." + + "eyJyb2xlcyI6WyJST0xFX0FETUlOIl0sInVzZXJfaWQiOiJhdXRoMHw1NzcxMGU5ZDE0MWIwN2YyMmU3NDNhYzciLCJlbWFpbCI6ImFyY3NlbGRvbit0cm5AZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYWppbG9uMS5hdXRoMC5jb20vIiwic3ViIjoiYXV0aDB8NTc3MTBlOWQxNDFiMDdmMjJlNzQzYWM3IiwiYXVkIjoibm5ld1NobHBHVDFBbkZpY1ExUGlKWXdheENuejE4eUIiLCJleHAiOjE0Njc3MDk5OTMsImlhdCI6MTQ2NzY3Mzk5M30" + + "." + + "XXXXX8V8H6WN3MSN1QhrFG4AxNTdFChPBQxrnuqPF0iBvf35v_z9oDzTERaPBDWFHzWT17h0ADxpl7tCIo43k0FoFie6RHa5j82iHnOKPhcqM5hArfKDYk3G5gc30lVmFiMm8PX8WKzDExygLqXZVnIzfB-EmcJWW_2fLiFEMpNC8KDTBVAiyds_n5kiGmW6F_QpLt11af3BDy71tg2fuqkyJE6pEHd1HsTHNCFQzWt7GevVB0HouJS099p6GphsH3kIhmAvHp5j267uYv49sndiUaLq7bL6GZnzv8dhzgQlucHvNaIZ6m6m6n4t43cjUxSrO0ZP9Crv9NBDJme0cA"; + final PublicKey publicKey = readPublicKey(RESOURCES_DIR + PUBLIC_KEY_PEM_FILENAME); + assertNotNull(publicKey); + new JWTVerifier(publicKey, "audience").verifySignature(token.split("\\."), Algorithm.RS256); + } + + /** + * Here we modify the payload section on an otherwise legal JWT Token and check verification using the correct Public Key and + * unaltered JWT signature (which now doesn't match the payload) fails + */ + @Test(expected = SignatureException.class) + public void shouldFailOnInvalidJWTTokenPayload() throws Exception { + final String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlFVTkVRelZCTXpoRk1FVTNRMFZGTURJNFFqYzROakJDTkRSQ1JFRkNSalkzUWpnMFJEVXlOZyJ9" + + "." + + "XXXXX2xlcyI6WyJST0xFX0FETUlOIl0sInVzZXJfaWQiOiJhdXRoMHw1NzcxMGU5ZDE0MWIwN2YyMmU3NDNhYzciLCJlbWFpbCI6ImFyY3NlbGRvbit0cm5AZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYWppbG9uMS5hdXRoMC5jb20vIiwic3ViIjoiYXV0aDB8NTc3MTBlOWQxNDFiMDdmMjJlNzQzYWM3IiwiYXVkIjoibm5ld1NobHBHVDFBbkZpY1ExUGlKWXdheENuejE4eUIiLCJleHAiOjE0Njc3MDk5OTMsImlhdCI6MTQ2NzY3Mzk5M30" + + "." + + "gQML78V8H6WN3MSN1QhrFG4AxNTdFChPBQxrnuqPF0iBvf35v_z9oDzTERaPBDWFHzWT17h0ADxpl7tCIo43k0FoFie6RHa5j82iHnOKPhcqM5hArfKDYk3G5gc30lVmFiMm8PX8WKzDExygLqXZVnIzfB-EmcJWW_2fLiFEMpNC8KDTBVAiyds_n5kiGmW6F_QpLt11af3BDy71tg2fuqkyJE6pEHd1HsTHNCFQzWt7GevVB0HouJS099p6GphsH3kIhmAvHp5j267uYv49sndiUaLq7bL6GZnzv8dhzgQlucHvNaIZ6m6m6n4t43cjUxSrO0ZP9Crv9NBDJme0cA"; + final PublicKey publicKey = readPublicKey(RESOURCES_DIR + PUBLIC_KEY_PEM_FILENAME); + assertNotNull(publicKey); + new JWTVerifier(publicKey, "audience").verifySignature(token.split("\\."), Algorithm.RS256); + } + + @Test(expected = IllegalStateException.class) + public void shouldFailWithJwtThaHasTamperedAlgorithm() throws Exception { + final File file = new File(RESOURCES_DIR + PUBLIC_KEY_PEM_FILENAME); + final byte[] data = Files.readAllBytes(file.toPath()); + JWTSigner signer = new JWTSigner(data); + Map claims = new HashMap<>(); + claims.put("sub", "userid"); + JWTSigner.Options options = new JWTSigner.Options(); + options.setAlgorithm(Algorithm.HS256); + String jwt = signer.sign(claims, options); + new JWTVerifier(data).verify(jwt); + final PublicKey publicKey = readPublicKey(RESOURCES_DIR + PUBLIC_KEY_PEM_FILENAME); + new JWTVerifier(publicKey).verify(jwt); + } +} + diff --git a/src/test/java/com/auth0/jwt/JWTVerifierTest.java b/src/test/java/com/auth0/jwt/JWTVerifierTest.java new file mode 100644 index 00000000..e11fd5ae --- /dev/null +++ b/src/test/java/com/auth0/jwt/JWTVerifierTest.java @@ -0,0 +1,247 @@ +package com.auth0.jwt; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.commons.codec.binary.Base64; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.security.SignatureException; + +import static org.junit.Assert.assertEquals; + +/** + * General library JWTVerifier related unit tests + */ +public class JWTVerifierTest { + + private static final Base64 decoder = new Base64(true); + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + public void constructorShouldFailOnEmptySecret() { + expectedException.expect(IllegalArgumentException.class); + new JWTVerifier(""); + } + + @Test + public void shouldFailOn1Segments() throws Exception { + expectedException.expect(IllegalStateException.class); + signatureVerifier().verify("crypto"); + } + + @Test + public void shouldFailOn2Segments() throws Exception { + expectedException.expect(IllegalStateException.class); + signatureVerifier().verify("much.crypto"); + } + + @Test + public void shouldFailOn4Segments() throws Exception { + expectedException.expect(IllegalStateException.class); + signatureVerifier().verify("much.crypto.so.token"); + } + + @Test + public void shouldFailOnEmptyStringToken() throws Exception { + expectedException.expect(IllegalStateException.class); + signatureVerifier().verify(""); + } + + @Test + public void shouldFailOnNullToken() throws Exception { + expectedException.expect(IllegalStateException.class); + signatureVerifier().verify(null); + } + + @Test + public void shouldFailIfAlgorithmIsNotSetOnToken() throws Exception { + expectedException.expect(IllegalStateException.class); + signatureVerifier().getAlgorithm(JsonNodeFactory.instance.objectNode()); + } + + @Test + public void shouldFailIfAlgorithmIsNotSupported() throws Exception { + expectedException.expect(JWTAlgorithmException.class); + signatureVerifier().getAlgorithm(createSingletonJSONNode("alg", "doge-crypt")); + } + + @Test + public void shouldWorkIfAlgorithmIsSupported() throws Exception { + signatureVerifier().getAlgorithm(createSingletonJSONNode("alg", "HS256")); + } + + @Test + public void shouldFailOnInvalidSignature() throws Exception { + expectedException.expect(SignatureException.class); + final String jws = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9" + + "." + + "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt" + + "cGxlLmNvbS9pc19yb290Ijp0cnVlfQ" + + "." + + "suchsignature_plzvalidate_zomgtokens"; + String secret = "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"; + signatureVerifier(secret).verifySignature(jws.split("\\."), Algorithm.HS256); + } + + @Test + public void shouldVerifySignature() throws Exception { + final String jws = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9" + + "." + + "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt" + + "cGxlLmNvbS9pc19yb290Ijp0cnVlfQ" + + "." + + "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"; + byte[] secret = decoder.decode("AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"); + signatureVerifier(secret) + .verifySignature(jws.split("\\."), Algorithm.HS256); + } + + @Test + public void shouldFailWithJwtThaHasTamperedAlgorithm() throws Exception { + expectedException.expect(IllegalStateException.class); + String tamperedAlg = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.QRsN2SlYJ3EEn7P9dnZGsq9tjyv3giOWzZJzhy67zZs"; + byte[] secret = decoder.decode("AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"); + JWTVerifier verifier = new JWTVerifier(secret); + verifier.verify(tamperedAlg); + } + + @Test + public void shouldFailWhenExpired1SecondAgo() throws Exception { + expectedException.expect(JWTExpiredException.class); + signatureVerifier().verifyExpiration( + createSingletonJSONNode("exp", Long.toString(System.currentTimeMillis() / 1000L - 1L))); + } + + @Test + public void shouldVerifyExpiration() throws Exception { + signatureVerifier().verifyExpiration( + createSingletonJSONNode("exp", Long.toString(System.currentTimeMillis() / 1000L + 50L))); + } + + @Test + public void shouldVerifyIssuer() throws Exception { + issuerVerifier("very issuer") + .verifyIssuer(createSingletonJSONNode("iss", "very issuer")); + } + + @Test + public void shouldFailIssuer() throws Exception { + expectedException.expect(JWTIssuerException.class); + issuerVerifier("very issuer") + .verifyIssuer(createSingletonJSONNode("iss", "wow")); + } + + @Test + public void shouldVerifyIssuerWhenNotFoundInClaimsSet() throws Exception { + expectedException.expect(JWTIssuerException.class); + issuerVerifier("very issuer") + .verifyIssuer(JsonNodeFactory.instance.objectNode()); + } + + @Test + public void shouldVerifyAudience() throws Exception { + audienceVerifier("amaze audience") + .verifyAudience(createSingletonJSONNode("aud", "amaze audience")); + } + + @Test + public void shouldFailAudience() throws Exception { + expectedException.expect(JWTAudienceException.class); + audienceVerifier("amaze audience") + .verifyAudience(createSingletonJSONNode("aud", "wow")); + } + + @Test + public void shouldVerifyAudienceWhenNotFoundInClaimsSet() throws Exception { + expectedException.expect(JWTAudienceException.class); + audienceVerifier("amaze audience") + .verifyAudience(JsonNodeFactory.instance.objectNode()); + } + + @Test + public void shouldVerifyNullAudience() throws Exception { + signatureVerifier() + .verifyAudience(createSingletonJSONNode("aud", "wow")); + } + + @Test + public void shouldVerifyArrayAudience() throws Exception { + audienceVerifier("amaze audience") + .verifyAudience(createSingletonJSONNode("aud", + new ObjectMapper().readValue("[ \"foo\", \"amaze audience\" ]", ArrayNode.class))); + } + + @Test + public void shouldFailArrayAudience() throws Exception { + expectedException.expect(JWTAudienceException.class); + audienceVerifier("amaze audience") + .verifyAudience(createSingletonJSONNode("aud", + new ObjectMapper().readValue("[ \"foo\" ]", ArrayNode.class))); + } + + @Test + public void decodeAndParse() throws Exception { + final Base64 encoder = new Base64(true); + final String encodedJSON = new String(encoder.encode("{\"some\": \"json\", \"number\": 123}".getBytes())); + final JWTVerifier jwtVerifier = new JWTVerifier("secret", "audience"); + + final JsonNode decodedJSON = jwtVerifier.decodeAndParse(encodedJSON); + + assertEquals("json", decodedJSON.get("some").asText()); + assertEquals(null, decodedJSON.get("unexisting_property")); + assertEquals("123", decodedJSON.get("number").asText()); + } + + @Test + public void shouldVerifyAudienceFromToken() throws Exception { + expectedException.expect(JWTAudienceException.class); + JWTVerifier verifier = new JWTVerifier("I.O.U a secret", "samples-api", null); + verifier.verify("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.wLlz9xDltxqKHQC7BeauPi5Q4KQK4nDjlRqQPvKVLYk"); + } + + @Test + public void shouldVerifyIssuerFromToken() throws Exception { + expectedException.expect(JWTIssuerException.class); + JWTVerifier verifier = new JWTVerifier("I.O.U a secret", null, "samples.auth0.com"); + verifier.verify("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.wLlz9xDltxqKHQC7BeauPi5Q4KQK4nDjlRqQPvKVLYk"); + } + + private static JWTVerifier signatureVerifier() { + return new JWTVerifier("such secret"); + } + + private static JWTVerifier signatureVerifier(String secret) { + return new JWTVerifier(secret); + } + + private static JWTVerifier signatureVerifier(byte[] secret) { + return new JWTVerifier(secret); + } + + private static JWTVerifier issuerVerifier(String issuer) { + return new JWTVerifier("such secret", null, issuer); + } + + private static JWTVerifier audienceVerifier(String audience) { + return new JWTVerifier("such secret", audience); + } + + private static JsonNode createSingletonJSONNode(String key, String value) { + final ObjectNode jsonNodes = JsonNodeFactory.instance.objectNode(); + jsonNodes.put(key, value); + return jsonNodes; + } + + private static JsonNode createSingletonJSONNode(String key, JsonNode value) { + final ObjectNode jsonNodes = JsonNodeFactory.instance.objectNode(); + jsonNodes.put(key, value); + return jsonNodes; + } +} diff --git a/src/test/resources/auth0-pem/key.pem b/src/test/resources/auth0-pem/key.pem new file mode 100644 index 00000000..ce12c0ab --- /dev/null +++ b/src/test/resources/auth0-pem/key.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC6jCCAdKgAwIBAgIJRJ6BX2ejIsNmMA0GCSqGSIb3DQEBBQUAMBwxGjAYBgNV +BAMTEWFqaWxvbjEuYXV0aDAuY29tMB4XDTE2MDYxNDA0MjUxMloXDTMwMDIyMTA0 +MjUxMlowHDEaMBgGA1UEAxMRYWppbG9uMS5hdXRoMC5jb20wggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDWP321jJBlY521B3JqLC7RxFdsIQdDCViav2Z+ +dIOWyN09LxGrAy7pmV8GIHeu5lrmrfzUTfV+MzMyF+9UzRvq79qmMEWfyHBRNCOs +Ig3Sw0DHm3OoyCpdXBAF5F+IclPe2r2Bey7zlXkTUIZ+q4qLuDNKFiONyZdhkBUa +C1TsuplTv7DF2IHwnQpI4MyvRghy8QvxbqMZOj39mBrQYMLCWz2/PXIYRWiu3lxx +WSZS4GJya/2mTZtIatacz1t1W6dLeoS+OuTsPWl4qHsLj14EYPOevaw+8Nzh4eAa +tFRP2VOSm1nqDipuLIRnERSHEF4B6YYiG9EI8E3KrogoeGovAgMBAAGjLzAtMAwG +A1UdEwQFMAMBAf8wHQYDVR0OBBYEFK1l4Why6NUQ8g/7cdIbFtSbBYYjMA0GCSqG +SIb3DQEBBQUAA4IBAQAH+pc6gt5Hyjmqe6GxMRuDqd6/rX8c0EN0XmZ4wDfgbN7l +tN3iQ6i3R5I66GuohfxHFxxCYBnlQcZPFJ4/ZcfgtK42md0dx9Lt1se7E12B32mc +WISWs/dtrKLF6x+kNXJj0j05C0fMBuuxaqmTWJuJZ7LOJG3VS/jLR8t9TIdWexzL +xIDrf8MYjR9D+phLOJmf0ZZMbfxpCb4+txVs+yMAqhhiosXmjluLEIo2X5fejC92 +GVNY+Dm7S1ecWvYwzvx6R8VNqbAZ0QbVU/1dTPff57dfeMlpiXdGf6vc7OLgs8re +Om1fjmXhB9X6G+RYkaReI2VYkfU7ZRIQ/dI9HnYN +-----END CERTIFICATE----- \ No newline at end of file diff --git a/src/test/resources/test-pem/test-auth0.key b/src/test/resources/test-pem/test-auth0.key new file mode 100644 index 00000000..663a7374 --- /dev/null +++ b/src/test/resources/test-pem/test-auth0.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAxmJWY0eJcuV2uBtLnQ4004fuknbODo5xIyRhkYNkls5n9OrB +q4Lok6cjv7G2Q8mxAdlIUmzhTSyuNkrMMKZrPaMsAkNKE/aNpeWuSLXqcMs8T/8g +YCDcEmC5KYEJakNtKb3ZX2FKwT4yHHpsNomLDzJD5DyJKbRpNBm2no7ggIy7TQRJ +2H00mogQIQu8/fUANXVeGPshvLJU8MXEy/eiXkHJIT3DDA4VSr/C/tfP0tGJSNTM +874urc4zej+4INuTuMPtesZS47J0AsPxQuxengS4M76cVt5cH+Iqd1nKe5UqiSKv +LCXacPYg/T/Kdx0tBnwHIjKo/cbzZ+r+XynsCwIDAQABAoIBAFPWWwu5v6x+rJ1B +a8MDre93Eqty6cHdEJL5XQJRtMDGmcg3LYF94SwFBmaMg6pCIjvVx2qN+OjUaQso +sQIeUlPKEV8jcLrfBx2E4xJ3Tow8V1C3UMdPG7Hojler4H633/oz8RkN1Lm1vxep +5PFnTw0tAOQDcTPeulb6RuLbHqU0FEnf/jVOMhtPLcMAwJ3fkAJQ+ljFW2VKCQ83 +d+ci1p+NHY/dbGLSR4lK58mVghcRMO3zhe5scrbECHJMfT6fCb2TXdjaueFUGC6+ +fqUXvDj8HRfUilzTegNq8ZhwgMSw1HeX/PuiczSKc3aHYSsohMBugTErnkW+qF4Z +kE+kxgECgYEA/sm7umcyFuZME+RWYL8Gsp8agH1OGEgsmIiMi1z6RTlTmdR8fN18 +ItzXyW+363VZln/1b5wCaPdLIxgASxybLAaxnKAXfmL7QvyVAaMwxj7N0ogvMQoN +x2VuSGZSam2+LFVIMWHq1C+3fvVnCDLm6oHvIMK/zvEsPBBtz+L6rlECgYEAx1Pr +KogaGHCi1XgsrNv9aFaayRvmhzZbmiigF0iWKAd3KKww94BdyyGSVfMfyL23LAbM +QDCrDNGpYAnpNZo/cL+OcGPYzlPsWDBrJub1HOA/H3WQlP4oEcfdbmJZhIkEwTGF +HaCHynEu4ekiCrWz9+XVNCquTyqnmaVDEzAfEZsCgYA8jQbfUt0Vkh+sboyUq3FV +C/jJZn4jyStICNOV3z/fKbOTkGsRZbW1t1RVHAbSn23uFXTn1GTCO1sQ+QhA0YiT +Gvgk5+sNb0qVbd+fpv/VbWGO0iyc8+24YIOoEyEtB+21LYNdsQ6U5M4wDvQwf6Bf +RQfmekIJVUmU8LaYPDIlMQKBgDSRiT/aTSeM7STnYMDl89sEnCXV2eJnD5mEhVQe +rJs5/M8ZOoDLtfDQlctdJ1DF1/0gfdWgADyNPuI5OuwMFhciLequKoufzoEjo97K +onJPIdamJs9kiCTIVTm7bmhpyns5GCZMJAPb/cVOus+gRCpozuXHK9ltIm5/C0WQ +N2FpAoGBAOss6RN2krieqbn1mG8e2v5mMUd0CJkiJu2y5MnF3dYHXSQ3/ePAh/Yg +JOthpgYgBh+mV0DLqJhx/1DLS/xiqcoHDlndQDmYbtvvY7RlMo00+nGzkRVOfrqy +hC+1KsYHGPbSQixNQXtvFbAAVMSo+RRBkVGINYGDFnlQUpkppYRk +-----END RSA PRIVATE KEY----- diff --git a/src/test/resources/test-pem/test-auth0.pem b/src/test/resources/test-pem/test-auth0.pem new file mode 100644 index 00000000..47e8e146 --- /dev/null +++ b/src/test/resources/test-pem/test-auth0.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIJALr9HwgrQ7GeMA0GCSqGSIb3DQEBBQUAMGIxGDAWBgNV +BAMTD2F1dGgwLmF1dGgwLmNvbTESMBAGA1UEChMJQXV0aDAgTExDMQswCQYDVQQG +EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDAeFw0x +MjEyMjkxNTMwNDdaFw0xMzAxMjgxNTMwNDdaMGIxGDAWBgNVBAMTD2F1dGgwLmF1 +dGgwLmNvbTESMBAGA1UEChMJQXV0aDAgTExDMQswCQYDVQQGEwJVUzETMBEGA1UE +CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAMZiVmNHiXLldrgbS50ONNOH7pJ2zg6OcSMkYZGDZJbO +Z/TqwauC6JOnI7+xtkPJsQHZSFJs4U0srjZKzDCmaz2jLAJDShP2jaXlrki16nDL +PE//IGAg3BJguSmBCWpDbSm92V9hSsE+Mhx6bDaJiw8yQ+Q8iSm0aTQZtp6O4ICM +u00ESdh9NJqIECELvP31ADV1Xhj7IbyyVPDFxMv3ol5BySE9wwwOFUq/wv7Xz9LR +iUjUzPO+Lq3OM3o/uCDbk7jD7XrGUuOydALD8ULsXp4EuDO+nFbeXB/iKndZynuV +Kokirywl2nD2IP0/yncdLQZ8ByIyqP3G82fq/l8p7AsCAwEAAaOBxzCBxDAdBgNV +HQ4EFgQUHI2rUXeBjTv1zAllaPGrHFcEK0YwgZQGA1UdIwSBjDCBiYAUHI2rUXeB +jTv1zAllaPGrHFcEK0ahZqRkMGIxGDAWBgNVBAMTD2F1dGgwLmF1dGgwLmNvbTES +MBAGA1UEChMJQXV0aDAgTExDMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu +Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZIIJALr9HwgrQ7GeMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAFrXIhCy4T4eGrikb0R2wHv/uS548r3pZyBV0CDb +cRwAtbnpJMvkGFqKVp4pmyoIDSVNK/j+sLEshB20XftezHZyRJbCUbtKvXQ6Fsxo +eZMlN0ITYKTaoBZKhUxxj90otAhNC58qwGUPqt2LewJhHyLucKkGJ1mQ3b5xKZ53 +2ToufouH9VLhig3H1KnxWo/zMD6Ke8cCk6qO9htuhI06s3GQGS1QWQtAmm17C6Tf +KgDwQFZwhqHUUZnwKRH8gU6OgZsvhgV1B7H5mjZcu57KMiDBekU9MEY0DCVTN3Wk +mcTII668zLsJrkNX6PEfck1AMBbVE6pEUKcWwq3uaLvlAUo= +-----END CERTIFICATE-----