Giter Club home page Giter Club logo

smallrye-jwt's Introduction

Contributing

Want to contribute? Great! We try to make it easy, and all contributions, even the smaller ones, are greatly welcome. This includes bug reports, fixes, documentation.

All SmallRye projects use GitHub Issues to manage issues. Open an issue directly in GitHub within the appropriate SmallRye project repository.

Becoming a Project Committer

Through continued contributions to SmallRye projects, other committers on the project can nominate you to become a committer too!

Check out the nomination process for full details.

All original contributions to SmallRye projects are licensed under the ASL - Apache License, version 2.0 or later, or, if another license is specified as governing the file or directory being modified, such other license.

All contributions are subject to the Developer Certificate of Origin (DCO). The DCO text is also included verbatim in the dco.txt file in the root directory of each repository.

Before you Contribute

To contribute, use GitHub Pull Requests, from your own fork.

Code Reviews

All submissions, including submissions by project members, need to be reviewed before they are merged.

Continuous Integration

We’re all human, so SmallRye projects use continuous integration to ensure consistency, particularly as most SmallRye projects need to pass the applicable MicroProfile TCK for that specification. Each pull request triggers a full build of the project. Please make sure to monitor the output of the build and act accordingly.

Tests and Documentation are not optional

Don’t forget to include tests in your pull requests. Also, don’t forget the documentation (Javadoc).

Setup

If you have not done so on your machine, you need to:

  • Install Git and configure your GitHub access

  • Install Java SDK (OpenJDK recommended)

  • Install Maven

IDE Config and Code Style

SmallRye projects have a strictly enforced code style. Code formatting is done by the Eclipse code formatter, using the config files found in Code Rules. By default when you run mvn install the code will be formatted automatically. When submitting a pull request the CI build will fail if running the formatter results in any code changes, so it is recommended that you always run a full Maven build before submitting a pull request.

Eclipse Setup

Open the Preferences window, and then navigate to JavaCode StyleFormatter. Click Import and then select the eclipse-format.xml file in the coderules directory.

Next navigate to JavaCode StyleOrganize Imports. Click Import and select the eclipse.importorder file.

IDEA Setup

