Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support fetching the JWKS #260

Merged
merged 3 commits into from
Nov 6, 2019
Merged

Support fetching the JWKS #260

merged 3 commits into from
Nov 6, 2019

Conversation

lbalmaceda
Copy link
Contributor

@lbalmaceda lbalmaceda commented Nov 6, 2019

Changes

This PR adds a method to the AuthenticationAPIClient to obtain the JSON Web Keys associated to the base domain. It only supports RSA keys used for verifying signatures (Public Keys). Other type of keys would not fail but will not be parsed either, resulting in an empty map.

The reason why I put it on the existing class is because it already "knows" how to make requests and has the HTTP client instance already configured with the different options. In the future, this HTTP client should be provided on demand by a singleton like method.

The name of the method is up to discussion.

References

This feature will be used to improve the OIDC compliance on a later PR.

Devs would normally not need to call this method on their own. It's going to be used to fetch the Auth0 tenant Public keys in order to verify RSA signed tokens. This keys information is available publicly on any tenant's well-known path, e.g. mine

Testing

  • This change adds unit test coverage

  • This change adds integration test coverage

  • This change has been tested on the latest version of the platform/language or why not

Checklist

@lbalmaceda lbalmaceda added CH: Added medium Medium review labels Nov 6, 2019
@lbalmaceda lbalmaceda requested a review from a team November 6, 2019 18:34
@jimmyjames jimmyjames requested review from jimmyjames and removed request for a team November 6, 2019 20:46
Copy link
Contributor

@jimmyjames jimmyjames left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to my questions and suggestions, can you provide info on how the added fetchJsonWebKeys() will be used by clients or the library? That helps understand the context of this PR. Also consider making sure you have test coverage for the swallowed exceptions when trying to generate the public key, to make sure the expected result is still returned.

@Override
public Map<String, PublicKey> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (!json.isJsonObject() || json.isJsonNull() || json.getAsJsonObject().entrySet().isEmpty()) {
throw new JsonParseException("jwks json is not a valid json object");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the appropriate exception type to throw here? Since the issue is the json is either not a JsonObject, or is null, or is an empty object - not an error parsing the JSON, it just doesn't meet other requirements. Also perhaps worth including in the exception message information that the json needs to be a non-empty valid JSON object

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is the same 3 line block used on the rest of the parsers. Parsers will only kick in if we explicitly tell the library that we want to parse a given response as that type. So, for this case that would only be for the endpoint that I added.

If the JSON present on that response is other than a non-empty object, we fail with that exception that is part of GSON, symbolizing in a way that the JSON input was unexpected.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, then it makes sense to use the JsonParseException. I do think it may be worthwhile to include info in the message about it needing to be a non-empty json object, otherwise the message can be misleading (an empty object is a valid json object)

JsonArray keys = object.getAsJsonArray("keys");
for (JsonElement k : keys) {
JsonObject currentKey = k.getAsJsonObject();
String keyAlg = context.deserialize(currentKey.remove("alg"), String.class);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use remove which mutates the object, instead of get? This question also applies to other usages of remove below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. On other scenarios we would end up keeping the remaining claims as an "extra props" param. We don't do this here so this can be changed to a regular get(key).

@lbalmaceda lbalmaceda added this to the v1-Next milestone Nov 6, 2019
@damieng damieng merged commit b47b84e into master Nov 6, 2019
@lbalmaceda lbalmaceda deleted the support-jwks branch November 6, 2019 22:39
@lbalmaceda lbalmaceda modified the milestone: v1-Next Nov 29, 2019
@lbalmaceda lbalmaceda modified the milestones: v1-Next, 1.20.0 Dec 23, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CH: Added medium Medium review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants