├── .github ├── dependabot.yml ├── project.yml └── workflows │ ├── build.yml │ ├── prepare-release.yml │ ├── publish-tck.yml │ ├── release.yml │ ├── review-release.yml │ └── update-milestone.yml ├── .gitignore ├── CODEOWNERS ├── LICENSE ├── README.adoc ├── coverage └── pom.xml ├── doc ├── antora-playbook.yml ├── antora.yml └── modules │ └── ROOT │ ├── nav.adoc │ └── pages │ ├── attributes.adoc │ ├── configuration.adoc │ ├── generate-jwt.adoc │ └── index.adoc ├── implementation ├── common │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── smallrye │ │ │ └── jwt │ │ │ ├── JsonProviderHolder.java │ │ │ ├── algorithm │ │ │ ├── ContentEncryptionAlgorithm.java │ │ │ ├── KeyEncryptionAlgorithm.java │ │ │ └── SignatureAlgorithm.java │ │ │ └── util │ │ │ ├── JWTUtilLogging.java │ │ │ ├── JWTUtilMessages.java │ │ │ ├── KeyUtils.java │ │ │ └── ResourceUtils.java │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── smallrye │ │ │ └── jwt │ │ │ └── util │ │ │ ├── GenerateSecretFromKeyEncryptionAlgoTest.java │ │ │ ├── GenerateSecretFromSignatureAlgoTest.java │ │ │ └── KeyUtilsTest.java │ │ └── resources │ │ ├── EDDSA-ED25519-private-key.pem │ │ ├── EDDSA-ED25519-public-key.pem │ │ ├── EDDSA-ED448-private-key.pem │ │ ├── EDDSA-ED448-public-key.pem │ │ ├── ES256-private-key.pem │ │ ├── ES256-public-key.pem │ │ ├── RS256-2048bit-private-key.pem │ │ └── RS256-2048bit-public-key.pem ├── jwt-auth │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── smallrye │ │ │ └── jwt │ │ │ ├── JWTLogging.java │ │ │ ├── JsonUtils.java │ │ │ ├── KeyFormat.java │ │ │ ├── KeyProvider.java │ │ │ ├── SmallryeJwtUtils.java │ │ │ ├── auth │ │ │ ├── AbstractBearerTokenExtractor.java │ │ │ ├── AuthLogging.java │ │ │ ├── cdi │ │ │ │ ├── CDILogging.java │ │ │ │ ├── CDIMessages.java │ │ │ │ ├── ClaimValueProducer.java │ │ │ │ ├── ClaimValueWrapper.java │ │ │ │ ├── CommonJwtProducer.java │ │ │ │ ├── JWTCallerPrincipalFactoryProducer.java │ │ │ │ ├── JsonValueProducer.java │ │ │ │ ├── NullJsonWebToken.java │ │ │ │ ├── OptionalClaimTypeProducer.java │ │ │ │ ├── PrincipalProducer.java │ │ │ │ ├── ProviderExtensionSupport.java │ │ │ │ └── RawClaimTypeProducer.java │ │ │ └── principal │ │ │ │ ├── AbstractKeyLocationResolver.java │ │ │ │ ├── AwsAlbKeyConfigurationValidator.java │ │ │ │ ├── AwsAlbKeyResolver.java │ │ │ │ ├── AwsAlbKeyResolverLogging.java │ │ │ │ ├── AwsAlbKeyResolverMessages.java │ │ │ │ ├── DecryptionKeyLocationResolver.java │ │ │ │ ├── DefaultJWTCallerPrincipal.java │ │ │ │ ├── DefaultJWTCallerPrincipalFactory.java │ │ │ │ ├── DefaultJWTParser.java │ │ │ │ ├── DefaultJWTTokenParser.java │ │ │ │ ├── JWTAuthContextInfo.java │ │ │ │ ├── JWTCallerPrincipal.java │ │ │ │ ├── JWTCallerPrincipalFactory.java │ │ │ │ ├── JWTParser.java │ │ │ │ ├── KeyLocationResolver.java │ │ │ │ ├── ParseException.java │ │ │ │ ├── PrincipalLogging.java │ │ │ │ ├── PrincipalMessages.java │ │ │ │ ├── PrincipalUtils.java │ │ │ │ ├── UnmatchedTokenKidException.java │ │ │ │ └── X509KeyLocationResolver.java │ │ │ └── config │ │ │ ├── ConfigLogging.java │ │ │ ├── ConfigMessages.java │ │ │ └── JWTAuthContextInfoProvider.java │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── smallrye │ │ │ └── jwt │ │ │ ├── JsonUtilsTests.java │ │ │ └── auth │ │ │ ├── AbstractBearerTokenExtractorTest.java │ │ │ ├── cdi │ │ │ ├── ClaimInjectionTest.java │ │ │ ├── ClaimQualifier.java │ │ │ ├── ClaimValueProducerIT.java │ │ │ ├── CustomJWTCallerPrincipalFactoryTest.java │ │ │ ├── JWTCallerPrincipalFactoryProducerTest.java │ │ │ ├── JsonValueProducerTest.java │ │ │ └── PrincipalProducerIT.java │ │ │ └── principal │ │ │ ├── AwsAlbKeyConfigurationValidatorTest.java │ │ │ ├── AwsAlbKeyResolverTest.java │ │ │ ├── DecryptionKeyLocationResolverTest.java │ │ │ ├── KeyLocationResolverTest.java │ │ │ ├── PrincipalUtilsTest.java │ │ │ └── X509KeyLocationResolverTest.java │ │ └── resources │ │ ├── META-INF │ │ └── beans.xml │ │ ├── decryptPrivateKey.jwk │ │ ├── privateKey.jwk │ │ ├── privateKey.pem │ │ ├── publicCrt.pem │ │ ├── publicKey.jwk │ │ ├── publicKey.pem │ │ └── token-claims.json ├── jwt-build │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── smallrye │ │ │ └── jwt │ │ │ └── build │ │ │ ├── Jwt.java │ │ │ ├── JwtClaimsBuilder.java │ │ │ ├── JwtEncryption.java │ │ │ ├── JwtEncryptionBuilder.java │ │ │ ├── JwtEncryptionException.java │ │ │ ├── JwtException.java │ │ │ ├── JwtSignature.java │ │ │ ├── JwtSignatureBuilder.java │ │ │ ├── JwtSignatureException.java │ │ │ ├── impl │ │ │ ├── ImplLogging.java │ │ │ ├── ImplMessages.java │ │ │ ├── JwtBuildUtils.java │ │ │ ├── JwtClaimsBuilderImpl.java │ │ │ ├── JwtEncryptionImpl.java │ │ │ ├── JwtProviderImpl.java │ │ │ └── JwtSignatureImpl.java │ │ │ └── spi │ │ │ ├── JwtProvider.java │ │ │ └── SpiMessages.java │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── smallrye │ │ │ └── jwt │ │ │ └── build │ │ │ ├── JwtBuildConfigSource.java │ │ │ ├── JwtClaimShortcutsTest.java │ │ │ ├── JwtClaimTypeVerifierTest.java │ │ │ ├── JwtEncryptJwkTest.java │ │ │ ├── JwtEncryptTest.java │ │ │ ├── JwtProviderTest.java │ │ │ ├── JwtSignEncryptTest.java │ │ │ ├── JwtSignJwkTest.java │ │ │ ├── JwtSignPS256Test.java │ │ │ └── JwtSignTest.java │ │ └── resources │ │ ├── META-INF │ │ └── services │ │ │ └── org.eclipse.microprofile.config.spi.ConfigSource │ │ ├── certificate.pem │ │ ├── customClaim.json │ │ ├── ecPrivateKey.pem │ │ ├── ecPublicKey.pem │ │ ├── edEcPrivateKey.jwk │ │ ├── edEcPublicKey.jwk │ │ ├── keystore.p12 │ │ ├── privateEncryptionKeys.jwks │ │ ├── privateKey.jwk │ │ ├── privateKey.pem │ │ ├── privateKey2.pem │ │ ├── privateKeyA128KW.jwk │ │ ├── privateKeyHS512.jwk │ │ ├── privateSigningKeys.jwks │ │ ├── publicKey.jwk │ │ ├── publicKey.pem │ │ └── token.json ├── jwt-cdi-extension │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── io │ │ └── smallrye │ │ └── jwt │ │ └── auth │ │ └── cdi │ │ └── SmallRyeJWTAuthCDIExtension.java ├── jwt-http-mechanism │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── io │ │ └── smallrye │ │ └── jwt │ │ └── auth │ │ └── mechanism │ │ ├── JWTHttpAuthenticationMechanism.java │ │ └── MechanismLogging.java ├── jwt-jaxrs │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── io │ │ └── smallrye │ │ └── jwt │ │ └── auth │ │ └── jaxrs │ │ ├── DenyAllFilter.java │ │ ├── JAXRSLogging.java │ │ ├── JAXRSMessages.java │ │ ├── JWTAuthenticationFilter.java │ │ ├── JWTAuthorizationFilterRegistrar.java │ │ ├── JWTSecurityContext.java │ │ ├── RolesAllowedFilter.java │ │ └── SmallRyeJWTAuthJaxRsFeature.java ├── pom.xml └── src │ └── test │ └── java │ └── io │ └── smallrye │ └── jwt │ └── config │ └── JWTAuthContextInfoProviderTest.java ├── message-ranges.txt ├── pom.xml ├── release └── pom.xml └── testsuite ├── basic ├── pom.xml └── src │ └── test │ ├── java │ └── io │ │ └── smallrye │ │ └── jwt │ │ ├── TestJsonWebToken.java │ │ ├── TestTokenClaimTypes.java │ │ ├── TestTokenRequireSub.java │ │ ├── TestTokenRequiredClaims.java │ │ ├── TestTokenWithGroupsPath.java │ │ ├── TestTokenWithGroupsPath2.java │ │ ├── TestTokenWithGroupsString.java │ │ ├── TestTokenWithSubPath.java │ │ ├── TestTokenWithoutGroupsClaim.java │ │ ├── auth │ │ └── principal │ │ │ ├── AwsAlbTokenTest.java │ │ │ ├── DefaultJWTCallerPrincipalTest.java │ │ │ ├── DefaultJWTParserTest.java │ │ │ ├── DefaultJWTTokenParserTest.java │ │ │ ├── KeyLocationResolverKeyContentTest.java │ │ │ ├── KeyLocationResolverTest.java │ │ │ └── KeyStoreLocationTest.java │ │ └── config │ │ └── JWTAuthContextInfoProviderTest.java │ └── resources │ ├── Token1.json │ ├── TokenGroupsPath.json │ ├── TokenGroupsPath2.json │ ├── TokenGroupsString.json │ ├── TokenNoGroups.json │ ├── TokenSubPath.json │ ├── certificate.pem │ ├── decryptPrivateKey.jwk │ ├── ecPrivateKey.jwk │ ├── ecPrivateKey.pem │ ├── ecPublicKey.pem │ ├── edEcPrivateKey.jwk │ ├── edEcPublicKey.jwk │ ├── encryptPublicKey.jwk │ ├── privateKey2.pem │ ├── publicKey.jwk │ ├── publicKey.pem │ ├── publicKeySet.jwk │ ├── publicSingleKeySetWithoutKid.jwk │ ├── rs256PrivateKey.jwk │ ├── secretKey.jwk │ ├── server-keystore.jks │ └── signatureJwkSet.jwk ├── pom.xml └── tck ├── pom.xml └── src └── test ├── java └── io │ └── smallrye │ └── jwt │ └── tck │ ├── OptionalAwareSmallRyeJWTAuthCDIExtension.java │ ├── SmallRyeJWTArchiveProcessor.java │ ├── SmallRyeJWTAuthJaxRsFeature.java │ ├── SmallRyeJWTExtension.java │ └── TestApplication.java └── resources ├── META-INF └── services │ └── org.jboss.arquillian.core.spi.LoadableExtension ├── arquillian.xml ├── jboss-web.xml ├── jetty-web.xml └── microprofile-config-local.properties /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: maven 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | ignore: 9 | - dependency-name: jakarta.servlet:jakarta.servlet-api 10 | versions: 11 | - ">= 5.a, < 6" 12 | -------------------------------------------------------------------------------- /.github/project.yml: -------------------------------------------------------------------------------- 1 | name: SmallRye JWT 2 | release: 3 | current-version: 4.6.2 4 | next-version: 4.6.3-SNAPSHOT 5 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: SmallRye Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths-ignore: 8 | - '.gitignore' 9 | - 'CODEOWNERS' 10 | - 'LICENSE' 11 | - 'NOTICE' 12 | - 'README*' 13 | pull_request: 14 | paths-ignore: 15 | - '.gitignore' 16 | - 'CODEOWNERS' 17 | - 'LICENSE' 18 | - 'NOTICE' 19 | - 'README*' 20 | 21 | jobs: 22 | build: 23 | runs-on: ubuntu-latest 24 | strategy: 25 | matrix: 26 | java: [11, 17, 21] 27 | name: build with jdk ${{matrix.java}} 28 | 29 | steps: 30 | - uses: actions/checkout@v4 31 | name: checkout 32 | 33 | - uses: actions/setup-java@v4 34 | name: set up jdk ${{matrix.java}} 35 | with: 36 | distribution: 'temurin' 37 | java-version: ${{matrix.java}} 38 | cache: 'maven' 39 | cache-dependency-path: '**/pom.xml' 40 | 41 | - name: build with maven 42 | run: mvn -B formatter:validate verify --file pom.xml 43 | 44 | - uses: actions/upload-artifact@v4 45 | name: tck-report 46 | with: 47 | name: tck-report-java-${{matrix.java}} 48 | path: testsuite/tck/target/surefire-reports 49 | 50 | build-windows: 51 | runs-on: windows-latest 52 | strategy: 53 | matrix: 54 | java: [11, 17, 21] 55 | name: build with jdk ${{matrix.java}} windows 56 | 57 | steps: 58 | - uses: actions/checkout@v4 59 | name: checkout 60 | 61 | - uses: actions/setup-java@v4 62 | name: set up jdk ${{matrix.java}} 63 | with: 64 | distribution: 'temurin' 65 | java-version: ${{matrix.java}} 66 | cache: 'maven' 67 | cache-dependency-path: '**/pom.xml' 68 | 69 | - name: build with maven 70 | run: mvn -B formatter:validate verify --file pom.xml 71 | 72 | quality: 73 | needs: [build] 74 | if: github.event_name == 'push' && github.repository_owner == 'smallrye' 75 | runs-on: ubuntu-latest 76 | name: quality 77 | 78 | steps: 79 | - uses: actions/checkout@v4 80 | with: 81 | fetch-depth: 0 82 | 83 | - uses: actions/setup-java@v4 84 | with: 85 | distribution: 'temurin' 86 | java-version: 11 87 | cache: 'maven' 88 | cache-dependency-path: '**/pom.xml' 89 | 90 | - name: build with docs and coverage 91 | run: mvn verify -Pcoverage javadoc:javadoc 92 | 93 | - uses: actions/setup-java@v4 94 | with: 95 | distribution: 'temurin' 96 | java-version: 17 97 | 98 | - name: sonar 99 | env: 100 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 101 | SONAR_TOKEN: ${{secrets.SONAR_TOKEN}} 102 | run: mvn sonar:sonar -Psonar -Dsonar.token=${{secrets.SONAR_TOKEN}} 103 | -------------------------------------------------------------------------------- /.github/workflows/prepare-release.yml: -------------------------------------------------------------------------------- 1 | name: SmallRye Prepare Release 2 | 3 | on: 4 | pull_request: 5 | types: [ closed ] 6 | paths: 7 | - '.github/project.yml' 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | prepare-release: 15 | name: Prepare Release 16 | if: ${{ github.event.pull_request.merged == true}} 17 | uses: smallrye/.github/.github/workflows/prepare-release.yml@main 18 | secrets: inherit 19 | -------------------------------------------------------------------------------- /.github/workflows/publish-tck.yml: -------------------------------------------------------------------------------- 1 | name: Publish TCK 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | version: 7 | required: true 8 | description: Tag version to perform release 9 | type: string 10 | 11 | jobs: 12 | publish-tck: 13 | name: Publish TCK 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | java: [ 11, 17, 21 ] 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | name: checkout ${{inputs.version}} 22 | with: 23 | ref: ${{inputs.version}} 24 | 25 | - uses: actions/setup-java@v4 26 | name: set up jdk ${{matrix.java}} 27 | with: 28 | distribution: 'temurin' 29 | java-version: ${{matrix.java}} 30 | cache: 'maven' 31 | cache-dependency-path: '**/pom.xml' 32 | 33 | - name: generate tck report for jdk ${{matrix.java}} 34 | env: 35 | GH_TOKEN: ${{secrets.GITHUB_TOKEN}} 36 | ZIP_NAME: smallrye-jwt-${{inputs.version}}-tck-results-java-${{matrix.java}}.zip 37 | run: | 38 | mvn -B formatter:validate verify --file pom.xml 39 | cd testsuite/tck/target 40 | zip -r $ZIP_NAME surefire-reports/ 41 | gh release upload ${{inputs.version}} $ZIP_NAME 42 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: SmallRye Release 2 | run-name: Perform ${{github.event.inputs.tag || github.ref_name}} Release 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | workflow_dispatch: 8 | inputs: 9 | tag: 10 | description: 'Tag to release' 11 | required: true 12 | 13 | permissions: 14 | attestations: write 15 | id-token: write 16 | # Needed for the publish-* workflows 17 | contents: write 18 | 19 | concurrency: 20 | group: ${{ github.workflow }}-${{ github.ref }} 21 | cancel-in-progress: true 22 | 23 | jobs: 24 | perform-release: 25 | name: Perform Release 26 | uses: smallrye/.github/.github/workflows/perform-release.yml@main 27 | secrets: inherit 28 | with: 29 | version: ${{github.event.inputs.tag || github.ref_name}} 30 | 31 | publish-tck: 32 | name: Publish TCK Report 33 | uses: ./.github/workflows/publish-tck.yml 34 | secrets: inherit 35 | with: 36 | version: ${{github.event.inputs.tag || github.ref_name}} 37 | -------------------------------------------------------------------------------- /.github/workflows/review-release.yml: -------------------------------------------------------------------------------- 1 | name: SmallRye Review Release 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - '.github/project.yml' 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | name: pre release 12 | 13 | steps: 14 | - uses: radcortez/project-metadata-action@main 15 | name: retrieve project metadata 16 | id: metadata 17 | with: 18 | github-token: ${{secrets.GITHUB_TOKEN}} 19 | metadata-file-path: '.github/project.yml' 20 | 21 | - name: Validate version 22 | if: contains(steps.metadata.outputs.current-version, 'SNAPSHOT') 23 | run: | 24 | echo '::error::Cannot release a SNAPSHOT version.' 25 | exit 1 26 | 27 | - uses: radcortez/milestone-review-action@main 28 | name: milestone review 29 | with: 30 | github-token: ${{secrets.GITHUB_TOKEN}} 31 | milestone-title: ${{steps.metadata.outputs.current-version}} 32 | -------------------------------------------------------------------------------- /.github/workflows/update-milestone.yml: -------------------------------------------------------------------------------- 1 | name: Update Milestone 2 | 3 | on: 4 | pull_request_target: 5 | types: [closed] 6 | 7 | jobs: 8 | update: 9 | runs-on: ubuntu-latest 10 | name: update-milestone 11 | if: ${{github.event.pull_request.merged == true}} 12 | 13 | steps: 14 | - uses: radcortez/milestone-set-action@main 15 | name: milestone set 16 | with: 17 | github-token: ${{secrets.GITHUB_TOKEN}} 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore .svn metadata files 2 | .svn 3 | # ignore Maven generated target folders 4 | ~ 5 | target 6 | # ignore downloaded maven 7 | /tools/maven 8 | /tools/maven.zip 9 | # ignore eclipse files 10 | .project 11 | .classpath 12 | .settings 13 | .metadata 14 | .checkstyle 15 | # ignore m2e annotation processing files 16 | .factorypath 17 | # ignore IDEA files 18 | *.iml 19 | *.ipr 20 | *.iws 21 | .idea 22 | # ignore NetBeans files 23 | nbactions.xml 24 | nb-configuration.xml 25 | catalog.xml 26 | # 27 | maven-ant-tasks.jar 28 | test-output 29 | transaction.log 30 | # vim files 31 | *.swp 32 | /.gitk-tmp.* 33 | atlassian-ide-plugin.xml 34 | # temp files 35 | *~ 36 | # maven versions plugin 37 | pom.xml.versionsBackup 38 | # hprof dumps 39 | /*.hprof 40 | # ignore 'randomly' strewn around logs 41 | server.log 42 | # ignore java crashes 43 | hs_err_pid*.log 44 | # H2 databases produced by tests 45 | *.h2.db 46 | # JBoss transaction generated files 47 | PutObjectStoreDirHere 48 | # ignore mvn-rpmbuild repo 49 | /.m2 50 | # ignore eap repo 51 | local-repo-eap 52 | 53 | #These keep hanging around 54 | arquillian/*/server.log* 55 | client/shade/dependency-reduced-pom.xml 56 | 57 | #OS X stuff 58 | .DS_Store 59 | 60 | # Zanata files 61 | **/.zanata-cache/ 62 | 63 | # Antora 64 | doc/build 65 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | .github @smallrye/jwt 2 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | :microprofile-jwt: https://github.com/eclipse/microprofile-jwt-auth/ 2 | :mp-jwt-name: Eclipse MicroProfile JWT RBAC 3 | :ci: https://github.com/smallrye/smallrye-jwt/actions?query=workflow%3A%22SmallRye+Build%22 4 | :sonar: https://sonarcloud.io/dashboard?id=io.smallrye%3Asmallrye-jwt 5 | 6 | image:https://github.com/smallrye/smallrye-jwt/workflows/SmallRye%20Build/badge.svg?branch=main[link={ci}] 7 | image:https://sonarcloud.io/api/project_badges/measure?project=io.smallrye%3Asmallrye-jwt&metric=alert_status["Quality Gate Status", link={sonar}] 8 | image:https://img.shields.io/github/license/smallrye/smallrye-jwt.svg["License", link="http://www.apache.org/licenses/LICENSE-2.0"] 9 | image:https://img.shields.io/maven-central/v/io.smallrye/smallrye-jwt?color=green[] 10 | 11 | = SmallRye JWT 12 | 13 | SmallRye JWT is a library for implementing the {microprofile-jwt}[{mp-jwt-name}]. Currently it is focused on supporting the MP-JWT 2.1 spec. It deals with the decryption and/or signature verification of the JWT token and parsing it into a JsonWebToken implementation. 14 | 15 | == Instructions 16 | 17 | Compile and install this project: 18 | 19 | [source,bash] 20 | ---- 21 | mvn clean install 22 | ---- 23 | 24 | === Project structure 25 | 26 | * link:implementation[] - Implementation of the {mp-jwt-name} library 27 | ** link:implementation/common[] - Common utility classes. 28 | ** link:implementation/jwt-auth[] - Core library implementation. 29 | ** link:implementation/jwt-cdi[] - Support for registering the implementation as CDI extension. 30 | ** link:implementation/jwt-http-mechanism[] - Support for registering the implementation as HTTP Authentication Mechanism. 31 | ** link:implementation/jwt-jaxrs[] - Support for registering the implementation as JAX-RS feature and filters. 32 | ** link:implementation/jwt-build[] - Support for generating JWT tokens - this module is not related to MP JWT 1.2. 33 | * link:testsuite[] - Test suites 34 | ** link:testsuite/basic[] Test suite with basic test cases. 35 | ** link:testsuite/tck[] Test suite to run the implementation against the {mp-jwt-name} TCK. 36 | * link:doc[] - Project documentation. 37 | 38 | === Contributing 39 | 40 | Please refer to our Wiki for the https://github.com/smallrye/smallrye-parent/wiki[Contribution Guidelines]. 41 | 42 | === Links 43 | 44 | * http://github.com/smallrye/smallrye-jwt/[Project Homepage] 45 | * {microprofile-jwt}[{mp-jwt-name}] 46 | * https://smallrye.io/docs/smallrye-jwt/index.html[Documentation] 47 | -------------------------------------------------------------------------------- /coverage/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 4.0.0 19 | 20 | 21 | io.smallrye 22 | smallrye-jwt-parent 23 | 4.6.1-SNAPSHOT 24 | 25 | 26 | smallrye-jwt-coverage 27 | pom 28 | 29 | SmallRye: MicroProfile JWT - Coverage 30 | 31 | 32 | 33 | io.smallrye 34 | smallrye-jwt 35 | 36 | 37 | io.smallrye 38 | smallrye-jwt-common 39 | 40 | 41 | io.smallrye 42 | smallrye-jwt-build 43 | 44 | 45 | io.smallrye 46 | smallrye-jwt-testsuite-basic 47 | ${project.version} 48 | 49 | 50 | io.smallrye 51 | smallrye-jwt-tck 52 | ${project.version} 53 | 54 | 55 | 56 | 57 | 58 | 59 | org.jacoco 60 | jacoco-maven-plugin 61 | 62 | 63 | aggregate-report 64 | verify 65 | 66 | report-aggregate 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /doc/antora-playbook.yml: -------------------------------------------------------------------------------- 1 | # partial playbook just for this project to be able to compile documentation without pushing it to GitHub 2 | # usage: antora generate antora-playbook.yml 3 | site: 4 | title: SmallRye JWT only documentation 5 | start_page: smallrye-jwt::index.adoc 6 | content: 7 | sources: 8 | - url: .. 9 | start_path: doc 10 | branches: HEAD 11 | ui: 12 | bundle: 13 | url: https://github.com/smallrye/smallrye-antora-ui/blob/main/build/ui-bundle.zip?raw=true 14 | snapshot: true 15 | -------------------------------------------------------------------------------- /doc/antora.yml: -------------------------------------------------------------------------------- 1 | name: smallrye-jwt 2 | title: SmallRye JWT 3 | version: master 4 | nav: 5 | - modules/ROOT/nav.adoc 6 | -------------------------------------------------------------------------------- /doc/modules/ROOT/nav.adoc: -------------------------------------------------------------------------------- 1 | * xref:index.adoc[Index] 2 | * xref:configuration.adoc[Configuration] 3 | * xref:generate-jwt.adoc[Generate JWT Tokens] 4 | -------------------------------------------------------------------------------- /doc/modules/ROOT/pages/attributes.adoc: -------------------------------------------------------------------------------- 1 | :version: 2.1.2-SNAPSHOT 2 | -------------------------------------------------------------------------------- /doc/modules/ROOT/pages/index.adoc: -------------------------------------------------------------------------------- 1 | [[index]] 2 | = SmallRye JWT Documentation 3 | 4 | SmallRye JWT is an implementation of https://github.com/eclipse/microprofile-jwt-auth/[Eclipse MicroProfile JWT RBAC]. 5 | Currently it is focused on supporting the MP-JWT 1.1 spec, and primarily deals with the parsing of the JWT string into 6 | a JsonWebToken implementation. 7 | 8 | In the future, when MP-JWT 2.0 can build on the JSR-375 security APIs, there should be more support for defining the CDI extension and security layer integration. 9 | 10 | == Runtimes 11 | 12 | Runtimes that currently use it as their JWT RBAC implementation include: 13 | 14 | * https://quarkus.io/[Quarkus] 15 | * https://wildfly.org/[WildFly] 16 | * https://thorntail.io/[Thorntail] 17 | 18 | == References 19 | 20 | * https://github.com/eclipse/microprofile-jwt-auth/[MP JWT] 21 | * https://tools.ietf.org/html/rfc7519[JSON Web Token] 22 | * https://tools.ietf.org/html/rfc7515[JSON Web Signature] 23 | * https://tools.ietf.org/html/rfc7516[JSON Web Encryption] 24 | * https://tools.ietf.org/html/rfc7518[JSON Web Algorithms] 25 | -------------------------------------------------------------------------------- /implementation/common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 4.0.0 21 | 22 | 23 | io.smallrye 24 | smallrye-jwt-implementation-parent 25 | 4.6.3-SNAPSHOT 26 | 27 | 28 | smallrye-jwt-common 29 | 30 | SmallRye: MicroProfile JWT Implementation Common 31 | 32 | 33 | 34 | jakarta.json 35 | jakarta.json-api 36 | provided 37 | 38 | 39 | org.bitbucket.b_c 40 | jose4j 41 | 42 | 43 | org.jboss.logging 44 | jboss-logging 45 | 46 | 47 | org.jboss.logging 48 | jboss-logging-annotations 49 | 50 | 51 | org.jboss.logging 52 | jboss-logging-processor 53 | 54 | 55 | 56 | 57 | junit 58 | junit 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /implementation/common/src/main/java/io/smallrye/jwt/JsonProviderHolder.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt; 2 | 3 | import jakarta.json.spi.JsonProvider; 4 | 5 | public final class JsonProviderHolder { 6 | 7 | private static final JsonProvider JSON_PROVIDER = JsonProvider.provider(); 8 | 9 | private JsonProviderHolder() { 10 | } 11 | 12 | public static JsonProvider jsonProvider() { 13 | return JSON_PROVIDER; 14 | } 15 | } -------------------------------------------------------------------------------- /implementation/common/src/main/java/io/smallrye/jwt/algorithm/ContentEncryptionAlgorithm.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.algorithm; 2 | 3 | /** 4 | * * JWT JSON Web Content Encryption Algorithms. 5 | * 6 | * @see https://tools.ietf.org/html/rfc7518#section-5 7 | */ 8 | public enum ContentEncryptionAlgorithm { 9 | A128GCM("A128GCM"), 10 | A192GCM("A192GCM"), 11 | A256GCM("A256GCM"), 12 | A128CBC_HS256("A128CBC-HS256"), 13 | A192CBC_HS384("A192CBC-HS384"), 14 | A256CBC_HS512("A256CBC-HS512"); 15 | 16 | private String algorithmName; 17 | 18 | private ContentEncryptionAlgorithm(String algorithmName) { 19 | this.algorithmName = algorithmName; 20 | } 21 | 22 | public String getAlgorithm() { 23 | return algorithmName; 24 | } 25 | 26 | public static ContentEncryptionAlgorithm fromAlgorithm(String algorithmName) { 27 | return ContentEncryptionAlgorithm.valueOf(algorithmName.replaceAll("-", "_").replaceAll("\\+", "_")); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /implementation/common/src/main/java/io/smallrye/jwt/algorithm/KeyEncryptionAlgorithm.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.algorithm; 2 | 3 | /** 4 | * JWT JSON Web Key Encryption (Management) Algorithms. 5 | * 6 | * @see https://tools.ietf.org/html/rfc7518#section-4 7 | */ 8 | public enum KeyEncryptionAlgorithm { 9 | RSA_OAEP("RSA-OAEP"), 10 | RSA_OAEP_256("RSA-OAEP-256"), 11 | ECDH_ES("ECDH-ES"), 12 | ECDH_ES_A128KW("ECDH-ES+A128KW"), 13 | ECDH_ES_A192KW("ECDH-ES+A192KW"), 14 | ECDH_ES_A256KW("ECDH-ES+A256KW"), 15 | A128KW("A128KW"), 16 | A192KW("A192KW"), 17 | A256KW("A256KW"), 18 | A128GCMKW("A128GCMKW"), 19 | A192GCMKW("A192GCMKW"), 20 | A256GCMKW("A256GCMKW"), 21 | PBES2_HS256_A128KW("PBES2-HS256+A128KW"), 22 | PBES2_HS384_A192KW("PBES2-HS384+A192KW"), 23 | PBES2_HS512_A256KW("PBES2-HS512+A256KW"), 24 | DIR("dir"); 25 | 26 | private String algorithmName; 27 | 28 | private KeyEncryptionAlgorithm(String algorithmName) { 29 | this.algorithmName = algorithmName; 30 | } 31 | 32 | public String getAlgorithm() { 33 | return algorithmName; 34 | } 35 | 36 | public static KeyEncryptionAlgorithm fromAlgorithm(String algorithmName) { 37 | return KeyEncryptionAlgorithm.valueOf(algorithmName.replaceAll("-", "_").replaceAll("\\+", "_")); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /implementation/common/src/main/java/io/smallrye/jwt/algorithm/SignatureAlgorithm.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.algorithm; 2 | 3 | import java.util.StringJoiner; 4 | 5 | /** 6 | * JWT JSON Web Signature Algorithms. 7 | * 8 | * @see https://tools.ietf.org/html/rfc7518#section-3 9 | */ 10 | public enum SignatureAlgorithm { 11 | RS256("RS256"), 12 | RS384("RS384"), 13 | RS512("RS512"), 14 | ES256("ES256"), 15 | ES384("ES384"), 16 | ES512("ES512"), 17 | EDDSA("EdDSA"), 18 | HS256("HS256"), 19 | HS384("HS384"), 20 | HS512("HS512"), 21 | PS256("PS256"), 22 | PS384("PS384"), 23 | PS512("PS512"); 24 | 25 | private final String algorithmName; 26 | 27 | SignatureAlgorithm(String algorithmName) { 28 | this.algorithmName = algorithmName; 29 | } 30 | 31 | public String getAlgorithm() { 32 | return algorithmName; 33 | } 34 | 35 | public static SignatureAlgorithm fromAlgorithm(String algorithmName) { 36 | try { 37 | return SignatureAlgorithm.valueOf(algorithmName.toUpperCase()); 38 | } catch (Exception e) { 39 | throw new IllegalArgumentException( 40 | "Invalid signature algorithm name: " + algorithmName + ", expected one of: " + getValidNames(), e); 41 | } 42 | } 43 | 44 | private static String getValidNames() { 45 | var names = new StringJoiner(", "); 46 | for (var alg : values()) { 47 | names.add(alg.getAlgorithm()); 48 | } 49 | return names.toString(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /implementation/common/src/main/java/io/smallrye/jwt/util/JWTUtilLogging.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.util; 2 | 3 | import org.jboss.logging.BasicLogger; 4 | import org.jboss.logging.Logger; 5 | import org.jboss.logging.annotations.Cause; 6 | import org.jboss.logging.annotations.LogMessage; 7 | import org.jboss.logging.annotations.Message; 8 | import org.jboss.logging.annotations.MessageLogger; 9 | 10 | @MessageLogger(projectCode = "SRJWT", length = 5) 11 | interface JWTUtilLogging extends BasicLogger { 12 | JWTUtilLogging log = Logger.getMessageLogger(JWTUtilLogging.class, JWTUtilLogging.class.getPackage().getName()); 13 | 14 | @LogMessage(level = Logger.Level.DEBUG) 15 | @Message(id = 1003, value = "Trying to create a key from the encoded PEM key...") 16 | void creatingKeyFromPemKey(); 17 | 18 | @LogMessage(level = Logger.Level.DEBUG) 19 | @Message(id = 1004, value = "Failed to create a key from the encoded PEM key") 20 | void creatingKeyFromPemKeyFailed(@Cause Throwable throwable); 21 | 22 | @LogMessage(level = Logger.Level.DEBUG) 23 | @Message(id = 1005, value = "Trying to create a key from the encoded PEM certificate...") 24 | void creatingKeyFromPemCertificate(); 25 | 26 | @LogMessage(level = Logger.Level.DEBUG) 27 | @Message(id = 1006, value = "Failed to to create a key from the encoded PEM certificate") 28 | void creatingKeyFromPemCertificateFailed(@Cause Throwable throwable); 29 | 30 | @LogMessage(level = Logger.Level.DEBUG) 31 | @Message(id = 1007, value = "Trying to load the local JWK(S)...") 32 | void loadingJwks(); 33 | 34 | @LogMessage(level = Logger.Level.DEBUG) 35 | @Message(id = 1008, value = "Failed to load the JWK(S)") 36 | void loadingJwksFailed(@Cause Throwable throwable); 37 | 38 | @LogMessage(level = Logger.Level.DEBUG) 39 | @Message(id = 1009, value = "Failed to parse the JWK JSON representation") 40 | void parsingJwksFailed(); 41 | 42 | @LogMessage(level = Logger.Level.DEBUG) 43 | @Message(id = 1010, value = "File %s is not found") 44 | void fileIsNotFound(String fileLocation); 45 | } -------------------------------------------------------------------------------- /implementation/common/src/main/java/io/smallrye/jwt/util/JWTUtilMessages.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.util; 2 | 3 | import java.io.IOException; 4 | import java.io.UncheckedIOException; 5 | import java.security.InvalidAlgorithmParameterException; 6 | import java.security.KeyStoreException; 7 | import java.security.NoSuchAlgorithmException; 8 | 9 | import org.jboss.logging.Messages; 10 | import org.jboss.logging.annotations.Cause; 11 | import org.jboss.logging.annotations.Message; 12 | import org.jboss.logging.annotations.MessageBundle; 13 | 14 | @MessageBundle(projectCode = "SRJWT", length = 5) 15 | interface JWTUtilMessages { 16 | JWTUtilMessages msg = Messages.getBundle(JWTUtilMessages.class); 17 | 18 | @Message(id = 0, value = "Failed to decode the JWKS Public Key") 19 | UncheckedIOException invalidJWKSPublicKey(@Cause IOException ioe); 20 | 21 | @Message(id = 1, value = "Unsupported key type %s") 22 | NoSuchAlgorithmException unsupportedAlgorithm(String algorithmName); 23 | 24 | @Message(id = 2, value = "No resource with the named %s location exists") 25 | IOException keyNotFound(String keyLocation); 26 | 27 | @Message(id = 3, value = "Algorithm %s is not a symmetric-key algorithm") 28 | InvalidAlgorithmParameterException requiresSymmetricAlgo(String algorithmName); 29 | 30 | @Message(id = 4, value = "Keystore provider %s is not found") 31 | KeyStoreException keystoreProviderNotFound(String provider); 32 | } 33 | -------------------------------------------------------------------------------- /implementation/common/src/test/java/io/smallrye/jwt/util/GenerateSecretFromKeyEncryptionAlgoTest.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.util; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.security.InvalidAlgorithmParameterException; 6 | import java.util.ArrayList; 7 | import java.util.Collection; 8 | import java.util.Map; 9 | 10 | import javax.crypto.SecretKey; 11 | 12 | import org.junit.Test; 13 | import org.junit.runner.RunWith; 14 | import org.junit.runners.Parameterized; 15 | 16 | import io.smallrye.jwt.algorithm.KeyEncryptionAlgorithm; 17 | 18 | @RunWith(Parameterized.class) 19 | public class GenerateSecretFromKeyEncryptionAlgoTest { 20 | 21 | @Parameterized.Parameters 22 | public static Collection data() { 23 | Collection args = new ArrayList<>(); 24 | for (Map.Entry e : KeyUtils.KEY_ENCRYPTION_BITS.entrySet()) { 25 | args.add(new Object[] { e.getKey().getAlgorithm(), e.getValue() }); 26 | } 27 | return args; 28 | } 29 | 30 | @Parameterized.Parameter 31 | public String algoName; 32 | 33 | @Parameterized.Parameter(1) 34 | public Integer keySizeInBits; 35 | 36 | @Test 37 | public void givenSymmetricAlgo_thenReturnSecretKey() throws InvalidAlgorithmParameterException { 38 | KeyEncryptionAlgorithm algo = KeyEncryptionAlgorithm.fromAlgorithm(algoName); 39 | SecretKey keySpec = KeyUtils.generateSecretKey(algo); 40 | assertEquals("AES", keySpec.getAlgorithm()); 41 | assertEquals(keySizeInBits / 8, keySpec.getEncoded().length); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /implementation/common/src/test/java/io/smallrye/jwt/util/GenerateSecretFromSignatureAlgoTest.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.util; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.security.InvalidAlgorithmParameterException; 6 | import java.util.ArrayList; 7 | import java.util.Collection; 8 | import java.util.Map; 9 | 10 | import javax.crypto.SecretKey; 11 | 12 | import org.junit.Test; 13 | import org.junit.runner.RunWith; 14 | import org.junit.runners.Parameterized; 15 | 16 | import io.smallrye.jwt.algorithm.SignatureAlgorithm; 17 | 18 | @RunWith(Parameterized.class) 19 | public class GenerateSecretFromSignatureAlgoTest { 20 | 21 | @Parameterized.Parameters 22 | public static Collection data() { 23 | Collection args = new ArrayList<>(); 24 | for (Map.Entry e : KeyUtils.SIGNATURE_ALGORITHM_BITS.entrySet()) { 25 | args.add(new Object[] { e.getKey().getAlgorithm(), e.getValue() }); 26 | } 27 | return args; 28 | } 29 | 30 | @Parameterized.Parameter 31 | public String algoName; 32 | 33 | @Parameterized.Parameter(1) 34 | public Integer keySizeInBits; 35 | 36 | @Test 37 | public void givenSymmetricAlgo_thenReturnSecretKey() throws InvalidAlgorithmParameterException { 38 | SignatureAlgorithm algo = SignatureAlgorithm.fromAlgorithm(algoName); 39 | SecretKey keySpec = KeyUtils.generateSecretKey(algo); 40 | assertEquals("HMAC", keySpec.getAlgorithm()); 41 | assertEquals(keySizeInBits / 8, keySpec.getEncoded().length); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /implementation/common/src/test/resources/EDDSA-ED25519-private-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MC4CAQAwBQYDK2VwBCIEIJwpRXu1bk843lYD9fpcSqNhCcOY4gxtW6JxQxioLNQn 3 | -----END PRIVATE KEY----- -------------------------------------------------------------------------------- /implementation/common/src/test/resources/EDDSA-ED25519-public-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MCowBQYDK2VwAyEAn4PUVRXUdG2GEl1rvP29Wf1hsNZAJIfVs7uuLhg0n54= 3 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /implementation/common/src/test/resources/EDDSA-ED448-private-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MEcCAQAwBQYDK2VxBDsEOSHKcAGw4zo0lBofAcAXaDmuXNpumyFcKv65tB072HMWDX+9HSxxwqjG 3 | SGLMMSDxL4xWKZYSjQxpqA== 4 | -----END PRIVATE KEY----- -------------------------------------------------------------------------------- /implementation/common/src/test/resources/EDDSA-ED448-public-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MEMwBQYDK2VxAzoAYY4baE68KOlXAU77zBEWcvaioC7uM5Nrogybx3UTbMTAwcHicYtQpF7ztc05 3 | Wd81FG3FnJAT0MwA 4 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /implementation/common/src/test/resources/ES256-private-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAoc0FpgUAJuZT8s1SmGvRT/nLEfuaN 3 | +nhOGlYLn1QiKw== 4 | -----END PRIVATE KEY----- -------------------------------------------------------------------------------- /implementation/common/src/test/resources/ES256-public-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuGXtwofKnwyJvyVV9EuokE0ksBcMNNiIxDlNEEJI 3 | rIZ02XoT64pC8dW3MEHLxmkhkdBomuq/P/jxKmKvaHwMBA== 4 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /implementation/common/src/test/resources/RS256-2048bit-private-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCrwrD7iu5yQNjBhpVF3dub7Sex 3 | 8yPxLpLkl4D+whMEjZbw3QHJVYHFmBxQhl3u464oNYkoQFfJHvE9lHYP3JrXpmhKifyMMTEETH7N 4 | 1xI2hVwHh0JMmKS1d4HxXyOjq5Ix8X68OIizfPX6GV8ztFubFKxmADiLB8UqR8+wHR6F8tyo2SD1 5 | mbQiMcu27fqyGpFTQOMvNgx6whjq/Flx1M3y91htvbIWbIN+NaL+ncmxW6/AxVT4C5sWqyMuQ7Ro 6 | RkxXk5G7orLQXAQAQ5nu/MT3bSpyHgtxD999L/Acvia4NOF8IbONtWkEg1gkhlr3He/6XeINe/o0 7 | ZkKjh36XpupTAgMBAAECggEABWUbnwMJo1ATHt0F0kh6LecgkI/VCK3QUlrJ4/afl0yFObKPbE4B 8 | wf2ZohPeXnMLVNr9oGSI/Vm59Re1L6FbwbtJ2lGEO7kN05c9gmSnf0voDJp8hCBlSAflbnnxCiKI 9 | +IWf1/SkopKhvUXPvjWDjRb0pU2LeR543G+d/+eiPk3J2KkjCLkc3JY8wIKipF+l2lLzeRDkbxcG 10 | bX4uXypcoYpKzbU1BzTRXxMJ8n0ZxvMLm0DPYY5ZOZTO0angYV3v1jlG4G7FSmTutu0THfshz0D2 11 | YCU9+cHF4kXHZufbFUIIWsaXfMVtcYT7gsgDYQepxZrbSMGc8JXkFxEtZ1sC7QKBgQDDPIjmEWFu 12 | IgCErzBS+4V+4SFAtMlyrTlNQMYTskGxX0cg0u0yOJ4K4UvzT9Tk0R+kNIhPsw/PoYKvNsdI1keg 13 | lyaWUwlCkCMtH/egAi3IMiunw5IOQskuacNNyYypAV62pj3E908pKz+oeuXSQzmzjd1HEMyGaN45 14 | ASp79uxQlQKBgQDhN7XPVd5pO5AvnotU4wF850welvtuVyV9cE7J5wfZ3mClCyyvUkqDUk56s3E/ 15 | Z8/H24efD2rA1VknPRrKTd3wMXT9ruhxaWugu+KC9ylsxef0FkAc5K9TPSCwaspFjOl93wmkq8zi 16 | Rcehg8F4V/uENbRqiKsDWMQVNISfkbENRwKBgFtVf2m56c1+5KUt27qGZh5ELa06ph8awHrOeZuP 17 | QcI7o2fMpSBgcjb+zOwnhZ4B4v6LgNVgHF5y3VMgmjwN2nZbH7clY2ibS4l5sftN6aMFLX0PNc2s 18 | Gre2zKIgTshllqx1uuHhHExTKjWkQM2Lm3vPOxxa1INwnb0nOXvCuSy9AoGAEwHbozrxAVqYiZxM 19 | 0AY0ivEOWIqPf7l1HYgL7jhETlvZNjSiOc2tIjYhD3Pze9FsFMbvRDpN3SZkVs5uY2J895eE8x/+ 20 | 2At4nOEedcUcRuTQ9aWnFYkrTtAa4SiyF3qT/h6DttUU/oe7GGOBQYHTZU4PAuqz3B1ytwNuqfTm 21 | x2MCgYAUhMIjd2N7DNJf5aqAs2rtNHIFpiG1sVoXlgK4w5Aeos//PBCzAsCTRqm8kHpM2PWGDQTA 22 | SmQXjEmHefXSa7f2uTuwNjKvSbyb+ZKvOaGMKVFCrCEPZrERJXklfWsgds3uyLrA2MTElpCyt2mG 23 | MF7umAaOBiUNY+fIRa/oPC1Pww== 24 | -----END PRIVATE KEY----- -------------------------------------------------------------------------------- /implementation/common/src/test/resources/RS256-2048bit-public-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq8Kw+4ruckDYwYaVRd3bm+0nsfMj8S6S 3 | 5JeA/sITBI2W8N0ByVWBxZgcUIZd7uOuKDWJKEBXyR7xPZR2D9ya16ZoSon8jDExBEx+zdcSNoVc 4 | B4dCTJiktXeB8V8jo6uSMfF+vDiIs3z1+hlfM7RbmxSsZgA4iwfFKkfPsB0ehfLcqNkg9Zm0IjHL 5 | tu36shqRU0DjLzYMesIY6vxZcdTN8vdYbb2yFmyDfjWi/p3JsVuvwMVU+AubFqsjLkO0aEZMV5OR 6 | u6Ky0FwEAEOZ7vzE920qch4LcQ/ffS/wHL4muDThfCGzjbVpBINYJIZa9x3v+l3iDXv6NGZCo4d+ 7 | l6bqUwIDAQAB 8 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/JWTLogging.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt; 2 | 3 | import org.jboss.logging.BasicLogger; 4 | import org.jboss.logging.Logger; 5 | import org.jboss.logging.annotations.LogMessage; 6 | import org.jboss.logging.annotations.Message; 7 | import org.jboss.logging.annotations.MessageLogger; 8 | 9 | @MessageLogger(projectCode = "SRJWT", length = 5) 10 | interface JWTLogging extends BasicLogger { 11 | JWTLogging log = Logger.getMessageLogger(JWTLogging.class, JWTLogging.class.getPackage().getName()); 12 | 13 | @LogMessage(level = Logger.Level.ERROR) 14 | @Message(id = 1000, value = "path.%s configuration will be ignored because the path depth is too large:" 15 | + " %d, maximum depth is %d.") 16 | void maximumPathDepthReached(String claimName, Object pathDepth, Object maxPathDepthSupported); 17 | 18 | @LogMessage(level = Logger.Level.ERROR) 19 | @Message(id = 1001, value = "Token header is not 'Cookie', the cookie name value will be ignored") 20 | void tokenHeaderIsNotCookieHeader(); 21 | 22 | @LogMessage(level = Logger.Level.ERROR) 23 | @Message(id = 1002, value = "Algorithm %s not supported") 24 | void unsupportedAlgorithm(String unsupportedAlgorithm); 25 | } 26 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/KeyFormat.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt; 2 | 3 | /** 4 | * Format or store type of the security key. 5 | */ 6 | public enum KeyFormat { 7 | /** 8 | * PEM file containing a Base64-encoded key. 9 | */ 10 | PEM_KEY, 11 | /** 12 | * PEM file containing a Base64-encoded certificate. 13 | */ 14 | PEM_CERTIFICATE, 15 | 16 | /** 17 | * JWK key set or single JWK key. 18 | */ 19 | JWK, 20 | 21 | /** 22 | * JWK key set or single JWK key which has been Base64URL-encoded. 23 | */ 24 | JWK_BASE64URL, 25 | 26 | /** 27 | * Key can be in any of the supported formats. 28 | */ 29 | ANY 30 | } 31 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/KeyProvider.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt; 2 | 3 | /** 4 | * Well-known key providers. 5 | */ 6 | public enum KeyProvider { 7 | /** 8 | * AWS Application Load Balancer. 9 | * 10 | * Verification key in PEM format is fetched from the URI which is created by 11 | * adding the current token `kid` (key identifier) header value to the AWS ALB URI. 12 | */ 13 | AWS_ALB, 14 | 15 | /** 16 | * Verification key is resolved as required by the MP JWT specification: 17 | * PEM or JWK key or JWK key set can be read from the local file system or fetched from URIs. 18 | */ 19 | DEFAULT 20 | } 21 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/SmallryeJwtUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package io.smallrye.jwt; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | import java.util.Optional; 22 | 23 | import org.eclipse.microprofile.jwt.Claims; 24 | 25 | import io.smallrye.jwt.auth.principal.JWTAuthContextInfo; 26 | 27 | /** 28 | * Utility methods for dealing with decoding public and private keys resources 29 | */ 30 | public class SmallryeJwtUtils { 31 | private static final Integer MAX_PATH_DEPTH = 4; 32 | private static final String COOKIE_HEADER = "Cookie"; 33 | 34 | private SmallryeJwtUtils() { 35 | } 36 | 37 | public static void setContextSubPath(JWTAuthContextInfo contextInfo, Optional subPath) { 38 | if (checkClaimPath(Claims.sub.name(), subPath)) { 39 | contextInfo.setSubjectPath(subPath.get()); 40 | } 41 | } 42 | 43 | public static void setContextGroupsPath(JWTAuthContextInfo contextInfo, Optional groupsPath) { 44 | if (checkClaimPath(Claims.groups.name(), groupsPath)) { 45 | contextInfo.setGroupsPath(groupsPath.get()); 46 | } 47 | } 48 | 49 | private static boolean checkClaimPath(String claimName, Optional claimPath) { 50 | if (claimPath.isPresent()) { 51 | final String[] pathSegments = claimPath.get().split("/"); 52 | if (MAX_PATH_DEPTH < pathSegments.length) { 53 | JWTLogging.log.maximumPathDepthReached(claimName, pathSegments.length, MAX_PATH_DEPTH); 54 | } else { 55 | return true; 56 | } 57 | } 58 | return false; 59 | } 60 | 61 | public static void setContextTokenCookie(JWTAuthContextInfo contextInfo, Optional cookieName) { 62 | if (COOKIE_HEADER.equals(contextInfo.getTokenHeader())) { 63 | if (cookieName.isPresent()) { 64 | contextInfo.setTokenCookie(cookieName.get()); 65 | } 66 | } 67 | } 68 | 69 | public static void setTokenSchemes(JWTAuthContextInfo contextInfo, String tokenSchemes) { 70 | String[] splitTokenSchemes = tokenSchemes.split(","); 71 | final List schemes = new ArrayList<>(splitTokenSchemes.length); 72 | for (final String s : splitTokenSchemes) { 73 | schemes.add(s.trim()); 74 | } 75 | contextInfo.setTokenSchemes(schemes); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/auth/AuthLogging.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.auth; 2 | 3 | import org.jboss.logging.BasicLogger; 4 | import org.jboss.logging.Logger; 5 | import org.jboss.logging.annotations.LogMessage; 6 | import org.jboss.logging.annotations.Message; 7 | import org.jboss.logging.annotations.MessageLogger; 8 | 9 | @MessageLogger(projectCode = "SRJWT", length = 5) 10 | interface AuthLogging extends BasicLogger { 11 | AuthLogging log = Logger.getMessageLogger(AuthLogging.class, AuthLogging.class.getPackage().getName()); 12 | 13 | @LogMessage(level = Logger.Level.DEBUG) 14 | @Message(id = 6000, value = "tokenHeaderName = %s") 15 | void tokenHeaderName(String headerName); 16 | 17 | @LogMessage(level = Logger.Level.DEBUG) 18 | @Message(id = 6001, value = "Header %s was null") 19 | void headerIsNull(String headerName); 20 | 21 | @LogMessage(level = Logger.Level.DEBUG) 22 | @Message(id = 6002, value = "tokenCookieName = %s") 23 | void tokenCookieName(String cookieName); 24 | 25 | @LogMessage(level = Logger.Level.DEBUG) 26 | @Message(id = 6003, value = "Cookie %s was null") 27 | void cookieIsNull(String cookieName); 28 | 29 | @LogMessage(level = Logger.Level.DEBUG) 30 | @Message(id = 6004, value = "Authorization header does not contain a Bearer prefix") 31 | void authHeaderDoesNotContainBearerPrefix(); 32 | 33 | @LogMessage(level = Logger.Level.DEBUG) 34 | @Message(id = 6005, value = "Authorization header was null") 35 | void authHeaderIsNull(); 36 | } -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/auth/cdi/CDIMessages.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.auth.cdi; 2 | 3 | import jakarta.enterprise.inject.spi.DeploymentException; 4 | import jakarta.enterprise.inject.spi.InjectionPoint; 5 | 6 | import org.jboss.logging.Messages; 7 | import org.jboss.logging.annotations.Message; 8 | import org.jboss.logging.annotations.MessageBundle; 9 | 10 | @MessageBundle(projectCode = "SRJWT", length = 5) 11 | interface CDIMessages { 12 | CDIMessages msg = Messages.getBundle(CDIMessages.class); 13 | 14 | @Message(id = 13000, value = "@Claim at: %s has no name or valid standard enum setting") 15 | DeploymentException claimHasNoNameOrValidStandardEnumSetting(InjectionPoint injectionPoint); 16 | } 17 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/auth/cdi/ClaimValueProducer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package io.smallrye.jwt.auth.cdi; 19 | 20 | import jakarta.enterprise.context.Dependent; 21 | import jakarta.enterprise.inject.Produces; 22 | import jakarta.enterprise.inject.spi.InjectionPoint; 23 | import jakarta.inject.Inject; 24 | 25 | import org.eclipse.microprofile.jwt.Claim; 26 | import org.eclipse.microprofile.jwt.ClaimValue; 27 | 28 | /** 29 | * A producer for the ClaimValue wrapper injection sites. 30 | */ 31 | @Dependent 32 | public class ClaimValueProducer { 33 | 34 | @Inject 35 | CommonJwtProducer util; 36 | 37 | @Produces 38 | @Claim("") 39 | ClaimValue produceClaim(InjectionPoint ip) { 40 | return new ClaimValueWrapper<>(ip, util); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/auth/cdi/CommonJwtProducer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package io.smallrye.jwt.auth.cdi; 18 | 19 | import java.lang.annotation.Annotation; 20 | import java.util.Optional; 21 | 22 | import jakarta.enterprise.context.RequestScoped; 23 | import jakarta.enterprise.inject.spi.InjectionPoint; 24 | import jakarta.inject.Inject; 25 | import jakarta.json.JsonValue; 26 | 27 | import org.eclipse.microprofile.jwt.Claim; 28 | import org.eclipse.microprofile.jwt.Claims; 29 | import org.eclipse.microprofile.jwt.JsonWebToken; 30 | 31 | import io.smallrye.jwt.JsonUtils; 32 | 33 | /** 34 | * A class that tracks the current validated MP-JWT and associated JsonWebToken via a thread 35 | * local to provide a @RequestScoped JsonWebToken producer method. 36 | * 37 | * It also provides utility methods for access the current JsonWebToken claim values. 38 | */ 39 | @RequestScoped 40 | public class CommonJwtProducer { 41 | 42 | @Inject 43 | JsonWebToken currentToken; 44 | 45 | /** 46 | * Return the indicated claim value as a JsonValue 47 | * 48 | * @param ip - injection point of the claim 49 | * @return a JsonValue wrapper 50 | */ 51 | public JsonValue generalJsonValueProducer(InjectionPoint ip) { 52 | String name = getName(ip); 53 | Object value = getValue(name, false); 54 | return JsonUtils.wrapValue(value); 55 | } 56 | 57 | public T getValue(String name, boolean isOptional) { 58 | if (currentToken == null) { 59 | CDILogging.log.getValue(name); 60 | return null; 61 | } 62 | 63 | Optional claimValue = currentToken.claim(name); 64 | if (!isOptional && !claimValue.isPresent()) { 65 | CDILogging.log.failedToFindClaim(name); 66 | } 67 | CDILogging.log.getValueResult(name, isOptional, claimValue); 68 | return claimValue.orElse(null); 69 | } 70 | 71 | public String getName(InjectionPoint ip) { 72 | String name = null; 73 | for (Annotation ann : ip.getQualifiers()) { 74 | if (ann instanceof Claim) { 75 | Claim claim = (Claim) ann; 76 | name = claim.standard() == Claims.UNKNOWN ? claim.value() : claim.standard().name(); 77 | } 78 | } 79 | return name; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/auth/cdi/JWTCallerPrincipalFactoryProducer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package io.smallrye.jwt.auth.cdi; 18 | 19 | import jakarta.enterprise.context.ApplicationScoped; 20 | import jakarta.enterprise.inject.Produces; 21 | 22 | import io.smallrye.jwt.auth.principal.JWTCallerPrincipalFactory; 23 | 24 | @ApplicationScoped 25 | public class JWTCallerPrincipalFactoryProducer { 26 | 27 | private JWTCallerPrincipalFactory callerPrincipalFactory; 28 | 29 | public JWTCallerPrincipalFactoryProducer() { 30 | initCallerPrincipalFactory(); 31 | } 32 | 33 | @Produces 34 | public JWTCallerPrincipalFactory getFactory() { 35 | return callerPrincipalFactory; 36 | } 37 | 38 | private void initCallerPrincipalFactory() { 39 | callerPrincipalFactory = JWTCallerPrincipalFactory.instance(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/auth/cdi/JsonValueProducer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package io.smallrye.jwt.auth.cdi; 19 | 20 | import java.util.Optional; 21 | 22 | import jakarta.enterprise.inject.Produces; 23 | import jakarta.enterprise.inject.spi.InjectionPoint; 24 | import jakarta.inject.Inject; 25 | import jakarta.json.JsonArray; 26 | import jakarta.json.JsonNumber; 27 | import jakarta.json.JsonObject; 28 | import jakarta.json.JsonString; 29 | import jakarta.json.JsonValue; 30 | 31 | import org.eclipse.microprofile.jwt.Claim; 32 | 33 | /** 34 | * A producer for JsonValue injection types 35 | */ 36 | public class JsonValueProducer { 37 | @Inject 38 | CommonJwtProducer util; 39 | 40 | @Produces 41 | @Claim("") 42 | public JsonString getJsonString(InjectionPoint ip) { 43 | return getValue(ip); 44 | } 45 | 46 | @Produces 47 | @Claim("") 48 | public Optional getOptionalJsonString(InjectionPoint ip) { 49 | return getOptionalValue(ip); 50 | } 51 | 52 | @Produces 53 | @Claim("") 54 | public JsonNumber getJsonNumber(InjectionPoint ip) { 55 | return getValue(ip); 56 | } 57 | 58 | @Produces 59 | @Claim("") 60 | public Optional getOptionalJsonNumber(InjectionPoint ip) { 61 | return getOptionalValue(ip); 62 | } 63 | 64 | @Produces 65 | @Claim("") 66 | public JsonArray getJsonArray(InjectionPoint ip) { 67 | return getValue(ip); 68 | } 69 | 70 | @Produces 71 | @Claim("") 72 | public Optional getOptionalJsonArray(InjectionPoint ip) { 73 | return getOptionalValue(ip); 74 | } 75 | 76 | @Produces 77 | @Claim("") 78 | public JsonObject getJsonObject(InjectionPoint ip) { 79 | return getValue(ip); 80 | } 81 | 82 | @Produces 83 | @Claim("") 84 | public Optional getOptionalJsonObject(InjectionPoint ip) { 85 | return getOptionalValue(ip); 86 | } 87 | 88 | @SuppressWarnings("unchecked") 89 | public T getValue(InjectionPoint ip) { 90 | CDILogging.log.jsonValueProducer(ip); 91 | return (T) util.generalJsonValueProducer(ip); 92 | } 93 | 94 | @SuppressWarnings("unchecked") 95 | public Optional getOptionalValue(InjectionPoint ip) { 96 | CDILogging.log.jsonValueProducer(ip); 97 | T jsonValue = (T) util.generalJsonValueProducer(ip); 98 | return Optional.ofNullable(jsonValue); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/auth/cdi/NullJsonWebToken.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.auth.cdi; 2 | 3 | import java.util.Set; 4 | 5 | import org.eclipse.microprofile.jwt.JsonWebToken; 6 | 7 | public class NullJsonWebToken implements JsonWebToken { 8 | 9 | @Override 10 | public String getName() { 11 | return null; 12 | } 13 | 14 | @Override 15 | public Set getClaimNames() { 16 | return null; 17 | } 18 | 19 | @Override 20 | public T getClaim(String claimName) { 21 | return null; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/auth/cdi/OptionalClaimTypeProducer.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.auth.cdi; 2 | 3 | import static io.smallrye.jwt.auth.cdi.RawClaimTypeProducer.getName; 4 | 5 | import java.util.Optional; 6 | import java.util.Set; 7 | 8 | import jakarta.enterprise.inject.Produces; 9 | import jakarta.enterprise.inject.spi.InjectionPoint; 10 | import jakarta.inject.Inject; 11 | 12 | import org.eclipse.microprofile.jwt.Claim; 13 | import org.eclipse.microprofile.jwt.JsonWebToken; 14 | 15 | import io.smallrye.jwt.JsonUtils; 16 | 17 | public class OptionalClaimTypeProducer { 18 | @Inject 19 | JsonWebToken currentToken; 20 | 21 | /** 22 | * Produces an Optional claim value wrapping a String. 23 | * 24 | * @param ip reference to the injection point 25 | * @return an optional claim value 26 | */ 27 | @Produces 28 | @Claim("") 29 | public Optional getOptionalString(InjectionPoint ip) { 30 | CDILogging.log.getOptionalString(ip); 31 | if (currentToken == null) { 32 | return Optional.empty(); 33 | } 34 | return Optional.ofNullable((String) JsonUtils.convert(String.class, currentToken.getClaim(getName(ip)))); 35 | } 36 | 37 | /** 38 | * Produces an Optional claim value wrapping a Set of Strings. 39 | * 40 | * @param ip reference to the injection point 41 | * @return an optional claim value 42 | */ 43 | @Produces 44 | @Claim("") 45 | public Optional> getOptionalStringSet(InjectionPoint ip) { 46 | CDILogging.log.getOptionalStringSet(ip); 47 | if (currentToken == null) { 48 | return Optional.empty(); 49 | } 50 | return Optional.ofNullable((Set) JsonUtils.convert(Set.class, currentToken.getClaim(getName(ip)))); 51 | } 52 | 53 | /** 54 | * Produces an Optional claim value wrapping a Long. 55 | * 56 | * @param ip reference to the injection point 57 | * @return an optional claim value 58 | */ 59 | @Produces 60 | @Claim("") 61 | public Optional getOptionalLong(InjectionPoint ip) { 62 | CDILogging.log.getOptionalLong(ip); 63 | if (currentToken == null) { 64 | return Optional.empty(); 65 | } 66 | return Optional.ofNullable((Long) JsonUtils.convert(Long.class, currentToken.getClaim(getName(ip)))); 67 | } 68 | 69 | /** 70 | * Produces an Optional claim value wrapping a Boolean. 71 | * 72 | * @param ip reference to the injection point 73 | * @return an optional claim value 74 | */ 75 | @Produces 76 | @Claim("") 77 | public Optional getOptionalBoolean(InjectionPoint ip) { 78 | CDILogging.log.getOptionalBoolean(ip); 79 | if (currentToken == null) { 80 | return Optional.empty(); 81 | } 82 | return Optional.ofNullable((Boolean) JsonUtils.convert(Boolean.class, currentToken.getClaim(getName(ip)))); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/auth/cdi/PrincipalProducer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package io.smallrye.jwt.auth.cdi; 18 | 19 | import jakarta.annotation.Priority; 20 | import jakarta.enterprise.context.RequestScoped; 21 | import jakarta.enterprise.inject.Alternative; 22 | import jakarta.enterprise.inject.Produces; 23 | 24 | import org.eclipse.microprofile.jwt.JsonWebToken; 25 | 26 | /** 27 | * Override the default CDI Principal bean to allow the injection of a Principal to be a JsonWebToken 28 | */ 29 | @Priority(1) 30 | @Alternative 31 | @RequestScoped 32 | public class PrincipalProducer { 33 | private JsonWebToken token; 34 | 35 | public void setJsonWebToken(JsonWebToken token) { 36 | this.token = token; 37 | } 38 | 39 | /** 40 | * The producer method for the current JsonWebToken 41 | * 42 | * @return JsonWebToken 43 | */ 44 | @Produces 45 | @RequestScoped 46 | JsonWebToken currentJWTPrincipalOrNull() { 47 | return token == null ? new NullJsonWebToken() : token; 48 | } 49 | } -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/auth/principal/AwsAlbKeyConfigurationValidator.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.auth.principal; 2 | 3 | import java.net.URI; 4 | 5 | import org.jose4j.lang.UnresolvableKeyException; 6 | 7 | import io.smallrye.jwt.algorithm.SignatureAlgorithm; 8 | 9 | interface AwsAlbKeyConfigurationValidator { 10 | 11 | public static void validateKeyConfiguration(JWTAuthContextInfo authContextInfo) throws UnresolvableKeyException { 12 | // public key location check 13 | var publicKeyLocation = authContextInfo.getPublicKeyLocation(); 14 | if (publicKeyLocation == null) { 15 | throw PrincipalMessages.msg.nullKeyLocation(); 16 | } 17 | if (containsSubPath(publicKeyLocation)) { 18 | throw AwsAlbKeyResolverMessages.msg.subPathNotAllowed(); 19 | } 20 | } 21 | 22 | public static void validatePublicKeyAlgorithmConfiguration(JWTAuthContextInfo authContextInfo) { 23 | var publicKeyAlgorithm = authContextInfo.getSignatureAlgorithm(); 24 | if (publicKeyAlgorithm == null) { 25 | AwsAlbKeyResolverLogging.log.publicKeyAlgorithmNotSet(); 26 | } 27 | if (publicKeyAlgorithm.size() != 1 || !publicKeyAlgorithm.contains(SignatureAlgorithm.ES256)) { 28 | AwsAlbKeyResolverLogging.log.publicKeyAlgorithmNotSetToES256(); 29 | } 30 | } 31 | 32 | /** 33 | * verifies the entry: mp.jwt.token.header=X-Amzn-Oidc-Data 34 | * 35 | * @param authContextInfo 36 | */ 37 | public static void validateTokenHeaderConfiguration(JWTAuthContextInfo authContextInfo) { 38 | var tokenHeader = authContextInfo.getTokenHeader(); 39 | if (tokenHeader == null || !"X-Amzn-Oidc-Data".equals(tokenHeader)) { 40 | AwsAlbKeyResolverLogging.log.invalidAWSTokenHeader(); 41 | } 42 | 43 | } 44 | 45 | /** 46 | * Remove ending slash from uri e.g. https://localhost:8080/ -> 47 | * https://localhost:8080 48 | * 49 | * @param uri public key location 50 | * @return uri without ending slash 51 | */ 52 | static String removeEndingSlash(String uri) { 53 | if (!uri.endsWith("/") || uri.length() == 1) { 54 | return uri; 55 | } 56 | var length = uri.length(); 57 | return uri.substring(0, length - 1); 58 | } 59 | 60 | /** 61 | * Check if public key location contains sub path e.g. 62 | * https://localhost:8080/subpath 63 | * Fails fast to prevent runtime errors 64 | * 65 | * @param publicKeyLocation to check 66 | * @return true if public key location contains sub path which is invalid 67 | */ 68 | static boolean containsSubPath(String publicKeyLocation) { 69 | var locationWithoutSlash = removeEndingSlash(publicKeyLocation); 70 | var uri = URI.create(locationWithoutSlash); 71 | return uri.getPath().contains("/"); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/auth/principal/AwsAlbKeyResolverLogging.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.auth.principal; 2 | 3 | import org.jboss.logging.BasicLogger; 4 | import org.jboss.logging.Logger; 5 | import org.jboss.logging.annotations.LogMessage; 6 | import org.jboss.logging.annotations.Message; 7 | import org.jboss.logging.annotations.MessageLogger; 8 | 9 | @MessageLogger(projectCode = "SRJWT", length = 5) 10 | interface AwsAlbKeyResolverLogging extends BasicLogger { 11 | AwsAlbKeyResolverLogging log = Logger.getMessageLogger(AwsAlbKeyResolverLogging.class, 12 | AwsAlbKeyResolverLogging.class.getPackage().getName()); 13 | 14 | @LogMessage(level = Logger.Level.DEBUG) 15 | @Message(id = 14000, value = "public key path: %s") 16 | void publicKeyPath(String path); 17 | 18 | @LogMessage(level = Logger.Level.DEBUG) 19 | @Message(id = 14001, value = "mp.jwt.verify.publickey.algorithm is not set." 20 | + "Falling back to default algorithm: RS256 which is not compabible with AWS ALB." 21 | + "Please set mp.jwt.verify.publickey.algorithm to ES256") 22 | void publicKeyAlgorithmNotSet(); 23 | 24 | @LogMessage(level = Logger.Level.DEBUG) 25 | @Message(id = 14002, value = "mp.jwt.verify.publickey.algorithm is not set to ES256") 26 | void publicKeyAlgorithmNotSetToES256(); 27 | 28 | @LogMessage(level = Logger.Level.DEBUG) 29 | @Message(id = 14003, value = "mp.jwt.token.header is not set to X-Amzn-Oidc-Data") 30 | void invalidAWSTokenHeader(); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/auth/principal/AwsAlbKeyResolverMessages.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.auth.principal; 2 | 3 | import org.jboss.logging.Messages; 4 | import org.jboss.logging.annotations.Message; 5 | import org.jboss.logging.annotations.MessageBundle; 6 | import org.jose4j.lang.UnresolvableKeyException; 7 | 8 | @MessageBundle(projectCode = "SRJWT", length = 5) 9 | interface AwsAlbKeyResolverMessages { 10 | AwsAlbKeyResolverMessages msg = Messages.getBundle(AwsAlbKeyResolverMessages.class); 11 | 12 | @Message(id = 15000, value = "Key is resolved from kid. Key location is not allowed. Provide only the path like: https://public-keys.auth.elb.[REGION].amazonaws.com") 13 | UnresolvableKeyException subPathNotAllowed(); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/auth/principal/DefaultJWTCallerPrincipalFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package io.smallrye.jwt.auth.principal; 18 | 19 | import org.jose4j.jwt.consumer.JwtContext; 20 | 21 | /** 22 | * A default implementation of the abstract JWTCallerPrincipalFactory that uses the Keycloak token parsing classes. 23 | */ 24 | public class DefaultJWTCallerPrincipalFactory extends JWTCallerPrincipalFactory { 25 | 26 | private final DefaultJWTTokenParser parser = new DefaultJWTTokenParser(); 27 | 28 | @Override 29 | public JWTCallerPrincipal parse(final String token, final JWTAuthContextInfo authContextInfo) throws ParseException { 30 | 31 | JwtContext jwtContext = parser.parse(token, authContextInfo); 32 | String type = jwtContext.getJoseObjects().get(0).getHeader("typ"); 33 | return new DefaultJWTCallerPrincipal(type, jwtContext.getJwtClaims()); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/auth/principal/ParseException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.smallrye.jwt.auth.principal; 17 | 18 | /** 19 | * The exception thrown when there is a failure to parse the JWT 20 | */ 21 | public class ParseException extends Exception { 22 | private static final long serialVersionUID = 1L; 23 | 24 | public ParseException(String message) { 25 | super(message); 26 | } 27 | 28 | public ParseException(String message, Throwable cause) { 29 | super(message, cause); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/auth/principal/UnmatchedTokenKidException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.smallrye.jwt.auth.principal; 17 | 18 | import org.jose4j.lang.UnresolvableKeyException; 19 | 20 | public class UnmatchedTokenKidException extends UnresolvableKeyException { 21 | 22 | private static final long serialVersionUID = 1L; 23 | 24 | public UnmatchedTokenKidException(String message) { 25 | super(message); 26 | } 27 | 28 | public UnmatchedTokenKidException(String message, Throwable cause) { 29 | super(message, cause); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/config/ConfigLogging.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.config; 2 | 3 | import org.jboss.logging.BasicLogger; 4 | import org.jboss.logging.Logger; 5 | import org.jboss.logging.annotations.LogMessage; 6 | import org.jboss.logging.annotations.Message; 7 | import org.jboss.logging.annotations.MessageLogger; 8 | 9 | @MessageLogger(projectCode = "SRJWT", length = 5) 10 | public interface ConfigLogging extends BasicLogger { 11 | ConfigLogging log = Logger.getMessageLogger(ConfigLogging.class, ConfigLogging.class.getPackage().getName()); 12 | 13 | @LogMessage(level = Logger.Level.DEBUG) 14 | @Message(id = 3000, value = "init, mpJwtPublicKey=%s, mpJwtIssuer=%s, mpJwtLocation=%s") 15 | void configValues(String jwtPublicKey, String jwtIssuer, String jwtLocation); 16 | 17 | @LogMessage(level = Logger.Level.DEBUG) 18 | @Message(id = 3001, value = "Neither mpJwtPublicKey nor mpJwtLocation properties are configured," 19 | + " JWTAuthContextInfo will not be available") 20 | void publicKeyAndLocationAreUnavailable(); 21 | 22 | @LogMessage(level = Logger.Level.DEBUG) 23 | @Message(id = 3002, value = "mpJwtPublicKey parsed as JWK(S)") 24 | void publicKeyParsedAsJwk(); 25 | 26 | @LogMessage(level = Logger.Level.DEBUG) 27 | @Message(id = 3003, value = "mpJwtPublicKey failed as JWK(S), %s") 28 | void parsingPublicKeyAsJwkFailed(String exceptionMessage); 29 | 30 | @LogMessage(level = Logger.Level.DEBUG) 31 | @Message(id = 3004, value = "mpJwtPublicKey parsed as PEM") 32 | void publicKeyParsedAsPem(); 33 | 34 | @LogMessage(level = Logger.Level.DEBUG) 35 | @Message(id = 3005, value = "Unsupported key format") 36 | void unsupportedKeyFormat(); 37 | 38 | @LogMessage(level = Logger.Level.WARN) 39 | @Message(id = 3006, value = "'%s' property is deprecated and will be removed in a future version. " + 40 | "Use '%s ' property instead") 41 | void replacedConfig(String originalConfig, String newConfig); 42 | 43 | @LogMessage(level = Logger.Level.WARN) 44 | @Message(id = 3007, value = "Public key is configured but either the secret key or key location are also configured and will be ignored") 45 | void publicKeyConfiguredButOtherKeyPropertiesAreAlsoUsed(); 46 | 47 | @LogMessage(level = Logger.Level.WARN) 48 | @Message(id = 3008, value = "Secret key is configured but the key location is also configured and will be ignored") 49 | void secretKeyConfiguredButKeyLocationIsAlsoUsed(); 50 | } 51 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/main/java/io/smallrye/jwt/config/ConfigMessages.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.config; 2 | 3 | import jakarta.enterprise.inject.spi.DeploymentException; 4 | 5 | import org.jboss.logging.Messages; 6 | import org.jboss.logging.annotations.Cause; 7 | import org.jboss.logging.annotations.Message; 8 | import org.jboss.logging.annotations.MessageBundle; 9 | 10 | @MessageBundle(projectCode = "SRJWT", length = 5) 11 | interface ConfigMessages { 12 | ConfigMessages msg = Messages.getBundle(ConfigMessages.class); 13 | 14 | @Message(id = 2000, value = "HMAC verification algorithms are not supported when the 'mp.jwt.verify.publickey.location' property is set, use 'smallrye.jwt.verify.key.location' instead") 15 | DeploymentException hmacNotSupported(); 16 | 17 | @Message(id = 2001, value = "Failed to decode the MP JWT Public Key") 18 | DeploymentException parsingPublicKeyFailed(@Cause Throwable throwable); 19 | 20 | @Message(id = 2002, value = "Failed to read the public key content from 'mp.jwt.verify.publickey.location'") 21 | DeploymentException readingPublicKeyLocationFailed(@Cause Throwable throwable); 22 | 23 | @Message(id = 2003, value = "'mp.jwt.verify.publickey.location' is invalid") 24 | DeploymentException invalidPublicKeyLocation(); 25 | 26 | @Message(id = 2004, value = "Failed to read the decryption key content from 'smallrye.jwt.decrypt.key.location'") 27 | DeploymentException readingDecryptKeyLocationFailed(@Cause Throwable throwable); 28 | 29 | @Message(id = 2005, value = "'smallrye.jwt.decrypt.key.location' is invalid") 30 | DeploymentException invalidDecryptKeyLocation(); 31 | 32 | @Message(id = 2006, value = "Only a single signature algorithm is supported for PEM key or certificate") 33 | DeploymentException singleSignatureAlgorithmForPemOnly(); 34 | } 35 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/test/java/io/smallrye/jwt/auth/cdi/ClaimQualifier.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.auth.cdi; 2 | 3 | import jakarta.enterprise.util.AnnotationLiteral; 4 | 5 | import org.eclipse.microprofile.jwt.Claim; 6 | import org.eclipse.microprofile.jwt.Claims; 7 | 8 | class ClaimQualifier extends AnnotationLiteral implements Claim { 9 | private static final long serialVersionUID = 1L; 10 | private final String value; 11 | private final Claims standard; 12 | 13 | ClaimQualifier(String value, Claims standard) { 14 | this.value = value != null ? value : ""; 15 | this.standard = standard != null ? standard : Claims.UNKNOWN; 16 | } 17 | 18 | @Override 19 | public String value() { 20 | return value; 21 | } 22 | 23 | @Override 24 | public Claims standard() { 25 | return standard; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/test/java/io/smallrye/jwt/auth/cdi/CustomJWTCallerPrincipalFactoryTest.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.auth.cdi; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertTrue; 4 | 5 | import java.util.HashMap; 6 | 7 | import jakarta.annotation.Priority; 8 | import jakarta.enterprise.context.ApplicationScoped; 9 | import jakarta.enterprise.inject.Alternative; 10 | 11 | import org.jboss.weld.context.bound.BoundRequestContext; 12 | import org.jboss.weld.junit5.WeldInitiator; 13 | import org.jboss.weld.junit5.WeldJunit5Extension; 14 | import org.jboss.weld.junit5.WeldSetup; 15 | import org.junit.jupiter.api.AfterEach; 16 | import org.junit.jupiter.api.BeforeEach; 17 | import org.junit.jupiter.api.Test; 18 | import org.junit.jupiter.api.extension.ExtendWith; 19 | 20 | import io.smallrye.jwt.auth.principal.JWTAuthContextInfo; 21 | import io.smallrye.jwt.auth.principal.JWTCallerPrincipal; 22 | import io.smallrye.jwt.auth.principal.JWTCallerPrincipalFactory; 23 | import io.smallrye.jwt.auth.principal.ParseException; 24 | 25 | @ExtendWith(WeldJunit5Extension.class) 26 | class CustomJWTCallerPrincipalFactoryTest { 27 | @WeldSetup 28 | WeldInitiator weld = WeldInitiator.of(JWTCallerPrincipalFactoryProducer.class, TestFactory.class); 29 | 30 | BoundRequestContext context; 31 | 32 | @BeforeEach 33 | void setUp() { 34 | context = weld.select(BoundRequestContext.class).get(); 35 | context.associate(new HashMap<>()); 36 | // Start Request Scope 37 | context.activate(); 38 | } 39 | 40 | @AfterEach 41 | void tearDown() { 42 | // End Request Scope 43 | context.deactivate(); 44 | } 45 | 46 | @Test 47 | void jwtCallerPrincipalFactory() { 48 | JWTCallerPrincipalFactory factory = weld.select(JWTCallerPrincipalFactory.class).get(); 49 | assertTrue(factory instanceof TestFactory); 50 | } 51 | 52 | @ApplicationScoped 53 | @Alternative 54 | @Priority(1) 55 | public static class TestFactory extends JWTCallerPrincipalFactory { 56 | 57 | @Override 58 | public JWTCallerPrincipal parse(String token, JWTAuthContextInfo authContextInfo) throws ParseException { 59 | return null; 60 | } 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/test/java/io/smallrye/jwt/auth/cdi/JWTCallerPrincipalFactoryProducerTest.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.auth.cdi; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertTrue; 4 | 5 | import java.util.HashMap; 6 | 7 | import org.jboss.weld.context.bound.BoundRequestContext; 8 | import org.jboss.weld.junit5.WeldInitiator; 9 | import org.jboss.weld.junit5.WeldJunit5Extension; 10 | import org.jboss.weld.junit5.WeldSetup; 11 | import org.junit.jupiter.api.AfterEach; 12 | import org.junit.jupiter.api.BeforeEach; 13 | import org.junit.jupiter.api.Test; 14 | import org.junit.jupiter.api.extension.ExtendWith; 15 | 16 | import io.smallrye.jwt.auth.principal.DefaultJWTCallerPrincipalFactory; 17 | import io.smallrye.jwt.auth.principal.JWTCallerPrincipalFactory; 18 | 19 | @ExtendWith(WeldJunit5Extension.class) 20 | class JWTCallerPrincipalFactoryProducerTest { 21 | 22 | @WeldSetup 23 | WeldInitiator weld = WeldInitiator.of(JWTCallerPrincipalFactoryProducer.class); 24 | 25 | BoundRequestContext context; 26 | 27 | @BeforeEach 28 | void setUp() { 29 | context = weld.select(BoundRequestContext.class).get(); 30 | context.associate(new HashMap<>()); 31 | // Start Request Scope 32 | context.activate(); 33 | } 34 | 35 | @AfterEach 36 | void tearDown() { 37 | // End Request Scope 38 | context.deactivate(); 39 | } 40 | 41 | @Test 42 | void jwtCallerPrincipalFactory() { 43 | JWTCallerPrincipalFactory factory = weld.select(JWTCallerPrincipalFactory.class).get(); 44 | assertTrue(factory instanceof DefaultJWTCallerPrincipalFactory); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/test/java/io/smallrye/jwt/auth/cdi/JsonValueProducerTest.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.auth.cdi; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertNotNull; 5 | import static org.junit.jupiter.api.Assertions.assertNull; 6 | 7 | import java.util.HashMap; 8 | import java.util.Optional; 9 | 10 | import jakarta.json.JsonString; 11 | import jakarta.json.JsonValue; 12 | 13 | import org.eclipse.microprofile.jwt.Claims; 14 | import org.eclipse.microprofile.jwt.JsonWebToken; 15 | import org.jboss.weld.context.bound.BoundRequestContext; 16 | import org.jboss.weld.junit5.WeldInitiator; 17 | import org.jboss.weld.junit5.WeldJunit5Extension; 18 | import org.jboss.weld.junit5.WeldSetup; 19 | import org.junit.jupiter.api.AfterEach; 20 | import org.junit.jupiter.api.BeforeEach; 21 | import org.junit.jupiter.api.Test; 22 | import org.junit.jupiter.api.extension.ExtendWith; 23 | import org.mockito.Mock; 24 | import org.mockito.Mockito; 25 | import org.mockito.MockitoAnnotations; 26 | 27 | @ExtendWith(WeldJunit5Extension.class) 28 | class JsonValueProducerTest { 29 | @WeldSetup 30 | WeldInitiator weld = WeldInitiator.of(PrincipalProducer.class, 31 | CommonJwtProducer.class, 32 | JsonValueProducer.class); 33 | 34 | @Mock 35 | JsonWebToken jwt; 36 | 37 | BoundRequestContext context; 38 | PrincipalProducer jwtProducer; 39 | 40 | @BeforeEach 41 | void setUp() { 42 | MockitoAnnotations.initMocks(this); 43 | context = weld.select(BoundRequestContext.class).get(); 44 | context.associate(new HashMap<>()); 45 | // Start Request Scope 46 | context.activate(); 47 | } 48 | 49 | @AfterEach 50 | void tearDown() { 51 | // End Request Scope 52 | context.deactivate(); 53 | } 54 | 55 | T selectJsonValue(String name, Class type) { 56 | return weld.select(type, new ClaimQualifier(name, null)).get(); 57 | } 58 | 59 | @Test 60 | void issuerNullPointerException() { 61 | JsonString issuer = selectJsonValue("iss", JsonString.class); 62 | assertNull(issuer); 63 | } 64 | 65 | @Test 66 | void issuerInjected() { 67 | jwtProducer = weld.select(PrincipalProducer.class).get(); 68 | jwtProducer.setJsonWebToken(jwt); 69 | Mockito.when(jwt.claim(Claims.iss.name())).thenReturn(Optional.of("issuer1")); 70 | JsonString issuer = selectJsonValue("iss", JsonString.class); 71 | 72 | assertNotNull(issuer); 73 | assertEquals("issuer1", issuer.getString()); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/test/java/io/smallrye/jwt/auth/cdi/PrincipalProducerIT.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.auth.cdi; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertNotNull; 5 | import static org.junit.jupiter.api.Assertions.assertNull; 6 | 7 | import java.util.Collections; 8 | import java.util.HashMap; 9 | 10 | import org.eclipse.microprofile.jwt.JsonWebToken; 11 | import org.jboss.weld.context.bound.BoundRequestContext; 12 | import org.jboss.weld.junit5.WeldInitiator; 13 | import org.jboss.weld.junit5.WeldJunit5Extension; 14 | import org.jboss.weld.junit5.WeldSetup; 15 | import org.junit.jupiter.api.AfterEach; 16 | import org.junit.jupiter.api.BeforeEach; 17 | import org.junit.jupiter.api.Test; 18 | import org.junit.jupiter.api.extension.ExtendWith; 19 | import org.mockito.Mock; 20 | import org.mockito.Mockito; 21 | import org.mockito.MockitoAnnotations; 22 | 23 | @ExtendWith(WeldJunit5Extension.class) 24 | class PrincipalProducerIT { 25 | 26 | @WeldSetup 27 | WeldInitiator weld = WeldInitiator.of(PrincipalProducer.class); 28 | 29 | @Mock 30 | JsonWebToken jwt; 31 | 32 | BoundRequestContext context; 33 | 34 | @BeforeEach 35 | void setUp() { 36 | MockitoAnnotations.initMocks(this); 37 | context = weld.select(BoundRequestContext.class).get(); 38 | context.associate(new HashMap<>()); 39 | // Start Request Scope 40 | context.activate(); 41 | } 42 | 43 | @AfterEach 44 | void tearDown() { 45 | // End Request Scope 46 | context.deactivate(); 47 | } 48 | 49 | @Test 50 | void nullPrincipal() { 51 | JsonWebToken jwt = weld.select(JsonWebToken.class).get(); 52 | assertNotNull(jwt); 53 | assertNull(jwt.getName()); 54 | assertNull(jwt.getClaimNames()); 55 | } 56 | 57 | @Test 58 | void principalInjected() { 59 | PrincipalProducer jwtProducer = weld.select(PrincipalProducer.class).get(); 60 | Mockito.when(jwt.getName()).thenReturn("User1"); 61 | Mockito.when(jwt.getClaimNames()).thenReturn(Collections.singleton("upn")); 62 | jwtProducer.setJsonWebToken(jwt); 63 | 64 | JsonWebToken jwt = weld.select(JsonWebToken.class).get(); 65 | assertNotNull(jwt); 66 | assertEquals("User1", jwt.getName()); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/test/java/io/smallrye/jwt/auth/principal/AwsAlbKeyConfigurationValidatorTest.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.auth.principal; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertFalse; 4 | import static org.junit.jupiter.api.Assertions.assertTrue; 5 | 6 | import org.junit.jupiter.api.Test; 7 | 8 | public class AwsAlbKeyConfigurationValidatorTest { 9 | 10 | @Test 11 | void containsSubPath() { 12 | assertTrue(AwsAlbKeyConfigurationValidator 13 | .containsSubPath("https://public-keys.auth.elb.eu-central-1.amazonaws.com/keyid")); 14 | assertTrue(AwsAlbKeyConfigurationValidator 15 | .containsSubPath("https://public-keys.auth.elb.eu-central-1.amazonaws.com/index/keyid")); 16 | assertTrue(AwsAlbKeyConfigurationValidator 17 | .containsSubPath("https://public-keys.auth.elb.eu-central-1.amazonaws.com/index.html")); 18 | assertFalse( 19 | AwsAlbKeyConfigurationValidator.containsSubPath("https://public-keys.auth.elb.eu-central-1.amazonaws.com/")); 20 | assertFalse(AwsAlbKeyConfigurationValidator.containsSubPath("https://public-keys.auth.elb.eu-central-1.amazonaws.com")); 21 | } 22 | 23 | @Test 24 | void removeEndingSlash() { 25 | assertTrue(AwsAlbKeyConfigurationValidator.removeEndingSlash("key-location/keyid") 26 | .equals("key-location/keyid")); 27 | assertTrue(AwsAlbKeyConfigurationValidator.removeEndingSlash("key-location/index/keyid/") 28 | .equals("key-location/index/keyid")); 29 | assertTrue(AwsAlbKeyConfigurationValidator.removeEndingSlash("key-location/index.html/") 30 | .equals("key-location/index.html")); 31 | assertTrue(AwsAlbKeyConfigurationValidator.removeEndingSlash("key-location/") 32 | .equals("key-location")); 33 | assertTrue(AwsAlbKeyConfigurationValidator.removeEndingSlash("key-location") 34 | .equals("key-location")); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/test/java/io/smallrye/jwt/auth/principal/AwsAlbKeyResolverTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package io.smallrye.jwt.auth.principal; 18 | 19 | import static org.junit.jupiter.api.Assertions.assertTrue; 20 | import static org.mockito.Mockito.when; 21 | 22 | import java.security.Key; 23 | import java.security.interfaces.ECPublicKey; 24 | import java.util.List; 25 | import java.util.Set; 26 | 27 | import org.jose4j.http.SimpleGet; 28 | import org.jose4j.http.SimpleResponse; 29 | import org.jose4j.jwk.JsonWebKey; 30 | import org.jose4j.jws.JsonWebSignature; 31 | import org.jose4j.jwx.Headers; 32 | import org.junit.jupiter.api.Test; 33 | import org.junit.jupiter.api.extension.ExtendWith; 34 | import org.mockito.Mock; 35 | import org.mockito.Mockito; 36 | import org.mockito.junit.jupiter.MockitoExtension; 37 | 38 | import io.smallrye.jwt.algorithm.SignatureAlgorithm; 39 | 40 | @ExtendWith(MockitoExtension.class) 41 | class AwsAlbKeyResolverTest { 42 | 43 | private static final String AWS_ALB_KEY = "-----BEGIN PUBLIC KEY-----" 44 | + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjPHY1j9umvc8nZEswOzs+lPpLKLn" 45 | + "qCBqvyZGJfBlXapmtGiqYEwpIqh/lZdkr4wDii7CP1DzIUSHONbc+jufiQ==" 46 | + "-----END PUBLIC KEY-----"; 47 | 48 | @Mock 49 | JsonWebSignature signature; 50 | @Mock 51 | Headers headers; 52 | @Mock 53 | SimpleGet simpleGet; 54 | @Mock 55 | SimpleResponse simpleResponse; 56 | 57 | AwsAlbKeyResolverTest() throws Exception { 58 | 59 | } 60 | 61 | @Test 62 | void loadAwsAlbVerificationKey() throws Exception { 63 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo( 64 | "https://localhost:8080", 65 | "https://cognito-idp.eu-central-1.amazonaws.com"); 66 | contextInfo.setSignatureAlgorithm(Set.of(SignatureAlgorithm.ES256)); 67 | 68 | AwsAlbKeyResolver keyLocationResolver = new AwsAlbKeyResolver(contextInfo); 69 | keyLocationResolver = Mockito.spy(keyLocationResolver); 70 | 71 | when(keyLocationResolver.getHttpGet()).thenReturn(simpleGet); 72 | 73 | when(simpleGet.get("https://localhost:8080/c2f80c8b-c05c-4068-af14-17299f7896b1")) 74 | .thenReturn(simpleResponse); 75 | 76 | when(simpleResponse.getBody()).thenReturn(AWS_ALB_KEY); 77 | 78 | when(signature.getHeaders()).thenReturn(headers); 79 | when(headers.getStringHeaderValue(JsonWebKey.KEY_ID_PARAMETER)).thenReturn("c2f80c8b-c05c-4068-af14-17299f7896b1"); 80 | 81 | Key key = keyLocationResolver.resolveKey(signature, List.of()); 82 | assertTrue(key instanceof ECPublicKey); 83 | // Confirm the cached key is returned 84 | Key key2 = keyLocationResolver.resolveKey(signature, List.of()); 85 | assertTrue(key2 == key); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/test/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/test/resources/decryptPrivateKey.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "kty":"RSA", 3 | "kid":"key1", 4 | "n":"iJw33l1eVAsGoRlSyo-FCimeOc-AaZbzQ2iESA3Nkuo3TFb1zIkmt0kzlnWVGt48dkaIl13Vdefh9hqw_r9yNF8xZqX1fp0PnCWc5M_TX_ht5fm9y0TpbiVmsjeRMWZn4jr3DsFouxQ9aBXUJiu26V0vd2vrECeeAreFT4mtoHY13D2WVeJvboc5mEJcp50JNhxRCJ5UkY8jR_wfUk2Tzz4-fAj5xQaBccXnqJMu_1C6MjoCEiB7G1d13bVPReIeAGRKVJIF6ogoCN8JbrOhc_48lT4uyjbgnd24beatuKWodmWYhactFobRGYo5551cgMe8BoxpVQ4to30cGA0qjQ", 5 | "e":"AQAB", 6 | "d":"AvIDTlsK_priQLTwEQf5IVf2Xl638Q7dHdXyDC-oAAPmv1GcqRVH7Wm5oAPW_CZQfWhV55WRVaJzP8AhksyD5NcslH79hQZT4NT6xgApGYecrvmseuZ4dfR-e1cxXTRNBxaoXvwSiv4LuOPHmC8XGX712AhOoCGKiZp1WFqqkKwTpkgJEApJFVb-XRIKQa0YaRKpJsJ534pLMwTh7LoPLM4BCaBVbRfHzH2H5L3TSJP718kyCuxg3z2p9Y7zIOLTmgFdeR0_kd_xKUFZ2ByN3SKlC0IWlLUSiMPsGYExRpZTMZHKyD939gv-2_Z-bOYfKlYNIvAmQH_8CcX2I039LQ", 7 | "p":"104AjPaxZoi_BiMBODlChnZOvRJT071PdkeZ283uyrdW8qqKD9q8FTMgUXzKoboHtUiHbJbLOobPmPDh93839rq7dTdCNzNVOuLmE-V3_bmaShdzvxEIazwPf6AvjbEZAc-zu2RS4SNkp1LbzgSl9nINSlF7t6Lkl6T28PYULys", 8 | "q":"om5ooyzxa4ZJ-dU0ODsEb-Bmz6xwb27xF9aEhBYJprHeoNs2QM1D64_A39weD9MYwBux4-ivshCJ0dVKEbDujJRLnzf-ssrasA6CFyaaCT4DKtq1oWb9rcG-2LQd5Bm9PttrUrSUNqitr085IYikaLEz7UU6gtXPoC8UOcJ4cSc", 9 | "dp":"DeWE95Q8oweUfMrpmz1m49LjBiUWsAX6CQJaFevWy9LFk-gZ_Sf7F8sy_M93LLUbJkJGK2YYO_DTmWWC0Dyv2gb3bntglLuFdsWKYCJhekjugnW9DMoGpxU7Utt99kFGAe3sBd5V0x47sukQMt3t8FgwL2nO-G1VH8yP-8GGT_0", 10 | "dq":"TGBeE1wuqMCcSD1YMJiPnYuGzF_o_nzMIMldxj4Wi6tXY4uwFwhtx3Xw21JFUGuSV8KuAtyGwNPF-kSwb2Eiyjdw140c1jVMXzxzLy-XfoEKPDxa62niHrHba0pGQ9tWgRfrfxgqGQl3odc-peX6aL_qCsdim-KtnkSE3iPzPkE", 11 | "qi":"Jzp5KnT24y0wOoPUn_11S3ZcYl0i03dkaH4c5zR02G1MJG9K017juurx2aXVTctOzrj7O226EUiL1Qbq3QtnWFDDGY6vNZuqzJM7AMXsvp1djq_6fEVhxCIOgfJbmhb3mkG82rxn4et9o_TNr6mvEmHzG15sHbvZbAnn4GeqToY" 12 | } -------------------------------------------------------------------------------- /implementation/jwt-auth/src/test/resources/privateKey.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "kty":"oct", 3 | "k":"Fdh9u8rINxfivbrianbbVT1u232VQBZYKx1HGAGPt2I", 4 | "kid": "secretkey1" 5 | } -------------------------------------------------------------------------------- /implementation/jwt-auth/src/test/resources/privateKey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCWK8UjyoHgPTLa 3 | PLQJ8SoXLLjpHSjtLxMqmzHnFscqhTVVaDpCRCb6e3Ii/WniQTWw8RA7vf4djz4H 4 | OzvlfBFNgvUGZHXDwnmGaNVaNzpHYFMEYBhE8VGGiveSkzqeLZI+Y02G6sQAfDtN 5 | qqzM/l5QX8X34oQFaTBW1r49nftvCpITiwJvWyhkWtXP9RP8sXi1im5Vi3dhupOh 6 | nelk5n0BfajUYIbfHA6ORzjHRbt7NtBl0L2J+0/FUdHyKs6KMlFGNw8O0Dq88qnM 7 | uXoLJiewhg9332W3DFMeOveel+//cvDnRsCRtPgd4sXFPHh+UShkso7+DRsChXa6 8 | oGGQD3GdAgMBAAECggEAAjfTSZwMHwvIXIDZB+yP+pemg4ryt84iMlbofclQV8hv 9 | 6TsI4UGwcbKxFOM5VSYxbNOisb80qasb929gixsyBjsQ8284bhPJR7r0q8h1C+jY 10 | URA6S4pk8d/LmFakXwG9Tz6YPo3pJziuh48lzkFTk0xW2Dp4SLwtAptZY/+ZXyJ6 11 | 96QXDrZKSSM99Jh9s7a0ST66WoxSS0UC51ak+Keb0KJ1jz4bIJ2C3r4rYlSu4hHB 12 | Y73GfkWORtQuyUDa9yDOem0/z0nr6pp+pBSXPLHADsqvZiIhxD/O0Xk5I6/zVHB3 13 | zuoQqLERk0WvA8FXz2o8AYwcQRY2g30eX9kU4uDQAQKBgQDmf7KGImUGitsEPepF 14 | KH5yLWYWqghHx6wfV+fdbBxoqn9WlwcQ7JbynIiVx8MX8/1lLCCe8v41ypu/eLtP 15 | iY1ev2IKdrUStvYRSsFigRkuPHUo1ajsGHQd+ucTDf58mn7kRLW1JGMeGxo/t32B 16 | m96Af6AiPWPEJuVfgGV0iwg+HQKBgQCmyPzL9M2rhYZn1AozRUguvlpmJHU2DpqS 17 | 34Q+7x2Ghf7MgBUhqE0t3FAOxEC7IYBwHmeYOvFR8ZkVRKNF4gbnF9RtLdz0DMEG 18 | 5qsMnvJUSQbNB1yVjUCnDAtElqiFRlQ/k0LgYkjKDY7LfciZl9uJRl0OSYeX/qG2 19 | tRW09tOpgQKBgBSGkpM3RN/MRayfBtmZvYjVWh3yjkI2GbHA1jj1g6IebLB9SnfL 20 | WbXJErCj1U+wvoPf5hfBc7m+jRgD3Eo86YXibQyZfY5pFIh9q7Ll5CQl5hj4zc4Y 21 | b16sFR+xQ1Q9Pcd+BuBWmSz5JOE/qcF869dthgkGhnfVLt/OQzqZluZRAoGAXQ09 22 | nT0TkmKIvlza5Af/YbTqEpq8mlBDhTYXPlWCD4+qvMWpBII1rSSBtftgcgca9XLB 23 | MXmRMbqtQeRtg4u7dishZVh1MeP7vbHsNLppUQT9Ol6lFPsd2xUpJDc6BkFat62d 24 | Xjr3iWNPC9E9nhPPdCNBv7reX7q81obpeXFMXgECgYEAmk2Qlus3OV0tfoNRqNpe 25 | Mb0teduf2+h3xaI1XDIzPVtZF35ELY/RkAHlmWRT4PCdR0zXDidE67L6XdJyecSt 26 | FdOUH8z5qUraVVebRFvJqf/oGsXc4+ex1ZKUTbY0wqY1y9E39yvB3MaTmZFuuqk8 27 | f3cg+fr8aou7pr9SHhJlZCU= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/test/resources/publicCrt.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE-----\nMIIDHDCCAgSgAwIBAgIIcdNq6CqSmxgwDQYJKoZIhvcNAQEFBQAwMTEvMC0GA1UE\nAxMmc2VjdXJldG9rZW4uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wHhcNMTkw\nODE2MjEyMTAwWhcNMTkwOTAyMDkzNjAwWjAxMS8wLQYDVQQDEyZzZWN1cmV0b2tl\nbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBAOmck250iO/lgPgq8WQ7CvHUSNpyXMZPwIJ+viTBKFWtBS99\np6hUskt/L4+dq4kpGh2TdO1SroeL318sKSHnoLFKcd9e7Dmgl5a4tIccupXUjJgu\njcKj8u02FeUhrERb6scUWfdtIoEev2Fz8jrIThDFYWhqiwyXhEgiPQui41Sl23b3\ntXXoBuFHoVrbf/TneMGVDqff0jdiIKCLWF/z1f+iTbC9aDQAb/lsEnuC4/HpJLOh\nZOeYbcMcOlM+vib3bPkRXgSO0TeU+QqPbF5J+WtEtzBLQOV4MTFnULe4jaTxSZAU\nXwwbuJqPcN1P1KVZFT2WbTf2LbRdNoZ084Q4YtsCAwEAAaM4MDYwDAYDVR0TAQH/\nBAIwADAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJ\nKoZIhvcNAQEFBQADggEBACCADIWtyqY+sTXI6PKBUag2QtzyK4JMsEIixw3HPOCT\nGfJcCeTENsk4dieGGUCwkZITo8vBs7JaxpZ+xZXvNbG82S7x7NoOgDbae/OHAKYs\nSj3bKMoXUt/HhLcAUPCWf5UKg4ROaLMvi+A1rMU0tBCCLSKHjuKh5D+iKm5tA5fM\nusztqlSiIA8xAbS7UK95ZIMQBSl4XPZbcmOZUKWqWQJr5aouLqGJIoKQUMHoeqGI\nxLTEnzcr1WTdApfXJsenHSfeugJ+/BYJUXAcldxUn8PozFYoGtgrGMlI89WaXBpZ\nrsSehnsnIDqbqZaPjrSOTUVZiY+vaFmgmHtH4A339nU=\n-----END CERTIFICATE-----\n 2 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/test/resources/publicKey.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "kty":"RSA", 3 | "n":"livFI8qB4D0y2jy0CfEqFyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm-ntyIv1p4kE1sPEQO73-HY8-Bzs75XwRTYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5eUF_F9-KEBWkwVta-PZ37bwqSE4sCb1soZFrVz_UT_LF4tYpuVYt3YbqToZ3pZOZ9AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYnsIYPd99ltwxTHjr3npfv_3Lw50bAkbT4HeLFxTx4flEoZLKO_g0bAoV2uqBhkA9xnQ", 4 | "e":"AQAB", 5 | "kid": "key1" 6 | } -------------------------------------------------------------------------------- /implementation/jwt-auth/src/test/resources/publicKey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlivFI8qB4D0y2jy0CfEq 3 | Fyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm+ntyIv1p4kE1sPEQO73+HY8+Bzs75XwR 4 | TYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5e 5 | UF/F9+KEBWkwVta+PZ37bwqSE4sCb1soZFrVz/UT/LF4tYpuVYt3YbqToZ3pZOZ9 6 | AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYn 7 | sIYPd99ltwxTHjr3npfv/3Lw50bAkbT4HeLFxTx4flEoZLKO/g0bAoV2uqBhkA9x 8 | nQIDAQAB 9 | -----END RSA PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /implementation/jwt-auth/src/test/resources/token-claims.json: -------------------------------------------------------------------------------- 1 | { 2 | "iss": "https://server.example.com", 3 | "jti": "a-123", 4 | "sub": "24400320", 5 | "upn": "jdoe@example.com", 6 | "preferred_username": "jdoe", 7 | "aud": "s6BhdRkqt3", 8 | "exp": 1311281970, 9 | "iat": 1311280970, 10 | "auth_time": 1311280969, 11 | 12 | "byte": 1, 13 | "short": 9, 14 | "integer": 99, 15 | "long": 999, 16 | "float": 99.9, 17 | "double": 99.99, 18 | "boolean": true, 19 | "char": "y", 20 | "string": "string", 21 | 22 | "stringArray": [ 23 | "value0", 24 | "value1", 25 | "value2" 26 | ], 27 | "integerArray": [ 28 | 0, 29 | 1, 30 | 2, 31 | 3 32 | ], 33 | "doubleArray": [ 34 | 0.1, 35 | 1.1, 36 | 2.2, 37 | 3.3, 38 | 4.4 39 | ], 40 | "address": { 41 | "street": "street", 42 | "code": "code" 43 | }, 44 | "customObject": { 45 | "my-service": { 46 | "groups": [ 47 | "group1", 48 | "group2" 49 | ], 50 | "roles": [ 51 | "role-in-my-service" 52 | ] 53 | }, 54 | "service-B": { 55 | "roles": [ 56 | "role-in-B" 57 | ] 58 | }, 59 | "service-C": { 60 | "groups": [ 61 | "groupC", 62 | "web-tier" 63 | ] 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /implementation/jwt-build/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 4.0.0 21 | 22 | 23 | io.smallrye 24 | smallrye-jwt-implementation-parent 25 | 4.6.3-SNAPSHOT 26 | 27 | 28 | smallrye-jwt-build 29 | 30 | SmallRye: MicroProfile JWT Build Implementation 31 | 32 | 33 | 34 | jakarta.json 35 | jakarta.json-api 36 | provided 37 | 38 | 39 | jakarta.annotation 40 | jakarta.annotation-api 41 | provided 42 | 43 | 44 | org.eclipse.microprofile.config 45 | microprofile-config-api 46 | 47 | 48 | org.eclipse.microprofile.jwt 49 | microprofile-jwt-auth-api 50 | 51 | 52 | org.bitbucket.b_c 53 | jose4j 54 | 55 | 56 | io.smallrye 57 | smallrye-jwt-common 58 | 59 | 60 | org.jboss.logging 61 | jboss-logging 62 | 63 | 64 | org.jboss.logging 65 | jboss-logging-annotations 66 | 67 | 68 | org.jboss.logging 69 | jboss-logging-processor 70 | 71 | 72 | 73 | 74 | org.junit.jupiter 75 | junit-jupiter 76 | 77 | 78 | org.eclipse.parsson 79 | parsson 80 | 81 | 82 | io.smallrye.config 83 | smallrye-config 84 | 85 | 86 | org.bouncycastle 87 | bcprov-jdk15on 88 | 89 | 90 | 91 | 92 | 93 | 94 | org.apache.maven.plugins 95 | maven-surefire-plugin 96 | 97 | true 98 | 99 | 100 | 101 | org.apache.maven.plugins 102 | maven-failsafe-plugin 103 | 104 | 105 | default-integration-test 106 | 107 | integration-test 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /implementation/jwt-build/src/main/java/io/smallrye/jwt/build/JwtEncryptionException.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.build; 2 | 3 | /** 4 | * JWT Encryption Exception 5 | */ 6 | @SuppressWarnings("serial") 7 | public class JwtEncryptionException extends JwtException { 8 | public JwtEncryptionException() { 9 | } 10 | 11 | public JwtEncryptionException(String errorMessage) { 12 | super(errorMessage); 13 | } 14 | 15 | public JwtEncryptionException(Throwable t) { 16 | super(t); 17 | } 18 | 19 | public JwtEncryptionException(String errorMessage, Throwable t) { 20 | super(errorMessage, t); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /implementation/jwt-build/src/main/java/io/smallrye/jwt/build/JwtException.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.build; 2 | 3 | /** 4 | * Base JWT Exception 5 | */ 6 | @SuppressWarnings("serial") 7 | public class JwtException extends RuntimeException { 8 | public JwtException() { 9 | } 10 | 11 | public JwtException(String errorMessage) { 12 | super(errorMessage); 13 | } 14 | 15 | public JwtException(Throwable t) { 16 | super(t); 17 | } 18 | 19 | public JwtException(String errorMessage, Throwable t) { 20 | super(errorMessage, t); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /implementation/jwt-build/src/main/java/io/smallrye/jwt/build/JwtSignatureBuilder.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.build; 2 | 3 | import java.security.PublicKey; 4 | import java.security.cert.X509Certificate; 5 | import java.util.List; 6 | 7 | import io.smallrye.jwt.algorithm.SignatureAlgorithm; 8 | 9 | /** 10 | * JWT JsonWebSignature Builder. 11 | * 12 | *

