Skip to content

Commit a36c921

Browse files
committed
Merge branch 'avdunn/fix-assertion-refresh' into avdunn/improve-credentials
# Conflicts: # msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClientCredentialTest.java
2 parents b80c4ab + fb0f51e commit a36c921

File tree

2 files changed

+77
-2
lines changed

2 files changed

+77
-2
lines changed

msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/ConfidentialClientApplication.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55

66
import org.slf4j.LoggerFactory;
77

8-
import java.util.Base64;
9-
import java.util.Date;
108
import java.util.concurrent.CompletableFuture;
119
import java.util.function.Function;
1210

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

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,83 @@ void OnBehalfOf_TenantOverride() throws Exception {
111111
verify(httpClientMock, times(2)).send(any());
112112
}
113113

114+
@Test
115+
void testCredentialPrecedenceAndMixing() throws Exception {
116+
DefaultHttpClient httpClientMock = mock(DefaultHttpClient.class);
117+
118+
// Create different credential types for testing
119+
IClientCredential appLevelCredential = ClientCredentialFactory.createFromSecret("appLevelSecret");
120+
IClientCredential requestLevelSecret = ClientCredentialFactory.createFromSecret("requestLevelSecret");
121+
String assertionValue = "test_assertion_value";
122+
IClientCredential requestLevelAssertion = ClientCredentialFactory.createFromClientAssertion(assertionValue);
123+
124+
// Create the application with the app-level credential
125+
ConfidentialClientApplication cca =
126+
ConfidentialClientApplication.builder("clientId", appLevelCredential)
127+
.authority("https://login.microsoftonline.com/tenant")
128+
.instanceDiscovery(false)
129+
.validateAuthority(false)
130+
.httpClient(httpClientMock)
131+
.build();
132+
133+
// Set up the mock to check which credential is being used
134+
when(httpClientMock.send(any(HttpRequest.class))).thenAnswer(invocation -> {
135+
HttpRequest request = invocation.getArgument(0);
136+
String requestBody = request.body();
137+
138+
// Check which credential type is included in the request and return a matching token
139+
if (requestBody.contains("client_secret=requestLevelSecret")) {
140+
HashMap<String, String> responseParams = new HashMap<>();
141+
responseParams.put("access_token", "request_secret_token");
142+
return TestHelper.expectedResponse(HttpStatus.HTTP_OK,
143+
TestHelper.getSuccessfulTokenResponse(responseParams));
144+
} else if (requestBody.contains("client_secret=appLevelSecret")) {
145+
HashMap<String, String> responseParams = new HashMap<>();
146+
responseParams.put("access_token", "app_secret_token");
147+
return TestHelper.expectedResponse(HttpStatus.HTTP_OK,
148+
TestHelper.getSuccessfulTokenResponse(responseParams));
149+
} else if (requestBody.contains("client_assertion=" + assertionValue)) {
150+
HashMap<String, String> responseParams = new HashMap<>();
151+
responseParams.put("access_token", "assertion_token");
152+
return TestHelper.expectedResponse(HttpStatus.HTTP_OK,
153+
TestHelper.getSuccessfulTokenResponse(responseParams));
154+
}
155+
return null;
156+
});
157+
158+
// Test 1: Request with same credential type (secret) at request level
159+
ClientCredentialParameters parametersWithRequestSecret =
160+
ClientCredentialParameters.builder(Collections.singleton("scope"))
161+
.clientCredential(requestLevelSecret)
162+
.skipCache(true)
163+
.build();
164+
165+
IAuthenticationResult result1 = cca.acquireToken(parametersWithRequestSecret).get();
166+
assertEquals("request_secret_token", result1.accessToken(),
167+
"Request-level secret should be used when provided");
168+
169+
// Test 2: Request with different credential type (assertion) at request level
170+
ClientCredentialParameters parametersWithAssertion =
171+
ClientCredentialParameters.builder(Collections.singleton("scope"))
172+
.clientCredential(requestLevelAssertion)
173+
.skipCache(true)
174+
.build();
175+
176+
IAuthenticationResult result2 = cca.acquireToken(parametersWithAssertion).get();
177+
assertEquals("assertion_token", result2.accessToken(),
178+
"Request-level assertion should be used when provided");
179+
180+
// Test 3: Request without credential specified should fall back to app-level
181+
ClientCredentialParameters parametersWithoutCredential =
182+
ClientCredentialParameters.builder(Collections.singleton("scope"))
183+
.skipCache(true)
184+
.build();
185+
186+
IAuthenticationResult result3 = cca.acquireToken(parametersWithoutCredential).get();
187+
assertEquals("app_secret_token", result3.accessToken(),
188+
"App-level credential should be used when request-level credential is not provided");
189+
}
190+
114191
@Test
115192
void acquireTokenClientCredentials_Callback() {
116193
// Create a counter to track how many times our callback is invoked

0 commit comments

Comments
 (0)