Giter VIP home page Giter VIP logo

jwks-rsa-java's Introduction

A Java library for obtaining JSON Web Keys from a JWKS (JSON Web Key Set) endpoint.

Build Status Coverage Status License Maven Central javadoc

Note As part of our ongoing commitment to best security practices, we have rotated the signing keys used to sign previous releases of this SDK. As a result, new patch builds have been released using the new signing key. Please upgrade at your earliest convenience.

While this change won't affect most developers, if you have implemented a dependency signature validation step in your build process, you may notice a warning that past releases can't be verified. This is expected, and a result of the key rotation process. Updating to the latest version will resolve this for you.

๐Ÿ“š Documentation - ๐Ÿš€ Getting Started - ๐Ÿ’ป API Reference ๐Ÿ’ฌ Feedback

Documentation

  • Examples - code samples for common jwks-rsa-java scenarios.
  • Docs site - explore our docs site and learn more about Auth0.

Getting Started

Requirements

Java 8 or above.

Installation

Add the dependency via Maven:

<dependency>
  <groupId>com.auth0</groupId>
  <artifactId>jwks-rsa</artifactId>
  <version>0.22.1</version>
</dependency>

or Gradle:

implementation 'com.auth0:jwks-rsa:0.22.1'

Usage

The JSON Web Tokens you obtain from an authorization server include a key id header parameter ("kid"), used to uniquely identify the Key used to sign the token.

Given the following JWT:

eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlJrSTVNakk1T1VZNU9EYzFOMFE0UXpNME9VWXpOa1ZHTVRKRE9VRXpRa0ZDT1RVM05qRTJSZyJ9.eyJpc3MiOiJodHRwczovL3NhbmRyaW5vLmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHw1NjMyNTAxZjQ2OGYwZjE3NTZmNGNhYjAiLCJhdWQiOiJQN2JhQnRTc3JmQlhPY3A5bHlsMUZEZVh0ZmFKUzRyViIsImV4cCI6MTQ2ODk2NDkyNiwiaWF0IjoxNDY4OTI4OTI2fQ.NaNeRSDCNu522u4hcVhV65plQOiGPStgSzVW4vR0liZYQBlZ_3OKqCmHXsu28NwVHW7_KfVgOz4m3BK6eMDZk50dAKf9LQzHhiG8acZLzm5bNMU3iobSAJdRhweRht544ZJkzJ-scS1fyI4gaPS5aD3SaLRYWR0Xsb6N1HU86trnbn-XSYSspNqzIUeJjduEpPwC53V8E2r1WZXbqEHwM9_BGEeNTQ8X9NqCUvbQtnylgYR3mfJRL14JsCWNFmmamgNNHAI0uAJo84mu_03I25eVuCK0VYStLPd0XFEyMVFpk48Bg9KNWLMZ7OUGTB_uv_1u19wKYtqeTbt9m1YcPMQ

Decode it using a JWT library or tool like jwt.io and extract the kid parameter from the Header claims.

{
  "typ": "JWT",
  "alg": "RS256",
  "kid": "RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg"
}

The kid value can then be used to obtain the JWK using a JwkProvider.

Create a JWKProvider using the domain from which to fetch the JWK. The provider will use the domain to build the URL https:{your-domain}/.well-known/jwks.json:

JwkProvider provider = new JwkProviderBuilder("https://samples.auth0.com/")
    .build();

A Jwk can be obtained using the get(String keyId) method:

Jwk jwk = provider.get("{kid of the signing key}"); // throws Exception when not found or can't get one

The provider can be configured to cache JWKs to avoid unnecessary network requests, as well as only fetch the JWKs within a defined rate limit:

JwkProvider provider = new JwkProviderBuilder("https://samples.auth0.com/")
        // up to 10 JWKs will be cached for up to 24 hours
        .cached(10, 24, TimeUnit.HOURS)
        // up to 10 JWKs can be retrieved within one minute
        .rateLimited(10, 1, TimeUnit.MINUTES)
        .build();

See the examples for additional configurations.

API Reference

Feedback

Contributing

We appreciate feedback and contribution to this repo! Before you get started, please see the following:

Raise an issue

To provide feedback or report a bug, please raise an issue on our issue tracker.

Vulnerability Reporting

Please do not report security vulnerabilities on the public Github issue tracker. The Responsible Disclosure Program details the procedure for disclosing security issues.


Auth0 Logo

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

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

jwks-rsa-java's People

Contributors

beckr avatar colin-b avatar dafortune avatar damieng avatar darthvalinor avatar evansims avatar foobert avatar fossabot avatar frederikprijck avatar ghostd avatar golszewski86 avatar hzalaz avatar jesseestum avatar jimmyjames avatar josephwitthuhntr avatar joshcanhelp avatar lbalmaceda avatar luisrudge avatar nvinuesa avatar pauldaviesc avatar poovamraj avatar ryber avatar saltukalakus avatar simon04 avatar sivertschou avatar skjolber avatar snyk-bot avatar sre-57-opslevel[bot] avatar w10t avatar xakepsdk avatar

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

jwks-rsa-java's Issues

Upgrade Jackson dependency to latest due to CVE-2019-12086

Description

com.fasterxml.jackson.core:jackson-databind:2.9.8

This was picked up by SourceClear and Snyk as a downstream dependendency vulnerability. I'm not sure where jackson is used in your code, but it appears to be a "high" vulnerability.

https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-12086
https://snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-174736

Solution: Upgrade to 2.9.9

Environment

  • Version of this library used: com.auth0:auth0:1.13.2

Flush JWT keys no longer available in key provider.

The current implementation caches individual JWK keys. This is a corner-case security issue because when the JWK source revokes (i.e. rotates its certificates), the old values are not ejected, as the library does not act on the fact that the revoked key is not present in the updated key list. So while currently applications will accept tokens signed with the new certificates, they will also keep accepting tokens signed with the revoked certificates.

Description

Walkthrough for a source with a single key.

Auth Service:

  1. Key A is created
  2. Tokens are issued with Key A

Application:
3. Token signed with key A is receieved.

Library:
4. Key A is requested
5. Key A is not in cache, visits Auth Service for key list
6. Source returns a list of keys: A
7. Key A is cached and returned

Application:
8. Key A is used to validate token signature

So far so good.

Auth Service:
9. Key A is revoked, Key B is created

Application:
10. Token signed with key A is receieved.

Library:
11. Key A is requested
12. Key A is already in cache and returned

Application:
13. Key A is used to validate token signature

So far so good. The application has no way of knowing that Key A is revoked.

Auth Service:
14. Tokens are issued with Key B

