Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…tion-library-for-java into avdunn/code-coverage
  • Loading branch information
Avery-Dunn committed Jan 22, 2025
2 parents 9e13c38 + 5259675 commit 452c2f5
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 12 deletions.
11 changes: 9 additions & 2 deletions msal4j-brokers/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
<version>1.18.36</version>
<scope>provided</scope>
</dependency>
<dependency>
Expand Down Expand Up @@ -126,7 +126,14 @@
<plugin>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-maven-plugin</artifactId>
<version>1.18.2.0</version>
<version>1.18.20.0</version>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
Expand Down
13 changes: 10 additions & 3 deletions msal4j-sdk/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
<version>1.18.36</version>
<scope>provided</scope>
</dependency>
<dependency>
Expand Down Expand Up @@ -207,7 +207,14 @@
<plugin>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-maven-plugin</artifactId>
<version>1.18.2.0</version>
<version>1.18.20.0</version>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
Expand Down Expand Up @@ -323,7 +330,7 @@
<plugin>
<groupId>biz.aQute.bnd</groupId>
<artifactId>bnd-maven-plugin</artifactId>
<version>4.3.1</version>
<version>5.2.0</version>
<executions>
<execution>
<goals>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,8 @@ private Optional<AccessTokenCacheEntity> getAccessTokenCacheEntity(

return accessTokens.values().stream().filter(
accessToken ->
accessToken.homeAccountId.equals(account.homeAccountId()) &&
accessToken.homeAccountId != null &&
accessToken.homeAccountId.equals(account.homeAccountId()) &&
environmentAliases.contains(accessToken.environment) &&
accessToken.realm.equals(authority.tenant()) &&
accessToken.clientId.equals(clientId) &&
Expand Down Expand Up @@ -552,6 +553,7 @@ private Optional<RefreshTokenCacheEntity> getRefreshTokenCacheEntity(

return refreshTokens.values().stream().filter(
refreshToken ->
refreshToken.homeAccountId != null &&
refreshToken.homeAccountId.equals(account.homeAccountId()) &&
environmentAliases.contains(refreshToken.environment) &&
refreshToken.clientId.equals(clientId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Getter(AccessLevel.PACKAGE)
Expand Down Expand Up @@ -118,9 +119,15 @@ private AuthenticationResult createAuthenticationResultFromOauthHttpResponse(
}

AccountCacheEntity accountCacheEntity = null;
if (!StringHelper.isNullOrBlank(tokens.getIDTokenString())) {
String idTokenJson;
try {
idTokenJson = new String(Base64.getDecoder().decode(tokens.getIDTokenString().split("\\.")[1]), StandardCharsets.UTF_8);
} catch (ArrayIndexOutOfBoundsException e) {
throw new MsalServiceException("Error parsing ID token, missing payload section. Ensure that the ID token is following the JWT format.",
AuthenticationErrorCode.INVALID_JWT);
}

if (tokens.getIDToken() != null) {
String idTokenJson = tokens.getIDToken().getParsedParts()[1].decodeToString();
IdToken idToken = JsonHelper.convertJsonToObject(idTokenJson, IdToken.class);

AuthorityType type = msalRequest.application().authenticationAuthority.authorityType;
Expand Down
70 changes: 70 additions & 0 deletions msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/CacheTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.microsoft.aad.msal4j;

import org.junit.jupiter.api.Test;

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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
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;

class CacheTests {

@Test
void cacheLookup_MixAccountBasedAndAssertionBasedSilentFlows() 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> responseParameters = new HashMap<>();
//Acquire a token with no ID token/account associated with it
responseParameters.put("access_token", "accessTokenNoAccount");

ClientCredentialParameters clientCredentialParameters = ClientCredentialParameters.builder(Collections.singleton("someScopes")).build();
when(httpClientMock.send(any(HttpRequest.class))).thenReturn(TestHelper.expectedResponse(200, TestHelper.getSuccessfulTokenResponse(responseParameters)));
IAuthenticationResult resultNoAccount = cca.acquireToken(clientCredentialParameters).get();

//Ensure there is one token in the cache, and the result had no account
assertEquals(1, cca.tokenCache.accessTokens.size());
assertNull(resultNoAccount.account());
verify(httpClientMock, times(1)).send(any());

//Acquire a second token, this time with an ID token/account
responseParameters.put("access_token", "accessTokenWithAccount");
responseParameters.put("id_token", TestHelper.createIdToken(new HashMap<>()));

when(httpClientMock.send(any(HttpRequest.class))).thenReturn(TestHelper.expectedResponse(200, TestHelper.getSuccessfulTokenResponse(responseParameters)));
OnBehalfOfParameters onBehalfOfParametersarameters = OnBehalfOfParameters.builder(Collections.singleton("someOtherScopes"), new UserAssertion(TestHelper.signedAssertion)).build();
IAuthenticationResult resultWithAccount = cca.acquireToken(onBehalfOfParametersarameters).get();

//Ensure there are now two tokens in the cache, and the result has an account
assertEquals(2, cca.tokenCache.accessTokens.size());
assertNull(resultNoAccount.account());
verify(httpClientMock, times(2)).send(any());

//Make two silent calls, one with the account and one without
SilentParameters silentParametersNoAccount = SilentParameters.builder(Collections.singleton("someScopes")).build();
SilentParameters silentParametersWithAccount = SilentParameters.builder(Collections.singleton("someOtherScopes"), resultWithAccount.account()).build();

resultNoAccount = cca.acquireTokenSilently(silentParametersNoAccount).get();
resultWithAccount = cca.acquireTokenSilently(silentParametersWithAccount).get();

//Ensure the correct access tokens were returned from each silent call
assertEquals("accessTokenNoAccount", resultNoAccount.accessToken());
assertEquals("accessTokenWithAccount", resultWithAccount.accessToken());
}
}
36 changes: 32 additions & 4 deletions msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/TestHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand All @@ -29,6 +29,17 @@ class TestHelper {
"\"expires_on\": %d ,\"expires_in\": %d," +
"\"token_type\":\"Bearer\"}";

static final String idTokenFormat = "{\"aud\": \"%s\"," +
"\"iss\": \"%s\"," +
"\"iat\": 1455833828," + "\"nbf\": 1455833828," + "\"exp\": 1455837728," +
"\"ipaddr\": \"131.107.159.117\"," +
"\"name\": \"%s\"," +
"\"oid\": \"%s\"," +
"\"preferred_username\": \"%s\"," +
"\"sub\": \"%s\"," +
"\"tid\": \"%s\"," +
"\"ver\": \"2.0\"}";

static String readResource(Class<?> classInstance, String resource) {
try {
return new String(Files.readAllBytes(Paths.get(classInstance.getResource(resource).toURI())));
Expand Down Expand Up @@ -76,10 +87,10 @@ static String getSuccessfulTokenResponse(HashMap<String, String> responseValues)

return String.format(successfulResponseFormat,
responseValues.getOrDefault("access_token", "access_token"),
responseValues.getOrDefault("id_token", "id_token"),
responseValues.getOrDefault("id_token", ""),
responseValues.getOrDefault("refresh_token", "refresh_token"),
responseValues.getOrDefault("client_id", "client_id"),
responseValues.getOrDefault("client_info", "client_info"),
responseValues.getOrDefault("client_info", "eyJ1aWQiOiI1OTdmODZjZC0xM2YzLTQ0YzAtYmVjZS1hMWU3N2JhNDMyMjgiLCJ1dGlkIjoiZjY0NWFkOTItZTM4ZC00ZDFhLWI1MTAtZDFiMDlhNzRhOGNhIn0"),
expiresOn,
expiresIn
);
Expand All @@ -97,4 +108,21 @@ static HttpResponse expectedResponse(int statusCode, String response) {

return httpResponse;
}
}

//Maps various values to the idTokenFormat string
static String createIdToken(HashMap<String, String> idTokenValues) {
String tokenValues = String.format(idTokenFormat,
idTokenValues.getOrDefault("aud", "e854a4a7-6c34-449c-b237-fc7a28093d84"),
idTokenValues.getOrDefault("iss", "https://login.microsoftonline.com/6c3d51dd-f0e5-4959-b4ea-a80c4e36fe5e/v2.0/"),
idTokenValues.getOrDefault("name", "name"),
idTokenValues.getOrDefault("oid", "oid"),
idTokenValues.getOrDefault("preferred_username", "preferred_username"),
idTokenValues.getOrDefault("sub", "K4_SGGxKqW1SxUAmhg6C1F6VPiFzcx-Qd80ehIEdFus"),
idTokenValues.getOrDefault("client_info", "eyJ1aWQiOiI1OTdmODZjZC0xM2YzLTQ0YzAtYmVjZS1hMWU3N2JhNDMyMjgiLCJ1dGlkIjoiZjY0NWFkOTItZTM4ZC00ZDFhLWI1MTAtZDFiMDlhNzRhOGNhIn0")
);

String encodedTokenValues = Base64.getUrlEncoder().encodeToString(tokenValues.getBytes());

return String.format("someheader.%s.somesignature", encodedTokenValues);
}
}

0 comments on commit 452c2f5

Please sign in to comment.