13 | * JwtSignatureBuilder implementations must set the 'alg' (algorithm) header to 'RS256' 14 | * and 'typ' (token type) header to 'JWT' unless they have already been set. 15 | *

16 | * Note that JwtSignatureBuilder implementations are not expected to be thread-safe. 17 | * 18 | * @see RFC7515 19 | */ 20 | public interface JwtSignatureBuilder extends JwtSignature { 21 | 22 | /** 23 | * Set a signature algorithm. 24 | * Note that only 'RS256' (default), 'ES256' and 'HS256' algorithms must be supported. 25 | * 26 | * @since 2.1.3 27 | * 28 | * @param algorithm the signature algorithm 29 | * @return JwtSignatureBuilder 30 | */ 31 | JwtSignatureBuilder algorithm(SignatureAlgorithm algorithm); 32 | 33 | /** 34 | * Set a signature algorithm. 35 | * Note that only 'RS256' (default), 'ES256' and 'HS256' algorithms must be supported. 36 | * 37 | * @deprecated Use {@link #algorithm} 38 | * 39 | * @param algorithm the signature algorithm 40 | * @return JwtSignatureBuilder 41 | */ 42 | @Deprecated 43 | default JwtSignatureBuilder signatureAlgorithm(SignatureAlgorithm algorithm) { 44 | return algorithm(algorithm); 45 | } 46 | 47 | /** 48 | * Set a 'kid' signature key id. 49 | * 50 | * @since 2.1.3 51 | * 52 | * @param keyId the key id 53 | * @return JwtSignatureBuilder 54 | */ 55 | JwtSignatureBuilder keyId(String keyId); 56 | 57 | /** 58 | * Set a 'kid' signature key id. 59 | * 60 | * @deprecated Use {@link #keyId} 61 | * 62 | * @param keyId the key id 63 | * @return JwtSignatureBuilder 64 | */ 65 | @Deprecated 66 | default JwtSignatureBuilder signatureKeyId(String keyId) { 67 | return keyId(keyId); 68 | } 69 | 70 | /** 71 | * Set X.509 Certificate SHA-1 'x5t' thumbprint. 72 | * 73 | * @param cert the certificate 74 | * @return JwtSignatureBuilder 75 | */ 76 | JwtSignatureBuilder thumbprint(X509Certificate cert); 77 | 78 | /** 79 | * Set X.509 Certificate SHA-256 'x5t#S256' thumbprint. 80 | * 81 | * @param cert the certificate 82 | * @return JwtSignatureBuilder 83 | */ 84 | JwtSignatureBuilder thumbprintS256(X509Certificate cert); 85 | 86 | /** 87 | * Set X.509 Certificate 'x5c' chain. 88 | * 89 | * @param cert the certificate 90 | * @return JwtSignatureBuilder 91 | */ 92 | default JwtSignatureBuilder chain(X509Certificate cert) { 93 | return chain(List.of(cert)); 94 | } 95 | 96 | /** 97 | * Set X.509 Certificate 'x5c' chain. 98 | * 99 | * @param chain the certificate chain 100 | * @return JwtSignatureBuilder 101 | */ 102 | JwtSignatureBuilder chain(List chain); 103 | 104 | /** 105 | * Set JSON Web Key 'jwk' key. 106 | * 107 | * @param key the public key 108 | * @return JwtSignatureBuilder 109 | */ 110 | JwtSignatureBuilder jwk(PublicKey key); 111 | 112 | /** 113 | * Set a token type (`typ`) header. 114 | * 115 | * @param type the token type 116 | * @return JwtSignatureBuilder 117 | */ 118 | JwtSignatureBuilder type(String type); 119 | 120 | /** 121 | * Custom JWT signature header. 122 | * 123 | * If the 'alg' (algorithm) header is set with this method then it 124 | * has to match one of the {@link SignatureAlgorithm} values. 125 | * 126 | * @param name the header name 127 | * @param value the header value 128 | * @return JwtSignatureBuilder 129 | */ 130 | JwtSignatureBuilder header(String name, Object value); 131 | } 132 | -------------------------------------------------------------------------------- /implementation/jwt-build/src/main/java/io/smallrye/jwt/build/JwtSignatureException.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.build; 2 | 3 | /** 4 | * JWT Signature Exception 5 | */ 6 | @SuppressWarnings("serial") 7 | public class JwtSignatureException extends JwtException { 8 | public JwtSignatureException() { 9 | } 10 | 11 | public JwtSignatureException(String errorMessage) { 12 | super(errorMessage); 13 | } 14 | 15 | public JwtSignatureException(Throwable t) { 16 | super(t); 17 | } 18 | 19 | public JwtSignatureException(String errorMessage, Throwable t) { 20 | super(errorMessage, t); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /implementation/jwt-build/src/main/java/io/smallrye/jwt/build/impl/ImplLogging.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.build.impl; 2 | 3 | import org.jboss.logging.BasicLogger; 4 | import org.jboss.logging.Logger; 5 | import org.jboss.logging.annotations.LogMessage; 6 | import org.jboss.logging.annotations.Message; 7 | import org.jboss.logging.annotations.MessageLogger; 8 | 9 | @MessageLogger(projectCode = "SRJWT", length = 5) 10 | interface ImplLogging extends BasicLogger { 11 | ImplLogging log = Logger.getMessageLogger(ImplLogging.class, ImplLogging.class.getPackage().getName()); 12 | 13 | @LogMessage(level = Logger.Level.WARN) 14 | @Message(id = 1000, value = "%s property is deprecated and will be removed in the next major release") 15 | void deprecatedProperty(String property); 16 | } 17 | -------------------------------------------------------------------------------- /implementation/jwt-build/src/main/java/io/smallrye/jwt/build/impl/JwtProviderImpl.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.build.impl; 2 | 3 | import java.util.LinkedHashMap; 4 | import java.util.Map; 5 | 6 | import jakarta.json.JsonObject; 7 | import jakarta.json.JsonValue; 8 | 9 | import org.eclipse.microprofile.jwt.Claims; 10 | import org.eclipse.microprofile.jwt.JsonWebToken; 11 | 12 | import io.smallrye.jwt.build.JwtClaimsBuilder; 13 | import io.smallrye.jwt.build.spi.JwtProvider; 14 | 15 | /** 16 | * Default service provider for JWT Claims Builder objects. 17 | * 18 | */ 19 | public class JwtProviderImpl extends JwtProvider { 20 | 21 | /** 22 | * {@inheritDoc} 23 | */ 24 | @Override 25 | public JwtClaimsBuilder claims() { 26 | return new JwtClaimsBuilderImpl(); 27 | } 28 | 29 | /** 30 | * {@inheritDoc} 31 | */ 32 | @Override 33 | public JwtClaimsBuilder claims(Map claims) { 34 | return new JwtClaimsBuilderImpl(claims); 35 | } 36 | 37 | /** 38 | * {@inheritDoc} 39 | */ 40 | public JwtClaimsBuilder claims(JsonObject jsonObject) { 41 | Map claims = new LinkedHashMap<>(); 42 | for (Map.Entry entry : jsonObject.entrySet()) { 43 | claims.put(entry.getKey(), entry.getValue()); 44 | } 45 | return claims(claims); 46 | } 47 | 48 | /** 49 | * {@inheritDoc} 50 | */ 51 | @Override 52 | public JwtClaimsBuilder claims(String jsonLocation) { 53 | return new JwtClaimsBuilderImpl(jsonLocation); 54 | } 55 | 56 | /** 57 | * {@inheritDoc} 58 | */ 59 | @Override 60 | public JwtClaimsBuilder claimsJson(String json) { 61 | return new JwtClaimsBuilderImpl(JwtBuildUtils.parseJwtContent(json)); 62 | } 63 | 64 | /** 65 | * {@inheritDoc} 66 | */ 67 | @Override 68 | public JwtClaimsBuilder claims(JsonWebToken jwt) { 69 | Map claims = new LinkedHashMap<>(); 70 | for (String name : jwt.getClaimNames()) { 71 | if (Claims.raw_token.name().equals(name)) { 72 | continue; 73 | } 74 | claims.put(name, jwt.getClaim(name)); 75 | } 76 | return claims(claims); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /implementation/jwt-build/src/main/java/io/smallrye/jwt/build/spi/SpiMessages.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.build.spi; 2 | 3 | import org.jboss.logging.Messages; 4 | import org.jboss.logging.annotations.Cause; 5 | import org.jboss.logging.annotations.Message; 6 | import org.jboss.logging.annotations.MessageBundle; 7 | 8 | import io.smallrye.jwt.build.JwtException; 9 | 10 | @MessageBundle(projectCode = "SRJWT", length = 5) 11 | interface SpiMessages { 12 | SpiMessages msg = Messages.getBundle(SpiMessages.class); 13 | 14 | @Message(id = 4000, value = "JwtProvider %s has not been found: %s") 15 | JwtException providerNotFound(String provider, String exceptionMessage, @Cause Throwable throwable); 16 | 17 | @Message(id = 4001, value = "JwtProvider %s class could not be accessed: %s") 18 | JwtException providerClassCannotBeAccessed(String provider, String exceptionMessage, @Cause Throwable throwable); 19 | 20 | @Message(id = 4002, value = "JwtProvider %s could not be instantiated: %s") 21 | JwtException providerCannotBeInstantiated(String provider, String exceptionMessage, @Cause Throwable throwable); 22 | } 23 | -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/java/io/smallrye/jwt/build/JwtProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package io.smallrye.jwt.build; 18 | 19 | import static org.junit.jupiter.api.Assertions.assertSame; 20 | import static org.junit.jupiter.api.Assertions.assertTrue; 21 | 22 | import org.junit.jupiter.api.Test; 23 | 24 | import io.smallrye.jwt.build.impl.JwtProviderImpl; 25 | import io.smallrye.jwt.build.spi.JwtProvider; 26 | 27 | class JwtProviderTest { 28 | @Test 29 | void provider() { 30 | JwtProvider provider = JwtProvider.provider(); 31 | assertTrue(provider instanceof JwtProviderImpl); 32 | assertSame(provider, JwtProvider.provider()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/java/io/smallrye/jwt/build/JwtSignPS256Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package io.smallrye.jwt.build; 18 | 19 | import static org.junit.jupiter.api.Assertions.assertEquals; 20 | 21 | import java.io.File; 22 | import java.security.Security; 23 | 24 | import org.jose4j.jws.JsonWebSignature; 25 | import org.jose4j.jwt.JwtClaims; 26 | import org.jose4j.lang.BouncyCastleProviderHelp; 27 | import org.junit.jupiter.api.AfterAll; 28 | import org.junit.jupiter.api.BeforeAll; 29 | import org.junit.jupiter.api.Test; 30 | 31 | import io.smallrye.jwt.algorithm.SignatureAlgorithm; 32 | import io.smallrye.jwt.util.KeyUtils; 33 | 34 | class JwtSignPS256Test { 35 | @BeforeAll 36 | public static void installBouncyCastleProviderIfNeeded() { 37 | if (!isPS256Supported()) { 38 | BouncyCastleProviderHelp.enableBouncyCastleProvider(); 39 | } 40 | } 41 | 42 | @AfterAll 43 | public static void uninstallBouncyCastleProviderIfNeeded() { 44 | if (!isPS256Supported()) { 45 | Security.removeProvider("org.bouncycastle.jce.provider.BouncyCastleProvider"); 46 | } 47 | } 48 | 49 | private static boolean isPS256Supported() { 50 | for (String sigAlg : Security.getAlgorithms("Signature")) { 51 | if ("RSASSA-PSS".equalsIgnoreCase(sigAlg)) { 52 | return true; 53 | } 54 | } 55 | return false; 56 | } 57 | 58 | @Test 59 | void signClaimsPS256() throws Exception { 60 | String path = "src/test/resources/privateKey.pem"; 61 | File file = new File(path); 62 | String jwt = Jwt.claims() 63 | .claim("customClaim", "custom-value") 64 | .jws().algorithm(SignatureAlgorithm.PS256) 65 | .sign("file:" + file.getAbsolutePath()); 66 | 67 | JsonWebSignature jws = JwtSignTest.getVerifiedJws(jwt, KeyUtils.readPublicKey("/publicKey.pem")); 68 | JwtClaims claims = JwtClaims.parse(jws.getPayload()); 69 | 70 | assertEquals(4, claims.getClaimsMap().size()); 71 | JwtSignTest.checkDefaultClaimsAndHeaders(JwtSignTest.getJwsHeaders(jwt, 2), claims, "PS256", 300); 72 | 73 | assertEquals("custom-value", claims.getClaimValue("customClaim")); 74 | } 75 | 76 | @Test 77 | void signClaimsPS256Configured() throws Exception { 78 | JwtBuildConfigSource configSource = JwtSignTest.getConfigSource(); 79 | configSource.setSignatureAlgorithm("PS256"); 80 | String jwt = null; 81 | try { 82 | jwt = Jwt.claims() 83 | .claim("customClaim", "custom-value") 84 | .sign("/privateKey.pem"); 85 | } finally { 86 | configSource.setSignatureAlgorithm(null); 87 | } 88 | 89 | JsonWebSignature jws = JwtSignTest.getVerifiedJws(jwt, KeyUtils.readPublicKey("/publicKey.pem")); 90 | JwtClaims claims = JwtClaims.parse(jws.getPayload()); 91 | 92 | assertEquals(4, claims.getClaimsMap().size()); 93 | JwtSignTest.checkDefaultClaimsAndHeaders(JwtSignTest.getJwsHeaders(jwt, 2), claims, "PS256", 300); 94 | 95 | assertEquals("custom-value", claims.getClaimValue("customClaim")); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource: -------------------------------------------------------------------------------- 1 | io.smallrye.jwt.build.JwtBuildConfigSource -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/resources/certificate.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC9DCCAdygAwIBAgIJAO0Y7B7dV9KpMA0GCSqGSIb3DQEBCwUAMA8xDTALBgNV 3 | BAMMBHRlc3QwHhcNMjAwODI1MTIzOTA1WhcNMjEwODI1MTIzOTA1WjAPMQ0wCwYD 4 | VQQDDAR0ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsl8Cqii/ 5 | 4UFg5Lq3R8kZ//Wmapq4KQn4k+foEOymfUbw44E6pCU+iCK0RbyKXgTMErMN3ZFD 6 | xpoDdSeEDoS2kdlRF4XNtFG8RW6+h1wLJGRj7gi9bc0Vg5CzTGWhDvI6oT23KtUa 7 | OBjIWknZtLAR5nEJ7vMADq3QKMHcxofx1GmmAQ2NDmVQJvTfM8wV02oZ2vX6yQjB 8 | 6t3vbMyIr+h2GU8teu9v/oUf9A9R2Pm6qULSZ80qyo5BXlwwG2D4HsGCxCdg5PqK 9 | Oi9SOkvlE65eBUR8NXxwHdou+SQ/ry//MPwLSpHo9AggVEmSYlfigyVo5w1FUVo6 10 | uYUG/abuKhCSoQIDAQABo1MwUTAdBgNVHQ4EFgQUcDgMETNCuUuEGWzKoXjrvS8+ 11 | kQAwHwYDVR0jBBgwFoAUcDgMETNCuUuEGWzKoXjrvS8+kQAwDwYDVR0TAQH/BAUw 12 | AwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAH0o4kU37vc7OR/+fPQJdrBQqQaukq5ri 13 | yuMSTrU1vSizEXpd0RFE8moSks6+Vh4mEzU7zLAU54N6glcGItEmBko5xgTuQRgd 14 | b0LtR7Bu28QKfRRJxZ9GnGxinDPtFPD+7oTXZfI2Ed/RAuVlbppEBr2Pr2eO9B1x 15 | fgYJNwA1K/XA38G7njxQ/wcpgOp/iFdV7dyR6CyAtwkD92sMnEZKPVz3trBT9DFM 16 | 5mynDFn9PHYVB7R5mUjIc7C9yskHGIsqqSBAfsxUqKfCS2NlWjn4+JZ8BYPLgy6X 17 | hlGxh5zhvJPoT6J9+gA5l1Z2xMXI08ym8quIIUJNoYovSf8x4bXVjQ== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/resources/customClaim.json: -------------------------------------------------------------------------------- 1 | { 2 | "customClaim": "custom-value" 3 | } 4 | -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/resources/ecPrivateKey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgvhj6xtHJanL3yBYt 3 | vmaLQ+ZlbO/zu66oWFYjQOxfpGahRANCAATDgeiG/A6PbUUFATU+sk4CU9FAzJaK 4 | aZcf2sgdrtgxNaLGRI1IWWu/fpApXBpu/Xl9Kv0BS5awPfTIZMzcujLS 5 | -----END PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/resources/ecPublicKey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEw4HohvwOj21FBQE1PrJOAlPRQMyW 3 | immXH9rIHa7YMTWixkSNSFlrv36QKVwabv15fSr9AUuWsD30yGTM3Loy0g== 4 | -----END PUBLIC KEY----- 5 | -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/resources/edEcPrivateKey.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "kty":"OKP", 3 | "crv":"Ed25519", 4 | "d":"nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A", 5 | "x":"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" 6 | } -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/resources/edEcPublicKey.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "kty":"OKP", 3 | "crv":"Ed25519", 4 | "x":"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" 5 | } -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/resources/keystore.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smallrye/smallrye-jwt/b43b673fb4cdfb06a7a9224b0b09529a4e8d9027/implementation/jwt-build/src/test/resources/keystore.p12 -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/resources/privateEncryptionKeys.jwks: -------------------------------------------------------------------------------- 1 | { 2 | "keys": [ 3 | { 4 | "kty":"oct", 5 | "k":"Fdh9u8rINxfivbrianbbVT1u232VQBZYKx1HGAGPt2I", 6 | "kid": "secretkey1" 7 | }, 8 | { 9 | "kty":"oct", 10 | "k":"mHgOIP5oLngqXKq0123456", 11 | "kid": "secretkey3", 12 | "alg": "A128KW" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/resources/privateKey.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "kty":"oct", 3 | "k":"Fdh9u8rINxfivbrianbbVT1u232VQBZYKx1HGAGPt2I", 4 | "kid": "secretkey1" 5 | } -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/resources/privateKey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCWK8UjyoHgPTLa 3 | PLQJ8SoXLLjpHSjtLxMqmzHnFscqhTVVaDpCRCb6e3Ii/WniQTWw8RA7vf4djz4H 4 | OzvlfBFNgvUGZHXDwnmGaNVaNzpHYFMEYBhE8VGGiveSkzqeLZI+Y02G6sQAfDtN 5 | qqzM/l5QX8X34oQFaTBW1r49nftvCpITiwJvWyhkWtXP9RP8sXi1im5Vi3dhupOh 6 | nelk5n0BfajUYIbfHA6ORzjHRbt7NtBl0L2J+0/FUdHyKs6KMlFGNw8O0Dq88qnM 7 | uXoLJiewhg9332W3DFMeOveel+//cvDnRsCRtPgd4sXFPHh+UShkso7+DRsChXa6 8 | oGGQD3GdAgMBAAECggEAAjfTSZwMHwvIXIDZB+yP+pemg4ryt84iMlbofclQV8hv 9 | 6TsI4UGwcbKxFOM5VSYxbNOisb80qasb929gixsyBjsQ8284bhPJR7r0q8h1C+jY 10 | URA6S4pk8d/LmFakXwG9Tz6YPo3pJziuh48lzkFTk0xW2Dp4SLwtAptZY/+ZXyJ6 11 | 96QXDrZKSSM99Jh9s7a0ST66WoxSS0UC51ak+Keb0KJ1jz4bIJ2C3r4rYlSu4hHB 12 | Y73GfkWORtQuyUDa9yDOem0/z0nr6pp+pBSXPLHADsqvZiIhxD/O0Xk5I6/zVHB3 13 | zuoQqLERk0WvA8FXz2o8AYwcQRY2g30eX9kU4uDQAQKBgQDmf7KGImUGitsEPepF 14 | KH5yLWYWqghHx6wfV+fdbBxoqn9WlwcQ7JbynIiVx8MX8/1lLCCe8v41ypu/eLtP 15 | iY1ev2IKdrUStvYRSsFigRkuPHUo1ajsGHQd+ucTDf58mn7kRLW1JGMeGxo/t32B 16 | m96Af6AiPWPEJuVfgGV0iwg+HQKBgQCmyPzL9M2rhYZn1AozRUguvlpmJHU2DpqS 17 | 34Q+7x2Ghf7MgBUhqE0t3FAOxEC7IYBwHmeYOvFR8ZkVRKNF4gbnF9RtLdz0DMEG 18 | 5qsMnvJUSQbNB1yVjUCnDAtElqiFRlQ/k0LgYkjKDY7LfciZl9uJRl0OSYeX/qG2 19 | tRW09tOpgQKBgBSGkpM3RN/MRayfBtmZvYjVWh3yjkI2GbHA1jj1g6IebLB9SnfL 20 | WbXJErCj1U+wvoPf5hfBc7m+jRgD3Eo86YXibQyZfY5pFIh9q7Ll5CQl5hj4zc4Y 21 | b16sFR+xQ1Q9Pcd+BuBWmSz5JOE/qcF869dthgkGhnfVLt/OQzqZluZRAoGAXQ09 22 | nT0TkmKIvlza5Af/YbTqEpq8mlBDhTYXPlWCD4+qvMWpBII1rSSBtftgcgca9XLB 23 | MXmRMbqtQeRtg4u7dishZVh1MeP7vbHsNLppUQT9Ol6lFPsd2xUpJDc6BkFat62d 24 | Xjr3iWNPC9E9nhPPdCNBv7reX7q81obpeXFMXgECgYEAmk2Qlus3OV0tfoNRqNpe 25 | Mb0teduf2+h3xaI1XDIzPVtZF35ELY/RkAHlmWRT4PCdR0zXDidE67L6XdJyecSt 26 | FdOUH8z5qUraVVebRFvJqf/oGsXc4+ex1ZKUTbY0wqY1y9E39yvB3MaTmZFuuqk8 27 | f3cg+fr8aou7pr9SHhJlZCU= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/resources/privateKey2.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCyXwKqKL/hQWDk 3 | urdHyRn/9aZqmrgpCfiT5+gQ7KZ9RvDjgTqkJT6IIrRFvIpeBMwSsw3dkUPGmgN1 4 | J4QOhLaR2VEXhc20UbxFbr6HXAskZGPuCL1tzRWDkLNMZaEO8jqhPbcq1Ro4GMha 5 | Sdm0sBHmcQnu8wAOrdAowdzGh/HUaaYBDY0OZVAm9N8zzBXTahna9frJCMHq3e9s 6 | zIiv6HYZTy1672/+hR/0D1HY+bqpQtJnzSrKjkFeXDAbYPgewYLEJ2Dk+oo6L1I6 7 | S+UTrl4FRHw1fHAd2i75JD+vL/8w/AtKkej0CCBUSZJiV+KDJWjnDUVRWjq5hQb9 8 | pu4qEJKhAgMBAAECggEAJvBs4X7B3MfsAiLszgQN4/3ZlZ4vI+5kUM2osMEo22J4 9 | RgI5Lgpfa1LALhUp07qSXmauWTdUJ3AJ3zKANrcsMAzUEiGItZu+UR4LA/vJBunP 10 | kvBfgi/qSW12ZvAsx9mDiR2y9evNrH9khalnmHVzgu4ccAimc43oSm1/5+tXlLoZ 11 | 1QK/FohxBxAshtuDHGs8yKUL0jpv7dOrjhCj2ibmPYe6AUk9F61sVWO0/i0Q8UAO 12 | cYT3L5nCS5WnLhdCdYpIJJ7xl2PrVE/BAD+JEG5uCOYfVeYh+iCZVfpX17ryfNNU 13 | aBtyxKEGVtHbje3mO86mYN3noaS0w/zpUjBPgV+KEQKBgQDsp6VTmDIqHFTp2cC2 14 | yrDMxRznif92EGv7ccJDZtbTC37mAuf2J7x5b6AiE1EfxEXyGYzSk99sCns+GbL1 15 | EHABUt5pimDCl33b6XvuccQNpnJ0MfM5eRX9Ogyt/OKdDRnQsvrTPNCWOyJjvG01 16 | HQM4mfxaBBnxnvl5meH2pyG/ZQKBgQDA87DnyqEFhTDLX5c1TtwHSRj2xeTPGKG0 17 | GyxOJXcxR8nhtY9ee0kyLZ14RytnOxKarCFgYXeG4IoGEc/I42WbA4sq88tZcbe4 18 | IJkdX0WLMqOTdMrdx9hMU1ytKVUglUJZBVm7FaTQjA+ArMwqkXAA5HBMtArUsfJK 19 | Ut3l0hMIjQKBgQDS1vmAZJQs2Fj+jzYWpLaneOWrk1K5yR+rQUql6jVyiUdhfS1U 20 | LUrJlh3Avh0EhEUc0I6Z/YyMITpztUmu9BoV09K7jMFwHK/RAU+cvFbDIovN4cKk 21 | bbCdjt5FFIyBB278dLjrAb+EWOLmoLVbIKICB47AU+8ZSV1SbTrYGUcD0QKBgQCA 22 | liZv4na6sg9ZiUPAr+QsKserNSiN5zFkULOPBKLRQbFFbPS1l12pRgLqNCu1qQV1 23 | 9H5tt6arSRpSfy5FB14gFxV4s23yFrnDyF2h2GsFH+MpEq1bbaI1A10AvUnQ5AeK 24 | QemRpxPmM2DldMK/H5tPzO0WAOoy4r/ATkc4sG4kxQKBgBL9neT0TmJtxlYGzjNc 25 | jdJXs3Q91+nZt3DRMGT9s0917SuP77+FdJYocDiH1rVa9sGG8rkh1jTdqliAxDXw 26 | Im5IGS/0OBnkaN1nnGDk5yTiYxOutC5NSj7ecI5Erud8swW6iGqgz2ioFpGxxIYq 27 | RlgTv/6mVt41KALfKrYIkVLw 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/resources/privateKeyA128KW.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "kty":"oct", 3 | "k":"mHgOIP5oLngqXKq0123456", 4 | "kid": "secretkey3", 5 | "alg": "A128KW" 6 | } -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/resources/privateKeyHS512.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "kty":"oct", 3 | "k":"mHgOIP5oLngqXKq0jo4AkG_I0aY0nRIgAfuB8p-MW9zvxTpW9GPapkIdNcHxe5Y1lCnfVWSePazRaePg2uf9Sg", 4 | "kid": "secretkey2", 5 | "alg": "HS512" 6 | } -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/resources/privateSigningKeys.jwks: -------------------------------------------------------------------------------- 1 | { 2 | "keys": [ 3 | { 4 | "kty":"oct", 5 | "k":"Fdh9u8rINxfivbrianbbVT1u232VQBZYKx1HGAGPt2I", 6 | "kid": "secretkey1" 7 | }, 8 | { 9 | "kty":"oct", 10 | "k":"mHgOIP5oLngqXKq0jo4AkG_I0aY0nRIgAfuB8p-MW9zvxTpW9GPapkIdNcHxe5Y1lCnfVWSePazRaePg2uf9Sg", 11 | "kid": "secretkey2", 12 | "alg": "HS512" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/resources/publicKey.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "kty":"RSA", 3 | "n":"livFI8qB4D0y2jy0CfEqFyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm-ntyIv1p4kE1sPEQO73-HY8-Bzs75XwRTYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5eUF_F9-KEBWkwVta-PZ37bwqSE4sCb1soZFrVz_UT_LF4tYpuVYt3YbqToZ3pZOZ9AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYnsIYPd99ltwxTHjr3npfv_3Lw50bAkbT4HeLFxTx4flEoZLKO_g0bAoV2uqBhkA9xnQ", 4 | "e":"AQAB", 5 | "kid": "key1" 6 | } -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/resources/publicKey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlivFI8qB4D0y2jy0CfEq 3 | Fyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm+ntyIv1p4kE1sPEQO73+HY8+Bzs75XwR 4 | TYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5e 5 | UF/F9+KEBWkwVta+PZ37bwqSE4sCb1soZFrVz/UT/LF4tYpuVYt3YbqToZ3pZOZ9 6 | AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYn 7 | sIYPd99ltwxTHjr3npfv/3Lw50bAkbT4HeLFxTx4flEoZLKO/g0bAoV2uqBhkA9x 8 | nQIDAQAB 9 | -----END RSA PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /implementation/jwt-build/src/test/resources/token.json: -------------------------------------------------------------------------------- 1 | { 2 | "iss": "https://server.example.com", 3 | "jti": "a-123", 4 | "sub": "24400320", 5 | "upn": "jdoe@example.com", 6 | "preferred_username": "jdoe", 7 | "aud": "s6BhdRkqt3", 8 | "exp": 1311281970, 9 | "iat": 1311280970, 10 | "auth_time": 1311280969 11 | } 12 | -------------------------------------------------------------------------------- /implementation/jwt-cdi-extension/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 4.0.0 21 | 22 | 23 | io.smallrye 24 | smallrye-jwt-implementation-parent 25 | 4.6.3-SNAPSHOT 26 | 27 | 28 | smallrye-jwt-cdi-extension 29 | 30 | SmallRye: MicroProfile JWT CDI Extension Implementation 31 | 32 | 33 | 34 | jakarta.enterprise 35 | jakarta.enterprise.cdi-api 36 | provided 37 | 38 | 39 | jakarta.annotation 40 | jakarta.annotation-api 41 | provided 42 | 43 | 44 | jakarta.servlet 45 | jakarta.servlet-api 46 | provided 47 | 48 | 49 | jakarta.json 50 | jakarta.json-api 51 | provided 52 | 53 | 54 | jakarta.security.enterprise 55 | jakarta.security.enterprise-api 56 | provided 57 | 58 | 59 | io.smallrye 60 | smallrye-jwt 61 | 62 | 63 | io.smallrye 64 | smallrye-jwt-jaxrs 65 | 66 | 67 | io.smallrye 68 | smallrye-jwt-http-mechanism 69 | 70 | 71 | org.jboss.logging 72 | jboss-logging 73 | 74 | 75 | org.jboss.logging 76 | jboss-logging-annotations 77 | 78 | 79 | org.jboss.logging 80 | jboss-logging-processor 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /implementation/jwt-http-mechanism/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 4.0.0 21 | 22 | 23 | io.smallrye 24 | smallrye-jwt-implementation-parent 25 | 4.6.3-SNAPSHOT 26 | 27 | 28 | smallrye-jwt-http-mechanism 29 | 30 | SmallRye: MicroProfile JWT HTTP Mechanism Implementation 31 | 32 | 33 | 34 | jakarta.enterprise 35 | jakarta.enterprise.cdi-api 36 | provided 37 | 38 | 39 | jakarta.annotation 40 | jakarta.annotation-api 41 | provided 42 | 43 | 44 | jakarta.servlet 45 | jakarta.servlet-api 46 | provided 47 | 48 | 49 | jakarta.json 50 | jakarta.json-api 51 | provided 52 | 53 | 54 | jakarta.security.enterprise 55 | jakarta.security.enterprise-api 56 | provided 57 | 58 | 59 | io.smallrye 60 | smallrye-jwt 61 | 62 | 63 | org.jboss.logging 64 | jboss-logging 65 | 66 | 67 | org.jboss.logging 68 | jboss-logging-annotations 69 | 70 | 71 | org.jboss.logging 72 | jboss-logging-processor 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /implementation/jwt-http-mechanism/src/main/java/io/smallrye/jwt/auth/mechanism/MechanismLogging.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.auth.mechanism; 2 | 3 | import org.jboss.logging.BasicLogger; 4 | import org.jboss.logging.Logger; 5 | import org.jboss.logging.annotations.Cause; 6 | import org.jboss.logging.annotations.LogMessage; 7 | import org.jboss.logging.annotations.Message; 8 | import org.jboss.logging.annotations.MessageLogger; 9 | 10 | @MessageLogger(projectCode = "SRJWT", length = 5) 11 | interface MechanismLogging extends BasicLogger { 12 | MechanismLogging log = Logger.getMessageLogger(MechanismLogging.class, MechanismLogging.class.getPackage().getName()); 13 | 14 | @LogMessage(level = Logger.Level.DEBUG) 15 | @Message(id = 11000, value = "Success") 16 | void success(); 17 | 18 | @LogMessage(level = Logger.Level.DEBUG) 19 | @Message(id = 11001, value = "Unable to validate bearer token") 20 | void unableToValidateBearerToken(@Cause Throwable throwable); 21 | 22 | @LogMessage(level = Logger.Level.DEBUG) 23 | @Message(id = 11002, value = "No usable bearer token was found in the request, continuing unauthenticated") 24 | void noUsableBearerTokenFound(); 25 | 26 | @LogMessage(level = Logger.Level.DEBUG) 27 | @Message(id = 11003, value = "Failed to resolve the key. Either corrupt or unavailable.") 28 | void noUsableKey(); 29 | 30 | @LogMessage(level = Logger.Level.DEBUG) 31 | @Message(id = 11004, value = "JWK set does not contain provided token 'kid'") 32 | void kidNotInJWkSet(); 33 | } 34 | -------------------------------------------------------------------------------- /implementation/jwt-jaxrs/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 4.0.0 21 | 22 | 23 | io.smallrye 24 | smallrye-jwt-implementation-parent 25 | 4.6.3-SNAPSHOT 26 | 27 | 28 | smallrye-jwt-jaxrs 29 | 30 | SmallRye: MicroProfile JWT JAX-RS Implementation 31 | 32 | 33 | 34 | jakarta.enterprise 35 | jakarta.enterprise.cdi-api 36 | provided 37 | 38 | 39 | jakarta.annotation 40 | jakarta.annotation-api 41 | provided 42 | 43 | 44 | jakarta.servlet 45 | jakarta.servlet-api 46 | provided 47 | 48 | 49 | jakarta.ws.rs 50 | jakarta.ws.rs-api 51 | provided 52 | 53 | 54 | jakarta.json 55 | jakarta.json-api 56 | provided 57 | 58 | 59 | jakarta.security.enterprise 60 | jakarta.security.enterprise-api 61 | provided 62 | 63 | 64 | 65 | io.smallrye 66 | smallrye-jwt 67 | 68 | 69 | 70 | org.jboss.logging 71 | jboss-logging 72 | 73 | 74 | org.jboss.logging 75 | jboss-logging-annotations 76 | 77 | 78 | org.jboss.logging 79 | jboss-logging-processor 80 | 81 | 82 | 83 | 84 | 85 | 86 | org.apache.maven.plugins 87 | maven-surefire-plugin 88 | 89 | true 90 | 91 | 92 | 93 | org.apache.maven.plugins 94 | maven-failsafe-plugin 95 | 96 | 97 | default-integration-test 98 | 99 | integration-test 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /implementation/jwt-jaxrs/src/main/java/io/smallrye/jwt/auth/jaxrs/DenyAllFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package io.smallrye.jwt.auth.jaxrs; 18 | 19 | import jakarta.annotation.Priority; 20 | import jakarta.ws.rs.ForbiddenException; 21 | import jakarta.ws.rs.Priorities; 22 | import jakarta.ws.rs.container.ContainerRequestContext; 23 | import jakarta.ws.rs.container.ContainerRequestFilter; 24 | 25 | /** 26 | * @author Michal Szynkiewicz, michal.l.szynkiewicz@gmail.com 27 | *
28 | * Date: 6/12/18 29 | */ 30 | @Priority(Priorities.AUTHORIZATION) 31 | public class DenyAllFilter implements ContainerRequestFilter { 32 | 33 | @Override 34 | public void filter(ContainerRequestContext requestContext) { 35 | throw new ForbiddenException(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /implementation/jwt-jaxrs/src/main/java/io/smallrye/jwt/auth/jaxrs/JAXRSLogging.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.auth.jaxrs; 2 | 3 | import org.jboss.logging.BasicLogger; 4 | import org.jboss.logging.Logger; 5 | import org.jboss.logging.annotations.Cause; 6 | import org.jboss.logging.annotations.LogMessage; 7 | import org.jboss.logging.annotations.Message; 8 | import org.jboss.logging.annotations.MessageLogger; 9 | 10 | @MessageLogger(projectCode = "SRJWT", length = 5) 11 | interface JAXRSLogging extends BasicLogger { 12 | JAXRSLogging log = Logger.getMessageLogger(JAXRSLogging.class, JAXRSLogging.class.getPackage().getName()); 13 | 14 | @LogMessage(level = Logger.Level.DEBUG) 15 | @Message(id = 10000, value = "Success") 16 | void success(); 17 | 18 | @LogMessage(level = Logger.Level.DEBUG) 19 | @Message(id = 10001, value = "Unable to validate bearer token") 20 | void unableToValidateBearerToken(@Cause Throwable throwable); 21 | 22 | @LogMessage(level = Logger.Level.DEBUG) 23 | @Message(id = 10002, value = "Failed to resolve the key. Either corrupt or unavailable.") 24 | void noUsableKey(); 25 | 26 | @LogMessage(level = Logger.Level.DEBUG) 27 | @Message(id = 10003, value = "EE Security is not in use, %s has been registered") 28 | void eeSecurityNotInUseButRegistered(String authenticationFilterName); 29 | 30 | @LogMessage(level = Logger.Level.DEBUG) 31 | @Message(id = 10004, value = "MP-JWT LoginConfig present, %s is enabled") 32 | void mpJWTLoginConfigPresent(String className); 33 | 34 | @LogMessage(level = Logger.Level.INFO) 35 | @Message(id = 10005, value = "LoginConfig not found on Application class, %s will not be enabled") 36 | void mpJWTLoginConfigNotFound(String className); 37 | 38 | @LogMessage(level = Logger.Level.DEBUG) 39 | @Message(id = 10006, value = "An invalid JWT was sent to an unauthenticated endpoint") 40 | void invalidJWTSentToUnauthenticatedEndpoint(); 41 | } 42 | -------------------------------------------------------------------------------- /implementation/jwt-jaxrs/src/main/java/io/smallrye/jwt/auth/jaxrs/JAXRSMessages.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.auth.jaxrs; 2 | 3 | import java.lang.annotation.Annotation; 4 | import java.util.Collection; 5 | 6 | import org.jboss.logging.Messages; 7 | import org.jboss.logging.annotations.Message; 8 | import org.jboss.logging.annotations.MessageBundle; 9 | import org.jboss.logging.annotations.Transform; 10 | 11 | @MessageBundle(projectCode = "SRJWT", length = 5) 12 | interface JAXRSMessages { 13 | JAXRSMessages msg = Messages.getBundle(JAXRSMessages.class); 14 | 15 | @Message(id = 9000, value = "Duplicate MicroProfile JWT annotations found on %s. Expected at most 1 annotation, found: %d") 16 | IllegalStateException duplicateJWTAnnotationsFound(String annotationPlacementDescriptor, 17 | @Transform(Transform.TransformType.SIZE) Collection annotations); 18 | } 19 | -------------------------------------------------------------------------------- /implementation/jwt-jaxrs/src/main/java/io/smallrye/jwt/auth/jaxrs/JWTSecurityContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package io.smallrye.jwt.auth.jaxrs; 18 | 19 | import java.security.Principal; 20 | 21 | import jakarta.ws.rs.core.SecurityContext; 22 | 23 | import org.eclipse.microprofile.jwt.JsonWebToken; 24 | 25 | /** 26 | * A delegating JAX-RS SecurityContext prototype that provides access to the JWTCallerPrincipal 27 | * TODO 28 | */ 29 | public class JWTSecurityContext implements SecurityContext { 30 | private SecurityContext delegate; 31 | private JsonWebToken principal; 32 | 33 | JWTSecurityContext(SecurityContext delegate, JsonWebToken principal) { 34 | this.delegate = delegate; 35 | this.principal = principal; 36 | } 37 | 38 | @Override 39 | public Principal getUserPrincipal() { 40 | return principal; 41 | } 42 | 43 | @Override 44 | public boolean isUserInRole(String role) { 45 | return principal.getGroups().contains(role); 46 | } 47 | 48 | @Override 49 | public boolean isSecure() { 50 | return delegate.isSecure(); 51 | } 52 | 53 | @Override 54 | public String getAuthenticationScheme() { 55 | return delegate.getAuthenticationScheme(); 56 | } 57 | } -------------------------------------------------------------------------------- /implementation/jwt-jaxrs/src/main/java/io/smallrye/jwt/auth/jaxrs/RolesAllowedFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package io.smallrye.jwt.auth.jaxrs; 18 | 19 | import static java.util.Arrays.asList; 20 | 21 | import java.util.HashSet; 22 | import java.util.Set; 23 | 24 | import jakarta.annotation.Priority; 25 | import jakarta.ws.rs.ForbiddenException; 26 | import jakarta.ws.rs.NotAuthorizedException; 27 | import jakarta.ws.rs.Priorities; 28 | import jakarta.ws.rs.container.ContainerRequestContext; 29 | import jakarta.ws.rs.container.ContainerRequestFilter; 30 | import jakarta.ws.rs.core.SecurityContext; 31 | 32 | /** 33 | * @author Michal Szynkiewicz, michal.l.szynkiewicz@gmail.com 34 | *
35 | * Date: 6/12/18 36 | */ 37 | @Priority(Priorities.AUTHORIZATION) 38 | public class RolesAllowedFilter implements ContainerRequestFilter { 39 | 40 | private final Set allowedRoles; 41 | private final boolean allRolesAllowed; 42 | 43 | public RolesAllowedFilter(String[] allowedRoles) { 44 | this.allowedRoles = new HashSet<>(asList(allowedRoles)); 45 | this.allRolesAllowed = this.allowedRoles.stream().anyMatch("*"::equals); 46 | } 47 | 48 | @Override 49 | public void filter(ContainerRequestContext requestContext) { 50 | SecurityContext securityContext = requestContext.getSecurityContext(); 51 | boolean isForbidden; 52 | if (allRolesAllowed) { 53 | isForbidden = securityContext.getUserPrincipal() == null; 54 | } else { 55 | isForbidden = allowedRoles.stream().noneMatch(securityContext::isUserInRole); 56 | } 57 | if (isForbidden) { 58 | if (requestContext.getSecurityContext().getUserPrincipal() == null) { 59 | throw new NotAuthorizedException("Bearer"); 60 | } else { 61 | throw new ForbiddenException(); 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /implementation/jwt-jaxrs/src/main/java/io/smallrye/jwt/auth/jaxrs/SmallRyeJWTAuthJaxRsFeature.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.jwt.auth.jaxrs; 17 | 18 | import jakarta.ws.rs.core.Application; 19 | import jakarta.ws.rs.core.Context; 20 | import jakarta.ws.rs.core.Feature; 21 | import jakarta.ws.rs.core.FeatureContext; 22 | 23 | import org.eclipse.microprofile.auth.LoginConfig; 24 | 25 | /** 26 | * JAX-RS Feature to support JWT authentication and authorization filters, This feature must 27 | * be enabled by client applications by using the 28 | * {@link Application#getClasses()} method or via another feature. 29 | * 30 | * @author Michael Edgar {@literal } 31 | */ 32 | public class SmallRyeJWTAuthJaxRsFeature implements Feature { 33 | 34 | @Context 35 | private Application restApplication; 36 | 37 | @Override 38 | public boolean configure(FeatureContext context) { 39 | boolean enabled = mpJwtEnabled(); 40 | 41 | if (enabled) { 42 | context.register(JWTAuthorizationFilterRegistrar.class); 43 | 44 | context.register(JWTAuthenticationFilter.class); 45 | 46 | JAXRSLogging.log.mpJWTLoginConfigPresent(getClass().getSimpleName()); 47 | } else { 48 | JAXRSLogging.log.mpJWTLoginConfigNotFound(getClass().getSimpleName()); 49 | } 50 | 51 | return enabled; 52 | } 53 | 54 | boolean mpJwtEnabled() { 55 | boolean enabled = false; 56 | 57 | if (restApplication != null) { 58 | Class applicationClass = restApplication.getClass(); 59 | 60 | if (applicationClass.isAnnotationPresent(LoginConfig.class)) { 61 | LoginConfig config = applicationClass.getAnnotation(LoginConfig.class); 62 | enabled = "MP-JWT".equals(config.authMethod()); 63 | } 64 | } 65 | 66 | return enabled; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /implementation/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 4.0.0 20 | 21 | 22 | io.smallrye 23 | smallrye-jwt-parent 24 | 4.6.3-SNAPSHOT 25 | 26 | 27 | pom 28 | smallrye-jwt-implementation-parent 29 | SmallRye: MicroProfile JWT - Implementation Parent 30 | 31 | 32 | common 33 | jwt-auth 34 | jwt-jaxrs 35 | jwt-http-mechanism 36 | jwt-cdi-extension 37 | jwt-build 38 | 39 | 40 | -------------------------------------------------------------------------------- /message-ranges.txt: -------------------------------------------------------------------------------- 1 | # This document is intended to establish the ranges for message IDs in the various sub-projects. 2 | 3 | # Range = owner 4 | 5 | 00000-00999 = smallrye-jwt [io.smallrye.jwt] (messages) 6 | 7 | 01000-01999 = smallrye-jwt [io.smallrye.jwt] (logging) 8 | 9 | 02000-02999 = smallrye-jwt [io.smallrye.jwt.config] (messages) 10 | 11 | 03000-03999 = smallrye-jwt [io.smallrye.jwt.config] (logging) 12 | 13 | 04000-04999 = smallrye-jwt [io.smallrye.jwt.build.spi] (messages) 14 | 15 | 05000-05999 = smallrye-jwt [io.smallrye.jwt.build.impl] (messages) 16 | 17 | 06000-06999 = smallrye-jwt [io.smallrye.jwt.auth] (logging) 18 | 19 | 07000-07999 = smallrye-jwt [io.smallrye.jwt.auth.principal] (messages) 20 | 21 | 08000-08999 = smallrye-jwt [io.smallrye.jwt.auth.principal] (logging) 22 | 23 | 09000-09999 = smallrye-jwt [io.smallrye.jwt.auth.jaxrs] (messages) 24 | 25 | 10000-10999 = smallrye-jwt [io.smallrye.jwt.auth.jaxrs] (logging) 26 | 27 | 11000-11999 = smallrye-jwt [io.smallrye.jwt.auth.mechanism] (logging) 28 | 29 | 12000-12999 = smallrye-jwt [io.smallrye.jwt.auth.cdi] (logging) 30 | 31 | 13000-13999 = smallrye-jwt [io.smallrye.jwt.auth.cdi] (messages) 32 | 33 | 14000-14999 = 34 | 35 | 15000-15999 = 36 | 37 | 16000-16999 = 38 | 39 | 17000-17999 = 40 | 41 | 18000-18999 = 42 | 43 | 19000-19999 = -------------------------------------------------------------------------------- /release/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.smallrye 7 | smallrye-jwt-parent 8 | 4.6.3-SNAPSHOT 9 | 10 | 11 | smallrye-jwt-release 12 | 13 | Empty Release Project to Avoid Maven Bug 14 | Empty Release Project to Avoid Maven Bug 15 | 16 | pom 17 | 18 | 19 | -------------------------------------------------------------------------------- /testsuite/basic/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 4.0.0 21 | 22 | 23 | io.smallrye 24 | smallrye-jwt-testsuite-parent 25 | 4.6.3-SNAPSHOT 26 | 27 | 28 | smallrye-jwt-testsuite-basic 29 | 30 | SmallRye: MicroProfile JWT Basic Testsuite 31 | 32 | 33 | 34 | org.junit.jupiter 35 | junit-jupiter 36 | 37 | 38 | io.smallrye 39 | smallrye-jwt 40 | test 41 | 42 | 43 | io.smallrye 44 | smallrye-jwt-build 45 | test 46 | 47 | 48 | jakarta.enterprise 49 | jakarta.enterprise.cdi-api 50 | test 51 | 52 | 53 | 54 | 55 | org.eclipse.microprofile.jwt 56 | microprofile-jwt-auth-tck 57 | test 58 | 59 | 60 | javax.inject 61 | javax.inject 62 | 63 | 64 | 65 | 66 | org.eclipse.microprofile.jwt 67 | microprofile-jwt-auth-tck 68 | test-jar 69 | test 70 | 71 | 72 | io.smallrye.config 73 | smallrye-config 74 | 75 | 76 | org.eclipse.parsson 77 | parsson 78 | 79 | 80 | 81 | 82 | 83 | 84 | org.apache.maven.plugins 85 | maven-surefire-plugin 86 | 87 | true 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/java/io/smallrye/jwt/TestTokenRequireSub.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt; 2 | 3 | import static org.eclipse.microprofile.jwt.tck.TCKConstants.TEST_ISSUER; 4 | import static org.junit.jupiter.api.Assertions.assertEquals; 5 | import static org.junit.jupiter.api.Assertions.assertNull; 6 | import static org.junit.jupiter.api.Assertions.assertThrows; 7 | 8 | import java.security.interfaces.RSAPublicKey; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | import org.eclipse.microprofile.jwt.JsonWebToken; 13 | import org.eclipse.microprofile.jwt.tck.util.SignatureAlgorithm; 14 | import org.eclipse.microprofile.jwt.tck.util.TokenUtils; 15 | import org.junit.jupiter.api.Test; 16 | 17 | import io.smallrye.jwt.auth.principal.JWTAuthContextInfo; 18 | import io.smallrye.jwt.auth.principal.JWTCallerPrincipalFactory; 19 | import io.smallrye.jwt.auth.principal.ParseException; 20 | 21 | class TestTokenRequireSub { 22 | @Test 23 | void defaultSubAvailable() throws Exception { 24 | Map timeClaims = new HashMap<>(); 25 | String token = TokenUtils.signClaims("/Token1.json", SignatureAlgorithm.RS256, null, timeClaims); 26 | RSAPublicKey publicKey = TokenUtils.readPublicKey("/publicKey.pem"); 27 | if (publicKey == null) { 28 | throw new IllegalStateException("Failed to load /publicKey.pem resource"); 29 | } 30 | 31 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo(publicKey, TEST_ISSUER); 32 | JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance(); 33 | JsonWebToken jwt = factory.parse(token, contextInfo); 34 | String sub = jwt.getSubject(); 35 | assertEquals(sub, "24400320"); 36 | } 37 | 38 | @Test 39 | void defaultSubNotAvailable() throws Exception { 40 | Map timeClaims = new HashMap<>(); 41 | String token = TokenUtils.signClaims("/TokenSubPath.json", SignatureAlgorithm.RS256, null, timeClaims); 42 | RSAPublicKey publicKey = TokenUtils.readPublicKey("/publicKey.pem"); 43 | if (publicKey == null) { 44 | throw new IllegalStateException("Failed to load /publicKey.pem resource"); 45 | } 46 | 47 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo(publicKey, TEST_ISSUER); 48 | JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance(); 49 | assertThrows(ParseException.class, () -> factory.parse(token, contextInfo)); 50 | } 51 | 52 | @Test 53 | void noSubValidation() throws Exception { 54 | Map timeClaims = new HashMap<>(); 55 | String token = TokenUtils.signClaims("/TokenSubPath.json", SignatureAlgorithm.RS256, null, timeClaims); 56 | RSAPublicKey publicKey = TokenUtils.readPublicKey("/publicKey.pem"); 57 | if (publicKey == null) { 58 | throw new IllegalStateException("Failed to load /publicKey.pem resource"); 59 | } 60 | 61 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo(publicKey, TEST_ISSUER); 62 | contextInfo.setRequireNamedPrincipal(false); 63 | JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance(); 64 | JsonWebToken jwt = factory.parse(token, contextInfo); 65 | String sub = jwt.getSubject(); 66 | assertNull(sub); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/java/io/smallrye/jwt/TestTokenRequiredClaims.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt; 2 | 3 | import static java.util.stream.Collectors.toSet; 4 | import static org.eclipse.microprofile.jwt.tck.TCKConstants.TEST_ISSUER; 5 | import static org.junit.jupiter.api.Assertions.assertThrows; 6 | import static org.junit.jupiter.api.Assertions.assertTrue; 7 | 8 | import java.security.interfaces.RSAPublicKey; 9 | import java.util.Collections; 10 | import java.util.stream.Stream; 11 | 12 | import org.eclipse.microprofile.jwt.tck.util.TokenUtils; 13 | import org.jose4j.jwt.consumer.InvalidJwtException; 14 | import org.junit.jupiter.api.Test; 15 | 16 | import io.smallrye.jwt.auth.principal.JWTAuthContextInfo; 17 | import io.smallrye.jwt.auth.principal.JWTCallerPrincipalFactory; 18 | import io.smallrye.jwt.auth.principal.ParseException; 19 | 20 | class TestTokenRequiredClaims { 21 | @Test 22 | void base() throws Exception { 23 | String token = TokenUtils.signClaims("/Token1.json"); 24 | RSAPublicKey publicKey = TokenUtils.readPublicKey("/publicKey.pem"); 25 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo(publicKey, TEST_ISSUER); 26 | JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance(); 27 | factory.parse(token, contextInfo); 28 | } 29 | 30 | @Test 31 | void missingRequiredClaim() throws Exception { 32 | String token = TokenUtils.signClaims("/Token1.json"); 33 | RSAPublicKey publicKey = TokenUtils.readPublicKey("/publicKey.pem"); 34 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo(publicKey, TEST_ISSUER); 35 | contextInfo.setRequiredClaims(Collections.singleton("something")); 36 | JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance(); 37 | 38 | final ParseException exception = assertThrows(ParseException.class, () -> factory.parse(token, contextInfo)); 39 | assertTrue(exception.getCause() instanceof InvalidJwtException); 40 | } 41 | 42 | @Test 43 | void missingRequiredClaims() throws Exception { 44 | String token = TokenUtils.signClaims("/Token1.json"); 45 | RSAPublicKey publicKey = TokenUtils.readPublicKey("/publicKey.pem"); 46 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo(publicKey, TEST_ISSUER); 47 | contextInfo.setRequiredClaims(Stream.of("something", "else").collect(toSet())); 48 | JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance(); 49 | 50 | final ParseException exception = assertThrows(ParseException.class, () -> factory.parse(token, contextInfo)); 51 | assertTrue(exception.getCause() instanceof InvalidJwtException); 52 | } 53 | 54 | @Test 55 | void requiredClaims() throws Exception { 56 | String token = TokenUtils.signClaims("/Token1.json"); 57 | RSAPublicKey publicKey = TokenUtils.readPublicKey("/publicKey.pem"); 58 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo(publicKey, TEST_ISSUER); 59 | contextInfo.setRequiredClaims(Stream.of("roles", "customObject", "customDoubleArray").collect(toSet())); 60 | JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance(); 61 | factory.parse(token, contextInfo); 62 | } 63 | 64 | @Test 65 | void requiredAndMissingClaims() throws Exception { 66 | String token = TokenUtils.signClaims("/Token1.json"); 67 | RSAPublicKey publicKey = TokenUtils.readPublicKey("/publicKey.pem"); 68 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo(publicKey, TEST_ISSUER); 69 | contextInfo.setRequiredClaims( 70 | Stream.of("roles", "customObject", "customDoubleArray", "something").collect(toSet())); 71 | JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance(); 72 | 73 | final ParseException exception = assertThrows(ParseException.class, () -> factory.parse(token, contextInfo)); 74 | assertTrue(exception.getCause() instanceof InvalidJwtException); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/java/io/smallrye/jwt/TestTokenWithGroupsPath2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package io.smallrye.jwt; 18 | 19 | import static org.eclipse.microprofile.jwt.tck.TCKConstants.TEST_ISSUER; 20 | import static org.junit.jupiter.api.Assertions.assertEquals; 21 | import static org.junit.jupiter.api.Assertions.assertTrue; 22 | 23 | import java.security.PublicKey; 24 | import java.util.HashMap; 25 | import java.util.Map; 26 | import java.util.Set; 27 | 28 | import org.eclipse.microprofile.jwt.JsonWebToken; 29 | import org.eclipse.microprofile.jwt.tck.util.SignatureAlgorithm; 30 | import org.eclipse.microprofile.jwt.tck.util.TokenUtils; 31 | import org.junit.jupiter.api.BeforeAll; 32 | import org.junit.jupiter.api.Test; 33 | 34 | import io.smallrye.jwt.auth.principal.JWTAuthContextInfo; 35 | import io.smallrye.jwt.auth.principal.JWTCallerPrincipalFactory; 36 | 37 | /** 38 | * A more extensive test of the how the token JSON content types are mapped 39 | * to values via the JsonWebToken implementation. 40 | */ 41 | class TestTokenWithGroupsPath2 { 42 | /** The test generated JWT token string */ 43 | private static String token; 44 | /** The /publicKey.pem instance */ 45 | private static PublicKey publicKey; 46 | 47 | @BeforeAll 48 | static void generateToken() throws Exception { 49 | Map timeClaims = new HashMap<>(); 50 | token = TokenUtils.signClaims("/TokenGroupsPath2.json", SignatureAlgorithm.RS256, null, timeClaims); 51 | publicKey = TokenUtils.readPublicKey("/publicKey.pem"); 52 | if (publicKey == null) { 53 | throw new IllegalStateException("Failed to load /publicKey.pem resource"); 54 | } 55 | } 56 | 57 | @Test 58 | void groupsObject() throws Exception { 59 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo(publicKey, TEST_ISSUER); 60 | contextInfo.setGroupsPath("groups/array"); 61 | JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance(); 62 | JsonWebToken jwt = factory.parse(token, contextInfo); 63 | Set groups = jwt.getGroups(); 64 | assertEquals(groups.size(), 1); 65 | assertTrue(groups.contains("microprofile_jwt_user")); 66 | } 67 | 68 | @Test 69 | void groupsString() throws Exception { 70 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo(publicKey, TEST_ISSUER); 71 | contextInfo.setGroupsPath("groups/groups"); 72 | contextInfo.setGroupsSeparator(","); 73 | JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance(); 74 | JsonWebToken jwt = factory.parse(token, contextInfo); 75 | Set groups = jwt.getGroups(); 76 | assertEquals(groups.size(), 2); 77 | assertTrue(groups.contains("microprofile_jwt_user1")); 78 | assertTrue(groups.contains("microprofile_jwt_user2")); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/java/io/smallrye/jwt/TestTokenWithGroupsString.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package io.smallrye.jwt; 18 | 19 | import static org.eclipse.microprofile.jwt.tck.TCKConstants.TEST_ISSUER; 20 | import static org.junit.jupiter.api.Assertions.assertEquals; 21 | import static org.junit.jupiter.api.Assertions.assertTrue; 22 | 23 | import java.security.PublicKey; 24 | import java.util.HashMap; 25 | import java.util.Map; 26 | import java.util.Set; 27 | 28 | import org.eclipse.microprofile.jwt.JsonWebToken; 29 | import org.eclipse.microprofile.jwt.tck.util.SignatureAlgorithm; 30 | import org.eclipse.microprofile.jwt.tck.util.TokenUtils; 31 | import org.junit.jupiter.api.BeforeAll; 32 | import org.junit.jupiter.api.Test; 33 | 34 | import io.smallrye.jwt.auth.principal.JWTAuthContextInfo; 35 | import io.smallrye.jwt.auth.principal.JWTCallerPrincipalFactory; 36 | 37 | /** 38 | * A more extensive test of the how the token JSON content types are mapped 39 | * to values via the JsonWebToken implementation. 40 | */ 41 | class TestTokenWithGroupsString { 42 | /** The test generated JWT token string */ 43 | private static String token; 44 | /** The /publicKey.pem instance */ 45 | private static PublicKey publicKey; 46 | 47 | @BeforeAll 48 | static void generateToken() throws Exception { 49 | Map timeClaims = new HashMap<>(); 50 | token = TokenUtils.signClaims("/TokenGroupsString.json", SignatureAlgorithm.RS256, null, timeClaims); 51 | publicKey = TokenUtils.readPublicKey("/publicKey.pem"); 52 | if (publicKey == null) { 53 | throw new IllegalStateException("Failed to load /publicKey.pem resource"); 54 | } 55 | } 56 | 57 | @Test 58 | void groupsString() throws Exception { 59 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo(publicKey, TEST_ISSUER); 60 | JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance(); 61 | JsonWebToken jwt = factory.parse(token, contextInfo); 62 | Set groups = jwt.getGroups(); 63 | assertEquals(groups.size(), 2); 64 | assertTrue(groups.contains("role1")); 65 | assertTrue(groups.contains("role2")); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/java/io/smallrye/jwt/TestTokenWithSubPath.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt; 2 | 3 | import static org.eclipse.microprofile.jwt.tck.TCKConstants.TEST_ISSUER; 4 | import static org.junit.jupiter.api.Assertions.assertEquals; 5 | import static org.junit.jupiter.api.Assertions.assertNull; 6 | 7 | import java.security.PublicKey; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | import org.eclipse.microprofile.jwt.JsonWebToken; 12 | import org.eclipse.microprofile.jwt.tck.util.SignatureAlgorithm; 13 | import org.eclipse.microprofile.jwt.tck.util.TokenUtils; 14 | import org.junit.jupiter.api.BeforeAll; 15 | import org.junit.jupiter.api.Test; 16 | 17 | import io.smallrye.jwt.auth.principal.JWTAuthContextInfo; 18 | import io.smallrye.jwt.auth.principal.JWTCallerPrincipalFactory; 19 | 20 | class TestTokenWithSubPath { 21 | private static String token; 22 | private static PublicKey publicKey; 23 | 24 | @BeforeAll 25 | static void generateToken() throws Exception { 26 | Map timeClaims = new HashMap<>(); 27 | token = TokenUtils.signClaims("/TokenSubPath.json", SignatureAlgorithm.RS256, null, timeClaims); 28 | publicKey = TokenUtils.readPublicKey("/publicKey.pem"); 29 | if (publicKey == null) { 30 | throw new IllegalStateException("Failed to load /publicKey.pem resource"); 31 | } 32 | } 33 | 34 | @Test 35 | void subClaimIsAvailableOnPath() throws Exception { 36 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo(publicKey, TEST_ISSUER); 37 | contextInfo.setSubjectPath("realm/access/sub/principal"); 38 | JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance(); 39 | JsonWebToken jwt = factory.parse(token, contextInfo); 40 | String sub = jwt.getSubject(); 41 | assertEquals(sub, "microprofile_jwt_principal"); 42 | } 43 | 44 | @Test 45 | void subClaimIsAvailableOnPathWithNamespace() throws Exception { 46 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo(publicKey, TEST_ISSUER); 47 | contextInfo.setSubjectPath("realm/\"https://idp/access\"/sub/principal"); 48 | JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance(); 49 | JsonWebToken jwt = factory.parse(token, contextInfo); 50 | String sub = jwt.getSubject(); 51 | assertEquals(sub, "namespace_microprofile_jwt_principal"); 52 | } 53 | 54 | @Test 55 | void subClaimIsNotAvailableOnTooDeepPath() throws Exception { 56 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo(publicKey, TEST_ISSUER); 57 | contextInfo.setRequireNamedPrincipal(false); 58 | contextInfo.setSubjectPath("realm/access/sub/principal/5"); 59 | JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance(); 60 | JsonWebToken jwt = factory.parse(token, contextInfo); 61 | assertNull(jwt.getSubject()); 62 | } 63 | 64 | @Test 65 | void subClaimIsNotAvailableIfClaimIsNotString() throws Exception { 66 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo(publicKey, TEST_ISSUER); 67 | contextInfo.setRequireNamedPrincipal(false); 68 | contextInfo.setSubjectPath("realm/access/sub"); 69 | JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance(); 70 | JsonWebToken jwt = factory.parse(token, contextInfo); 71 | assertNull(jwt.getSubject()); 72 | } 73 | 74 | @Test 75 | void subClaimIsNotAvailableOnWrongPath() throws Exception { 76 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo(publicKey, TEST_ISSUER); 77 | contextInfo.setRequireNamedPrincipal(false); 78 | contextInfo.setSubjectPath("realm/access/user/principal"); 79 | JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance(); 80 | JsonWebToken jwt = factory.parse(token, contextInfo); 81 | assertNull(jwt.getSubject()); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/java/io/smallrye/jwt/TestTokenWithoutGroupsClaim.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package io.smallrye.jwt; 18 | 19 | import static org.eclipse.microprofile.jwt.tck.TCKConstants.TEST_ISSUER; 20 | import static org.junit.jupiter.api.Assertions.assertEquals; 21 | import static org.junit.jupiter.api.Assertions.assertTrue; 22 | 23 | import java.security.PublicKey; 24 | import java.util.HashMap; 25 | import java.util.Map; 26 | import java.util.Set; 27 | 28 | import org.eclipse.microprofile.jwt.JsonWebToken; 29 | import org.eclipse.microprofile.jwt.tck.util.SignatureAlgorithm; 30 | import org.eclipse.microprofile.jwt.tck.util.TokenUtils; 31 | import org.junit.jupiter.api.BeforeAll; 32 | import org.junit.jupiter.api.Test; 33 | 34 | import io.smallrye.jwt.auth.principal.JWTAuthContextInfo; 35 | import io.smallrye.jwt.auth.principal.JWTCallerPrincipalFactory; 36 | 37 | /** 38 | * A more extensive test of the how the token JSON content types are mapped 39 | * to values via the JsonWebToken implementation. 40 | */ 41 | class TestTokenWithoutGroupsClaim { 42 | /** The test generated JWT token string */ 43 | private static String token; 44 | /** The /publicKey.pem instance */ 45 | private static PublicKey publicKey; 46 | 47 | @BeforeAll 48 | static void generateToken() throws Exception { 49 | Map timeClaims = new HashMap<>(); 50 | token = TokenUtils.signClaims("/TokenNoGroups.json", SignatureAlgorithm.RS256, null, timeClaims); 51 | publicKey = TokenUtils.readPublicKey("/publicKey.pem"); 52 | if (publicKey == null) { 53 | throw new IllegalStateException("Failed to load /publicKey.pem resource"); 54 | } 55 | } 56 | 57 | @Test 58 | void defaultGroupsClaimIsAvailable() throws Exception { 59 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo(publicKey, TEST_ISSUER); 60 | contextInfo.setDefaultGroupsClaim("microprofile_jwt_user"); 61 | JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance(); 62 | JsonWebToken jwt = factory.parse(token, contextInfo); 63 | Set groups = jwt.getGroups(); 64 | assertEquals(1, groups.size()); 65 | assertTrue(groups.contains("microprofile_jwt_user")); 66 | } 67 | 68 | @Test 69 | void groupsClaimIsNotAvailable() throws Exception { 70 | JWTAuthContextInfo contextInfo = new JWTAuthContextInfo(publicKey, TEST_ISSUER); 71 | JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance(); 72 | JsonWebToken jwt = factory.parse(token, contextInfo); 73 | assertTrue(jwt.getGroups().isEmpty()); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/java/io/smallrye/jwt/auth/principal/AwsAlbTokenTest.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.auth.principal; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import java.util.Set; 6 | 7 | import org.eclipse.microprofile.jwt.JsonWebToken; 8 | import org.junit.jupiter.api.Test; 9 | 10 | import io.smallrye.jwt.algorithm.SignatureAlgorithm; 11 | 12 | public class AwsAlbTokenTest { 13 | 14 | private static final String AWS_ALB_KEY = "-----BEGIN PUBLIC KEY-----" 15 | + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjPHY1j9umvc8nZEswOzs+lPpLKLn" 16 | + "qCBqvyZGJfBlXapmtGiqYEwpIqh/lZdkr4wDii7CP1DzIUSHONbc+jufiQ==" 17 | + "-----END PUBLIC KEY-----"; 18 | 19 | private static final String JWT = "eyJ0eXAiOiJKV1QiLCJraWQiOiJjMmY4MGM4Yi1jMDVjLTQwNjgtYWYxNC0xNzI5OWY3ODk2YjEiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtY2VudHJhbC0xLmFtYXpvbmF3cy5jb20vZXUtY2VudHJhbC0xX015UnJPQ0hRdyIsImNsaWVudCI6IjRmbXZodDIydGpyZ2Q3ZDNrM3RnaHR0Y3Q3Iiwic2lnbmVyIjoiYXJuOmF3czplbGFzdGljbG9hZGJhbGFuY2luZzpldS1jZW50cmFsLTE6MTk3MjgwOTU4MjI1OmxvYWRiYWxhbmNlci9hcHAvZWNzLXdpdGgtY29nbml0by1sYi82Mjg0YmU2NWI4MjdjNTk4IiwiZXhwIjoxNjg3NzQ4MDQ1fQ==" 20 | + ".eyJzdWIiOiIyM2Q0OThiMi0zMDMxLTcwZDItOGExNS00OWRkODg2YTA4N2IiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6ImR1a2VAc3VuLmNvbSIsInVzZXJuYW1lIjoiZHVrZSIsImV4cCI6MTY4Nzc0ODA0NSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS1jZW50cmFsLTEuYW1hem9uYXdzLmNvbS9ldS1jZW50cmFsLTFfTXlSck9DSFF3In0=" 21 | + ".Jd7RXHsOj8vw2b4irZCxxWO-0UQBZ2X1bRNsKZ9D02JWJaNOvOnrV8T-qrcmWNpl7MjNhsGSm1C4e2rAjaF0jg=="; 22 | 23 | @Test 24 | void parseToken() throws Exception { 25 | JWTAuthContextInfo config = new JWTAuthContextInfo(); 26 | config.setPublicKeyContent(AWS_ALB_KEY); 27 | config.setIssuedBy("https://cognito-idp.eu-central-1.amazonaws.com/eu-central-1_MyRrOCHQw"); 28 | // ES256 is used to sign 29 | config.setSignatureAlgorithm(Set.of(SignatureAlgorithm.ES256)); 30 | // Token has no `iat` 31 | config.setMaxTimeToLiveSecs(-1L); 32 | // It has already expired so for the test to pass the clock skew has to be set 33 | config.setClockSkew(Integer.MAX_VALUE); 34 | JWTParser parser = new DefaultJWTParser(config); 35 | JsonWebToken jwt = parser.parse(JWT); 36 | assertEquals("duke", jwt.getClaim("username")); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/java/io/smallrye/jwt/auth/principal/DefaultJWTCallerPrincipalTest.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.auth.principal; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertArrayEquals; 4 | import static org.junit.jupiter.api.Assertions.assertEquals; 5 | import static org.junit.jupiter.api.Assertions.assertNotNull; 6 | 7 | import java.security.interfaces.RSAPublicKey; 8 | import java.util.Set; 9 | 10 | import org.eclipse.microprofile.jwt.Claims; 11 | import org.eclipse.microprofile.jwt.tck.util.TokenUtils; 12 | import org.jose4j.jwt.JwtClaims; 13 | import org.jose4j.jwt.consumer.JwtContext; 14 | import org.junit.jupiter.api.BeforeEach; 15 | import org.junit.jupiter.api.Test; 16 | 17 | class DefaultJWTCallerPrincipalTest { 18 | 19 | private static final String TCK_TOKEN1_AUD = "s6BhdRkqt3"; 20 | 21 | RSAPublicKey publicKey; 22 | DefaultJWTTokenParser parser; 23 | JWTAuthContextInfo config; 24 | JwtContext context; 25 | 26 | @BeforeEach 27 | void setUp() throws Exception { 28 | publicKey = TokenUtils.readPublicKey("/publicKey.pem"); 29 | parser = new DefaultJWTTokenParser(); 30 | config = new JWTAuthContextInfo(publicKey, "https://server.example.com"); 31 | context = parser.parse(TokenUtils.signClaims("/Token1.json"), config); 32 | } 33 | 34 | @Test 35 | void getAudience() { 36 | DefaultJWTCallerPrincipal principal = new DefaultJWTCallerPrincipal(context.getJwtClaims()); 37 | Set audience = principal.getAudience(); 38 | assertNotNull(audience); 39 | assertEquals(1, audience.size()); 40 | assertArrayEquals(new String[] { TCK_TOKEN1_AUD }, audience.toArray(new String[0])); 41 | } 42 | 43 | @Test 44 | void getAudienceClaimValue() { 45 | DefaultJWTCallerPrincipal principal = new DefaultJWTCallerPrincipal(context.getJwtClaims()); 46 | @SuppressWarnings("unchecked") 47 | Set audience = (Set) principal.getClaimValue(Claims.aud.name()); 48 | assertNotNull(audience); 49 | assertEquals(1, audience.size()); 50 | assertArrayEquals(new String[] { TCK_TOKEN1_AUD }, audience.toArray(new String[0])); 51 | } 52 | 53 | @Test 54 | void getAudienceClaim() { 55 | DefaultJWTCallerPrincipal principal = new DefaultJWTCallerPrincipal(context.getJwtClaims()); 56 | Set audience = principal.getClaim(Claims.aud.name()); 57 | assertNotNull(audience); 58 | assertEquals(1, audience.size()); 59 | assertArrayEquals(new String[] { TCK_TOKEN1_AUD }, audience.toArray(new String[0])); 60 | } 61 | 62 | @Test 63 | void claimsWithDecimalValues() { 64 | Double exp = 1311281970.5; 65 | Double iat = 1311280970.5; 66 | 67 | final JwtClaims claims = context.getJwtClaims(); 68 | claims.setClaim(Claims.exp.name(), exp); 69 | claims.setClaim(Claims.iat.name(), iat); 70 | DefaultJWTCallerPrincipal principal = new DefaultJWTCallerPrincipal(claims); 71 | 72 | Long expClaim = principal.getExpirationTime(); 73 | Long iatClaim = principal.getIssuedAtTime(); 74 | 75 | assertNotNull(expClaim); 76 | assertNotNull(iatClaim); 77 | 78 | assertEquals(exp.longValue(), expClaim); 79 | assertEquals(iat.longValue(), iatClaim); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/java/io/smallrye/jwt/auth/principal/KeyLocationResolverKeyContentTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package io.smallrye.jwt.auth.principal; 18 | 19 | import static org.junit.jupiter.api.Assertions.assertNotNull; 20 | import static org.junit.jupiter.api.Assertions.assertThrows; 21 | import static org.junit.jupiter.api.Assertions.assertTrue; 22 | 23 | import java.io.BufferedReader; 24 | import java.io.InputStream; 25 | import java.io.InputStreamReader; 26 | import java.io.StringWriter; 27 | import java.nio.charset.StandardCharsets; 28 | import java.security.PrivateKey; 29 | import java.util.Base64; 30 | 31 | import org.eclipse.microprofile.jwt.tck.util.TokenUtils; 32 | import org.jose4j.lang.UnresolvableKeyException; 33 | import org.junit.jupiter.api.Test; 34 | 35 | import io.smallrye.jwt.config.JWTAuthContextInfoProvider; 36 | import io.smallrye.jwt.util.KeyUtils; 37 | 38 | class KeyLocationResolverKeyContentTest { 39 | @Test 40 | void verifyWithPemKey() throws Exception { 41 | verifyToken(null, readKeyContent("/publicKey.pem")); 42 | } 43 | 44 | @Test 45 | void verifyWithInvalidPemKey() throws Exception { 46 | PrivateKey privateKey = TokenUtils.readPrivateKey("/privateKey.pem"); 47 | String token = TokenUtils.signClaims(privateKey, null, "/Token1.json", null, null); 48 | JWTAuthContextInfoProvider provider = JWTAuthContextInfoProvider.createWithKey("invalidkey", 49 | "https://server.example.com"); 50 | JWTAuthContextInfo contextInfo = provider.getContextInfo(); 51 | ParseException thrown = assertThrows(ParseException.class, () -> new DefaultJWTTokenParser().parse(token, contextInfo), 52 | "UnresolvableKeyException is expected"); 53 | assertTrue(thrown.getCause() instanceof UnresolvableKeyException); 54 | } 55 | 56 | @Test 57 | void verifyWithPemKeyTrimmed() throws Exception { 58 | verifyToken(null, KeyUtils.removePemKeyBeginEnd(readKeyContent("/publicKey.pem"))); 59 | } 60 | 61 | @Test 62 | void verifyWithJwkKey() throws Exception { 63 | verifyToken(null, 64 | Base64.getUrlEncoder().encodeToString(readKeyContent("/publicKey.jwk").getBytes(StandardCharsets.UTF_8))); 65 | } 66 | 67 | @Test 68 | void verifyWithJwkKeySet() throws Exception { 69 | verifyToken("key1", 70 | Base64.getUrlEncoder().encodeToString(readKeyContent("/publicKeySet.jwk").getBytes(StandardCharsets.UTF_8))); 71 | } 72 | 73 | private void verifyToken(String kid, String publicKey) throws Exception { 74 | PrivateKey privateKey = TokenUtils.readPrivateKey("/privateKey.pem"); 75 | String token = TokenUtils.signClaims(privateKey, kid, "/Token1.json", null, null); 76 | JWTAuthContextInfoProvider provider = JWTAuthContextInfoProvider.createWithKey(publicKey, 77 | "https://server.example.com"); 78 | JWTAuthContextInfo contextInfo = provider.getContextInfo(); 79 | assertNotNull(new DefaultJWTTokenParser().parse(token, contextInfo)); 80 | } 81 | 82 | private String readKeyContent(String keyLocation) throws Exception { 83 | InputStream is = KeyUtils.class.getResourceAsStream(keyLocation); 84 | StringWriter contents = new StringWriter(); 85 | try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { 86 | String line = null; 87 | while ((line = reader.readLine()) != null) { 88 | contents.write(line); 89 | } 90 | } 91 | return contents.toString(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/java/io/smallrye/jwt/auth/principal/KeyStoreLocationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package io.smallrye.jwt.auth.principal; 18 | 19 | import static org.junit.jupiter.api.Assertions.assertEquals; 20 | import static org.junit.jupiter.api.Assertions.assertNotNull; 21 | 22 | import java.security.KeyStore; 23 | import java.security.PrivateKey; 24 | import java.security.PublicKey; 25 | import java.util.Optional; 26 | 27 | import org.eclipse.microprofile.jwt.tck.util.TokenUtils; 28 | import org.jose4j.jwt.JwtClaims; 29 | import org.junit.jupiter.api.Test; 30 | 31 | import io.smallrye.jwt.config.JWTAuthContextInfoProvider; 32 | import io.smallrye.jwt.util.KeyUtils; 33 | 34 | class KeyStoreLocationTest { 35 | @Test 36 | void verifyToken() throws Exception { 37 | KeyStore keyStore = KeyUtils.loadKeyStore("server-keystore.jks", "password", Optional.empty(), Optional.empty()); 38 | PrivateKey signingKey = (PrivateKey) keyStore.getKey("server", "password".toCharArray()); 39 | String jwt = TokenUtils.signClaims(signingKey, null, "/Token1.json"); 40 | 41 | JWTAuthContextInfoProvider provider = JWTAuthContextInfoProvider.createWithKeyStoreLocation("server-keystore.jks", 42 | Optional.of("password"), Optional.of("server"), Optional.empty(), 43 | "https://server.example.com"); 44 | JwtClaims claims = new DefaultJWTTokenParser().parse(jwt, provider.getContextInfo()).getJwtClaims(); 45 | assertNotNull(claims); 46 | assertEquals("https://server.example.com", claims.getIssuer()); 47 | } 48 | 49 | @Test 50 | void decryptToken() throws Exception { 51 | KeyStore keyStore = KeyUtils.loadKeyStore("server-keystore.jks", "password", Optional.empty(), Optional.empty()); 52 | PublicKey encryptionKey = keyStore.getCertificate("server").getPublicKey(); 53 | String jwt = TokenUtils.encryptClaims(encryptionKey, null, "/Token1.json"); 54 | 55 | JWTAuthContextInfoProvider provider = JWTAuthContextInfoProvider.createWithKeyStoreLocation("server-keystore.jks", 56 | Optional.of("password"), Optional.empty(), Optional.of("server"), 57 | "https://server.example.com"); 58 | JwtClaims claims = new DefaultJWTTokenParser().parse(jwt, provider.getContextInfo()).getJwtClaims(); 59 | assertNotNull(claims); 60 | assertEquals("https://server.example.com", claims.getIssuer()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/Token1.json: -------------------------------------------------------------------------------- 1 | { 2 | "iss": "https://server.example.com", 3 | "jti": "a-123", 4 | "sub": "24400320", 5 | "upn": "jdoe@example.com", 6 | "preferred_username": "jdoe", 7 | "aud": "s6BhdRkqt3", 8 | "exp": 1311281970, 9 | "iat": 1311280970, 10 | "auth_time": 1311280969, 11 | "roles": [ 12 | "Echoer" 13 | ], 14 | "groups": [ 15 | "Echoer", 16 | "Tester", 17 | "group1", 18 | "group2" 19 | ], 20 | "customString": "customStringValue", 21 | "customInteger": 123456789, 22 | "customDouble": 3.141592653589793, 23 | "customStringArray": [ 24 | "value0", 25 | "value1", 26 | "value2" 27 | ], 28 | "customIntegerArray": [ 29 | 0, 30 | 1, 31 | 2, 32 | 3 33 | ], 34 | "customDoubleArray": [ 35 | 0.1, 36 | 1.1, 37 | 2.2, 38 | 3.3, 39 | 4.4 40 | ], 41 | "customObject": { 42 | "my-service": { 43 | "groups": [ 44 | "group1", 45 | "group2" 46 | ], 47 | "roles": [ 48 | "role-in-my-service" 49 | ] 50 | }, 51 | "service-B": { 52 | "roles": [ 53 | "role-in-B" 54 | ] 55 | }, 56 | "service-C": { 57 | "groups": [ 58 | "groupC", 59 | "web-tier" 60 | ] 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/TokenGroupsPath.json: -------------------------------------------------------------------------------- 1 | { 2 | "iss": "https://server.example.com", 3 | "jti": "a-123", 4 | "sub": "24400320", 5 | "upn": "jdoe@example.com", 6 | "preferred_username": "jdoe", 7 | "aud": "s6BhdRkqt3", 8 | "exp": 1311281970, 9 | "iat": 1311280970, 10 | "auth_time": 1311280969, 11 | "realm": { 12 | "access": { 13 | "groups": { 14 | "array": [ 15 | "microprofile_jwt_user" 16 | ] 17 | }, 18 | "https://idp/groups": { 19 | "array": [ 20 | "namespace_microprofile_jwt_user" 21 | ] 22 | } 23 | } 24 | }, 25 | "scope": "read write", 26 | "auth": "read,write" 27 | } 28 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/TokenGroupsPath2.json: -------------------------------------------------------------------------------- 1 | { 2 | "iss": "https://server.example.com", 3 | "jti": "a-123", 4 | "sub": "24400320", 5 | "upn": "jdoe@example.com", 6 | "preferred_username": "jdoe", 7 | "aud": "s6BhdRkqt3", 8 | "exp": 1311281970, 9 | "iat": 1311280970, 10 | "auth_time": 1311280969, 11 | "groups": { 12 | "array": [ 13 | "microprofile_jwt_user" 14 | ], 15 | "groups":"microprofile_jwt_user1,microprofile_jwt_user2" 16 | }, 17 | "scope": "read write", 18 | "auth": "read,write" 19 | } 20 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/TokenGroupsString.json: -------------------------------------------------------------------------------- 1 | { 2 | "iss": "https://server.example.com", 3 | "jti": "a-123", 4 | "sub": "24400320", 5 | "upn": "jdoe@example.com", 6 | "preferred_username": "jdoe", 7 | "aud": "s6BhdRkqt3", 8 | "exp": 1311281970, 9 | "iat": 1311280970, 10 | "auth_time": 1311280969, 11 | "groups": "role1 role2", 12 | "scope": "read write", 13 | "auth": "read,write" 14 | } 15 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/TokenNoGroups.json: -------------------------------------------------------------------------------- 1 | { 2 | "iss": "https://server.example.com", 3 | "jti": "a-123", 4 | "sub": "24400320", 5 | "upn": "jdoe@example.com", 6 | "preferred_username": "jdoe", 7 | "aud": "s6BhdRkqt3", 8 | "exp": 1311281970, 9 | "iat": 1311280970, 10 | "auth_time": 1311280969 11 | } 12 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/TokenSubPath.json: -------------------------------------------------------------------------------- 1 | { 2 | "iss": "https://server.example.com", 3 | "jti": "a-123", 4 | "aud": "s6BhdRkqt3", 5 | "exp": 1311281970, 6 | "iat": 1311280970, 7 | "auth_time": 1311280969, 8 | "realm": { 9 | "access": { 10 | "sub": { 11 | "principal": "microprofile_jwt_principal" 12 | } 13 | }, 14 | "https://idp/access": { 15 | "sub": { 16 | "principal": "namespace_microprofile_jwt_principal" 17 | } 18 | } 19 | }, 20 | "groups": [ 21 | "Echoer", 22 | "Tester", 23 | "group1", 24 | "group2" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/certificate.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC9DCCAdygAwIBAgIJAO0Y7B7dV9KpMA0GCSqGSIb3DQEBCwUAMA8xDTALBgNV 3 | BAMMBHRlc3QwHhcNMjAwODI1MTIzOTA1WhcNMjEwODI1MTIzOTA1WjAPMQ0wCwYD 4 | VQQDDAR0ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsl8Cqii/ 5 | 4UFg5Lq3R8kZ//Wmapq4KQn4k+foEOymfUbw44E6pCU+iCK0RbyKXgTMErMN3ZFD 6 | xpoDdSeEDoS2kdlRF4XNtFG8RW6+h1wLJGRj7gi9bc0Vg5CzTGWhDvI6oT23KtUa 7 | OBjIWknZtLAR5nEJ7vMADq3QKMHcxofx1GmmAQ2NDmVQJvTfM8wV02oZ2vX6yQjB 8 | 6t3vbMyIr+h2GU8teu9v/oUf9A9R2Pm6qULSZ80qyo5BXlwwG2D4HsGCxCdg5PqK 9 | Oi9SOkvlE65eBUR8NXxwHdou+SQ/ry//MPwLSpHo9AggVEmSYlfigyVo5w1FUVo6 10 | uYUG/abuKhCSoQIDAQABo1MwUTAdBgNVHQ4EFgQUcDgMETNCuUuEGWzKoXjrvS8+ 11 | kQAwHwYDVR0jBBgwFoAUcDgMETNCuUuEGWzKoXjrvS8+kQAwDwYDVR0TAQH/BAUw 12 | AwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAH0o4kU37vc7OR/+fPQJdrBQqQaukq5ri 13 | yuMSTrU1vSizEXpd0RFE8moSks6+Vh4mEzU7zLAU54N6glcGItEmBko5xgTuQRgd 14 | b0LtR7Bu28QKfRRJxZ9GnGxinDPtFPD+7oTXZfI2Ed/RAuVlbppEBr2Pr2eO9B1x 15 | fgYJNwA1K/XA38G7njxQ/wcpgOp/iFdV7dyR6CyAtwkD92sMnEZKPVz3trBT9DFM 16 | 5mynDFn9PHYVB7R5mUjIc7C9yskHGIsqqSBAfsxUqKfCS2NlWjn4+JZ8BYPLgy6X 17 | hlGxh5zhvJPoT6J9+gA5l1Z2xMXI08ym8quIIUJNoYovSf8x4bXVjQ== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/decryptPrivateKey.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "kty":"RSA", 3 | "n":"iJw33l1eVAsGoRlSyo-FCimeOc-AaZbzQ2iESA3Nkuo3TFb1zIkmt0kzlnWVGt48dkaIl13Vdefh9hqw_r9yNF8xZqX1fp0PnCWc5M_TX_ht5fm9y0TpbiVmsjeRMWZn4jr3DsFouxQ9aBXUJiu26V0vd2vrECeeAreFT4mtoHY13D2WVeJvboc5mEJcp50JNhxRCJ5UkY8jR_wfUk2Tzz4-fAj5xQaBccXnqJMu_1C6MjoCEiB7G1d13bVPReIeAGRKVJIF6ogoCN8JbrOhc_48lT4uyjbgnd24beatuKWodmWYhactFobRGYo5551cgMe8BoxpVQ4to30cGA0qjQ", 4 | "e":"AQAB", 5 | "d":"AvIDTlsK_priQLTwEQf5IVf2Xl638Q7dHdXyDC-oAAPmv1GcqRVH7Wm5oAPW_CZQfWhV55WRVaJzP8AhksyD5NcslH79hQZT4NT6xgApGYecrvmseuZ4dfR-e1cxXTRNBxaoXvwSiv4LuOPHmC8XGX712AhOoCGKiZp1WFqqkKwTpkgJEApJFVb-XRIKQa0YaRKpJsJ534pLMwTh7LoPLM4BCaBVbRfHzH2H5L3TSJP718kyCuxg3z2p9Y7zIOLTmgFdeR0_kd_xKUFZ2ByN3SKlC0IWlLUSiMPsGYExRpZTMZHKyD939gv-2_Z-bOYfKlYNIvAmQH_8CcX2I039LQ", 6 | "p":"104AjPaxZoi_BiMBODlChnZOvRJT071PdkeZ283uyrdW8qqKD9q8FTMgUXzKoboHtUiHbJbLOobPmPDh93839rq7dTdCNzNVOuLmE-V3_bmaShdzvxEIazwPf6AvjbEZAc-zu2RS4SNkp1LbzgSl9nINSlF7t6Lkl6T28PYULys", 7 | "q":"om5ooyzxa4ZJ-dU0ODsEb-Bmz6xwb27xF9aEhBYJprHeoNs2QM1D64_A39weD9MYwBux4-ivshCJ0dVKEbDujJRLnzf-ssrasA6CFyaaCT4DKtq1oWb9rcG-2LQd5Bm9PttrUrSUNqitr085IYikaLEz7UU6gtXPoC8UOcJ4cSc", 8 | "dp":"DeWE95Q8oweUfMrpmz1m49LjBiUWsAX6CQJaFevWy9LFk-gZ_Sf7F8sy_M93LLUbJkJGK2YYO_DTmWWC0Dyv2gb3bntglLuFdsWKYCJhekjugnW9DMoGpxU7Utt99kFGAe3sBd5V0x47sukQMt3t8FgwL2nO-G1VH8yP-8GGT_0", 9 | "dq":"TGBeE1wuqMCcSD1YMJiPnYuGzF_o_nzMIMldxj4Wi6tXY4uwFwhtx3Xw21JFUGuSV8KuAtyGwNPF-kSwb2Eiyjdw140c1jVMXzxzLy-XfoEKPDxa62niHrHba0pGQ9tWgRfrfxgqGQl3odc-peX6aL_qCsdim-KtnkSE3iPzPkE", 10 | "qi":"Jzp5KnT24y0wOoPUn_11S3ZcYl0i03dkaH4c5zR02G1MJG9K017juurx2aXVTctOzrj7O226EUiL1Qbq3QtnWFDDGY6vNZuqzJM7AMXsvp1djq_6fEVhxCIOgfJbmhb3mkG82rxn4et9o_TNr6mvEmHzG15sHbvZbAnn4GeqToY" 11 | } -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/ecPrivateKey.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "kty":"EC", 3 | "crv":"P-256", 4 | "x":"weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ", 5 | "y":"e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck", 6 | "d":"VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw", 7 | "kid": "eckey" 8 | } -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/ecPrivateKey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgvhj6xtHJanL3yBYt 3 | vmaLQ+ZlbO/zu66oWFYjQOxfpGahRANCAATDgeiG/A6PbUUFATU+sk4CU9FAzJaK 4 | aZcf2sgdrtgxNaLGRI1IWWu/fpApXBpu/Xl9Kv0BS5awPfTIZMzcujLS 5 | -----END PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/ecPublicKey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEw4HohvwOj21FBQE1PrJOAlPRQMyW 3 | immXH9rIHa7YMTWixkSNSFlrv36QKVwabv15fSr9AUuWsD30yGTM3Loy0g== 4 | -----END PUBLIC KEY----- 5 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/edEcPrivateKey.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "kty":"OKP", 3 | "crv":"Ed25519", 4 | "d":"nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A", 5 | "x":"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" 6 | } -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/edEcPublicKey.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "kty":"OKP", 3 | "crv":"Ed25519", 4 | "x":"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" 5 | } -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/encryptPublicKey.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "kty":"RSA", 3 | "n":"iJw33l1eVAsGoRlSyo-FCimeOc-AaZbzQ2iESA3Nkuo3TFb1zIkmt0kzlnWVGt48dkaIl13Vdefh9hqw_r9yNF8xZqX1fp0PnCWc5M_TX_ht5fm9y0TpbiVmsjeRMWZn4jr3DsFouxQ9aBXUJiu26V0vd2vrECeeAreFT4mtoHY13D2WVeJvboc5mEJcp50JNhxRCJ5UkY8jR_wfUk2Tzz4-fAj5xQaBccXnqJMu_1C6MjoCEiB7G1d13bVPReIeAGRKVJIF6ogoCN8JbrOhc_48lT4uyjbgnd24beatuKWodmWYhactFobRGYo5551cgMe8BoxpVQ4to30cGA0qjQ", 4 | "e":"AQAB" 5 | } -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/privateKey2.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCyXwKqKL/hQWDk 3 | urdHyRn/9aZqmrgpCfiT5+gQ7KZ9RvDjgTqkJT6IIrRFvIpeBMwSsw3dkUPGmgN1 4 | J4QOhLaR2VEXhc20UbxFbr6HXAskZGPuCL1tzRWDkLNMZaEO8jqhPbcq1Ro4GMha 5 | Sdm0sBHmcQnu8wAOrdAowdzGh/HUaaYBDY0OZVAm9N8zzBXTahna9frJCMHq3e9s 6 | zIiv6HYZTy1672/+hR/0D1HY+bqpQtJnzSrKjkFeXDAbYPgewYLEJ2Dk+oo6L1I6 7 | S+UTrl4FRHw1fHAd2i75JD+vL/8w/AtKkej0CCBUSZJiV+KDJWjnDUVRWjq5hQb9 8 | pu4qEJKhAgMBAAECggEAJvBs4X7B3MfsAiLszgQN4/3ZlZ4vI+5kUM2osMEo22J4 9 | RgI5Lgpfa1LALhUp07qSXmauWTdUJ3AJ3zKANrcsMAzUEiGItZu+UR4LA/vJBunP 10 | kvBfgi/qSW12ZvAsx9mDiR2y9evNrH9khalnmHVzgu4ccAimc43oSm1/5+tXlLoZ 11 | 1QK/FohxBxAshtuDHGs8yKUL0jpv7dOrjhCj2ibmPYe6AUk9F61sVWO0/i0Q8UAO 12 | cYT3L5nCS5WnLhdCdYpIJJ7xl2PrVE/BAD+JEG5uCOYfVeYh+iCZVfpX17ryfNNU 13 | aBtyxKEGVtHbje3mO86mYN3noaS0w/zpUjBPgV+KEQKBgQDsp6VTmDIqHFTp2cC2 14 | yrDMxRznif92EGv7ccJDZtbTC37mAuf2J7x5b6AiE1EfxEXyGYzSk99sCns+GbL1 15 | EHABUt5pimDCl33b6XvuccQNpnJ0MfM5eRX9Ogyt/OKdDRnQsvrTPNCWOyJjvG01 16 | HQM4mfxaBBnxnvl5meH2pyG/ZQKBgQDA87DnyqEFhTDLX5c1TtwHSRj2xeTPGKG0 17 | GyxOJXcxR8nhtY9ee0kyLZ14RytnOxKarCFgYXeG4IoGEc/I42WbA4sq88tZcbe4 18 | IJkdX0WLMqOTdMrdx9hMU1ytKVUglUJZBVm7FaTQjA+ArMwqkXAA5HBMtArUsfJK 19 | Ut3l0hMIjQKBgQDS1vmAZJQs2Fj+jzYWpLaneOWrk1K5yR+rQUql6jVyiUdhfS1U 20 | LUrJlh3Avh0EhEUc0I6Z/YyMITpztUmu9BoV09K7jMFwHK/RAU+cvFbDIovN4cKk 21 | bbCdjt5FFIyBB278dLjrAb+EWOLmoLVbIKICB47AU+8ZSV1SbTrYGUcD0QKBgQCA 22 | liZv4na6sg9ZiUPAr+QsKserNSiN5zFkULOPBKLRQbFFbPS1l12pRgLqNCu1qQV1 23 | 9H5tt6arSRpSfy5FB14gFxV4s23yFrnDyF2h2GsFH+MpEq1bbaI1A10AvUnQ5AeK 24 | QemRpxPmM2DldMK/H5tPzO0WAOoy4r/ATkc4sG4kxQKBgBL9neT0TmJtxlYGzjNc 25 | jdJXs3Q91+nZt3DRMGT9s0917SuP77+FdJYocDiH1rVa9sGG8rkh1jTdqliAxDXw 26 | Im5IGS/0OBnkaN1nnGDk5yTiYxOutC5NSj7ecI5Erud8swW6iGqgz2ioFpGxxIYq 27 | RlgTv/6mVt41KALfKrYIkVLw 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/publicKey.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "kty":"RSA", 3 | "n":"livFI8qB4D0y2jy0CfEqFyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm-ntyIv1p4kE1sPEQO73-HY8-Bzs75XwRTYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5eUF_F9-KEBWkwVta-PZ37bwqSE4sCb1soZFrVz_UT_LF4tYpuVYt3YbqToZ3pZOZ9AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYnsIYPd99ltwxTHjr3npfv_3Lw50bAkbT4HeLFxTx4flEoZLKO_g0bAoV2uqBhkA9xnQ", 4 | "e":"AQAB", 5 | "kid": "key1" 6 | } -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/publicKey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlivFI8qB4D0y2jy0CfEq 3 | Fyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm+ntyIv1p4kE1sPEQO73+HY8+Bzs75XwR 4 | TYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5e 5 | UF/F9+KEBWkwVta+PZ37bwqSE4sCb1soZFrVz/UT/LF4tYpuVYt3YbqToZ3pZOZ9 6 | AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYn 7 | sIYPd99ltwxTHjr3npfv/3Lw50bAkbT4HeLFxTx4flEoZLKO/g0bAoV2uqBhkA9x 8 | nQIDAQAB 9 | -----END RSA PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/publicKeySet.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "keys": [ 3 | { 4 | "kty":"RSA", 5 | "n":"ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddxHmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMsD1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSHSXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ", 6 | "e":"AQAB", 7 | "kid": "key2" 8 | }, 9 | { 10 | "kty":"RSA", 11 | "n":"livFI8qB4D0y2jy0CfEqFyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm-ntyIv1p4kE1sPEQO73-HY8-Bzs75XwRTYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5eUF_F9-KEBWkwVta-PZ37bwqSE4sCb1soZFrVz_UT_LF4tYpuVYt3YbqToZ3pZOZ9AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYnsIYPd99ltwxTHjr3npfv_3Lw50bAkbT4HeLFxTx4flEoZLKO_g0bAoV2uqBhkA9xnQ", 12 | "e":"AQAB", 13 | "kid": "key1" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/publicSingleKeySetWithoutKid.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "keys": [ 3 | { 4 | "kty":"RSA", 5 | "n":"livFI8qB4D0y2jy0CfEqFyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm-ntyIv1p4kE1sPEQO73-HY8-Bzs75XwRTYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5eUF_F9-KEBWkwVta-PZ37bwqSE4sCb1soZFrVz_UT_LF4tYpuVYt3YbqToZ3pZOZ9AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYnsIYPd99ltwxTHjr3npfv_3Lw50bAkbT4HeLFxTx4flEoZLKO_g0bAoV2uqBhkA9xnQ", 6 | "e":"AQAB" 7 | } 8 | ] 9 | } -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/rs256PrivateKey.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "kty":"RSA", 3 | "n":"iJw33l1eVAsGoRlSyo-FCimeOc-AaZbzQ2iESA3Nkuo3TFb1zIkmt0kzlnWVGt48dkaIl13Vdefh9hqw_r9yNF8xZqX1fp0PnCWc5M_TX_ht5fm9y0TpbiVmsjeRMWZn4jr3DsFouxQ9aBXUJiu26V0vd2vrECeeAreFT4mtoHY13D2WVeJvboc5mEJcp50JNhxRCJ5UkY8jR_wfUk2Tzz4-fAj5xQaBccXnqJMu_1C6MjoCEiB7G1d13bVPReIeAGRKVJIF6ogoCN8JbrOhc_48lT4uyjbgnd24beatuKWodmWYhactFobRGYo5551cgMe8BoxpVQ4to30cGA0qjQ", 4 | "e":"AQAB", 5 | "d":"AvIDTlsK_priQLTwEQf5IVf2Xl638Q7dHdXyDC-oAAPmv1GcqRVH7Wm5oAPW_CZQfWhV55WRVaJzP8AhksyD5NcslH79hQZT4NT6xgApGYecrvmseuZ4dfR-e1cxXTRNBxaoXvwSiv4LuOPHmC8XGX712AhOoCGKiZp1WFqqkKwTpkgJEApJFVb-XRIKQa0YaRKpJsJ534pLMwTh7LoPLM4BCaBVbRfHzH2H5L3TSJP718kyCuxg3z2p9Y7zIOLTmgFdeR0_kd_xKUFZ2ByN3SKlC0IWlLUSiMPsGYExRpZTMZHKyD939gv-2_Z-bOYfKlYNIvAmQH_8CcX2I039LQ", 6 | "p":"104AjPaxZoi_BiMBODlChnZOvRJT071PdkeZ283uyrdW8qqKD9q8FTMgUXzKoboHtUiHbJbLOobPmPDh93839rq7dTdCNzNVOuLmE-V3_bmaShdzvxEIazwPf6AvjbEZAc-zu2RS4SNkp1LbzgSl9nINSlF7t6Lkl6T28PYULys", 7 | "q":"om5ooyzxa4ZJ-dU0ODsEb-Bmz6xwb27xF9aEhBYJprHeoNs2QM1D64_A39weD9MYwBux4-ivshCJ0dVKEbDujJRLnzf-ssrasA6CFyaaCT4DKtq1oWb9rcG-2LQd5Bm9PttrUrSUNqitr085IYikaLEz7UU6gtXPoC8UOcJ4cSc", 8 | "dp":"DeWE95Q8oweUfMrpmz1m49LjBiUWsAX6CQJaFevWy9LFk-gZ_Sf7F8sy_M93LLUbJkJGK2YYO_DTmWWC0Dyv2gb3bntglLuFdsWKYCJhekjugnW9DMoGpxU7Utt99kFGAe3sBd5V0x47sukQMt3t8FgwL2nO-G1VH8yP-8GGT_0", 9 | "dq":"TGBeE1wuqMCcSD1YMJiPnYuGzF_o_nzMIMldxj4Wi6tXY4uwFwhtx3Xw21JFUGuSV8KuAtyGwNPF-kSwb2Eiyjdw140c1jVMXzxzLy-XfoEKPDxa62niHrHba0pGQ9tWgRfrfxgqGQl3odc-peX6aL_qCsdim-KtnkSE3iPzPkE", 10 | "qi":"Jzp5KnT24y0wOoPUn_11S3ZcYl0i03dkaH4c5zR02G1MJG9K017juurx2aXVTctOzrj7O226EUiL1Qbq3QtnWFDDGY6vNZuqzJM7AMXsvp1djq_6fEVhxCIOgfJbmhb3mkG82rxn4et9o_TNr6mvEmHzG15sHbvZbAnn4GeqToY", 11 | "kid":"rsakey" 12 | } -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/secretKey.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "kty":"oct", 3 | "k":"Fdh9u8rINxfivbrianbbVT1u232VQBZYKx1HGAGPt2I" 4 | } -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/server-keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smallrye/smallrye-jwt/b43b673fb4cdfb06a7a9224b0b09529a4e8d9027/testsuite/basic/src/test/resources/server-keystore.jks -------------------------------------------------------------------------------- /testsuite/basic/src/test/resources/signatureJwkSet.jwk: -------------------------------------------------------------------------------- 1 | { 2 | "keys": [ 3 | { 4 | "kty":"RSA", 5 | "n":"iJw33l1eVAsGoRlSyo-FCimeOc-AaZbzQ2iESA3Nkuo3TFb1zIkmt0kzlnWVGt48dkaIl13Vdefh9hqw_r9yNF8xZqX1fp0PnCWc5M_TX_ht5fm9y0TpbiVmsjeRMWZn4jr3DsFouxQ9aBXUJiu26V0vd2vrECeeAreFT4mtoHY13D2WVeJvboc5mEJcp50JNhxRCJ5UkY8jR_wfUk2Tzz4-fAj5xQaBccXnqJMu_1C6MjoCEiB7G1d13bVPReIeAGRKVJIF6ogoCN8JbrOhc_48lT4uyjbgnd24beatuKWodmWYhactFobRGYo5551cgMe8BoxpVQ4to30cGA0qjQ", 6 | "e":"AQAB", 7 | "kid": "rsakey" 8 | }, 9 | 10 | { 11 | "kty":"EC", 12 | "x":"weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ", 13 | "y":"e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck", 14 | "crv":"P-256", 15 | "kid": "eckey" 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /testsuite/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 4.0.0 20 | 21 | 22 | io.smallrye 23 | smallrye-jwt-parent 24 | 4.6.3-SNAPSHOT 25 | 26 | 27 | pom 28 | smallrye-jwt-testsuite-parent 29 | SmallRye: MicroProfile JWT - Testsuite Parent 30 | 31 | 32 | 2.3.1 33 | 3.1.1 34 | 6.2.2.Final 35 | 3.0.1.Final 36 | 37 | 6.0.5.Final 38 | 25.0.1.Final 39 | 5.1.3.Final 40 | 41 | 42 | 43 | 44 | 45 | 46 | org.eclipse.microprofile.jwt 47 | microprofile-jwt-auth-tck 48 | ${version.eclipse.microprofile.jwt} 49 | 50 | 51 | org.eclipse.microprofile.jwt 52 | microprofile-jwt-auth-tck 53 | test-jar 54 | ${version.eclipse.microprofile.jwt} 55 | 56 | 57 | io.smallrye.testing 58 | smallrye-testing-bom-tck 59 | ${version.smallrye.testing} 60 | pom 61 | import 62 | 63 | 64 | io.smallrye.config 65 | smallrye-config 66 | ${version.smallrye.config} 67 | test 68 | 69 | 70 | org.jboss.resteasy 71 | resteasy-bom 72 | ${version.resteasy} 73 | pom 74 | import 75 | 76 | 77 | org.jboss.resteasy.microprofile 78 | microprofile-rest-client 79 | ${version.resteasy.client} 80 | test 81 | 82 | 83 | 84 | 85 | 86 | 87 | basic 88 | tck 89 | 90 | 91 | 92 | 93 | 94 | org.apache.maven.plugins 95 | maven-install-plugin 96 | 97 | true 98 | 99 | 100 | 101 | org.sonatype.plugins 102 | nexus-staging-maven-plugin 103 | 104 | true 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /testsuite/tck/src/test/java/io/smallrye/jwt/tck/OptionalAwareSmallRyeJWTAuthCDIExtension.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.tck; 2 | 3 | import io.smallrye.jwt.auth.cdi.SmallRyeJWTAuthCDIExtension; 4 | 5 | public class OptionalAwareSmallRyeJWTAuthCDIExtension extends SmallRyeJWTAuthCDIExtension { 6 | // TODO - radcortez - This should be changed in the original extension. This is how Elytron is doing it. 7 | // Maybe because difference between 1.0 and 1.1? Right now it doesn't make sense to keeo it as is, since it will fail the TCK. 8 | @Override 9 | protected boolean registerOptionalClaimTypeProducer() { 10 | return true; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /testsuite/tck/src/test/java/io/smallrye/jwt/tck/SmallRyeJWTArchiveProcessor.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.tck; 2 | 3 | import java.util.Map; 4 | 5 | import jakarta.enterprise.inject.spi.Extension; 6 | 7 | import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor; 8 | import org.jboss.arquillian.test.spi.TestClass; 9 | import org.jboss.shrinkwrap.api.Archive; 10 | import org.jboss.shrinkwrap.api.ArchivePath; 11 | import org.jboss.shrinkwrap.api.Node; 12 | import org.jboss.shrinkwrap.api.spec.WebArchive; 13 | 14 | public class SmallRyeJWTArchiveProcessor implements ApplicationArchiveProcessor { 15 | @Override 16 | public void process(Archive applicationArchive, TestClass testClass) { 17 | if (applicationArchive instanceof WebArchive) { 18 | WebArchive war = (WebArchive) applicationArchive; 19 | war.addClass(OptionalAwareSmallRyeJWTAuthCDIExtension.class); 20 | war.addClass(SmallRyeJWTAuthJaxRsFeature.class); 21 | war.addAsServiceProvider(Extension.class, OptionalAwareSmallRyeJWTAuthCDIExtension.class); 22 | 23 | // MP Config in wrong place - See https://github.com/eclipse/microprofile/issues/46. 24 | Map content = war.getContent(object -> object.get().matches(".*META-INF/.*")); 25 | content.forEach((archivePath, node) -> { 26 | if (node.getAsset() != null) { 27 | war.addAsResource(node.getAsset(), node.getPath()); 28 | } 29 | }); 30 | 31 | if (!war.contains("META-INF/microprofile-config.properties")) { 32 | war.addAsWebInfResource("microprofile-config-local.properties", "microprofile-config.properties"); 33 | } 34 | 35 | // A few tests require the apps to be deployed in the root. Check PublicKeyAsJWKLocationURLTest and PublicKeyAsPEMLocationURLTest 36 | // Both tests set the public key location url to be in root. 37 | war.addAsWebInfResource("jboss-web.xml"); 38 | war.addAsWebInfResource("jetty-web.xml"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /testsuite/tck/src/test/java/io/smallrye/jwt/tck/SmallRyeJWTAuthJaxRsFeature.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.tck; 2 | 3 | import jakarta.ws.rs.ext.Provider; 4 | 5 | /** 6 | * This is to register the JAX-RS Feature to add the SmallRye JWT Filters. This cannot be registed as a Provider 7 | * Service Loader, because it would initialize before the JAX-RS Application is available in the Context. This is 8 | * required to check the LoginModule in the Application class and provide correct registration of the filters. 9 | */ 10 | @Provider 11 | public class SmallRyeJWTAuthJaxRsFeature extends io.smallrye.jwt.auth.jaxrs.SmallRyeJWTAuthJaxRsFeature { 12 | } 13 | -------------------------------------------------------------------------------- /testsuite/tck/src/test/java/io/smallrye/jwt/tck/SmallRyeJWTExtension.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.tck; 2 | 3 | import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor; 4 | import org.jboss.arquillian.core.spi.LoadableExtension; 5 | 6 | public class SmallRyeJWTExtension implements LoadableExtension { 7 | @Override 8 | public void register(final ExtensionBuilder builder) { 9 | builder.service(ApplicationArchiveProcessor.class, SmallRyeJWTArchiveProcessor.class); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /testsuite/tck/src/test/java/io/smallrye/jwt/tck/TestApplication.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.jwt.tck; 2 | 3 | import static jakarta.ws.rs.core.MediaType.TEXT_PLAIN; 4 | 5 | import java.io.IOException; 6 | import java.net.HttpURLConnection; 7 | import java.net.URL; 8 | import java.util.HashSet; 9 | import java.util.Set; 10 | 11 | import jakarta.enterprise.context.RequestScoped; 12 | import jakarta.servlet.annotation.WebServlet; 13 | import jakarta.servlet.http.HttpServlet; 14 | import jakarta.servlet.http.HttpServletRequest; 15 | import jakarta.servlet.http.HttpServletResponse; 16 | import jakarta.ws.rs.ApplicationPath; 17 | import jakarta.ws.rs.GET; 18 | import jakarta.ws.rs.Path; 19 | import jakarta.ws.rs.client.ClientBuilder; 20 | import jakarta.ws.rs.client.WebTarget; 21 | import jakarta.ws.rs.core.Response; 22 | 23 | import org.jboss.arquillian.container.test.api.Deployment; 24 | import org.jboss.arquillian.container.test.api.RunAsClient; 25 | import org.jboss.arquillian.test.api.ArquillianResource; 26 | import org.jboss.arquillian.testng.Arquillian; 27 | import org.jboss.shrinkwrap.api.ArchivePaths; 28 | import org.jboss.shrinkwrap.api.ShrinkWrap; 29 | import org.jboss.shrinkwrap.api.asset.EmptyAsset; 30 | import org.jboss.shrinkwrap.api.spec.WebArchive; 31 | import org.testng.Assert; 32 | import org.testng.annotations.Test; 33 | 34 | public class TestApplication extends Arquillian { 35 | /** 36 | * The base URL for the container under test 37 | */ 38 | @ArquillianResource 39 | private URL baseURL; 40 | 41 | @Deployment 42 | public static WebArchive createDeployment() { 43 | return ShrinkWrap 44 | .create(WebArchive.class) 45 | .addClass(TestServlet.class) 46 | .addClass(RestApplication.class) 47 | .addClass(TestEndpoint.class) 48 | .addAsWebInfResource(EmptyAsset.INSTANCE, ArchivePaths.create("beans.xml")); 49 | } 50 | 51 | @Test 52 | @RunAsClient 53 | public void servlet() { 54 | String uri = baseURL.toExternalForm() + "servlet"; 55 | WebTarget echoEndpointTarget = ClientBuilder.newClient().target(uri); 56 | Response response = echoEndpointTarget.request(TEXT_PLAIN).get(); 57 | Assert.assertEquals(response.getStatus(), HttpURLConnection.HTTP_OK); 58 | } 59 | 60 | @Test 61 | @RunAsClient 62 | public void rest() { 63 | String uri = baseURL.toExternalForm() + "rest"; 64 | WebTarget echoEndpointTarget = ClientBuilder.newClient().target(uri); 65 | Response response = echoEndpointTarget.request(TEXT_PLAIN).get(); 66 | Assert.assertEquals(response.getStatus(), HttpURLConnection.HTTP_OK); 67 | } 68 | 69 | @WebServlet(urlPatterns = "/servlet") 70 | public static class TestServlet extends HttpServlet { 71 | @Override 72 | protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws IOException { 73 | resp.getWriter().write("hello"); 74 | } 75 | } 76 | 77 | @ApplicationPath("/rest") 78 | public static class RestApplication extends jakarta.ws.rs.core.Application { 79 | @Override 80 | public Set> getClasses() { 81 | final HashSet> classes = new HashSet<>(); 82 | classes.add(TestEndpoint.class); 83 | return classes; 84 | } 85 | } 86 | 87 | @RequestScoped 88 | @Path("/") 89 | public static class TestEndpoint { 90 | @GET 91 | public String hello() { 92 | return "hello"; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /testsuite/tck/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension: -------------------------------------------------------------------------------- 1 | io.smallrye.jwt.tck.SmallRyeJWTExtension 2 | -------------------------------------------------------------------------------- /testsuite/tck/src/test/resources/arquillian.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | ${jacocoArgLine} 9 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /testsuite/tck/src/test/resources/jboss-web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | / 8 | 9 | 10 | -------------------------------------------------------------------------------- /testsuite/tck/src/test/resources/jetty-web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | / 5 | 6 | -------------------------------------------------------------------------------- /testsuite/tck/src/test/resources/microprofile-config-local.properties: -------------------------------------------------------------------------------- 1 | mp.jwt.verify.publickey.location=publicKey.pem 2 | mp.jwt.verify.issuer=https://server.example.com 3 | --------------------------------------------------------------------------------