Skip to content

Commit 1652f7b

Browse files
committed
Add more tests for machine token specific verifiers
1 parent 4d1e875 commit 1652f7b

3 files changed

Lines changed: 409 additions & 0 deletions

File tree

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package com.clerk.backend_api.helpers.security.token_verifiers.impl;
2+
3+
import com.clerk.backend_api.helpers.security.models.MachineAuthVerificationData;
4+
import com.clerk.backend_api.helpers.security.models.TokenVerificationErrorReason;
5+
import com.clerk.backend_api.helpers.security.models.TokenVerificationException;
6+
import com.clerk.backend_api.helpers.security.models.TokenVerificationResponse;
7+
import com.clerk.backend_api.helpers.security.models.VerifyTokenOptions;
8+
import com.fasterxml.jackson.databind.ObjectMapper;
9+
import java.net.http.HttpClient;
10+
import java.net.http.HttpRequest;
11+
import java.net.http.HttpResponse;
12+
import java.util.Arrays;
13+
import org.junit.jupiter.api.Test;
14+
import org.mockito.MockedStatic;
15+
16+
import static org.junit.jupiter.api.Assertions.assertEquals;
17+
import static org.junit.jupiter.api.Assertions.assertNotNull;
18+
import static org.junit.jupiter.api.Assertions.assertNull;
19+
import static org.junit.jupiter.api.Assertions.assertThrows;
20+
import static org.mockito.Mockito.any;
21+
import static org.mockito.Mockito.mock;
22+
import static org.mockito.Mockito.mockStatic;
23+
import static org.mockito.Mockito.when;
24+
25+
public class APIKeyTokenVerifierTests {
26+
27+
private final ObjectMapper objectMapper = new ObjectMapper();
28+
29+
@Test
30+
void verify_shouldReturnValidResponse_whenHttpStatusIs200() throws Exception {
31+
String token = "ak_test_token";
32+
String jsonResponse = mockResponse();
33+
34+
HttpClient mockClient = mock(HttpClient.class);
35+
HttpResponse<String> mockResponse = mock(HttpResponse.class);
36+
37+
when(mockResponse.statusCode()).thenReturn(200);
38+
when(mockResponse.body()).thenReturn(jsonResponse);
39+
when(mockClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class)))
40+
.thenReturn(mockResponse);
41+
42+
try (MockedStatic<HttpClient> staticHttpClient = mockStatic(HttpClient.class)) {
43+
staticHttpClient.when(HttpClient::newHttpClient).thenReturn(mockClient);
44+
45+
APIKeyTokenVerifier verifier = new APIKeyTokenVerifier();
46+
47+
VerifyTokenOptions options = new VerifyTokenOptions.Builder().build();
48+
49+
TokenVerificationResponse<MachineAuthVerificationData> result = verifier.verify(token, options);
50+
51+
assertNotNull(result);
52+
MachineAuthVerificationData payload = result.payload();
53+
assertEquals("api_key", payload.getObject());
54+
assertEquals("key_id", payload.getId());
55+
assertEquals("machine", payload.getType());
56+
assertEquals("MyKey", payload.getName());
57+
assertEquals("sub_123", payload.getSubject());
58+
assertEquals(Arrays.asList("read", "write"), payload.getScopes());
59+
assertNotNull(payload.getClaims());
60+
assertEquals(Arrays.asList("org:read", "org:write"), payload.getClaims().getPermissions());
61+
assertEquals(Long.valueOf(1625158800L), payload.getCreatedAt());
62+
assertEquals(Long.valueOf(1625162400L), payload.getUpdatedAt());
63+
assertEquals(Long.valueOf(1725162400L), payload.getExpiration());
64+
assertEquals(false, payload.getRevoked());
65+
assertNull(payload.getRevocationReason());
66+
assertEquals(false, payload.getExpired());
67+
assertEquals("admin_user_id", payload.getCreatedBy());
68+
69+
}
70+
}
71+
72+
@Test
73+
void verify_shouldThrowTokenVerificationException_whenHttpStatusIsNot200() throws Exception {
74+
HttpClient mockClient = mock(HttpClient.class);
75+
HttpResponse<String> mockResponse = mock(HttpResponse.class);
76+
77+
when(mockResponse.statusCode()).thenReturn(403);
78+
when(mockClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class)))
79+
.thenReturn(mockResponse);
80+
81+
try (MockedStatic<HttpClient> staticHttpClient = mockStatic(HttpClient.class)) {
82+
staticHttpClient.when(HttpClient::newHttpClient).thenReturn(mockClient);
83+
84+
APIKeyTokenVerifier verifier = new APIKeyTokenVerifier();
85+
86+
VerifyTokenOptions options = new VerifyTokenOptions.Builder().build();
87+
88+
assertThrows(TokenVerificationException.class, () -> verifier.verify("ak_token", options));
89+
}
90+
}
91+
92+
@Test
93+
void verify_shouldThrowTokenVerificationException_whenResponseIsInvalidJson() throws Exception {
94+
HttpClient mockClient = mock(HttpClient.class);
95+
HttpResponse<String> mockResponse = mock(HttpResponse.class);
96+
97+
when(mockResponse.statusCode()).thenReturn(200);
98+
when(mockResponse.body()).thenReturn("invalid json");
99+
when(mockClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class)))
100+
.thenReturn(mockResponse);
101+
102+
try (MockedStatic<HttpClient> staticHttpClient = mockStatic(HttpClient.class)) {
103+
staticHttpClient.when(HttpClient::newHttpClient).thenReturn(mockClient);
104+
105+
APIKeyTokenVerifier verifier = new APIKeyTokenVerifier();
106+
107+
VerifyTokenOptions options = new VerifyTokenOptions.Builder().build();
108+
109+
TokenVerificationException ex = assertThrows(TokenVerificationException.class,
110+
() -> verifier.verify("ak_token", options));
111+
assertEquals(TokenVerificationErrorReason.FAILED_TO_PROCESS_RESPONSE, ex.reason());
112+
}
113+
}
114+
115+
private static String mockResponse(){
116+
return "{"
117+
+ "\"object\":\"api_key\","
118+
+ "\"id\":\"key_id\","
119+
+ "\"type\":\"machine\","
120+
+ "\"name\":\"MyKey\","
121+
+ "\"subject\":\"sub_123\","
122+
+ "\"scopes\":[\"read\",\"write\"],"
123+
+ "\"claims\":{"
124+
+ "\"permissions\":[\"org:read\",\"org:write\"]"
125+
+ "},"
126+
+ "\"created_at\":1625158800,"
127+
+ "\"updated_at\":1625162400,"
128+
+ "\"expiration\":1725162400,"
129+
+ "\"revoked\":false,"
130+
+ "\"revocation_reason\":null,"
131+
+ "\"expired\":false,"
132+
+ "\"created_by\":\"admin_user_id\""
133+
+ "}";
134+
}
135+
}
136+
137+
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package com.clerk.backend_api.helpers.security.token_verifiers.impl;
2+
3+
import com.clerk.backend_api.helpers.security.models.MachineAuthVerificationData;
4+
import com.clerk.backend_api.helpers.security.models.TokenVerificationErrorReason;
5+
import com.clerk.backend_api.helpers.security.models.TokenVerificationException;
6+
import com.clerk.backend_api.helpers.security.models.TokenVerificationResponse;
7+
import com.clerk.backend_api.helpers.security.models.VerifyTokenOptions;
8+
import com.fasterxml.jackson.databind.ObjectMapper;
9+
import java.net.http.HttpClient;
10+
import java.net.http.HttpRequest;
11+
import java.net.http.HttpResponse;
12+
import java.util.Arrays;
13+
import org.junit.jupiter.api.Test;
14+
import org.mockito.MockedStatic;
15+
16+
import static org.junit.jupiter.api.Assertions.assertEquals;
17+
import static org.junit.jupiter.api.Assertions.assertFalse;
18+
import static org.junit.jupiter.api.Assertions.assertNotNull;
19+
import static org.junit.jupiter.api.Assertions.assertNull;
20+
import static org.junit.jupiter.api.Assertions.assertThrows;
21+
import static org.mockito.Mockito.any;
22+
import static org.mockito.Mockito.mock;
23+
import static org.mockito.Mockito.mockStatic;
24+
import static org.mockito.Mockito.when;
25+
26+
class MachineTokenVerifierTest {
27+
28+
private final ObjectMapper objectMapper = new ObjectMapper();
29+
30+
@Test
31+
void verify_shouldReturnValidResponse_whenHttpStatusIs200() throws Exception {
32+
String token = "mt_test_token";
33+
34+
HttpClient mockClient = mock(HttpClient.class);
35+
HttpResponse<String> mockResponse = mock(HttpResponse.class);
36+
37+
when(mockResponse.statusCode()).thenReturn(200);
38+
when(mockResponse.body()).thenReturn(getMockResponse());
39+
when(mockClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class)))
40+
.thenReturn(mockResponse);
41+
42+
try (MockedStatic<HttpClient> staticHttpClient = mockStatic(HttpClient.class)) {
43+
staticHttpClient.when(HttpClient::newHttpClient).thenReturn(mockClient);
44+
45+
MachineTokenVerifier verifier = new MachineTokenVerifier();
46+
47+
VerifyTokenOptions options = new VerifyTokenOptions.Builder().build();
48+
49+
TokenVerificationResponse<MachineAuthVerificationData> result = verifier.verify(token, options);
50+
51+
assertNotNull(result);
52+
MachineAuthVerificationData payload = result.payload();
53+
assertNotNull(payload);
54+
assertEquals("api_key", payload.getObject());
55+
assertEquals("key_id", payload.getId());
56+
assertEquals("machine", payload.getType());
57+
assertEquals("MyKey", payload.getName());
58+
assertEquals("sub_123", payload.getSubject());
59+
assertEquals(Arrays.asList("read", "write"), payload.getScopes());
60+
assertNotNull(payload.getClaims());
61+
assertEquals(Arrays.asList("org:read", "org:write"), payload.getClaims().getPermissions());
62+
assertEquals(Long.valueOf(1625158800L), payload.getCreatedAt());
63+
assertEquals(Long.valueOf(1625162400L), payload.getUpdatedAt());
64+
assertEquals(Long.valueOf(1725162400L), payload.getExpiration());
65+
assertFalse(payload.getRevoked());
66+
assertNull(payload.getRevocationReason());
67+
assertFalse(payload.getExpired());
68+
assertEquals("admin_user_id", payload.getCreatedBy());
69+
}
70+
}
71+
72+
@Test
73+
void verify_shouldThrowTokenVerificationException_whenHttpStatusIsNot200() throws Exception {
74+
HttpClient mockClient = mock(HttpClient.class);
75+
HttpResponse<String> mockResponse = mock(HttpResponse.class);
76+
77+
when(mockResponse.statusCode()).thenReturn(401);
78+
when(mockClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class)))
79+
.thenReturn(mockResponse);
80+
81+
try (MockedStatic<HttpClient> staticHttpClient = mockStatic(HttpClient.class)) {
82+
staticHttpClient.when(HttpClient::newHttpClient).thenReturn(mockClient);
83+
84+
MachineTokenVerifier verifier = new MachineTokenVerifier();
85+
VerifyTokenOptions options = new VerifyTokenOptions.Builder().build();
86+
87+
assertThrows(TokenVerificationException.class, () -> verifier.verify("mt_token", options));
88+
}
89+
}
90+
91+
@Test
92+
void verify_shouldThrowTokenVerificationException_whenJsonParsingFails() throws Exception {
93+
HttpClient mockClient = mock(HttpClient.class);
94+
HttpResponse<String> mockResponse = mock(HttpResponse.class);
95+
96+
when(mockResponse.statusCode()).thenReturn(200);
97+
when(mockResponse.body()).thenReturn("this is not json");
98+
when(mockClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class)))
99+
.thenReturn(mockResponse);
100+
101+
try (MockedStatic<HttpClient> staticHttpClient = mockStatic(HttpClient.class)) {
102+
staticHttpClient.when(HttpClient::newHttpClient).thenReturn(mockClient);
103+
104+
MachineTokenVerifier verifier = new MachineTokenVerifier();
105+
106+
VerifyTokenOptions options = new VerifyTokenOptions.Builder().build();
107+
108+
TokenVerificationException ex = assertThrows(TokenVerificationException.class,
109+
() -> verifier.verify("mt_token", options));
110+
assertEquals(TokenVerificationErrorReason.FAILED_TO_PROCESS_RESPONSE, ex.reason());
111+
}
112+
}
113+
114+
private static String getMockResponse(){
115+
return "{"
116+
+ "\"object\":\"api_key\","
117+
+ "\"id\":\"key_id\","
118+
+ "\"type\":\"machine\","
119+
+ "\"name\":\"MyKey\","
120+
+ "\"subject\":\"sub_123\","
121+
+ "\"scopes\":[\"read\",\"write\"],"
122+
+ "\"claims\":{"
123+
+ "\"permissions\":[\"org:read\",\"org:write\"]"
124+
+ "},"
125+
+ "\"created_at\":1625158800,"
126+
+ "\"updated_at\":1625162400,"
127+
+ "\"expiration\":1725162400,"
128+
+ "\"revoked\":false,"
129+
+ "\"revocation_reason\":null,"
130+
+ "\"expired\":false,"
131+
+ "\"created_by\":\"admin_user_id\""
132+
+ "}";
133+
}
134+
}
135+

0 commit comments

Comments
 (0)