Application:
15. Token signed with key B is receieved.

Library:
16. Key B is requested
17. Key B is not in cache, visits Auth Service for key list
18. Source returns a list of keys: B
19. Key B is cached and returned

Application:
20. Key B is used to validate token signature.

So far so good. But because of step 19 does not flush A, we can still do

Application:
21. Token signed with key A is receieved.

Library:
22. Key A is requested
23. Key A is already in cache and returned

Prerequisites

Environment

Please provide the following:

  • Version of this library used: latest
  • Version of Java used: 8
  • Additional libraries that might be affecting your instance: None

Reproduction

See unit test

TestRevokingKey

in

https://github.com/skjolber/jwks-rsa-java/tree/revokeIssue

GuavaCachedJwkProvider vs UrlJwkProvider

Use of GuavaCachedJwkProvider together with UrlJwkProvider could be improved.

As an URL can contain several sertificates (UrlJwkProvider.getAll()), the whole cache can be refreshed rather than one key at a time.

Lets imagine that some tokens are issued for certificate A. Something happens and the certificate owner invalidates certificate A and and issues certificate B. Then the cache will continue to validate tokens signed with certificate A even after visiting the URL for getting certificate B.

UrlJwkProvider.get is hitting the internet on every call

Description

UrlJwkProvider.get is hitting the internet on every call. I'd expect to hit at most once on construction to obtain the public keys once

Reproduction

The original problem I was trying to solve was handling the case where auth0 was holding multiple public keys and they need to be matched to the JWT being verified. The obvious code to write would be like this

  val provider = new UrlJwkProvider(issuer)
  val decoded = JWT.decode(token)
    val keyId = decoded.getKeyId
    val keyInfo = provider.get(keyId)
    val publicKey = keyInfo.getPublicKey.asInstanceOf[RSAPublicKey]
    val algorithm = Algorithm.RSA256(publicKey, null)
    val verifier = JWT.require(algorithm)
      .withIssuer(issuer)
      .withAudience(audience)
      .build

    assertThrows[TokenExpiredException] {
      val jwt = verifier.verify(token)
    }

where we obtain only the right public key from the provider, which obtains it from the URL. However, the provider.get does an internet check on every call, which defeats the purpose of JWT verification being self-contained and fast

Expectation

UrlJwkProvider instances should load public keys only once.

Also, it would be good to have an explicitly documented way of verifying a JWT subject to multiple keys - auth0 docs say this case should be accounted for but I find no code samples that do it well. My above may not be the preferred way. If so, I'll take alternative code

Environment

Please provide the following:
jwks-rsa-0.9.0
deps were

  "com.auth0" % "java-jwt" % "3.8.3",
  "com.auth0" % "jwks-rsa" % "0.9.0"

