Skip to content

Commit

Permalink
Merge pull request #22 from darthvalinor/master
Browse files Browse the repository at this point in the history
Issue #20 added url constructor to JwkProviderBuilder
  • Loading branch information
lbalmaceda authored Apr 26, 2018
2 parents 363d2cf + d07af0c commit f6a209b
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 70 deletions.
49 changes: 34 additions & 15 deletions src/main/java/com/auth0/jwk/JwkProviderBuilder.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package com.auth0.jwk;

import java.net.URL;
import java.util.concurrent.TimeUnit;

import static com.auth0.jwk.UrlJwkProvider.urlForDomain;

/**
* JwkProvider builder
*/
@SuppressWarnings("WeakerAccess")
public class JwkProviderBuilder {

private final String url;
private final URL url;
private TimeUnit expiresUnit;
private long expiresIn;
private long cacheSize;
Expand All @@ -17,16 +20,16 @@ public class JwkProviderBuilder {
private boolean rateLimited;

/**
* Creates a new Builder with a URL from where to load the jwks.
* It can be a url lik 'https://samples.auth0.com' or just the Auth0 domain 'samples.auth0.com'.
* Creates a new Builder with the given URL where to load the jwks from.
*
* @param domain from where to load the jwks
* @param url to load the jwks
* @throws IllegalStateException if url is null
*/
public JwkProviderBuilder(String domain) {
if (domain == null) {
throw new IllegalStateException("Cannot build provider without domain");
public JwkProviderBuilder(URL url) {
if (url == null) {
throw new IllegalStateException("Cannot build provider without url to jwks");
}
this.url = normalizeDomain(domain);
this.url = url;
this.cached = true;
this.expiresIn = 10;
this.expiresUnit = TimeUnit.HOURS;
Expand All @@ -35,6 +38,29 @@ public JwkProviderBuilder(String domain) {
this.bucket = new BucketImpl(10, 1, TimeUnit.MINUTES);
}

/**
* Creates a new Builder with a domain where to look for the jwks.
* <br><br> It can be a url link 'https://samples.auth0.com' or just a domain 'samples.auth0.com'.
* If the protocol (http or https) is not provided then https is used by default.
* The default jwks path "/.well-known/jwks.json" is appended to the given string domain.
* <br><br> For example, when the domain is "samples.auth0.com"
* the jwks url that will be used is "https://samples.auth0.com/.well-known/jwks.json"
* <br><br> Use {@link #JwkProviderBuilder(URL)} if you need to pass a full URL.
* @param domain where jwks is published
* @throws IllegalStateException if domain is null
* @see UrlJwkProvider#UrlJwkProvider(String)
*/
public JwkProviderBuilder(String domain) {
this(buildJwkUrl(domain));
}

private static URL buildJwkUrl(String domain) {
if (domain == null) {
throw new IllegalStateException("Cannot build provider without domain");
}
return urlForDomain(domain);
}

/**
* Toggle the cache of Jwk. By default the provider will use cache.
*
Expand Down Expand Up @@ -101,11 +127,4 @@ public JwkProvider build() {
}
return urlProvider;
}

private String normalizeDomain(String domain) {
if (!domain.startsWith("http")) {
return "https://" + domain;
}
return domain;
}
}
35 changes: 24 additions & 11 deletions src/main/java/com/auth0/jwk/UrlJwkProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Strings;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;

import java.io.IOException;
Expand All @@ -14,40 +14,53 @@
import java.util.List;
import java.util.Map;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.isNullOrEmpty;

/**
* Jwk provider that loads them from a {@link URL}
*/
@SuppressWarnings("WeakerAccess")
public class UrlJwkProvider implements JwkProvider {

@VisibleForTesting
static final String WELL_KNOWN_JWKS_PATH = "/.well-known/jwks.json";

final URL url;

/**
* Creates a provider that loads from a given URL
* Creates a provider that loads from the given URL
* @param url to load the jwks
*/
public UrlJwkProvider(URL url) {
if (url == null) {
throw new IllegalArgumentException("A non-null url is required");
}
checkArgument(url != null, "A non-null url is required");
this.url = url;
}

/**
* Creates a provider that loads from the given domain's well-known directory
* @param domain domain where to look for the jwks.json file
* Creates a provider that loads from the given domain's well-known directory.
* <br><br> It can be a url link 'https://samples.auth0.com' or just a domain 'samples.auth0.com'.
* If the protocol (http or https) is not provided then https is used by default.
* The default jwks path "/.well-known/jwks.json" is appended to the given string domain.
* <br><br> For example, when the domain is "samples.auth0.com"
* the jwks url that will be used is "https://samples.auth0.com/.well-known/jwks.json"
* <br><br> Use {@link #UrlJwkProvider(URL)} if you need to pass a full URL.
* @param domain where jwks is published
*/
public UrlJwkProvider(String domain) {
this(urlForDomain(domain));
}

private static URL urlForDomain(String domain) {
if (Strings.isNullOrEmpty(domain)) {
throw new IllegalArgumentException("A domain is required");
static URL urlForDomain(String domain) {
checkArgument(!isNullOrEmpty(domain), "A domain is required");

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

try {
final URL url = new URL(domain);
return new URL(url, "/.well-known/jwks.json");
return new URL(url, WELL_KNOWN_JWKS_PATH);
} catch (MalformedURLException e) {
throw new IllegalArgumentException("Invalid jwks uri", e);
}
Expand Down
73 changes: 53 additions & 20 deletions src/test/java/com/auth0/jwk/JwkProviderBuilderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
import org.junit.Test;
import org.junit.rules.ExpectedException;

import java.net.URL;
import java.util.concurrent.TimeUnit;

import static com.auth0.jwk.UrlJwkProvider.WELL_KNOWN_JWKS_PATH;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
Expand All @@ -15,26 +18,42 @@ public class JwkProviderBuilderTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();

private String domain = "samples.auth0.com";
private String normalizedDomain = "https://" + domain;

@Test
public void shouldCreateForUrl() throws Exception {
URL urlToJwks = new URL(normalizedDomain + WELL_KNOWN_JWKS_PATH);
assertThat(new JwkProviderBuilder(urlToJwks).build(), notNullValue());
}

@Test
public void shouldCreateForDomain() throws Exception {
assertThat(new JwkProviderBuilder("samples.auth0.com").build(), notNullValue());
public void shouldCreateForDomain() {
assertThat(new JwkProviderBuilder(domain).build(), notNullValue());
}

@Test
public void shouldCreateForHttpUrl() throws Exception {
assertThat(new JwkProviderBuilder("https://samples.auth0.com").build(), notNullValue());
public void shouldCreateForNormalizedDomain() {
assertThat(new JwkProviderBuilder(normalizedDomain).build(), notNullValue());
}

@Test
public void shouldFailWhenNoUrlIsProvided() {
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("Cannot build provider without url to jwks");
new JwkProviderBuilder((URL) null).build();
}

@Test
public void shouldFailWhenNoUrlIsProvided() throws Exception {
public void shouldFailWhenNoDomainIsProvided() {
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("Cannot build provider without domain");
new JwkProviderBuilder(null).build();
new JwkProviderBuilder((String) null).build();
}

@Test
public void shouldCreateCachedProvider() throws Exception {
JwkProvider provider = new JwkProviderBuilder("samples.auth0.com")
public void shouldCreateCachedProvider() {
JwkProvider provider = new JwkProviderBuilder(domain)
.rateLimited(false)
.cached(true)
.build();
Expand All @@ -44,8 +63,8 @@ public void shouldCreateCachedProvider() throws Exception {
}

@Test
public void shouldCreateCachedProviderWithCustomValues() throws Exception {
JwkProvider provider = new JwkProviderBuilder("samples.auth0.com")
public void shouldCreateCachedProviderWithCustomValues() {
JwkProvider provider = new JwkProviderBuilder(domain)
.rateLimited(false)
.cached(10, 24, TimeUnit.HOURS)
.build();
Expand All @@ -55,8 +74,8 @@ public void shouldCreateCachedProviderWithCustomValues() throws Exception {
}

@Test
public void shouldCreateRateLimitedProvider() throws Exception {
JwkProvider provider = new JwkProviderBuilder("samples.auth0.com")
public void shouldCreateRateLimitedProvider() {
JwkProvider provider = new JwkProviderBuilder(domain)
.cached(false)
.rateLimited(true)
.build();
Expand All @@ -66,8 +85,8 @@ public void shouldCreateRateLimitedProvider() throws Exception {
}

@Test
public void shouldCreateRateLimitedProviderWithCustomValues() throws Exception {
JwkProvider provider = new JwkProviderBuilder("samples.auth0.com")
public void shouldCreateRateLimitedProviderWithCustomValues() {
JwkProvider provider = new JwkProviderBuilder(domain)
.cached(false)
.rateLimited(10, 24, TimeUnit.HOURS)
.build();
Expand All @@ -77,8 +96,8 @@ public void shouldCreateRateLimitedProviderWithCustomValues() throws Exception {
}

@Test
public void shouldCreateCachedAndRateLimitedProvider() throws Exception {
JwkProvider provider = new JwkProviderBuilder("samples.auth0.com")
public void shouldCreateCachedAndRateLimitedProvider() {
JwkProvider provider = new JwkProviderBuilder(domain)
.cached(true)
.rateLimited(true)
.build();
Expand All @@ -90,8 +109,8 @@ public void shouldCreateCachedAndRateLimitedProvider() throws Exception {
}

@Test
public void shouldCreateCachedAndRateLimitedProviderWithCustomValues() throws Exception {
JwkProvider provider = new JwkProviderBuilder("samples.auth0.com")
public void shouldCreateCachedAndRateLimitedProviderWithCustomValues() {
JwkProvider provider = new JwkProviderBuilder(domain)
.cached(10, 24, TimeUnit.HOURS)
.rateLimited(10, 24, TimeUnit.HOURS)
.build();
Expand All @@ -103,12 +122,26 @@ public void shouldCreateCachedAndRateLimitedProviderWithCustomValues() throws Ex
}

@Test
public void shouldCreateCachedAndRateLimitedProviderByDefault() throws Exception {
JwkProvider provider = new JwkProviderBuilder("samples.auth0.com").build();
public void shouldCreateCachedAndRateLimitedProviderByDefault() {
JwkProvider provider = new JwkProviderBuilder(domain).build();
assertThat(provider, notNullValue());
assertThat(provider, instanceOf(GuavaCachedJwkProvider.class));
JwkProvider baseProvider = ((GuavaCachedJwkProvider) provider).getBaseProvider();
assertThat(baseProvider, instanceOf(RateLimitedJwkProvider.class));
assertThat(((RateLimitedJwkProvider) baseProvider).getBaseProvider(), instanceOf(UrlJwkProvider.class));
}

@Test
public void shouldSupportUrlToJwksDomainWithSubPath() throws Exception {
String urlToJwksWithSubPath = normalizedDomain + "/sub/path" + WELL_KNOWN_JWKS_PATH;
URL url = new URL(urlToJwksWithSubPath);
JwkProvider provider = new JwkProviderBuilder(url)
.rateLimited(false)
.cached(false)
.build();
assertThat(provider, notNullValue());
assertThat(provider, instanceOf(UrlJwkProvider.class));
UrlJwkProvider urlJwkProvider = (UrlJwkProvider) provider;
assertThat(urlJwkProvider.url.toString(), equalTo(urlToJwksWithSubPath));
}
}
Loading

0 comments on commit f6a209b

Please sign in to comment.