Open the Preferences window, navigate to Plugins and install the [Eclipse Code Formatter Plugin](https://plugins.jetbrains.com/plugin/6546-eclipse-code-formatter).

Restart your IDE, open the Preferences window again and navigate to Other SettingsEclipse Code Formatter.

Select Use the Eclipse Code Formatter, then change the Eclipse Java Formatter Config File to point to the eclipse-format.xml file in the coderules directory. Make sure the Optimize Imports box is ticked, and select the eclipse.importorder file as the import order config file.

Signing Commits

Signing commits is required to make sure that the contributor matches the author. To be able to sign commits, use the following instructions: https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits

The small print

This project is an open source project, please act responsibly, be nice, polite, and enjoy!

smallrye-jwt's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

smallrye-jwt's Issues

JwtConsumer#processContext(JwtContext) called twice

The jose4j method org.jose4j.jwt.consumer.JwtConsumer.processContext(JwtContext) is called twice from DefaultJWTTokenParser. First (indirectly) during the call to org.jose4j.jwt.consumer.JwtConsumer.process(String) and then directly from DefaultJWTTokenParser after returning from process.

Improve the CDI code

Right now Thorntail and Quarkus have some CDI code which ideally should be located in smallrye-jwt in the form of CDIUtils and may be AbstractExtension referring to these CDIUtils for Thorntail (and may be WildFly) CDI extension code, as well as any Quarkus code integrating smallrye-jwt be able to reuse the same code.

Support the symmetric signature verification

It can be possible that the the server itself creates and signs the original JWT token to be used later for the cookie-based authentication (ex, JHipster). To access such tokens via MP JWT Api smallrye-jwt needs to optionally support the hash HS* algorithms which are currently blocked and then a user would just set a whitelist property enabling HS*.
The major change would have to be done in KeyLocationResolver. It will only be supported for the keys stored in the JWK format, and the verificationKey property would have to become just a Key type.
The somewhat unfortunate bit is that the location property is called mp.jwt.publickey.location, so a smallrye.jwt.secretkey.location would likely need to be introduced (it is unlikely the secret keys will be supported at the spec level)

Allow unverified JWT

Hi,
I asked in MP-JWT github about a way to configure no verification for the JWT. It might be something proprietary so I'll try asking here too. Is it possible to inject an un-verified JWT? I had to manually parse (and verify the auth header) instead of just using @Inject like I think should be possible.

Support the custom groups claims

For example a Keycloak token has its own nested claim for specifying the roles. It would be useful to be able to map it to the MP JWT groups

Claim CDI producer methods missing @RequestScoped

I didn't notice this before because I was directly using JsonWebTokens, but the producer methods in ClaimValueProducer, JsonValueProducer, and RawClaimTypeProducer do not specify a scope, which defaults to @Dependent. When injecting into @ApplicationScoped JAX-RS resources (and also @Stateless resources), the claims are not updated per each request.

NullPointerException when claims contain null values

When the value of a claim is an array that contains a null entry, a NullPointerException is thrown when the value is added to the JsonArrayBuilder in JWTCallerPrincipal.

It looks like jsonValue in JWTCallerPrincipal.wrapClaimValue() should be initialized to JsonValue.NULL instead of null.

Make DefaultJWTTokenParser easier to extend

At some stage the parsers may become pluggable but at the moment the pluggability at the factory level seems sufficient, so for now we can just make it very easy to customize specific parsing aspects for the users offering a custom factory

Introduce key format and JWK 'kid' properties and optimize PublicKey creation

At the moment 'KeyLocationResolver' loads a public key from the external resource on every request. This can be mostly optimized which will need to be done anyway (have a local volatile PublicKey property should do it for PEM or single JWK files).

But if it is a JWK set (which may contain N entries) then the problem is that the incoming 'kid' property can vary in theory so we can't settle on the single public key so iterating over the set every time can be expensive. In reality though it would be better and typically expected to have the same 'kid' - which would be managed at the key rotation point ex in the OIDC server. Expecting that every client may have used a different private key to sign is not really realistic from the security POV and as such the floating selection of keys from the JWK set can and should be optionally restricted to the specific 'kid' - and this will let it optimize the PublicKey creation as well.

Furthermore, with a new proiperty for specifying the key store format (PEM file, JKS store (in the future), JWK, JWKSet) the key selection can be further optimized.

It is related to #82 (we would not be able to do the above if the control of the JWK selection would stay inside Jose4J) so I'll fix both issues with a single PR

Create RFC7662 TokenIntrospectionFactory

RFC 7662 talks about OAuth2/OIDC servers returning token introspection responses.
Keycloak also implements it: https://issues.jboss.org/browse/KEYCLOAK-2266

Having such a factory will let the users (optionally) integrate with any certified OIDC servers. It will also allow to support the encrypted tokens issued by such servers (which choose to encrypt them) since importing the private keys of these providers into MP-JWT endpoints is not possible.

NullPointerException when loading a public key with a wrong resource name

Currently I'm working on a project with Quarkus and I was stuck on a NullPointerException that
was just logged on the console output.

[io.sm.jw.au.pr.DefaultJWTTokenParser]] (executor-thread-1) Token is invalid: JWT processing failed. Additional details: [[17] Unexpected exception encountered while processing JOSE object (java.lang.NullPointerException): JsonWebSignature{"kid":"....

After some debugging it appeared that I just mistyped the resource name in mp.jwt.verify.publickey.location.

So I will propose you a little modification to manage this case and avoid the NullPointerException.

The scope to group claim mapping will not work

The scope claim, if present, will have the value such as a b c as opposed to the expectation it would be an array. So if the mapping of scope to groups is needed then it won't work. A simple check that if it is a scope then extract the roles from a string should do

error when a add Authorization: Bearer string in curl header

DEBUG [io.qu.sm.jw.ru.au.JwtIdentityManager]] (executor-thread-1) failed, [email protected], credential=io.quarkus.smallrye.jwt.runtime.auth.JWTCredential@7619667a: org.wildfly.security.auth.server.RealmUnavailableException: Failed to verify token
	at io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator.validateClaimsSet(MpJwtValidator.java:44)
	at io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator.validate(MpJwtValidator.java:35)
	at io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator_ClientProxy.validate(Unknown Source)
	at org.wildfly.security.auth.realm.token.TokenSecurityRealm$TokenRealmIdentity.validateToken(TokenSecurityRealm.java:207)
	at org.wildfly.security.auth.realm.token.TokenSecurityRealm$TokenRealmIdentity.getClaims(TokenSecurityRealm.java:195)
	at org.wildfly.security.auth.realm.token.TokenSecurityRealm$TokenRealmIdentity.exists(TokenSecurityRealm.java:157)
	at org.wildfly.security.auth.realm.token.TokenSecurityRealm$TokenRealmIdentity.getEvidenceVerifySupport(TokenSecurityRealm.java:186)
	at org.wildfly.security.auth.server.ServerAuthenticationContext$UnassignedState.verifyEvidence(ServerAuthenticationContext.java:1659)
	at org.wildfly.security.auth.server.ServerAuthenticationContext$InactiveState.verifyEvidence(ServerAuthenticationContext.java:1391)
	at org.wildfly.security.auth.server.ServerAuthenticationContext.verifyEvidence(ServerAuthenticationContext.java:759)
	at org.wildfly.security.auth.server.SecurityDomain.authenticate(SecurityDomain.java:309)
	at org.wildfly.security.auth.server.SecurityDomain.authenticate(SecurityDomain.java:270)
	at io.quarkus.smallrye.jwt.runtime.auth.JwtIdentityManager.verify(JwtIdentityManager.java:36)
	at io.quarkus.smallrye.jwt.runtime.auth.JWTAuthMechanism.authenticate(JWTAuthMechanism.java:53)
	at io.undertow.security.impl.SecurityContextImpl$AuthAttempter.transition(SecurityContextImpl.java:245)
	at io.undertow.security.impl.SecurityContextImpl$AuthAttempter.transition(SecurityContextImpl.java:268)
	at io.undertow.security.impl.SecurityContextImpl$AuthAttempter.access$100(SecurityContextImpl.java:231)
	at io.undertow.security.impl.SecurityContextImpl.attemptAuthentication(SecurityContextImpl.java:125)
	at io.undertow.security.impl.SecurityContextImpl.authTransition(SecurityContextImpl.java:99)
	at io.undertow.security.impl.SecurityContextImpl.authenticate(SecurityContextImpl.java:92)
	at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:55)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
	at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
	at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
	at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
	at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.server.handlers.PathHandler.handleRequest(PathHandler.java:91)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292)
	at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
	at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138)
	at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
	at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
	at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
	at io.quarkus.undertow.runtime.UndertowDeploymentTemplate$8$1$1.call(UndertowDeploymentTemplate.java:482)
	at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
	at io.undertow.servlet.handlers.ServletInitialHandler.handleRequest(ServletInitialHandler.java:197)
	at io.undertow.server.handlers.HttpContinueReadHandler.handleRequest(HttpContinueReadHandler.java:65)
	at io.quarkus.undertow.runtime.UndertowDeploymentTemplate$1.handleRequest(UndertowDeploymentTemplate.java:90)
	at io.undertow.server.handlers.CanonicalPathHandler.handleRequest(CanonicalPathHandler.java:49)
	at io.quarkus.undertow.deployment.devmode.UndertowHotReplacementSetup.handleHotDeploymentRequest(UndertowHotReplacementSetup.java:77)
	at io.quarkus.undertow.deployment.devmode.UndertowHotReplacementSetup$1$1.handleRequest(UndertowHotReplacementSetup.java:56)
	at io.undertow.server.Connectors.executeRootHandler(Connectors.java:364)
	at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
	at io.quarkus.runtime.CleanableExecutor$CleaningRunnable.run(CleanableExecutor.java:243)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
	at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1538)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1395)
	at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
	at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:32)
	at java.base/java.lang.Thread.run(Thread.java:834)
	at org.jboss.threads.JBossThread.run(JBossThread.java:479)
