Skip to content

Commit f042744

Browse files
committed
Replace integration test with unit test
1 parent 0dcdc8b commit f042744

File tree

3 files changed

+122
-47
lines changed

3 files changed

+122
-47
lines changed

msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/OnBehalfOfIT.java

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -123,49 +123,6 @@ void acquireTokenWithOBO_testCache(String environment) throws Exception {
123123
assertNotEquals(result6.accessToken(), result2.accessToken());
124124
}
125125

126-
@Test
127-
void acquireTokenWithOBO_TenantOverride() throws Exception {
128-
cfg = new Config(AzureEnvironment.AZURE);
129-
String accessToken = this.getAccessToken();
130-
131-
final String clientId = cfg.appProvider.getOboAppId();
132-
final String password = cfg.appProvider.getOboAppPassword();
133-
134-
ConfidentialClientApplication cca =
135-
ConfidentialClientApplication.builder(clientId, ClientCredentialFactory.createFromSecret(password)).
136-
authority(cfg.tenantSpecificAuthority()).
137-
build();
138-
139-
//This token should be cached with the tenant-specific authority set at the application level
140-
IAuthenticationResult resultNoOverride = cca.acquireToken(OnBehalfOfParameters.builder(
141-
Collections.singleton(cfg.graphDefaultScope()),
142-
new UserAssertion(accessToken)).build()).
143-
get();
144-
145-
//This token should be cached with an 'organizations' authority set at the request level
146-
IAuthenticationResult resultOrganizations = cca.acquireToken(OnBehalfOfParameters.builder(
147-
Collections.singleton(cfg.graphDefaultScope()),
148-
new UserAssertion(accessToken))
149-
.tenant("organizations")
150-
.build()).
151-
get();
152-
153-
//This token should come from the cache and match the token with the 'organizations' authority
154-
IAuthenticationResult resultOrganizationsCached = cca.acquireToken(OnBehalfOfParameters.builder(
155-
Collections.singleton(cfg.graphDefaultScope()),
156-
new UserAssertion(accessToken))
157-
.tenant("organizations")
158-
.build()).
159-
get();
160-
161-
assertResultNotNull(resultNoOverride);
162-
assertResultNotNull(resultOrganizations);
163-
assertResultNotNull(resultOrganizationsCached);
164-
165-
assertNotEquals(resultNoOverride.accessToken(), resultOrganizations.accessToken());
166-
assertEquals(resultOrganizations.accessToken(), resultOrganizationsCached.accessToken());
167-
}
168-
169126
private void assertResultNotNull(IAuthenticationResult result) {
170127
assertNotNull(result);
171128
assertNotNull(result.accessToken());
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.microsoft.aad.msal4j;
5+
6+
import java.util.Collections;
7+
import java.util.HashMap;
8+
import java.util.List;
9+
import java.util.Map;
10+
11+
import org.junit.jupiter.api.Test;
12+
import org.junit.jupiter.api.extension.ExtendWith;
13+
import org.mockito.junit.jupiter.MockitoExtension;
14+
import static org.junit.jupiter.api.Assertions.assertEquals;
15+
import static org.mockito.ArgumentMatchers.any;
16+
import static org.mockito.Mockito.*;
17+
import static org.mockito.Mockito.times;
18+
19+
@ExtendWith(MockitoExtension.class)
20+
class OnBehalfOfTests {
21+
22+
private String getSuccessfulResponse() {
23+
return "{\"access_token\":\"accessToken\",\"expires_in\": \""+ 60*60*1000 +"\",\"token_type\":" +
24+
"\"Bearer\",\"client_id\":\"client_id\",\"Content-Type\":\"text/html; charset=utf-8\"}";
25+
}
26+
27+
private HttpResponse expectedResponse(int statusCode, String response) {
28+
Map<String, List<String>> headers = new HashMap<String, List<String>>();
29+
headers.put("Content-Type", Collections.singletonList("application/json"));
30+
31+
HttpResponse httpResponse = new HttpResponse();
32+
httpResponse.statusCode(statusCode);
33+
httpResponse.body(response);
34+
httpResponse.addHeaders(headers);
35+
36+
return httpResponse;
37+
}
38+
39+
@Test
40+
void OnBehalfOf_InternalCacheLookup_Success() throws Exception {
41+
DefaultHttpClient httpClientMock = mock(DefaultHttpClient.class);
42+
43+
when(httpClientMock.send(any(HttpRequest.class))).thenReturn(expectedResponse(200, getSuccessfulResponse()));
44+
45+
ConfidentialClientApplication cca =
46+
ConfidentialClientApplication.builder("clientId", ClientCredentialFactory.createFromSecret("password"))
47+
.authority("https://login.microsoftonline.com/tenant/")
48+
.instanceDiscovery(false)
49+
.validateAuthority(false)
50+
.httpClient(httpClientMock)
51+
.build();
52+
53+
OnBehalfOfParameters parameters = OnBehalfOfParameters.builder(Collections.singleton("scopes"), new UserAssertion(TestHelper.signedToken)).build();
54+
55+
IAuthenticationResult result = cca.acquireToken(parameters).get();
56+
IAuthenticationResult result2 = cca.acquireToken(parameters).get();
57+
58+
//OBO flow should perform an internal cache lookup, so similar parameters should only cause one HTTP client call
59+
assertEquals(result.accessToken(), result2.accessToken());
60+
verify(httpClientMock, times(1)).send(any());
61+
}
62+
63+
@Test
64+
void OnBehalfOf_TenantOverride() throws Exception {
65+
DefaultHttpClient httpClientMock = mock(DefaultHttpClient.class);
66+
67+
when(httpClientMock.send(any(HttpRequest.class))).thenReturn(expectedResponse(200, getSuccessfulResponse()));
68+
69+
ConfidentialClientApplication cca =
70+
ConfidentialClientApplication.builder("clientId", ClientCredentialFactory.createFromSecret("password"))
71+
.authority("https://login.microsoftonline.com/tenant")
72+
.instanceDiscovery(false)
73+
.validateAuthority(false)
74+
.httpClient(httpClientMock)
75+
.build();
76+
77+
OnBehalfOfParameters parameters = OnBehalfOfParameters.builder(Collections.singleton("scopes"), new UserAssertion(TestHelper.signedToken)).build();
78+
//The two acquireToken calls have the same parameters and should only cause one call from the HTTP client
79+
80+
cca.acquireToken(parameters).get();
81+
cca.acquireToken(parameters).get();
82+
verify(httpClientMock, times(1)).send(any());
83+
84+
parameters = OnBehalfOfParameters.builder(Collections.singleton("scopes"), new UserAssertion(TestHelper.signedToken)).tenant("otherTenant").build();
85+
//Overriding the tenant parameter in the request should lead to a new token call being made, but followup calls should not
86+
cca.acquireToken(parameters).get();
87+
cca.acquireToken(parameters).get();
88+
verify(httpClientMock, times(2)).send(any());
89+
}
90+
}

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

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33

44
package com.microsoft.aad.msal4j;
55

6+
import com.nimbusds.jose.*;
7+
import com.nimbusds.jose.crypto.RSASSASigner;
8+
import com.nimbusds.jose.jwk.RSAKey;
9+
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
10+
611
import java.io.File;
712
import java.io.FileWriter;
813
import java.io.IOException;
@@ -12,10 +17,16 @@
1217

1318
class TestHelper {
1419

15-
static String readResource(Class<?> classInstance, String resource) throws IOException, URISyntaxException {
16-
return new String(
17-
Files.readAllBytes(
18-
Paths.get(classInstance.getResource(resource).toURI())));
20+
//Signed JWT which should be enough to pass the parsing/validation in the library, useful if a unit test needs an
21+
// assertion in a request or token in a response but that is not the focus of the test
22+
static String signedToken = generateToken();
23+
24+
static String readResource(Class<?> classInstance, String resource) {
25+
try {
26+
return new String(Files.readAllBytes(Paths.get(classInstance.getResource(resource).toURI())));
27+
} catch (IOException | URISyntaxException e) {
28+
throw new RuntimeException(e);
29+
}
1930
}
2031

2132
static void deleteFileContent(Class<?> classInstance, String resource)
@@ -27,4 +38,21 @@ static void deleteFileContent(Class<?> classInstance, String resource)
2738
fileWriter.write("");
2839
fileWriter.close();
2940
}
41+
42+
static String generateToken() {
43+
try {
44+
RSAKey rsaJWK = new RSAKeyGenerator(2048)
45+
.keyID("kid")
46+
.generate();
47+
JWSObject jwsObject = new JWSObject(
48+
new JWSHeader.Builder(JWSAlgorithm.RS256).keyID(rsaJWK.getKeyID()).build(),
49+
new Payload("payload"));
50+
51+
jwsObject.sign(new RSASSASigner(rsaJWK));
52+
53+
return jwsObject.serialize();
54+
} catch (JOSEException e) {
55+
throw new RuntimeException(e);
56+
}
57+
}
3058
}

0 commit comments

Comments
 (0)