Skip to content

Commit

Permalink
Add unit test for client credential flow
Browse files Browse the repository at this point in the history
  • Loading branch information
Avery-Dunn committed Dec 18, 2024
1 parent 82633f2 commit a1a394a
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,20 @@

package com.microsoft.aad.msal4j;

import java.util.Collections;
import java.util.HashMap;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class ClientCredentialTest {
Expand All @@ -32,4 +42,69 @@ void testSecretNullAndEmpty() {

assertTrue(ex.getMessage().contains("clientSecret is null or empty"));
}

@Test
void OnBehalfOf_InternalCacheLookup_Success() throws Exception {
DefaultHttpClient httpClientMock = mock(DefaultHttpClient.class);

when(httpClientMock.send(any(HttpRequest.class))).thenReturn(TestHelper.expectedResponse(200, TestHelper.getSuccessfulTokenResponse(new HashMap<>())));

ConfidentialClientApplication cca =
ConfidentialClientApplication.builder("clientId", ClientCredentialFactory.createFromSecret("password"))
.authority("https://login.microsoftonline.com/tenant/")
.instanceDiscovery(false)
.validateAuthority(false)
.httpClient(httpClientMock)
.build();

ClientCredentialParameters parameters = ClientCredentialParameters.builder(Collections.singleton("scopes")).build();

IAuthenticationResult result = cca.acquireToken(parameters).get();
IAuthenticationResult result2 = cca.acquireToken(parameters).get();

//OBO flow should perform an internal cache lookup, so similar parameters should only cause one HTTP client call
assertEquals(result.accessToken(), result2.accessToken());
verify(httpClientMock, times(1)).send(any());
}

@Test
void OnBehalfOf_TenantOverride() throws Exception {
DefaultHttpClient httpClientMock = mock(DefaultHttpClient.class);

ConfidentialClientApplication cca =
ConfidentialClientApplication.builder("clientId", ClientCredentialFactory.createFromSecret("password"))
.authority("https://login.microsoftonline.com/tenant")
.instanceDiscovery(false)
.validateAuthority(false)
.httpClient(httpClientMock)
.build();

HashMap<String, String> tokenResponseValues = new HashMap<>();
tokenResponseValues.put("access_token", "accessTokenFirstCall");

when(httpClientMock.send(any(HttpRequest.class))).thenReturn(TestHelper.expectedResponse(200, TestHelper.getSuccessfulTokenResponse(tokenResponseValues)));
ClientCredentialParameters parameters = ClientCredentialParameters.builder(Collections.singleton("scopes")).build();

//The two acquireToken calls have the same parameters...
IAuthenticationResult resultAppLevelTenant = cca.acquireToken(parameters).get();
IAuthenticationResult resultAppLevelTenantCached = cca.acquireToken(parameters).get();
//...so only one token should be added to the cache, and the mocked HTTP client's "send" method should only have been called once
assertEquals(1, cca.tokenCache.accessTokens.size());
assertEquals(resultAppLevelTenant.accessToken(), resultAppLevelTenantCached.accessToken());
verify(httpClientMock, times(1)).send(any());

tokenResponseValues.put("access_token", "accessTokenSecondCall");

when(httpClientMock.send(any(HttpRequest.class))).thenReturn(TestHelper.expectedResponse(200, TestHelper.getSuccessfulTokenResponse(tokenResponseValues)));
parameters = ClientCredentialParameters.builder(Collections.singleton("scopes")).tenant("otherTenant").build();

//Overriding the tenant parameter in the request should lead to a new token call being made...
IAuthenticationResult resultRequestLevelTenant = cca.acquireToken(parameters).get();
IAuthenticationResult resultRequestLevelTenantCached = cca.acquireToken(parameters).get();
//...which should be different from the original token, and thus the cache should have two tokens created from two HTTP calls
assertEquals(2, cca.tokenCache.accessTokens.size());
assertEquals(resultRequestLevelTenant.accessToken(), resultRequestLevelTenantCached.accessToken());
assertNotEquals(resultAppLevelTenant.accessToken(), resultRequestLevelTenant.accessToken());
verify(httpClientMock, times(2)).send(any());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class OnBehalfOfTests {
Expand Down

0 comments on commit a1a394a

Please sign in to comment.