Caused by: io.smallrye.jwt.auth.principal.ParseException: Failed to verify token
	at io.smallrye.jwt.auth.principal.DefaultJWTTokenParser.parse(DefaultJWTTokenParser.java:102)
	at io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator.validateClaimsSet(MpJwtValidator.java:41)
	... 56 more
Caused by: org.jose4j.jwt.consumer.InvalidJwtException: JWT processing failed. Additional details: [[17] Unable to process JOSE object (cause: org.jose4j.lang.UnresolvableKeyException: Failed to read location as any of JWK, JWKS, PEM; META-INF/resources/publicKey.pem): JsonWebSignature{"kid":"\/privateKey.pem","typ":"JWT","alg":"RS256"}-> **public-key-here**
	at org.jose4j.jwt.consumer.JwtConsumer.processContext(JwtConsumer.java:271)
	at org.jose4j.jwt.consumer.JwtConsumer.process(JwtConsumer.java:433)
	at io.smallrye.jwt.auth.principal.DefaultJWTTokenParser.parse(DefaultJWTTokenParser.java:70)
	... 57 more
Caused by: org.jose4j.lang.UnresolvableKeyException: Failed to read location as any of JWK, JWKS, PEM; META-INF/resources/publicKey.pem
	at io.smallrye.jwt.auth.principal.KeyLocationResolver.resolveKey(KeyLocationResolver.java:70)
	at org.jose4j.jwt.consumer.JwtConsumer.processContext(JwtConsumer.java:213)
	... 59 more

12:48:57 INFO  [io.un.re.security]] (executor-thread-1) Failed to authenticate JWT bearer token