For reference, the dodgy code in question is in UrlJwkProvider

    @Override
    public Jwk get(String keyId) throws JwkException {
        final List<Jwk> jwks = getAll();  // This calls getJwks, which then does the network hit
        if (keyId == null && jwks.size() == 1) {
            return jwks.get(0);
        }

p.s. I'm using scala for my testing but it is close enough to Java to understand

Add possibility to configure jwks endpoint path.

Describe the problem you'd like to have solved

My JWK provider is located at /.well-known/openid-configuration/jwks, but the library does not let me configure that. It currently only supports this path: /.well-known/jwks.json

Describe the ideal solution

I want to configure the JWK provider path using the JWKProviderBuilder, by doing something like this:

new JwkProviderBuilder(domain)
    .path("/.well-known/openid-configuration/jwks")
    .build();

If a path is not specified in the builder, then the default can still be /.well-known/jwks.json.

Alternatives and current work-arounds

No work-around as far as I know.

Additional information, if any

Bad design of jwks cache

Describe the problem you'd like to have solved

  1. Users may affect each other calling the server, that under the hood uses JwkProvider to validate the tokens. See the code below:
fun main() {
  val jwksUrl = "https://login.microsoftonline.com/common/discovery/keys".let {
    URI(it).normalize().toURL()
  }

  val foundKey = UrlJwkProvider(jwksUrl).all.first().id
  val notFoundKey = UUID.randomUUID().toString()

  val jwkProvider =
    JwkProviderBuilder(jwksUrl)
      .cached(100, 10, TimeUnit.MINUTES)
      .rateLimited(10, 1, TimeUnit.MINUTES)
      .build()

  /*
    someone requesting server with JWT, but which has invalid kid
   */
  repeat(11) {
    assertThrows<SigningKeyNotFoundException> {
      jwkProvider.get(notFoundKey)
    }
  }

  /*
    someone would like to request the server with valid JWT and will get rate limit error
   */
  jwkProvider.get(foundKey)
}
  1. If oauth2 server has several jwks (with different kid and algorithms) then library will call jwks endpoint as many times as there are keys. https://github.com/auth0/jwks-rsa-java/blob/master/src/main/java/com/auth0/jwk/UrlJwkProvider.java#L163

Describe the ideal solution

  1. Rate limit should not be there at all - it's responsibility of upper layer
  2. It's more preferable to cache all jwks at once, not one by one

I think the strategy should be the following: cache all jwks response from server and return found jwk by kid. Cache should be update by time.

Alternatives and current work-arounds

class CachedJwkProvider(
  private val delegate: UrlJwkProvider,
  private val expiration: Duration
) : JwkProvider, Closeable {

  private var cache = mapOf<String, Jwk>()

  private val cacheUpdaterJob = timer(
    name = "jwks-cache-updater",
    daemon = true,
    period = expiration.toMillis()
  ) {
    val actual = delegate.all.associateBy { it.id }
    cache = actual
  }

  override fun get(keyId: String): Jwk {
    return cache[keyId] ?: throw SigningKeyNotFoundException("No key found with kid $keyId", null)
  }

  override fun close() {
    cacheUpdaterJob.cancel()
  }
}

fun main() {
  val jwksUrl = "https://login.microsoftonline.com/common/discovery/keys".let {
    URI(it).normalize().toURL()
  }
  val urlJwkProvider = UrlJwkProvider(jwksUrl)
  val foundKey = urlJwkProvider.all.first().id
  val notFoundKey = UUID.randomUUID().toString()

  val jwkProvider = CachedJwkProvider(urlJwkProvider, Duration.ofMinutes(10))

  /*
    waiting cache to load. It's up to implementation make the "get()" call blocking or not. But I
    prefer do not wait any 3party system, therefore we need to wait here just for test
   */
  while (runCatching { jwkProvider.get(foundKey) }.isFailure)

  /*
    someone requesting server with JWT, but which has invalid kid
   */
  repeat(1000) {
    assertThrows<SigningKeyNotFoundException> {
      jwkProvider.get(notFoundKey)
    }
  }

  /*
    someone would like to request the server with valid JWT and will NOT get rate limit error
   */
  jwkProvider.get(foundKey)
}

BucketImpl is not public

BucketImpl is not public so I cannot use rate limiting without using JwkProviderBuilder. (Also I cannot set a connect and read timeout with JwkProviderBuilder, otherwise I would have just used it).

e.g. this is impossible:

JwkProvider url = new UrlJwkProvider("https://samples.auth0.com/");
Bucket bucket = new Bucket(10, 1, TimeUnit.MINUTES);
JwkProvider provider = new RateLimitJwkProvider(url, bucket);

Accept application/jwk-set+json as content type. [SDK-2131]

Description

The JWKS endpoint I am using supplies the key set with the content type application/jwk-set+json, as is in line with the spec. I saw that since #59 the header is set to accept only the application/json-type though. This leads to the call to UrlJwkProvider.getAll() throwing a SigningKeyNotFoundException, because 406: Not acceptable is returned by the server, as the content type in the accept-header is not matching the content type of the key set. I would recommend adding the possibility to supply a content type for the accept-header to the UrlJwkProvider or allowing it to accept either application/json or application/jwk-set+json

Reproduction

To reproduce this simply try using the library with a JWKS-Endpoint that supplies the key set with the content type application/jwk-set+json.

Stacktrace (JWK URL and android package are modified):

com.auth0.jwk.SigningKeyNotFoundException: Cannot obtain jwks from url https://example.com/app/authorization/v1/jwks
        at com.auth0.jwk.UrlJwkProvider.getJwks(UrlJwkProvider.java:112)
        at com.auth0.jwk.UrlJwkProvider.getAll(UrlJwkProvider.java:118)
        at com.auth0.jwk.UrlJwkProvider.get(UrlJwkProvider.java:136)
        at com.myapp.fragments.setup.OAuthFragment.validateToken(OAuthFragment.kt:167)
        at com.myapp.fragments.setup.OAuthFragment.access$validateToken(OAuthFragment.kt:53)
        at com.myapp.fragments.setup.OAuthFragment$onActivityResult$1$1$1.invokeSuspend(OAuthFragment.kt:110)
        at com.myapp.fragments.setup.OAuthFragment$onActivityResult$1$1$1.invoke(Unknown Source:10)
        at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:91)
        at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:155)
        at kotlinx.coroutines.BuildersKt.withContext(Unknown Source:1)
        at com.myapp.fragments.setup.OAuthFragment$onActivityResult$1$1.invokeSuspend(OAuthFragment.kt:106)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:238)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:742)
     Caused by: java.io.FileNotFoundException: https://example.com/app/authorization/v1/jwks
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:255)
        at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getInputStream(DelegatingHttpsURLConnection.java:211)
        at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:30)
        at com.auth0.jwk.UrlJwkProvider.getJwks(UrlJwkProvider.java:108)
        at com.auth0.jwk.UrlJwkProvider.getAll(UrlJwkProvider.java:118)ย 
        at com.auth0.jwk.UrlJwkProvider.get(UrlJwkProvider.java:136)ย 
        at com.myapp.fragments.setup.OAuthFragment.validateToken(OAuthFragment.kt:167)ย 
        at com.myapp.fragments.setup.OAuthFragment.access$validateToken(OAuthFragment.kt:53)ย 
        at com.myapp.fragments.setup.OAuthFragment$onActivityResult$1$1$1.invokeSuspend(OAuthFragment.kt:110)ย 
        at com.myapp.fragments.setup.OAuthFragment$onActivityResult$1$1$1.invoke(Unknown Source:10)ย 
        at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:91)ย 
        at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:155)ย 
        at kotlinx.coroutines.BuildersKt.withContext(Unknown Source:1)ย 
        at com.myapp.fragments.setup.OAuthFragment$onActivityResult$1$1.invokeSuspend(OAuthFragment.kt:106)ย 
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)ย 
        at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:238)ย 
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)ย 
        at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)ย 
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:742)ย 

Environment

  • Version of this library used: 0.9.0
  • I am using the library in Android.

Outdated Guava causing binary incompatibility

Describe the problem

Exception in thread "main" java.lang.NoSuchMethodError: 'com.google.common.cache.CacheBuilder com.google.common.cache.CacheBuilder.expireAfterWrite(java.time.Duration)'
   at com.auth0.jwk.GuavaCachedJwkProvider.<init>(GuavaCachedJwkProvider.java:54)
   at com.auth0.jwk.JwkProviderBuilder.build(JwkProviderBuilder.java:180)

Using the current version: 0.20.0 along with any recent version of the Google SDK (which brings in 31.0.x of Guava).

Feature Request: Full URLs in Builder Constructor

Hi,

would it not be useful if the constructor of the convenience class JwkProviderBuilder would also accept a URL? Currently it is unusable for situations where the URL differs from the standard pattern (ending with "/.well-known/jwks.json"). It assumes, that the given string is only the domain-name and "/.well-known/jwks.json" is appended.

PS: I thought I write a feature request before implementing it myself and starting a pull request.

Cheers and thanks for your work,
Dobo

Readme.md improvement

Checklist

  • I have looked into the Readme and Examples, and have not found a suitable solution or answer.
  • I have looked into the API documentation and have not found a suitable solution or answer.
  • I have searched the issues and have not found a suitable solution or answer.
  • I have searched the Auth0 Community forums and have not found a suitable solution or answer.
  • I agree to the terms within the Auth0 Code of Conduct.

Description

In the readme.md the example shows a JwkProvider with both caching and rate limiting.

Screenshot 2023-06-19 at 11 43 41

I don't think this is valid given the current builder.

https://github.com/auth0/jwks-rsa-java/blob/7eb15a274338dfed57bef063fe36291da5d9fae0/src/main/java/com/auth0/jwk/JwkProviderBuilder.java#L174C5-L183

Reproduction

n/a

Additional context

n/a

jwks-rsa version

current

Java version

n/a

Can't cast Jwk to RSAPublicKey

Using UrlJwkProvider here's my code.

JwkProvider provider = new UrlJwkProvider(url);
Jwk jwk = provider.get(keyId);
RSAPublicKey publicKey = (RSAPublicKey) jwk;

The reason I need the conversion is to use java-jwt library to be able to do this:

Algorithm algorithm = Algorithm.RSA256(publicKey, null);
JWTVerifier verifier = JWT.require(algorithm)
                       .withIssuer("auth0")
                       .build();
