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
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,16 @@ private static VerifyTokenOptions buildVerifyTokenOptions(AuthenticateRequestOpt
.authorizedParties(options.authorizedParties()) //
.clockSkew(options.clockSkewInMs(), TimeUnit.MILLISECONDS) //
.build();
} else {
}
else if (options.machineSecretKey().isPresent()) {
return VerifyTokenOptions
.machineSecretKey(options.machineSecretKey().get())
.audience(options.audience())
.authorizedParties(options.authorizedParties())
.clockSkew(options.clockSkewInMs(), TimeUnit.MILLISECONDS)
.build();
}
else {
return new VerifyTokenOptions.Builder().build();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public final class AuthenticateRequestOptions {

private final Optional<String> secretKey;
private final Optional<String> jwtKey;
private final Optional<String> machineSecretKey;
private final Optional<String> audience;
private final Set<String> authorizedParties;
private final long clockSkewInMs;
Expand All @@ -42,6 +43,7 @@ public final class AuthenticateRequestOptions {
public AuthenticateRequestOptions(
Optional<String> secretKey,
Optional<String> jwtKey,
Optional<String> machineSecretKey,
Optional<String> audience,
Set<String> authorizedParties,
Optional<Long> clockSkewInMs,
Expand All @@ -50,12 +52,14 @@ public AuthenticateRequestOptions(

Utils.checkNotNull(secretKey, "secretKey");
Utils.checkNotNull(jwtKey, "jwtKey");
Utils.checkNotNull(machineSecretKey, "machineSecretKey");
Utils.checkNotNull(audience, "audience");
Utils.checkNotNull(authorizedParties, "authorizedParties");
Utils.checkNotNull(clockSkewInMs, "clockSkewInMs");

this.secretKey = secretKey;
this.jwtKey = jwtKey;
this.machineSecretKey = machineSecretKey;
this.audience = audience;
this.authorizedParties = authorizedParties;
this.clockSkewInMs = clockSkewInMs.orElse(DEFAULT_CLOCK_SKEW_MS);
Expand All @@ -72,6 +76,10 @@ public Optional<String> jwtKey() {
return jwtKey;
}

public Optional<String> machineSecretKey() {
return machineSecretKey;
}

public Optional<String> audience() {
return audience;
}
Expand Down Expand Up @@ -105,6 +113,7 @@ public static final class Builder {

private Optional<String> secretKey = Optional.empty();
private Optional<String> jwtKey = Optional.empty();
private Optional<String> machineSecretKey = Optional.empty();
private Optional<String> audience = Optional.empty();
private Set<String> authorizedParties = new HashSet<>();
private Optional<List<String>> acceptsToken = Optional.empty();
Expand All @@ -126,6 +135,13 @@ public static Builder withJwtKey(String jwtKey) {
return builder;
}

public static Builder withMachineSecretKey(String machineSecretKey) {
Utils.checkNotNull(machineSecretKey, "machineSecretKey");
Builder builder = new Builder();
builder.machineSecretKey = Optional.of(machineSecretKey);
return builder;
}

public Builder audience(String audience) {
Utils.checkNotNull(audience, "audience");
return audience(Optional.of(audience));
Expand Down Expand Up @@ -171,6 +187,7 @@ public Builder acceptsTokens(List<String> acceptsToken) {
public AuthenticateRequestOptions build() {
return new AuthenticateRequestOptions(secretKey,
jwtKey,
machineSecretKey,
audience,
authorizedParties,
Optional.of(clockSkewInMs),acceptsToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public final class VerifyTokenOptions {

private final Optional<String> secretKey;
private final Optional<String> jwtKey;
private final Optional<String> machineSecretKey;
private final Optional<String> audience;
private final Set<String> authorizedParties;
private final long clockSkewInMs;
Expand Down Expand Up @@ -47,6 +48,7 @@ public final class VerifyTokenOptions {
public VerifyTokenOptions(
Optional<String> secretKey,
Optional<String> jwtKey,
Optional<String> machineSecretKey,
Optional<String> audience,
Set<String> authorizedParties,
Optional<Long> clockSkewInMs,
Expand All @@ -58,6 +60,7 @@ public VerifyTokenOptions(
Utils.checkNotNull(clockSkewInMs, "clockSkewInMs");
Utils.checkNotNull(jwtKey, "jwtKey");
Utils.checkNotNull(secretKey, "secretKey");
Utils.checkNotNull(machineSecretKey, "machineSecretKey");
Utils.checkNotNull(apiUrl, "apiUrl");
Utils.checkNotNull(apiVersion, "apiVersion");

Expand All @@ -66,6 +69,7 @@ public VerifyTokenOptions(
this.clockSkewInMs = clockSkewInMs.orElse(DEFAULT_CLOCK_SKEW_MS);
this.jwtKey = jwtKey;
this.secretKey = secretKey;
this.machineSecretKey = machineSecretKey;
this.apiUrl = apiUrl.orElse(DEFAULT_API_URL);
this.apiVersion = apiVersion.orElse(DEFAULT_API_VERSION);
}
Expand All @@ -90,6 +94,10 @@ public Optional<String> secretKey() {
return secretKey;
}

public Optional<String> machineSecretKey() {
return machineSecretKey;
}

public String apiUrl() {
return apiUrl;
}
Expand All @@ -106,11 +114,15 @@ public static Builder jwtKey(String jwtKey) {
return Builder.withJwtKey(jwtKey);
}

public static Builder machineSecretKey(String machineSecretKey) {
return Builder.withMachineSecretKey(machineSecretKey);
}

public static final class Builder {

private Optional<String> secretKey = Optional.empty();
private Optional<String> jwtKey = Optional.empty();

private Optional<String> machineSecretKey = Optional.empty();
private Optional<String> audience = Optional.empty();
private Set<String> authorizedParties = new HashSet<>();
private long clockSkewInMs = DEFAULT_CLOCK_SKEW_MS;
Expand All @@ -131,6 +143,13 @@ public static Builder withJwtKey(String jwtKey) {
return builder;
}

public static Builder withMachineSecretKey(String machineSecretKey) {
Utils.checkNotNull(machineSecretKey, "machineSecretKey");
Builder builder = new Builder();
builder.machineSecretKey = Optional.of(machineSecretKey);
return builder;
}

public Builder audience(String audience) {
Utils.checkNotNull(audience, "audience");
return audience(Optional.of(audience));
Expand Down Expand Up @@ -194,6 +213,7 @@ public Builder apiVersion(Optional<String> apiVersion) {
public VerifyTokenOptions build() {
return new VerifyTokenOptions(secretKey,
jwtKey,
machineSecretKey,
audience,
authorizedParties,
Optional.of(clockSkewInMs),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public TokenVerificationResponse<MachineAuthVerificationData> verify(String toke
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(options.apiUrl() + MACHINE_TOKEN_VERIFICATION_URL))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + options.secretKey().get())
.header("Authorization", "Bearer " + ( options.secretKey().isPresent() ? options.secretKey().get() : options.machineSecretKey().get()))
.timeout(Duration.ofSeconds(30))
.POST(HttpRequest.BodyPublishers.ofString(jsonPayload))
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.ArgumentMatchers.argThat;

class MachineTokenVerifierTests {

Expand Down Expand Up @@ -70,6 +72,62 @@ void verify_shouldReturnValidResponse_whenHttpStatusIs200() throws Exception {
}
}

@Test
void verify_shouldUseSecretKeyInAuthorizationHeader_whenSecretKeyIsPresent() throws Exception {
String token = "mt_test_token";
String secretKey = "sk_test_secret_key";

HttpClient mockClient = mock(HttpClient.class);
HttpResponse<String> mockResponse = mock(HttpResponse.class);

when(mockResponse.statusCode()).thenReturn(200);
when(mockResponse.body()).thenReturn(getMockResponse());
when(mockClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class)))
.thenReturn(mockResponse);

try (MockedStatic<HttpClient> staticHttpClient = mockStatic(HttpClient.class)) {
staticHttpClient.when(HttpClient::newHttpClient).thenReturn(mockClient);

MachineTokenVerifier verifier = new MachineTokenVerifier();
VerifyTokenOptions options = VerifyTokenOptions.secretKey(secretKey).build();

verifier.verify(token, options);

// Verify the authorization header contains the secret key
verify(mockClient).send(argThat(request -> request.headers().firstValue("Authorization")
.map(auth -> auth.equals("Bearer " + secretKey))
.orElse(false)), any(HttpResponse.BodyHandler.class));
}
}

@Test
void verify_shouldUseMachineSecretKeyInAuthorizationHeader_whenMachineSecretKeyIsPresent() throws Exception {
String token = "mt_test_token";
String machineSecretKey = "msk_test_machine_secret_key";

HttpClient mockClient = mock(HttpClient.class);
HttpResponse<String> mockResponse = mock(HttpResponse.class);

when(mockResponse.statusCode()).thenReturn(200);
when(mockResponse.body()).thenReturn(getMockResponse());
when(mockClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class)))
.thenReturn(mockResponse);

try (MockedStatic<HttpClient> staticHttpClient = mockStatic(HttpClient.class)) {
staticHttpClient.when(HttpClient::newHttpClient).thenReturn(mockClient);

MachineTokenVerifier verifier = new MachineTokenVerifier();
VerifyTokenOptions options = VerifyTokenOptions.machineSecretKey(machineSecretKey).build();

verifier.verify(token, options);

// Verify the authorization header contains the machine secret key
verify(mockClient).send(argThat(request -> request.headers().firstValue("Authorization")
.map(auth -> auth.equals("Bearer " + machineSecretKey))
.orElse(false)), any(HttpResponse.BodyHandler.class));
}
}

@Test
void verify_shouldThrowTokenVerificationException_whenHttpStatusIsNot200() throws Exception {
HttpClient mockClient = mock(HttpClient.class);
Expand Down