Support OIDC client web servers better

This may become an MP-JWT issue, but some initial experiments can be done in smallrye-jwt.
Currently, as far as MP-JWT is concerned it can work well in cases where OIDC client (browser or webserver) acquires an access token and uses them to access RSs which is where MP-JWT helps.

For example, OIDC authorization code flow would typically involve a web server acting as OIDC client, redirecting the user to IDP, getting the authorization code, exchanging it for the access and ID tokens, and using the access token to make the remote RS calls.

Now, if MP-JWT is used in such the OIDC client then it can easily validate either ID or the access token, but it can't redirect the user back to IDP and it can't keep some session state. In fact it may better be done at the Quarkus/Thorntail/etc level, but I'm opening the issue here for some further investigations

Optimize KeyLocationResolver

KeyLocationResolver needs more work to clean it up, and remove the volatile qualifier from the verificationKey

Support elliptic curve ES256 public keys

I followed the instructions for AWS ALB OIDC authentication and configured Quarkus/SmallRye to read in the JWT from an HTTP header in the MP application.properties file:

#mp.jwt.verify.publickey.location=https://public-keys.auth.elb.us-west-1.amazonaws.com/some-uuid
mp.jwt.verify.publickey.location=META-INF/aws-jwt.pem
mp.jwt.verify.issuer=https://someorg.okta.com
smallrye.jwt.token.header=X-Amzn-Oidc-Data
quarkus.smallrye-jwt.auth-mechanism=MP-JWT
quarkus.smallrye-jwt.enabled=true

For whatever reason AWS resigns the JWT with their own key and they use Elilptic Curve based encryption and not RSA. When SmallRye tries to parse the PEM file remotely or locally it only tries to decode the PEM file as an RSA public key and fails.

Public key from http (without SSL) on Windows

We're facing a problem in our local environment when trying to get the public key from a non-SSL-protected server:

