Skip to content

Commit 8d1f418

Browse files
committed
Address PR feedback
1 parent 66dea81 commit 8d1f418

File tree

6 files changed

+60
-33
lines changed

6 files changed

+60
-33
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
@EqualsAndHashCode
1313
final class ClientAssertion implements IClientAssertion {
1414

15-
static final String ASSERTION_TYPE = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
15+
static final String ASSERTION_TYPE_JWT_BEARER = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
1616
private final String assertion;
1717

1818
ClientAssertion(final String assertion) {

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

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
package com.microsoft.aad.msal4j;
55

66
import java.net.URL;
7-
import java.nio.charset.StandardCharsets;
8-
import java.util.Base64;
97
import java.util.concurrent.CompletableFuture;
108

119
/**
@@ -67,17 +65,10 @@ default IAuthenticationResult parseBrokerAuthResult(String authority, String idT
6765
if (idToken != null) {
6866
builder.idToken(idToken);
6967
if (accountId != null) {
70-
String idTokenJson;
71-
72-
try {
73-
idTokenJson = new String(Base64.getDecoder().decode(idToken.split("\\.")[1]), StandardCharsets.UTF_8);
74-
} catch (ArrayIndexOutOfBoundsException e) {
75-
throw new MsalServiceException("Error parsing ID token, missing payload section. Ensure that the ID token is following the JWT format.",
76-
AuthenticationErrorCode.INVALID_JWT);
77-
}
68+
IdToken idTokenObj = JsonHelper.createIdTokenFromEncodedTokenString(idToken);
7869

7970
builder.accountCacheEntity(AccountCacheEntity.create(clientInfo,
80-
Authority.createAuthority(new URL(authority)), JsonHelper.convertJsonToObject(idTokenJson, IdToken.class), null));
71+
Authority.createAuthority(new URL(authority)), idTokenObj, null));
8172
}
8273
}
8374
if (accessToken != null) {

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

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,8 @@
1515
import com.fasterxml.jackson.databind.JsonNode;
1616

1717
import java.io.IOException;
18-
import java.util.ArrayList;
19-
import java.util.Iterator;
20-
import java.util.Map;
21-
import java.util.Set;
18+
import java.nio.charset.StandardCharsets;
19+
import java.util.*;
2220

2321
class JsonHelper {
2422
static ObjectMapper mapper;
@@ -41,6 +39,18 @@ static <T> T convertJsonToObject(final String json, final Class<T> tClass) {
4139
}
4240
}
4341

42+
static IdToken createIdTokenFromEncodedTokenString(String token) {
43+
String idTokenJson;
44+
try {
45+
idTokenJson = new String(Base64.getUrlDecoder().decode(token.split("\\.")[1]), StandardCharsets.UTF_8);
46+
} catch (ArrayIndexOutOfBoundsException e) {
47+
throw new MsalClientException("Error parsing ID token, missing payload section.",
48+
AuthenticationErrorCode.INVALID_JWT);
49+
}
50+
51+
return JsonHelper.convertJsonToObject(idTokenJson, IdToken.class);
52+
}
53+
4454
//This method is used to convert a JSON string to an object which implements the JsonSerializable interface from com.azure.json
4555
static <T extends JsonSerializable<T>> T convertJsonStringToJsonSerializableObject(String jsonResponse, ReadValueCallback<JsonReader, T> readFunction) {
4656
try (JsonReader jsonReader = JsonProviders.createReader(jsonResponse)) {

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,7 @@ static ClientAssertion buildJwt(String clientId, final ClientCertificate credent
3030
header.put("typ", "JWT");
3131

3232
if (sendX5c) {
33-
List<String> certs = new ArrayList<>();
34-
for (String cert : credential.getEncodedPublicKeyCertificateChain()) {
35-
certs.add(cert);
36-
}
33+
List<String> certs = new ArrayList<>(credential.getEncodedPublicKeyCertificateChain());
3734
header.put("x5c", certs);
3835
}
3936

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

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,11 @@
33

44
package com.microsoft.aad.msal4j;
55

6-
import com.nimbusds.oauth2.sdk.ParseException;
7-
import com.nimbusds.oauth2.sdk.SerializeException;
86
import org.slf4j.Logger;
97
import org.slf4j.LoggerFactory;
108

119
import java.io.IOException;
1210
import java.net.MalformedURLException;
13-
import java.nio.charset.StandardCharsets;
1411
import java.util.*;
1512

1613
class TokenRequestExecutor {
@@ -110,7 +107,7 @@ private void addQueryParameters(OAuthHttpRequest oauthHttpRequest) {
110107

111108
private void addJWTBearerAssertionParams(Map<String, String> queryParameters, String assertion) {
112109
queryParameters.put("client_assertion", assertion);
113-
queryParameters.put("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer");
110+
queryParameters.put("client_assertion_type", ClientAssertion.ASSERTION_TYPE_JWT_BEARER);
114111
}
115112

116113
private AuthenticationResult createAuthenticationResultFromOauthHttpResponse(HttpResponse oauthHttpResponse) {
@@ -121,15 +118,7 @@ private AuthenticationResult createAuthenticationResultFromOauthHttpResponse(Htt
121118

122119
AccountCacheEntity accountCacheEntity = null;
123120
if (!StringHelper.isNullOrBlank(response.idToken())) {
124-
String idTokenJson;
125-
try {
126-
idTokenJson = new String(Base64.getUrlDecoder().decode(response.idToken().split("\\.")[1]), StandardCharsets.UTF_8);
127-
} catch (ArrayIndexOutOfBoundsException e) {
128-
throw new MsalServiceException("Error parsing ID token, missing payload section. Ensure that the ID token is following the JWT format.",
129-
AuthenticationErrorCode.INVALID_JWT);
130-
}
131-
132-
IdToken idToken = JsonHelper.convertJsonToObject(idTokenJson, IdToken.class);
121+
IdToken idToken = JsonHelper.createIdTokenFromEncodedTokenString(response.idToken());
133122

134123
AuthorityType type = msalRequest.application().authenticationAuthority.authorityType;
135124
if (!StringHelper.isBlank(response.getClientInfo())) {

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

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

66
import org.junit.jupiter.api.Test;
77

8+
import java.nio.charset.StandardCharsets;
89
import java.security.NoSuchAlgorithmException;
910
import java.security.cert.CertificateEncodingException;
1011
import java.util.*;
@@ -147,4 +148,43 @@ void JwtHelper_buildJwt_ValidSha1AndSha256Assertions() throws MsalClientExceptio
147148
// Verify the correct certificate hash method was called
148149
verify(clientCertificateMock).publicCertificateHash();
149150
}
151+
152+
@Test
153+
void JsonHelper_createIdTokenFromEncodedTokenString_Base64URLCharacters() {
154+
HashMap<String, String> tokenParameters = new HashMap<>();
155+
tokenParameters.put("preferred_username", "~nameWith~specialChars");
156+
String encodedIDToken = TestHelper.createIdToken(tokenParameters);
157+
158+
try {
159+
//TestHelper.createIdToken() should use Base64URL encoding, so first we prove that the encoded token cannot be decoded with Base64 decoder
160+
Base64.getDecoder().decode(encodedIDToken);
161+
162+
fail("IllegalArgumentException was expected but not thrown.");
163+
} catch (IllegalArgumentException e) {
164+
//Encoded token should have some "-" characters in it
165+
assertTrue(e.getMessage().contains("Illegal base64 character 2e"));
166+
}
167+
168+
// Act
169+
IdToken idToken = JsonHelper.createIdTokenFromEncodedTokenString(encodedIDToken);
170+
171+
// Assert
172+
assertNotNull(idToken);
173+
assertEquals("~nameWith~specialChars", idToken.preferredUsername);
174+
}
175+
176+
@Test
177+
void JsonHelper_createIdTokenFromEncodedTokenString_InvalidJsonInToken() {
178+
// Arrange
179+
String invalidPayload = "{not-valid-json}";
180+
String encodedPayload = Base64.getUrlEncoder().withoutPadding()
181+
.encodeToString(invalidPayload.getBytes(StandardCharsets.UTF_8));
182+
String invalidToken = "header." + encodedPayload + ".signature";
183+
184+
// Act & Assert
185+
MsalJsonParsingException exception = assertThrows(MsalJsonParsingException.class,
186+
() -> JsonHelper.createIdTokenFromEncodedTokenString(invalidToken));
187+
188+
assertEquals(AuthenticationErrorCode.INVALID_JSON, exception.errorCode());
189+
}
150190
}

0 commit comments

Comments
 (0)