DecodedJWT jwt = verifier.verify(mToken);

I am getting an error saying
com.auth0.jwk.Jwk cannot be cast to java.security.interfaces.RSAPublicKey
even though it's in their documentation and they pointed me to this library (all under auth0).
Also

RSAPublicKey publicKey = jwk.getPublicKey();

doesn't work on Android because of missing decodebase64 error.
Any ideas?

Upgrade compliance to jdk8 and allow usage of java.time.Duration in builder(s)

I start a new springboot project that allow to use duration in properties file see (https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-conversion-duration) so to define for exemple cacheduration in JwkProviderBuilder I would prefer to use a Duration instead of the method
public JwkProviderBuilder cached(long cacheSize, long expiresIn, TimeUnit unit); this involve to upgrade the hava minimum compliance to jdk8.

How to enable Http Proxy?

We are deploying our code in openshift container and we are unable to communicate with auth0 provider as we need to connect to external world using proxy?

How to use proxy using java-rsa jar?

Related to #19

NetworkException not being thrown when using cached JwkProviderBuilder instead of directly UrlJwkProvider

Describe the problem

As per: examples we should be able to catch NetworkException when getting JWK using cached JwkProviderBuilder. But in here that error is caught and replaced with SigningKeyNotFoundException (as ExecutionException includes NetworkException):

@Override
public Jwk get(final String keyId) throws JwkException {
    try {
        String cacheKey = keyId == null ? NULL_KID_KEY : keyId;
        return cache.get(cacheKey, new Callable<Jwk>() {
            @Override
            public Jwk call() throws Exception {
                return provider.get(keyId);
            }
        });
    } catch (ExecutionException e) {
        throw new SigningKeyNotFoundException("Failed to get key with kid " + keyId, e);
    }
}

This basically recreates the issue: #79.

What was the expected behavior?

NetworkException being thrown directly from: JwkProviderBuilder(URL(...)).cached(...).build().get(...) method when unable to connect to the url.

Reproduction

  • Create cached provider for some urlPath of an offline server: val provider = JwkProviderBuilder(URL(urlPath)).cached(10, 1, TimeUnit.MINUTES).build()
  • Try to access the JWK for some keyId: provider.get(keyId)
  • Get the SigningKeyNotFoundException: Failed to get key with kid ****
  • Only able to trace exception.cause: java.util.concurrent.ExecutionException: com.auth0.jwk.NetworkException: Cannot obtain jwks from url ****

Environment

  • Version of this library used: 0.21.2
  • Version of Java used: 11 (Kotlin 1.3.72)
  • Other modules/plugins/libraries that might be involved:
  • Any other relevant information you think would be useful:

com.auth0.jwk.SigningKeyNotFoundException: Cannot obtain jwks from url https://<oauth_server>/.well-known/jwks.json

I am trying to validate incoming request that has authorization token (jwt) via Java JWT api. I was able to decode header and payload via that API but having trouble to validate the token. Little I know of this area, I thought I have to add jwks-rs-java api to my test project in order to handle validation part so I imported and ran following statements based on the documentation I read.

JwkProvider provider = new UrlJwkProvider("oauth_Server");
Jwk jwk = provider.get("keyId");

Then I got SingingKeyNotFoundException but caused by javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

I am trying to understand the problem itself and how to rectify it. Did I provide wrong key id? Do I need to import a certificate of the remote "oauth_server" into my local box in where I build/execute project in IDE?

I'd appreciate your advice and input on this matter. Thank you!

Improve release procedure

To help reduce the burden of making a new release, we need to first:

  • Add new Changelog labels
  • Add a properchangelog.md file.
  • Move from Maven to Gradle
  • Make use of our oss plugin
  • Move from Travis to CircleCI v2
  • Update status badges at the top of the Readme
  • Enforce snyk.io checks on PRs

Provide a Jwk constructor from a map of values

I am using this project but I would really need a way to create a Jwk from a Json object.

Since there already exists a (package private) method fromValues in the Jwk class that takes a Map as parameter, making it public could be an easy way for providing an static method for creation from a json.

UrlJwkProvider failed to load keys and throws ssl handshake exception

Trying to load keys from "https://inferno.healthit.gov/suites/custom/g10_certification/.well-known/jwks.json" fails with below error.
com.auth0.jwk.SigningKeyNotFoundException: Cannot obtain jwks from url https://inferno.healthit.gov/suites/custom/g10_certification/.well-known/jwks.json
at com.auth0.jwk.UrlJwkProvider.getJwks(UrlJwkProvider.java:112)
at com.auth0.jwk.UrlJwkProvider.getAll(UrlJwkProvider.java:118)
at com.auth0.jwk.UrlJwkProvider.get(UrlJwkProvider.java:136)
at com.ge.util.JWTVerifier.getPublicKeys(JWTVerifier.java:134)
at JwtSignerVerifier.ClientSecretJwtTest.testjwksLoad(ClientSecretJwtTest.java:128)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alert.createSSLException(Alert.java:131)
at sun.security.ssl.TransportContext.fatal(TransportContext.java:370)
at sun.security.ssl.TransportContext.fatal(TransportContext.java:313)
at sun.security.ssl.TransportContext.fatal(TransportContext.java:308)
at sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:652)
at sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:471)
at sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:367)
at sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:376)
at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:479)
at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:457)
at sun.security.ssl.TransportContext.dispatch(TransportContext.java:200)
at sun.security.ssl.SSLTransport.decode(SSLTransport.java:154)
at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1290)
at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1199)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:401)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:373)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:587)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:197)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1570)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1498)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:268)
at com.auth0.jwk.UrlJwkProvider.getJwks(UrlJwkProvider.java:108)
... 27 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:439)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306)
at sun.security.validator.Validator.validate(Validator.java:271)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:312)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:221)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:128)
at sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:636)
... 44 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:434)

The same url in reachable from the browser but fails from code. Could you please look into the issue.

Java 11 and artifactId is jwks-rsa version 0.9.0

Thanks

To support higher TLS Version

