Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -364,4 +364,3 @@ cd library && mvn spotless:apply
- The File Watchers plugin can format `.java` files on save

- See watcher configuration in [`watcherTasks.xml`](./.idea/watcherTasks.xml)

Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,28 @@ public final class UserAgent {
private static final String PRODUCT = "Mastercard-OAuth2-Client";
private static final String UNKNOWN_VERSION = "0.0.0-unknown";
private static final String VERSION = readVersionFile();
// Cache the user-agent string to avoid rebuilding it on every call
Comment thread
jaaufauvre marked this conversation as resolved.
Outdated
private static final String CACHED_USER_AGENT = buildUserAgent();

private UserAgent() {}

/**
* Builds a stable user-agent string:
* Returns a stable, pre-built user-agent string:
* Product/Version (Runtime; OS [OS Version])
* Example:
* Mastercard-OAuth2-Client/1.0.0 (Java/17.0.2; Linux 5.15)
*/
public static String get() {
return CACHED_USER_AGENT;
Comment thread
jaaufauvre marked this conversation as resolved.
Outdated
}

private static String buildUserAgent() {
String javaVer = System.getProperty("java.version", "unknown");
String osName = System.getProperty("os.name", "unknown");
String osVer = System.getProperty("os.version", "").trim();
var runtime = "Java/" + javaVer;
String runtime = "Java/" + javaVer;
String osPart = osName + (osVer.isEmpty() ? "" : " " + osVer);
return String.format("%s/%s (%s; %s)", PRODUCT, VERSION, runtime, osPart);
return PRODUCT + "/" + VERSION + " (" + runtime + "; " + osPart + ")";
}

private static String readVersionFile() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.mastercard.developer.oauth2.internal.json;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.mastercard.developer.oauth2.internal.json.exception.OAuth2ClientJsonException;
import java.lang.reflect.Type;
Expand All @@ -9,13 +10,18 @@

public class GsonJsonProvider implements JsonProvider {

private static final Gson gson = new Gson();
// Use a configured Gson instance and cache the Map type to avoid allocating a new TypeToken on each parse.
Comment thread
jaaufauvre marked this conversation as resolved.
Outdated
private static final Gson gson = new GsonBuilder()
Comment thread
jaaufauvre marked this conversation as resolved.
Outdated
.disableHtmlEscaping()
.serializeNulls()
.create();

private static final Type MAP_TYPE = new TypeToken<Map<String, Object>>() {}.getType();
Comment thread
jaaufauvre marked this conversation as resolved.

@Override
public Map<String, Object> parse(String json) throws OAuth2ClientJsonException {
try {
Type type = new TypeToken<Map<String, Object>>() {}.getType();
return gson.fromJson(json, type);
return gson.fromJson(json, MAP_TYPE);
} catch (Exception e) {
throw new OAuth2ClientJsonException("Failed to read JSON", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ public class JacksonJsonProvider implements JsonProvider {

private static final ObjectMapper mapper = new ObjectMapper();

// Cache the TypeReference to avoid creating a new anonymous subclass on each parse call.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This comment doesn’t add value and can be removed.

private static final TypeReference<Map<String, Object>> MAP_TYPE_REFERENCE = new TypeReference<Map<String, Object>>() {};
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

👍


@Override
public Map<String, Object> parse(String json) throws OAuth2ClientJsonException {
try {
var typeReference = new TypeReference<Map<String, Object>>() {};
return mapper.readValue(json, typeReference);
return mapper.readValue(json, MAP_TYPE_REFERENCE);
} catch (Exception e) {
throw new OAuth2ClientJsonException("Failed to read JSON", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Named;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.function.ThrowingSupplier;
import org.junit.jupiter.params.provider.Arguments;
import org.opentest4j.TestAbortedException;

public abstract class BaseClientTest extends BaseTest {

Expand Down Expand Up @@ -68,63 +70,27 @@ protected static Stream<Arguments> serverAndKeyProvider() {
}

protected static TestConfig getMastercardConfig() {
try {
return TestConfig.getMastercardApiConfig();
} catch (IllegalStateException e) {
throw e;
} catch (Exception e) {
throw new IllegalStateException(e);
}
return runOrWrap(TestConfig::getMastercardApiConfig);
}

private static TestConfig getMastercardConfigWithEcKey() {
try {
return TestConfig.getMastercardApiConfig(StaticKeys.EC_KEY_PAIR);
} catch (IllegalStateException e) {
throw e;
} catch (Exception e) {
throw new IllegalStateException(e);
}
return runOrWrap(() -> TestConfig.getMastercardApiConfig(StaticKeys.EC_KEY_PAIR));
}

private static TestConfig getMastercardConfigWithRsaKey() {
try {
return TestConfig.getMastercardApiConfig(StaticKeys.RSA_KEY_PAIR);
} catch (IllegalStateException e) {
throw e;
} catch (Exception e) {
throw new IllegalStateException(e);
}
return runOrWrap(() -> TestConfig.getMastercardApiConfig(StaticKeys.RSA_KEY_PAIR));
}

protected static TestConfig getFakeConfig() {
try {
return TestConfig.getFakeApiConfig(authorizationServer, resourceServer);
} catch (IllegalStateException e) {
throw e;
} catch (Exception e) {
throw new IllegalStateException(e);
}
return runOrWrap(() -> TestConfig.getFakeApiConfig(authorizationServer, resourceServer));
}

private static TestConfig getFakeConfigWithEcKey() {
try {
return TestConfig.getFakeApiConfig(authorizationServer, resourceServer, StaticKeys.EC_KEY_PAIR);
} catch (IllegalStateException e) {
throw e;
} catch (Exception e) {
throw new IllegalStateException(e);
}
return runOrWrap(() -> TestConfig.getFakeApiConfig(authorizationServer, resourceServer, StaticKeys.EC_KEY_PAIR));
}

private static TestConfig getFakeConfigWithRsaKey() {
try {
return TestConfig.getFakeApiConfig(authorizationServer, resourceServer, StaticKeys.RSA_KEY_PAIR);
} catch (IllegalStateException e) {
throw e;
} catch (Exception e) {
throw new IllegalStateException(e);
}
return runOrWrap(() -> TestConfig.getFakeApiConfig(authorizationServer, resourceServer, StaticKeys.RSA_KEY_PAIR));
}

private static Arguments createConfigArgument(String name, Supplier<TestConfig> configSupplier) {
Expand All @@ -135,4 +101,14 @@ protected static String readResourceId(String resource) throws OAuth2ClientJsonE
Map<String, Object> jsonMap = JsonProvider.getInstance().parse(resource);
return (String) jsonMap.get("id");
}

private static <T> T runOrWrap(ThrowingSupplier<T> action) {
try {
return action.get();
} catch (TestAbortedException | IllegalStateException e) {
throw e;
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.mastercard.developer.oauth2.test.fixtures;

import static org.junit.jupiter.api.Assumptions.assumeTrue;

import com.mastercard.developer.oauth2.config.OAuth2Config;
import com.mastercard.developer.oauth2.config.SecurityProfile;
import com.mastercard.developer.oauth2.core.dpop.StaticDPoPKeyProvider;
Expand Down Expand Up @@ -51,14 +53,19 @@ public static TestConfig getMastercardApiConfig(KeyPair dpopKeyPair) throws Exce
String readScopes = getEnv("READ_SCOPES");
String writeScopes = getEnv("WRITE_SCOPES");

validateEnvVariable("PRIVATE_KEY", privateKeyContent);
validateEnvVariable("CLIENT_ID", clientId);
validateEnvVariable("KID", kid);
validateEnvVariable("TOKEN_ENDPOINT", tokenEndpoint);
validateEnvVariable("ISSUER", issuer);
validateEnvVariable("API_BASE_URL", apiBaseUrlEnv);
validateEnvVariable("READ_SCOPES", readScopes);
validateEnvVariable("WRITE_SCOPES", readScopes);
try {
validateEnvVariable("PRIVATE_KEY", privateKeyContent);
validateEnvVariable("CLIENT_ID", clientId);
validateEnvVariable("KID", kid);
validateEnvVariable("TOKEN_ENDPOINT", tokenEndpoint);
validateEnvVariable("ISSUER", issuer);
validateEnvVariable("API_BASE_URL", apiBaseUrlEnv);
validateEnvVariable("READ_SCOPES", readScopes);
validateEnvVariable("WRITE_SCOPES", readScopes);
} catch (Exception e) {
// Disable the calling test when environment variables are missing
assumeTrue(false, "Test disabled: %s".formatted(e.getMessage()));
}

OAuth2Config oauth2Config = OAuth2Config.builder()
.securityProfile(SecurityProfile.FAPI2SP_PRIVATE_KEY_DPOP)
Expand Down
Loading