java.nio.file.InvalidPathException: Illegal char <:> at index 4: http://localhost:30000/auth/realms/test/protocol/openid-connect/certs
at sun.nio.fs.WindowsPathParser.normalize(WindowsPathParser.java:182)
at sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:153)
at sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:77)
at sun.nio.fs.WindowsPath.parse(WindowsPath.java:94)
at sun.nio.fs.WindowsFileSystem.getPath(WindowsFileSystem.java:255)
at sun.nio.fs.AbstractPath.resolve(AbstractPath.java:53)
at io.quarkus.runner.RuntimeClassLoader.findApplicationResourceContent(RuntimeClassLoader.java:446)
at io.quarkus.runner.RuntimeClassLoader.getResourceAsStream(RuntimeClassLoader.java:149)
at io.smallrye.jwt.auth.principal.KeyLocationResolver.getAsClasspathResource(KeyLocationResolver.java:287)
at io.smallrye.jwt.auth.principal.KeyLocationResolver.readKeyContent(KeyLocationResolver.java:188)
at io.smallrye.jwt.auth.principal.KeyLocationResolver.initializeKeyContent(KeyLocationResolver.java:161)
at io.smallrye.jwt.auth.principal.KeyLocationResolver.(KeyLocationResolver.java:77)
at io.smallrye.jwt.auth.principal.DefaultJWTTokenParser.getKeyResolver(DefaultJWTTokenParser.java:229)
at io.smallrye.jwt.auth.principal.DefaultJWTTokenParser.parse(DefaultJWTTokenParser.java:74)
at io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator.validateClaimsSet(MpJwtValidator.java:41)
at io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator.validate(MpJwtValidator.java:35)
at io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator_ClientProxy.validate(MpJwtValidator_ClientProxy.zig:193)
at org.wildfly.security.auth.realm.token.TokenSecurityRealm$TokenRealmIdentity.validateToken(TokenSecurityRealm.java:207)
at org.wildfly.security.auth.realm.token.TokenSecurityRealm$TokenRealmIdentity.getClaims(TokenSecurityRealm.java:195)
at org.wildfly.security.auth.realm.token.TokenSecurityRealm$TokenRealmIdentity.exists(TokenSecurityRealm.java:157)
at org.wildfly.security.auth.realm.token.TokenSecurityRealm$TokenRealmIdentity.getEvidenceVerifySupport(TokenSecurityRealm.java:186)
at org.wildfly.security.auth.server.ServerAuthenticationContext$UnassignedState.verifyEvidence(ServerAuthenticationContext.java:1659)
at org.wildfly.security.auth.server.ServerAuthenticationContext$InactiveState.verifyEvidence(ServerAuthenticationContext.java:1391)
at org.wildfly.security.auth.server.ServerAuthenticationContext.verifyEvidence(ServerAuthenticationContext.java:759)
at org.wildfly.security.auth.server.SecurityDomain.authenticate(SecurityDomain.java:309)
at org.wildfly.security.auth.server.SecurityDomain.authenticate(SecurityDomain.java:270)
at io.quarkus.smallrye.jwt.runtime.auth.JwtIdentityManager.verify(JwtIdentityManager.java:36)
at io.quarkus.smallrye.jwt.runtime.auth.JWTAuthMechanism.authenticate(JWTAuthMechanism.java:53)
at io.undertow.security.impl.SecurityContextImpl$AuthAttempter.transition(SecurityContextImpl.java:245)
at io.undertow.security.impl.SecurityContextImpl$AuthAttempter.transition(SecurityContextImpl.java:268)
at io.undertow.security.impl.SecurityContextImpl$AuthAttempter.access$100(SecurityContextImpl.java:231)
at io.undertow.security.impl.SecurityContextImpl.attemptAuthentication(SecurityContextImpl.java:125)
at io.undertow.security.impl.SecurityContextImpl.authTransition(SecurityContextImpl.java:99)
at io.undertow.security.impl.SecurityContextImpl.authenticate(SecurityContextImpl.java:92)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:55)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:65)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PathHandler.handleRequest(PathHandler.java:91)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:270)
at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:59)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:116)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:113)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$8$1$1.call(UndertowDeploymentRecorder.java:433)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:250)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:59)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:82)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:290)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:665)
at io.quarkus.runtime.CleanableExecutor$CleaningRunnable.run(CleanableExecutor.java:224)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1535)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1426)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
at java.lang.Thread.run(Thread.java:748)
at org.jboss.threads.JBossThread.run(JBossThread.java:479)

It might be possible that this is only a problem on Windows, because of the different PathParser. I think, at KeyLocationResolver.readKeyContent it is excepted that getAsClasspathResource returns with null if it didn't find anything. But the WindowsPathPatser instead throws an exception. So the last chance is = new URL(keyLocation).openStream(); isn't reached in my case.

KeyLocationResolver base64 decoding breaks pem processing

As part of my earlier PR #61 I tried to optimize the way base64 processing is done and pushed it out of JWK processing code to the loadContent ones. This broke the PEM processing which I only caught with Thorntail TCK tests.
I propose simply remove the Base64 decoding attempt as it was only meant originally for JWK but JWKs are not usually get Base64 encoded as the whole (but Base64Url encoded if they included as JOSE header properties).

Add a maximum time to live property

The tokens have to be short-lived in general, this is why, in OIDC/OAuth2 flows, refresh tokens with the longer life span exist, to refresh the ATs and thus minimize the theft risk.

JWT has an expiry claim but it may be set for a long time in the future. Sometimes to simplify the client code issuing the tokens. As such there has to be a property which can block the tokens which have been around for too long

Add configuration to verify and/or require audience claim

Utilizing JwtConsumerBuilder.setExpectedAudience(Boolean, String...). The logic should align with what is currently done to require/validate the issuer claim.

smallrye.jwt.verify.audiences (Optional<Set<String>>)
smallrye.jwt.verify.requireaud (Optional<Boolean>)

Potential configurations if incorporated into specification:
mp.jwt.verify.audiences
mp.jwt.verify.requireaud

Edit: make expected audiences property plural to align with JOSE4J API and OpenLiberty implementation.

Move the tck module into testsuite/basic similarly to smallrye-rest-client

Right now the tck module tests are not running the real TCK tests against a server, so the proposal is to move the current tests into a new testsuite/basic module and at some later stage a testsuite/tck can be added as well (may be the TCK can be run against WildFly and the authentication mechanism Mike Edgar is working upon, etc).

Make mapping from a single string to the groups claim more generic