currently to get the jwk keys from discovery URL(https://login.microsoftonline.com/tenentID/discovery/v2.0/keys). It creates default URLConnection and TLS.
How we can create customized TLS connection. My server is disabled TLSv1 and TLSv1.1.
class:
public class UrlJwkProvider implements JwkProvider {
method:
private Map<String, Object> getJwks() throws SigningKeyNotFoundException {

URLConnection connection = (URLConnection) url.openConnection();

Something similar like this.
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();

SSLContext sc = SSLContext.getInstance("TLSv1.2");
sc.init(null, null, new java.security.SecureRandom());

com.auth0.jwk.Jwk.getPublicKey() returns null if not RSA

The javadoc and the implementation of this method don't match, I expect a InvalidPublicKeyException if the key type is not RSA, but I instead get null:

/**
 * Returns a {@link PublicKey} if the {@code 'alg'} is {@code 'RSA'}
 * @return a public key
 * @throws InvalidPublicKeyException if the key cannot be built or the key type is not RSA
 */
@SuppressWarnings("WeakerAccess")
public PublicKey getPublicKey() throws InvalidPublicKeyException {
    if (!PUBLIC_KEY_ALGORITHM.equalsIgnoreCase(type)) {
        return null;
    }

Ability to drop cache

Checklist

  • I have looked into the Readme and Examples, and have not found a suitable solution or answer.
  • I have looked into the API documentation and have not found a suitable solution or answer.
  • I have searched the issues and have not found a suitable solution or answer.
  • I have searched the Auth0 Community forums and have not found a suitable solution or answer.
  • I agree to the terms within the Auth0 Code of Conduct.

Describe the problem you'd like to have solved

Some jwk providers rotate their keys (AWS for example), their documentation says that if issuer matches but keyId is wrong, to get latest JWK keys. This is not possible with the current caching of this library.
https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html

Describe the ideal solution

Perhaps there should be an exposed function to drop the cache or try to pull latest before throwing an Exception?

Alternatives and current workarounds

No response

Additional context

No response

Base 64 decoder changed

Describe the problem

In version 0.17.1 the implementation of Base64 decoding was changed from apache commons codec to the java build in one.

See for example here:

BigInteger modulus = new BigInteger(1, Base64.getUrlDecoder().decode(stringValue("n")));

The problem is, that this also changed from the not url safe implementation of apache commons codec to the url safe variant of jdk. Which breaks existing code.

What was the expected behavior?

The implementation now is the correct one, as spec clearly says that the data in the jwk has to be base64 url encoded. I just wonder if there is a possibility to add compatibility code into e.g.

return (String) additionalAttributes.get(key);

like suggested here: https://stackoverflow.com/a/26354677 (just doing a string replace)

That would not break existing code and would give users a chance to fix their jwk implementation, as the code would accept both url encoded and not encoded JSONs. The compatibility code can then be removed in a breaking release version like 1.0.0

Reproduction

  • Create a JWK with normal Base64 encoded exponent
  • JWK will work in version 0.17.0
  • JWK will not work for version 0.17.1 onwards

Environment

  • Version of this library used:: 0.18.0
  • **Version of Java used:**11

kid

how to generation the kid?and how to put the kid to the JwkProvider?

Remove commons-codec dependency

Describe the problem you'd like to have solved

Remove commons-codec dependency

Describe the ideal solution

It's only used for Base64, since Java 8, Java has standard api for dealing with Base64

UrlJwkProvider crashes when pulling the same keys twice in a row

Describe the problem

UrlJwkProvider crashes when pulling the same keys twice in a row. This problem only appeared after the recent Network Edge Migration. It seems the problem is related to the following line:

return reader.readValue(inputStream);

Replacing it with

var bytes = inputStream.readAllBytes();
return reader.readValue(bytes);

seems to fix the issue. My guess is that the existing connection isn't properly closed and Cloudflare doesn't seem to like that.

Reproduction

final var provider = new UrlJwkProvider("https://auth.rideos.ai/");
provider.getAll();
provider.getAll();
Exception in thread "main" com.auth0.jwk.NetworkException: Cannot obtain jwks from url https://auth.rideos.ai/.well-known/jwks.json
	at com.auth0.jwk.UrlJwkProvider.getJwks(UrlJwkProvider.java:127)
	at com.auth0.jwk.UrlJwkProvider.getAll(UrlJwkProvider.java:133)
	at main(main.java:100)
Caused by: java.io.IOException: Server returned HTTP response code: 403 for URL: https://auth.rideos.ai/.well-known/jwks.json
	at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1913)
	at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1509)
	at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:245)
	at com.auth0.jwk.UrlJwkProvider.getJwks(UrlJwkProvider.java:123)
	... 2 more

Environment

  • Version of this library used: com.auth0:jwks-rsa:0.15.0
  • Version of Java used: 11.0.1
  • Other modules/plugins/libraries that might be involved: com.fasterxml.jackson:2.12.0
  • Any other relevant information you think would be useful:

provider.get("key") no key found in tenant with kid "key

I am trying to retrieve my kid from my jwks.json through this library and I can not seem to extract the kid even though my jwks.json looks like

{
"keys": [
  {
    "alg": "RS256",
    "kty": "RSA",
    "use": "sig",
    "x5c": [
      "MIIC+DCCAeCgAwIBAgIJBIGjYW6hFpn2MA0GCSqGSIb3DQEBBQUAMCMxITAfBgNVBAMTGGN1c3RvbWVyLWRlbW9zLmF1dGgwLmNvbTAeFw0xNjExMjIyMjIyMDVaFw0zMDA4MDEyMjIyMDVaMCMxITAfBgNVBAMTGGN1c3RvbWVyLWRlbW9zLmF1dGgwLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMnjZc5bm/eGIHq09N9HKHahM7Y31P0ul+A2wwP4lSpIwFrWHzxw88/7Dwk9QMc+orGXX95R6av4GF+Es/nG3uK45ooMVMa/hYCh0Mtx3gnSuoTavQEkLzCvSwTqVwzZ+5noukWVqJuMKNwjL77GNcPLY7Xy2/skMCT5bR8UoWaufooQvYq6SyPcRAU4BtdquZRiBT4U5f+4pwNTxSvey7ki50yc1tG49Per/0zA4O6Tlpv8x7Red6m1bCNHt7+Z5nSl3RX/QYyAEUX1a28VcYmR41Osy+o2OUCXYdUAphDaHo4/8rbKTJhlu8jEcc1KoMXAKjgaVZtG/v5ltx6AXY0CAwEAAaMvMC0wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQUQxFG602h1cG+pnyvJoy9pGJJoCswDQYJKoZIhvcNAQEFBQADggEBAGvtCbzGNBUJPLICth3mLsX0Z4z8T8iu4tyoiuAshP/Ry/ZBnFnXmhD8vwgMZ2lTgUWwlrvlgN+fAtYKnwFO2G3BOCFw96Nm8So9sjTda9CCZ3dhoH57F/hVMBB0K6xhklAc0b5ZxUpCIN92v/w+xZoz1XQBHe8ZbRHaP1HpRM4M7DJk2G5cgUCyu3UBvYS41sHvzrxQ3z7vIePRA4WF4bEkfX12gvny0RsPkrbVMXX1Rj9t6V7QXrbPYBAO+43JvDGYawxYVvLhz+BJ45x50GFQmHszfY3BR9TPK8xmMmQwtIvLu1PMttNCs7niCYkSiUv2sc2mlq1i3IashGkkgmo="
    ],
    "n": "yeNlzlub94YgerT030codqEztjfU_S6X4DbDA_iVKkjAWtYfPHDzz_sPCT1Axz6isZdf3lHpq_gYX4Sz-cbe4rjmigxUxr-FgKHQy3HeCdK6hNq9ASQvMK9LBOpXDNn7mei6RZWom4wo3CMvvsY1w8tjtfLb-yQwJPltHxShZq5-ihC9irpLI9xEBTgG12q5lGIFPhTl_7inA1PFK97LuSLnTJzW0bj096v_TMDg7pOWm_zHtF53qbVsI0e3v5nmdKXdFf9BjIARRfVrbxVxiZHjU6zL6jY5QJdh1QCmENoejj_ytspMmGW7yMRxzUqgxcAqOBpVm0b-_mW3HoBdjQ",
    "e": "AQAB",
    "kid": "NjVBRjY5MDlCMUIwNzU4RTA2QzZFMDQ4QzQ2MDAyQjVDNjk1RTM2Qg",
    "x5t": "NjVBRjY5MDlCMUIwNzU4RTA2QzZFMDQ4QzQ2MDAyQjVDNjk1RTM2Qg"
  }
]}

I am trying to do

JwkProvider provider = new UrlJwkProvider("https://samples.auth0.com/");
Jwk jwk = provider.get("kid"); 

but no luck.

Retrieval of Jwk token is blocking

This could also be viewed as a feature request, but I think it is more of a bug given that I've later discovered the following line of JwkProvider to be a blocking call:

    Jwk get(String keyId) throws JwkException;

Should we not return a future instead?

UrlJwkProvider not able to retrieve jwk

Describe the problem

The UrlJwkProvider is not able to retrieve jwk with this URL https://localhost:31300/.well-known/openid-configuration/jwks
I am getting SigningKeyNotFoundException at provider.get(jwt.getKeyId()); The jwt.getKeyId() works

Does it only work for xxx/jwks.json ? I can get response by using postman

{
    "keys": [
        {
            "kty": "RSA",
            "use": "sig",
            "kid": "0538f4763b647a8a01305774b9f4d5f1",
            "e": "AQAB",
            "n": "6h5hL5UfOW8SGFRNeVuU9M92p6cOWF-941vGqZ8y-PL6jC-B_2S7kp_Cw7SvOajd6CqBpQyiuP21pjhQILU4ikqq7-WbnxNZcvOQcYPLpUzupn5MBQkHk_bYONPInu-jU55FZhuYdO3sz0qS58AEqlnQbKZYLvU_KS_Ou4mSnTJr_hfwrk75cnsAMzhkVcsMt9GaSJZbj4zccIEUVQpiYLTY3gK_Nbym5ZKYfsayOHDSwLLsZchJ5VJnc1mAiZwGtszyjdCJSipQF_wdFcacmfGDwyXY4mnER32aT5Fo20lihnEJ5T1IXkwFMgWJVesiaHJQNqxAMEg86SWSN3_A0Q",
            "alg": "RS256"
        }
    ]
}

Distinct between connection issues and attacks in UrlJwkProvider

Describe the problem you'd like to have solved

Hi there in UrlJwkProvider a SigningKeyNotFoundException is thrown in the method "Jwk get(String keyId)" for two different reasons:

  1. If in getAll()-> getJwks() the connection to the location of the JWK fails. Which is an serious issue for operation of the service, as most likely all token could not be verified)
  2. If the KeyId in the token could not be found. (most likely if an attacker sets an arbitrary key id in the token)

