Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions auth0-api-java/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ repositories {
mavenCentral()
}

processResources {
filesMatching('auth0-client-info.properties') {
expand(version: project.version)
}
}

test {
useJUnit()
testLogging {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.auth0.telemetry;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Properties;

/**
* Provides the Base64-encoded Auth0-Client telemetry header value.
*
* The payload is a JSON object: {"name":"springboot-api","version":"x.y.z","java":"17"}
*/
public final class TelemetryProvider {

private static final String PROPERTIES_FILE = "auth0-client-info.properties";
private static final String UNKNOWN = "unknown";

private static volatile String cachedHeaderValue;

private TelemetryProvider() {
}

/**
* Returns the Base64url-encoded telemetry header value.
*
* @return the Auth0-Client header value, or null if it cannot be built
*/
public static String getHeaderValue() {
if (cachedHeaderValue != null) {
return cachedHeaderValue;
}
synchronized (TelemetryProvider.class) {
if (cachedHeaderValue != null) {
return cachedHeaderValue;
}
cachedHeaderValue = buildHeaderValue();
return cachedHeaderValue;
}
}

private static String buildHeaderValue() {
String name = UNKNOWN;
String version = UNKNOWN;

try (InputStream is = TelemetryProvider.class.getClassLoader()
.getResourceAsStream(PROPERTIES_FILE)) {
if (is != null) {
Properties props = new Properties();
props.load(is);
name = props.getProperty("name", UNKNOWN);
version = props.getProperty("version", UNKNOWN);
}
} catch (IOException ignored) {
// Fall through with defaults
}

String javaVersion = System.getProperty("java.version", UNKNOWN);

String json = "{\"name\":\"" + name + "\",\"version\":\"" + version + "\",\"java\":\"" + javaVersion + "\"}";

return java.util.Base64.getUrlEncoder().withoutPadding()
.encodeToString(json.getBytes(StandardCharsets.UTF_8));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.models.HttpRequestInfo;
import com.auth0.telemetry.TelemetryProvider;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;

import static com.auth0.jwt.JWT.require;
Expand Down Expand Up @@ -41,7 +47,7 @@ public JWTValidator(AuthOptions authOptions) {
}

this.authOptions = authOptions;
this.jwkProvider = new UrlJwkProvider(authOptions.getDomain());
this.jwkProvider = createJwkProvider(authOptions.getDomain());
}

/**
Expand Down Expand Up @@ -170,6 +176,28 @@ private BaseAuthException wrapAsValidationException(Exception e) {
return new VerifyAccessTokenException("JWT claim validation failed");
}

private static JwkProvider createJwkProvider(String domain) {
Map<String, String> headers = new HashMap<>();
headers.put("Accept", "application/json");

String telemetry = TelemetryProvider.getHeaderValue();
if (telemetry != null) {
headers.put("Auth0-Client", telemetry);
}

String normalizedDomain = domain;
if (!normalizedDomain.startsWith("http")) {
normalizedDomain = "https://" + normalizedDomain;
}
try {
URI uri = new URI(normalizedDomain + "/.well-known/jwks.json").normalize();
URL url = uri.toURL();
return new UrlJwkProvider(url, null, null, null, headers);
} catch (URISyntaxException | MalformedURLException e) {
throw new IllegalArgumentException("Invalid domain: " + domain, e);
}
}

public AuthOptions getAuthOptions() {
return authOptions;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
version=${version}
name=springboot-api
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.auth0.telemetry;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;

public class TelemetryProviderTest {

@Test
@SuppressWarnings("unchecked")
public void getHeaderValue_returnsValidBase64Json() throws Exception {
String headerValue = TelemetryProvider.getHeaderValue();
assertThat(headerValue).isNotNull().isNotEmpty();

byte[] decoded = Base64.getUrlDecoder().decode(headerValue);
String json = new String(decoded, StandardCharsets.UTF_8);

ObjectMapper mapper = new ObjectMapper();
Map<String, String> payload = mapper.readValue(json, Map.class);

assertThat(payload).containsKey("name");
assertThat(payload).containsKey("version");
assertThat(payload).containsKey("java");
assertThat(payload.get("name")).isEqualTo("springboot-api");
assertThat(payload.get("java")).isEqualTo(System.getProperty("java.version"));
}

@Test
public void getHeaderValue_isCached() {
String first = TelemetryProvider.getHeaderValue();
String second = TelemetryProvider.getHeaderValue();
assertThat(first).isSameAs(second);
}
}
Loading