Skip to content

Commit 11abc43

Browse files
committed
Use configs from server
1 parent 62fcb33 commit 11abc43

File tree

4 files changed

+383
-175
lines changed

4 files changed

+383
-175
lines changed

msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/RunnerHelper.java

Lines changed: 84 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
import com.fasterxml.jackson.databind.JsonNode;
44

5+
import java.io.IOException;
56
import java.util.ArrayList;
67
import java.util.HashMap;
78
import java.util.List;
89
import java.util.Map;
9-
10-
import static com.microsoft.aad.msal4j.ManagedIdentitySourceType.SERVICE_FABRIC;
1110
import static org.junit.jupiter.api.Assertions.assertEquals;
1211

1312
import com.microsoft.aad.msal4j.Shortcuts.TestConfig;
@@ -31,7 +30,7 @@ static Map<String, ManagedIdentityApplication> createAppsFromConfig(TestConfig c
3130
if ("ManagedIdentityClient".equals(appObject.getType())) {
3231
ManagedIdentityId identityId = createManagedIdentityId(appObject);
3332
List<String> capabilities = extractClientCapabilities(appObject);
34-
IEnvironmentVariables envVars = createEnvironmentVariables(config);
33+
IEnvironmentVariables envVars = setEnvironmentVariables(config);
3534
// TODO: other application properties
3635

3736
ManagedIdentityApplication app = ManagedIdentityApplication.builder(identityId)
@@ -53,21 +52,19 @@ static Map<String, ManagedIdentityApplication> createAppsFromConfig(TestConfig c
5352
*/
5453
static IAuthenticationResult executeAction(ManagedIdentityApplication app, TestAction action) throws Exception {
5554
if (action.getMethodName().equals("AcquireTokenForManagedIdentity")) {
56-
LOG.info(String.format("Executing action: %s", action.getMethodName()));
57-
55+
LOG.info(String.format("===Executing action: %s", action.getMethodName()));
5856
ManagedIdentityParameters params = buildManagedIdentityParameters(action);
59-
6057
IAuthenticationResult result = app.acquireTokenForManagedIdentity(params).get();
6158

62-
LOG.info("Action result:");
63-
LOG.info(String.format("Access Token: %s", result.accessToken()));
64-
LOG.info(String.format("ID Token : %s", result.idToken()));
65-
LOG.info(String.format("Account : %s", result.account()));
66-
LOG.info(String.format("Token Source: %s", result.metadata().tokenSource()));
59+
LOG.info("---Action result");
60+
LOG.info(String.format("-Access Token: %s", result.accessToken()));
61+
LOG.info(String.format("-ID Token : %s", result.idToken()));
62+
LOG.info(String.format("-Account : %s", result.account()));
63+
LOG.info(String.format("-Token Source: %s", result.metadata().tokenSource()));
6764

6865
return result;
6966
} else {
70-
//TODO: other token calls and apps
67+
//TODO: other token calls and confidential/public client apps
7168
throw new UnsupportedOperationException("Unsupported action: " + action.getMethodName());
7269
}
7370
}
@@ -80,10 +77,10 @@ static void validateAssertions(IAuthenticationResult result, Map<String, JsonNod
8077
assertions.forEach((key, value) -> {
8178
switch (key) {
8279
case "token_source":
83-
LOG.info("Validating token source");
80+
LOG.info("===Validating token source");
8481
validateTokenSource(value.asText(), result);
8582
break;
86-
//TODO: other assertions
83+
//TODO: other assertions, such as exceptions checks, token content, etc.
8784
default:
8885
// Optional: Handle unknown assertion types
8986
break;
@@ -95,13 +92,23 @@ static void validateAssertions(IAuthenticationResult result, Map<String, JsonNod
9592
* Create managed identity ID from test object
9693
*/
9794
static ManagedIdentityId createManagedIdentityId(TestObject appObject) {
98-
String idType = appObject.getProperty("managed_identity").get("ManagedIdentityIdType").asText();
99-
100-
if ("SystemAssigned".equals(idType)) {
101-
return ManagedIdentityId.systemAssigned();
102-
} else {
103-
// TODO: handle user assertions
104-
return null;
95+
JsonNode managedIdentityNode = appObject.getProperty("managed_identity");
96+
String idType = managedIdentityNode.get("ManagedIdentityIdType").asText();
97+
98+
switch (idType) {
99+
case "SystemAssigned":
100+
return ManagedIdentityId.systemAssigned();
101+
case "ClientId":
102+
String clientId = managedIdentityNode.get("Id").asText();
103+
return ManagedIdentityId.userAssignedClientId(clientId);
104+
case "ObjectId":
105+
String objectId = managedIdentityNode.get("Id").asText();
106+
return ManagedIdentityId.userAssignedObjectId(objectId);
107+
case "ResourceId":
108+
String resourceId = managedIdentityNode.get("Id").asText();
109+
return ManagedIdentityId.userAssignedResourceId(resourceId);
110+
default:
111+
throw new IllegalArgumentException("Unsupported ManagedIdentityIdType: " + idType);
105112
}
106113
}
107114

@@ -116,16 +123,29 @@ static List<String> extractClientCapabilities(TestObject testObject) {
116123
capabilitiesNode.forEach(node -> capabilities.add(node.asText()));
117124
}
118125

119-
LOG.info(String.format("Extracted client capabilities: %s", capabilities));
126+
LOG.info(String.format("---Extracted client capabilities: %s", capabilities));
120127

121128
return capabilities;
122129
}
123130

124-
//TODO: Re-used from other Managed Identity tests, specific to this proof-of-concept but should be more generic
125-
static IEnvironmentVariables createEnvironmentVariables(TestConfig config) {
126-
return new EnvironmentVariablesHelper(
127-
SERVICE_FABRIC,
128-
config.getEnvironmentVariable("IDENTITY_ENDPOINT"));
131+
/**
132+
* Creates provider for mocked environment variables using the test configuration.
133+
*
134+
* @param config The test configuration containing the environment variables
135+
* @return An IEnvironmentVariables implementation with the configured variables
136+
*/
137+
static IEnvironmentVariables setEnvironmentVariables(TestConfig config) {
138+
// Get all environment variables from the config
139+
final Map<String, String> envVars = config.getAllEnvironmentVariables();
140+
141+
LOG.info(String.format("---Configured environment variables: %s", envVars.keySet()));
142+
143+
return new IEnvironmentVariables() {
144+
@Override
145+
public String getEnvironmentVariable(String envVariable) {
146+
return envVars.get(envVariable);
147+
}
148+
};
129149
}
130150

131151
/**
@@ -141,7 +161,8 @@ static ManagedIdentityParameters buildManagedIdentityParameters(TestAction actio
141161

142162
// Add optional claims challenge
143163
if (action.hasParameter("claims_challenge")) {
144-
builder.claims(action.getParameter("claims_challenge").asText());
164+
String validatedClaimsChallenge = Shortcuts.validateAndGetClaimsChallenge(action);
165+
builder.claims(validatedClaimsChallenge);
145166
}
146167

147168
//TODO: other parameters
@@ -155,9 +176,42 @@ static ManagedIdentityParameters buildManagedIdentityParameters(TestAction actio
155176
static void validateTokenSource(String expectedSource, IAuthenticationResult result) {
156177
TokenSource expected = "identity_provider".equals(expectedSource) ?
157178
TokenSource.IDENTITY_PROVIDER : TokenSource.CACHE;
158-
LOG.info(String.format("Expected token source: %s", expected));
159-
LOG.info(String.format("Actual token source : %s", result.metadata().tokenSource()));
179+
LOG.info(String.format("---Expected token source: %s", expected));
180+
LOG.info(String.format("---Actual token source : %s", result.metadata().tokenSource()));
160181

161182
assertEquals(expected, result.metadata().tokenSource());
162183
}
184+
185+
/**
186+
* Complete workflow to get all test case configs
187+
*
188+
* @param indexEndpoint The URL of the index containing test case URLs
189+
* @return Map of test case names to their JSON configurations
190+
*/
191+
static Map<String, JsonNode> getAllTestCaseConfigs(String indexEndpoint) throws IOException {
192+
// Get list of SML test case URLs
193+
List<String> smlUrls = RunnerJsonHelper.getTestCaseUrlsFromEndpoint(indexEndpoint);
194+
195+
// Convert SML URLs to JSON URLs
196+
List<String> jsonUrls = Shortcuts.convertSmlUrlsToJsonUrls(smlUrls);
197+
198+
// Fetch content for each JSON URL
199+
Map<String, JsonNode> testCaseConfigs = new HashMap<>();
200+
for (String jsonUrl : jsonUrls) {
201+
String testCaseName = extractTestCaseName(jsonUrl);
202+
JsonNode config = RunnerJsonHelper.fetchJsonContent(jsonUrl);
203+
testCaseConfigs.put(testCaseName, config);
204+
}
205+
206+
return testCaseConfigs;
207+
}
208+
209+
/**
210+
* Extract test case name from URL
211+
*/
212+
private static String extractTestCaseName(String url) {
213+
String[] parts = url.split("/");
214+
String fileName = parts[parts.length - 1];
215+
return fileName.substring(0, fileName.lastIndexOf('.'));
216+
}
163217
}

msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/RunnerJsonHelper.java

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22

33
import com.fasterxml.jackson.databind.JsonNode;
44

5+
import java.io.BufferedReader;
6+
import java.io.IOException;
7+
import java.io.InputStreamReader;
8+
import java.net.URL;
9+
import java.util.ArrayList;
510
import java.util.HashMap;
11+
import java.util.List;
612
import java.util.Map;
713

814
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -11,6 +17,8 @@
1117
import com.microsoft.aad.msal4j.Shortcuts.TestStep;
1218
import com.microsoft.aad.msal4j.Shortcuts.TestAction;
1319

20+
import javax.net.ssl.HttpsURLConnection;
21+
1422
//TODO: Too specific for the test case used in this proof-of-concept, should be able to reuse the regular JsonHelper class
1523
class RunnerJsonHelper {
1624
private static final ObjectMapper mapper = new ObjectMapper();
@@ -101,4 +109,77 @@ private static Map<String, JsonNode> parseAssertions(JsonNode assertNode) {
101109
return assertions;
102110
}
103111
}
112+
113+
/**
114+
* Fetches test case URLs from an endpoint containing JSON with a "testcases" array.
115+
*
116+
* @param endpointUrl The URL to fetch test cases from
117+
* @return List of test case URLs
118+
*/
119+
static List<String> getTestCaseUrlsFromEndpoint(String endpointUrl) throws IOException {
120+
List<String> testCaseUrls = new ArrayList<>();
121+
122+
URL url = new URL(endpointUrl);
123+
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
124+
connection.setRequestMethod("GET");
125+
connection.setRequestProperty("Content-Type", "application/json");
126+
127+
int responseCode = connection.getResponseCode();
128+
if (responseCode == HttpsURLConnection.HTTP_OK) {
129+
try (BufferedReader reader = new BufferedReader(
130+
new InputStreamReader(connection.getInputStream()))) {
131+
StringBuilder response = new StringBuilder();
132+
String line;
133+
while ((line = reader.readLine()) != null) {
134+
response.append(line);
135+
}
136+
137+
ObjectMapper mapper = new ObjectMapper();
138+
JsonNode rootNode = mapper.readTree(response.toString());
139+
140+
if (rootNode.has("testcases") && rootNode.get("testcases").isArray()) {
141+
JsonNode testcasesNode = rootNode.get("testcases");
142+
for (JsonNode testcase : testcasesNode) {
143+
testCaseUrls.add(testcase.asText());
144+
}
145+
} else {
146+
throw new IllegalStateException("JSON response does not contain a 'testcases' array");
147+
}
148+
}
149+
} else {
150+
throw new IOException("HTTP request failed with status code: " + responseCode);
151+
}
152+
153+
return testCaseUrls;
154+
}
155+
156+
/**
157+
* Fetches JSON content from a URL
158+
*
159+
* @param jsonUrl The URL to fetch JSON content from
160+
* @return The JSON content parsed as a JsonNode
161+
*/
162+
static JsonNode fetchJsonContent(String jsonUrl) throws IOException {
163+
URL url = new URL(jsonUrl);
164+
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
165+
connection.setRequestMethod("GET");
166+
connection.setRequestProperty("Content-Type", "application/json");
167+
168+
int responseCode = connection.getResponseCode();
169+
if (responseCode == HttpsURLConnection.HTTP_OK) {
170+
try (BufferedReader reader = new BufferedReader(
171+
new InputStreamReader(connection.getInputStream()))) {
172+
StringBuilder response = new StringBuilder();
173+
String line;
174+
while ((line = reader.readLine()) != null) {
175+
response.append(line);
176+
}
177+
178+
ObjectMapper mapper = new ObjectMapper();
179+
return mapper.readTree(response.toString());
180+
}
181+
} else {
182+
throw new IOException("Failed to fetch JSON content. HTTP status: " + responseCode);
183+
}
184+
}
104185
}
Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,59 @@
11
package com.microsoft.aad.msal4j;
22

3-
import org.junit.jupiter.api.Test;
4-
3+
import com.fasterxml.jackson.databind.JsonNode;
54
import com.microsoft.aad.msal4j.Shortcuts.TestConfig;
65
import com.microsoft.aad.msal4j.Shortcuts.TestStep;
6+
import org.junit.jupiter.params.ParameterizedTest;
7+
import org.junit.jupiter.params.provider.MethodSource;
8+
import org.slf4j.Logger;
9+
import org.slf4j.LoggerFactory;
710

811
import java.util.Map;
12+
import java.util.stream.Stream;
913

1014
class RunnerTest {
15+
private static final Logger LOG = LoggerFactory.getLogger(RunnerTest.class);
16+
17+
/**
18+
* Defines a set of test cases for a single unit test to run.
19+
*/
20+
static Stream<String> managedIdentityTestsProvider() {
21+
return Stream.of(
22+
"mi_capability",
23+
"token_sha256_to_refresh",
24+
"mi_vm_pod"
25+
);
26+
}
27+
28+
@ParameterizedTest
29+
@MethodSource("managedIdentityTestsProvider")
30+
void runManagedIdentityTest(String testCaseName) throws Exception {
31+
LOG.info("==========Executing Test Case==========");
32+
33+
// Get all test configurations
34+
Map<String, JsonNode> configs = RunnerHelper.getAllTestCaseConfigs("https://smile-test.azurewebsites.net/testcases.json");
1135

12-
@Test
13-
void testManagedIdentityWithJsonConfig() throws Exception {
14-
//TODO: get test cases list from the server
15-
TestConfig config = RunnerJsonHelper.parseTestConfig(Shortcuts.getTestConfigJson());
36+
LOG.info(String.format("---Found test case: %s", configs.get(testCaseName).toString()));
37+
38+
TestConfig config = RunnerJsonHelper.parseTestConfig(configs.get(testCaseName).toString());
39+
40+
// Create applications from the configuration
1641
Map<String, ManagedIdentityApplication> apps = RunnerHelper.createAppsFromConfig(config);
1742

43+
// For each application, execute all steps
1844
for (ManagedIdentityApplication app : apps.values()) {
19-
//Execute the "steps" section of the test config
45+
app.tokenCache.accessTokens.clear(); // Clear the static token cache for each test run
46+
47+
// Execute each step in the test configuration
2048
for (TestStep step : config.getSteps()) {
21-
//Execute the "act" section of the test config
49+
LOG.info("----------Executing step----------");
50+
51+
// Execute the action
2252
IAuthenticationResult result = RunnerHelper.executeAction(app, step.getAction());
2353

24-
//Execute the "assert" section of the test config
54+
// Validate assertions
2555
RunnerHelper.validateAssertions(result, step.getAssertions());
2656
}
2757
}
2858
}
29-
}
59+
}

0 commit comments

Comments
 (0)