Describe the ideal solution

Please make it possible to distinct between these two cases with a proper exception being thrown. To not break any existing code, which is calling the methods, the new exception should be a child class of SigningKeyNotFoundException or a RuntimeException.

Alternatives and current work-arounds

A current workaround will be to look at the cause of the exception, which is a fragile, as one has to know which specific connection issues could occur and that there is no other place, where such an exception could be thrown.

An alternative of the approach above will be to change the return type of "Jwk get(String keyId)" to "Optional get(String keyId)" that there is a distinction between the the more common case, where a key with the wrong keyId is requested an an exceptional connection problem. This will involve more rework.

Thank you for considering this change.

Support EC key type in JWK

JWK entries can have type key types (kty) according to RFC 7517: RSA and EC. The current implementation is covering only RSA.

I'm working on a project where the token provider is signing JWT's with EC and those must be checked with JWKS which is containing the public keys of rotating EC .

I would like to make the Jwk class to work the way that it is recognising both key types and it is able to return the corresponding public keys according to the specified parameters in the JWK JSON entry.

com.auth0.jwk.Jwk#getPublicKey recreates PublicKey object on every access

Even when using a cached JwkProvider, the com.auth0.jwk.Jwk#getPublicKey method will reconstruct a public key object in memory on every call.

Although the caching prevents remote calls, at high volumes (eg thousands requests/sec, each requiring JWT verification) this amount of object allocation creates a measureable overhead.

Build error due to adding jwks-rsa-java library

Hi!

I added jwks-rsa-java as a dependency in the build.gradle file in my /{PROJECT_NAME}/app directory as below (jwks-rsa-java is added right at the end)

apply plugin: 'com.android.application'
apply plugin: "androidx.navigation.safeargs"

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.example.android.intouch_android"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        manifestPlaceholders = [auth0Domain: "@string/com_auth0_domain", auth0Scheme: "demo"]
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    def lifecycle_version = "1.1.1"

    // LiveData + ViewModel
    implementation "android.arch.lifecycle:extensions:$lifecycle_version"
    // Retrofit (HTTP client library)
    implementation 'com.squareup.retrofit2:retrofit:2.4.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
    // GSON (JSON library)
    implementation 'com.google.code.gson:gson:2.8.5'

    // Parceler (library for de/serializing complex objects
    implementation 'org.parceler:parceler-api:1.1.11'
    annotationProcessor 'org.parceler:parceler:1.1.11'

    def nav_version = "1.0.0-alpha06"

    implementation "android.arch.navigation:navigation-fragment:$nav_version"
    implementation "android.arch.navigation:navigation-ui:$nav_version"

    def room_version = "1.1.1"

    implementation "android.arch.persistence.room:runtime:$room_version"
    annotationProcessor "android.arch.persistence.room:compiler:$room_version"

    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support:design:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    implementation 'com.android.support:support-vector-drawable:28.0.0'
    implementation 'com.android.support:support-v4:28.0.0'
    implementation 'com.android.support:recyclerview-v7:28.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

    // Identity authentication
    implementation 'com.auth0.android:auth0:1.14.1'
    implementation'com.auth0:java-jwt:3.4.1'
    implementation 'com.auth0:jwks-rsa:0.6.1'
}