At the moment, if a path to the custom claim containing the group values points to a non-array, single string, then it is only processed if it is a well known scope claim which has the space separated values.
The Quarkus discussion around the JHipster integration highlighted a limitation of the above approach, since the custom auth claim created by JHipster has the comma-separated values.
A new smallrye.jwt.groups-separator needs to be introduced with the default value " " for the current scope support to stay as currently is for the users.

Optimize the utility code for setting and calculating the path properties

Right now SmallryeJwtUtils has a nearly identical code for setting the sub and group path properties and DefaultJWTTokenParser has a nearly identical code for resolving those paths.
In the former case both functions can delegate to the internal one, while in the latter the common function can look for a final segment and let the cast be done in the sub and groups path code branches

Consolidate the way JWK sets are loaded

At the moment the JWT sets are dealt with in two different places. First mp.jwt.publickey.location is checked if it points to a JWK set resource in KeyLocationResolver. Next if an internal followMpJwt11Rules is set then it is assumed that instead of mp.jwt.publickey.location jwksUri was set and the keys are loaded not in the resolver but in the parser. So we have two ways to point to JWKs, only one of them is used in smallrye-jwt while the jwksUri path is used via a followMpJwt11Rules diversion from Thorntail.

This really needs to change and followMpJwt11Rules needs to go as it is confusing (and will become more so when we move to newer versions of MP JWT). Instead KeyLocationResolver should keep all the code for loading the keys, for example, it can check if the location starts from https etc.
JWTAuthContextInfo jwksUri should also be renamed to publicKeyLocation or similar, otherwise at the moment, if is actually used to load PEM keys as well, it is initialized with mp.jwt.publickey.location which adds the extra confusion.

Load mp.jwt.verify.publickey.location from current folder

As stated in MP-JWT Spec 1.1,

Relative or non-URL paths supplied as the location are resolved in the following order:

  1. new File(location)
  2. Thread.currentThread().getContextClassLoader().getResource(location)

However the first case is not working.

In my microprofile-config.properties, I have:

mp.jwt.verify.publickey.location=jwk-signature.json

If I put jwk-signature.json in the current folder and run

java -jar target/my-quarkus-runner.jar

I get:

2019-07-03 11:32:37,006 WARN  [io.sma.jwt.aut.pri.DefaultJWTTokenParser] (executor-thread-1) Token is invalid: JWT processing failed. Additional details: [[17] Unable to process JOSE object (cause: org.jose4j.lang.UnresolvableKeyException: Failed to load a key from: jwk-signature.json): JsonWebSignature{"alg":"RS256","kid":"..."}->...]

CDI extension and JSR-375

Is there any potential for this library to incorporate a CDI extension and perhaps an implementation of HttpAuthenticationMechanism, falling back to the JAX-RS filter if no runtime is available? Using JSR-375 seems like a natural fit for an implementation of MP-JWT (knowing that the API does not use JSR-375).

Are JWKS files cached locally?

Hello and thank you for your work.

I've introduced smallrye-jwt into my application and faced an SSL issue when the first request hit the secured endpoint.

So I'm guessing fetching JWKS from a remote location is lazy. Fine.

Is this put in a cache though ? I'm really concerned about this, since it could really slow down the incoming traffic dramatically, or even fail if JWKS endpoint is down for a moment.

I tried to look here but I'm not 100% sure.

Could you please confirm and close this issue/question if you have a few minutes? That'd be really helpful.

Thank you.

Improve the documentation

smallrye-jwt configuration has been significantly enhanced. The documentation needs to reflect it

KeyLocationResolver does not match on key ID

The io.smallrye.jwt.auth.principal.KeyLocationResolver.tryAsJWKx(String) does not compare the kid argument to the kid entry on the JWK(S) object(s) fetched from mp.jwt.verify.publickey.location.

JWTCallerPrincipal @RequestScoped

I'm using Microprofile JWT for Thorntail (which is using this library) and in my @ApplicationScoped bean, the principal (JsonWebToken) isn't @RequestScoped.

According to the specification 1.1 (or even 1.0), "7.1.1. Injection of JsonWebToken", JsonWebToken needs to be @RequestScoped, so the current caller is injected in @ApplicationScoped beans.

I'm not sure if JWTCallerPrincipal should get a @RequestScoped-annotation or if the thorntail-library should add a producer or something like this. But current behaviour is dangerous, because a second caller is getting identity from the first one.

So, is this the right place for this issue?

Support HTTPs based PEM files

It can help with doing the demos for example, given that the MP JWT spec mentions HTTPS but without restricting it to JWKS.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.