When I try to build my project in Android Studio 3.3 Preview, I get an error saying:

Error: Program type already present: com.google.common.util.concurrent.internal.InternalFutureFailureAccess

I have confirmed that the build error is due to adding jwks-rsa-java. Would anyone happen to have a clue on what's going on here?

Thanks for the help!

RateLimitedJwkProvider multi-threading behaviour

If there is an influx of requests (i.e. when a pod goes online on kubernetes), RateLimitReachedException could be thrown because the bucket size is exceeded before the UrlJwkProvider returns. Also, multiple requests would be issued for the same data.

Description

A proper solution would synchronize threads so that this cannot happen; let the first thread fetch the data and block the subsequent threads untill it returns.

Prerequisites

Environment

Reproduction

Add JDK 9+ / modules support

Describe the problem you'd like to have solved

Using this library deterministicly as an dependency in a JDK 9+ project; fixing the module name.

Describe the ideal solution

Multi-release jar.

Alternatives and current work-arounds

Automatic-Module-Name goes a long way.

Provide a getPrivateKey method in Jwk

Description

Signing JWT tokens will become easier if the Jwk class were to have a createPrivateKey method, similar to its getPublicKey method.
The returned private key could be used in a KeyProvider, which in turn can be used to create an algorithm with the capability to sign JWT tokens.

Like you already used for the public key, the RFC states which parameters should be used for creating its private counterpart.
I would expect the method to raise an error if the jwk does not contain the correct parameters to create a private key.

Prerequisites

Environment

Please provide the following:

  • Version of this library used: 0.7.0
  • Version of Java used: 11
  • Additional libraries that might be affecting your instance: -

URI null host

I'm getting an IllegalArgumentException because of a null URI host when attempting to authenitcate an OAuth JWT token with JwtAuthenticationProvider.jwtVerifier

Caused by: java.lang.IllegalArgumentException: protocol = https host = null
2018-02-14T13:48:35.702463+00:00 app[web.1]: at sun.net.spi.DefaultProxySelector.select(DefaultProxySelector.java:177) ~[na:1.8.0_161-heroku]
2018-02-14T13:48:35.702464+00:00 app[web.1]: at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1150) ~[na:1.8.0_161-heroku]
2018-02-14T13:48:35.702465+00:00 app[web.1]: at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1050) ~[na:1.8.0_161-heroku]
2018-02-14T13:48:35.702466+00:00 app[web.1]: at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:177) ~[na:1.8.0_161-heroku]
2018-02-14T13:48:35.702479+00:00 app[web.1]: at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1564) ~[na:1.8.0_161-heroku]
2018-02-14T13:48:35.702480+00:00 app[web.1]: at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492) ~[na:1.8.0_161-heroku]
2018-02-14T13:48:35.702481+00:00 app[web.1]: at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:263) ~[na:1.8.0_161-heroku]
2018-02-14T13:48:35.702482+00:00 app[web.1]: at java.net.URL.openStream(URL.java:1045) ~[na:1.8.0_161-heroku]
2018-02-14T13:48:35.702484+00:00 app[web.1]: at com.auth0.jwk.UrlJwkProvider.getJwks(UrlJwkProvider.java:58) ~[jwks-rsa-0.2.0.jar!/:na]
2018-02-14T13:48:35.702508+00:00 app[web.1]: at com.auth0.jwk.UrlJwkProvider.getAll(UrlJwkProvider.java:71) ~[jwks-rsa-0.2.0.jar!/:na]
2018-02-14T13:48:35.702509+00:00 app[web.1]: at com.auth0.jwk.UrlJwkProvider.get(UrlJwkProvider.java:89) ~[jwks-rsa-0.2.0.jar!/:na]
2018-02-14T13:48:35.702511+00:00 app[web.1]: at com.auth0.jwk.RateLimitedJwkProvider.get(RateLimitedJwkProvider.java:30) ~[jwks-rsa-0.2.0.jar!/:na]
2018-02-14T13:48:35.702512+00:00 app[web.1]: at com.auth0.jwk.GuavaCachedJwkProvider$1.call(GuavaCachedJwkProvider.java:49) ~[jwks-rsa-0.2.0.jar!/:na]
2018-02-14T13:48:35.702513+00:00 app[web.1]: at com.auth0.jwk.GuavaCachedJwkProvider$1.call(GuavaCachedJwkProvider.java:46) ~[jwks-rsa-0.2.0.jar!/:na]
2018-02-14T13:48:35.702514+00:00 app[web.1]: at com.google.common.cache.LocalCache$LocalManualCache$1.load(LocalCache.java:4793) ~[guava-19.0.jar!/:na]
2018-02-14T13:48:35.702515+00:00 app[web.1]: at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3542) ~[guava-19.0.jar!/:na]
2018-02-14T13:48:35.702516+00:00 app[web.1]: at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2323) ~[guava-19.0.jar!/:na]
2018-02-14T13:48:35.702518+00:00 app[web.1]: at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2286) ~[guava-19.0.jar!/:na]
2018-02-14T13:48:35.702519+00:00 app[web.1]: at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2201) ~[guava-19.0.jar!/:na]

The exception is thrown from line 164 of sun.net.spi.DefaultProxySelector because the URI host is not being set correctly and is null.

java -version
openjdk version "1.8.0_161-heroku"
OpenJDK Runtime Environment (build 1.8.0_161-heroku-b12)
OpenJDK 64-Bit Server VM (build 25.161-b12, mixed mode)

Get rid of guava

Describe the problem you'd like to have solved

I want to get rid of guava. It's very big and not modularized.
Project i work on is 100% modularized and i need this library, but it uses guava.

Describe the ideal solution

  1. Get rid of Guava where possible
  2. On modules side use requires static and in runtime check once if guava is available and if it's not available and guava cached provider requested, throw an exception, both features can be implemented using multi version jars

Alternatives and current work-arounds

From this project side:

  1. Get rid of Guava where possible, it's every class except GuavaCachedJwkProvider

From my project side:

  1. Use build plugins to generate module descriptor
  2. Strictly check to not use cached provider <- not sure how well this will work with modules

Additional information, if any

I will create PR to get rid of guava where possible

Send HTTP_ACCEPT as application/json

Description

When attempting to fetch the JWKS from a new server the following is set in the Accept Header
'HTTP_ACCEPT: text/html, image/gif, image/jpeg, *; q=.2, /; q=.2'

This is the standard Java HTTP library behaviour.

However Django Rest Framework will return it's API browser page if HTML is mentioned in the ACCEPT field, which obviously cannot be parsed as JSON.

I have included a small patch below, which should fix this, you can use the 'git apply-patch' to recreate my commit.

From b71c07db38ab983b3ab9e072145db1c5e589a3be Mon Sep 17 00:00:00 2001
From: Chris Huang-Leaver <[email protected]>
Date: Mon, 15 Apr 2019 11:20:28 +1000
Subject: [PATCH] Explicitly set Accept parameter to request only JSON from
 server

Django REST Framework in particular returns HTML if 'text/html' is present in the 'Accept' field,  (it defaults to JSON if Accept is missing)

Explicitly setting Accept to 'application/json' ensures the correct behavior,  as content other than JSON will cause the key extraction process to fail.
---
 src/main/java/com/auth0/jwk/UrlJwkProvider.java | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/main/java/com/auth0/jwk/UrlJwkProvider.java b/src/main/java/com/auth0/jwk/UrlJwkProvider.java
index 790ffe1..f6fc9fc 100644
--- a/src/main/java/com/auth0/jwk/UrlJwkProvider.java
+++ b/src/main/java/com/auth0/jwk/UrlJwkProvider.java
@@ -96,6 +96,7 @@ public class UrlJwkProvider implements JwkProvider {
             if (readTimeout != null) {
                 c.setReadTimeout(readTimeout);
             }
+            c.setRequestProperty("Accept", "application/json");
             final InputStream inputStream = c.getInputStream();
             final JsonFactory factory = new JsonFactory();
             final JsonParser parser = factory.createParser(inputStream);
-- 
2.20.1

com.auth0.jwk.NetworkException: Cannot obtain jwks from url

Hello, I'm encountering the issue "com.auth0.jwk.NetworkException: Cannot obtain jwks from url"

I'm trying to get the jwks from microsoft. But encountering the below issue

com.auth0.jwk.NetworkException: Cannot obtain jwks from url https://login.microsoftonline.com/common/discovery/v2.0/keys
        at com.auth0.jwk.UrlJwkProvider.getJwks(UrlJwkProvider.java:139) ~[jwks-rsa-0.21.2.jar:0.21.2]
        at com.auth0.jwk.UrlJwkProvider.getAll(UrlJwkProvider.java:145) ~[jwks-rsa-0.21.2.jar:0.21.2]
        at com.auth0.jwk.UrlJwkProvider.get(UrlJwkProvider.java:163) ~[jwks-rsa-0.21.2.jar:0.21.2]

What was the expected behavior?

Successfully obtain jwks from the specified url

Reproduction

--

Environment

  • Version of this library used:0.21.2
  • Version of Java used:14
  • Other modules/plugins/libraries that might be involved:--
  • Any other relevant information you think would be useful:--

Why isn't there a constructor that takes a jwt token as a parameter?

Checklist

  • I have looked into the Readme and Examples, and have not found a suitable solution or answer.
  • I have looked into the API documentation and have not found a suitable solution or answer.
  • I have searched the issues and have not found a suitable solution or answer.
  • I have searched the Auth0 Community forums and have not found a suitable solution or answer.
  • I agree to the terms within the Auth0 Code of Conduct.

Describe the problem you'd like to have solved

static URL urlForDomain(String domain) {
    Util.checkArgument(!Util.isNullOrEmpty(domain), "A domain is required");

    if (!domain.startsWith("http")) {
        domain = "https://" + domain;
    }

    try {
        final URI uri = new URI(domain + WELL_KNOWN_JWKS_PATH).normalize();
        return uri.toURL();
    } catch (MalformedURLException | URISyntaxException e) {
        throw new IllegalArgumentException("Invalid jwks uri", e);
    }
}

// UrlJwkProvider.class

You can create an instance with the current URL object or a string as a parameter.
But when I wrote a constructor with a string
unexpected issues arise, such as an additional WELL_KNOWN_JWKS_PATH appended to the domain address.
In fact, if we have a JWT token, we don't even need to know the JWKS URL.

image image

To get the JWKS URL, you don't need to know the JWKS URL explicitly. Instead,
you can access the {iss}/.well-known/openid-configuration address to retrieve the jwks_url.
For instance, if you examine Google's OIDC, you'll notice that the JWK URL does not include the WELL_KNOWN_JWKS_PATH segment.

Describe the ideal solution

I want to create a constructor that takes a token as a parameter and doesn't need to know the JWK URL automatically.

Alternatives and current workarounds

No response

Additional context

No response

Dependency convergence errors when using alongside com.auth0:java-jwt:3.4.0

Dependency convergence error for commons-codec:commons-codec:1.11 paths to dependency are:
+-myproject
+-com.auth0:java-jwt:3.4.0
+-commons-codec:commons-codec:1.11
and
+-myproject
+-com.auth0:jwks-rsa:0.6.0
+-commons-codec:commons-codec:1.9

Dependency convergence error for com.fasterxml.jackson.core:jackson-databind:2.9.6 paths to dependency are:
+-myproject
+-com.auth0:java-jwt:3.4.0
+-com.fasterxml.jackson.core:jackson-databind:2.9.6
and
+-myproject
+-com.auth0:jwks-rsa:0.6.0
+-com.fasterxml.jackson.core:jackson-databind:2.8.11.1

Breaking changes

Describe the problem

I am upgrading from JWKS RSA 0.6.1 to 0.7.0 and the build breaks.

What was the expected behavior?

I should be able to run mvn clean install with version 0.9.0 and get the same results as if I ran mvn clean install with 0.6.1

Reproduction

The issue shows up in legacy code. That makes use of

    <dependency>
      <groupId>com.auth0</groupId>
      <artifactId>java-jwt</artifactId>
      <version>3.15.0</version>
    </dependency>

    <dependency>
      <groupId>com.auth0</groupId>
      <artifactId>jwks-rsa</artifactId>
      <version>0.9.0</version>
    </dependency>

I was unable to reproduce the issue after creating a test project by following this guide https://www.toolsqa.com/java/maven/create-new-maven-project-eclipse/. I thought I could narrow the scope of the decencies to just these two and work out the issue, but it is possible other dependencies are contributing to this issue. I'd like to know if anyone else experienced breaking changes in their upgrade.

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.