Skip to content

Commit f264456

Browse files
committed
Remove and replace various Nimbus imports
1 parent 1643890 commit f264456

File tree

9 files changed

+149
-132
lines changed

9 files changed

+149
-132
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ public class AuthenticationErrorCode {
9393
*/
9494
public final static String INVALID_REDIRECT_URI = "invalid_redirect_uri";
9595

96+
/**
97+
* Indicates token endpoint is invalid. Ensure authority and tenant are correctly set, as this endpoint is typically created using those values.
98+
*/
99+
public final static String INVALID_ENDPOINT_URI = "invalid_endpoint_uri";
100+
96101
/**
97102
* MSAL was unable to open the user-default browser. This is either because the current platform
98103
* does not support {@link java.awt.Desktop} or {@link java.awt.Desktop.Action#BROWSE}. Interactive

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
package com.microsoft.aad.msal4j;
55

6-
import com.nimbusds.oauth2.sdk.auth.JWTAuthentication;
76
import lombok.EqualsAndHashCode;
87
import lombok.Getter;
98
import lombok.experimental.Accessors;
@@ -13,7 +12,7 @@
1312
@EqualsAndHashCode
1413
final class ClientAssertion implements IClientAssertion {
1514

16-
static final String assertionType = JWTAuthentication.CLIENT_ASSERTION_TYPE;
15+
static final String ASSERTION_TYPE = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
1716
private final String assertion;
1817

1918
ClientAssertion(final String assertion) {

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

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

66
import com.fasterxml.jackson.annotation.JsonProperty;
7-
import com.nimbusds.jose.util.StandardCharset;
87

8+
import java.nio.charset.StandardCharsets;
99
import java.util.Base64;
1010

1111
import static com.microsoft.aad.msal4j.Constants.POINT_DELIMITER;
@@ -23,9 +23,9 @@ public static ClientInfo createFromJson(String clientInfoJsonBase64Encoded) {
2323
return null;
2424
}
2525

26-
byte[] decodedInput = Base64.getUrlDecoder().decode(clientInfoJsonBase64Encoded.getBytes(StandardCharset.UTF_8));
26+
byte[] decodedInput = Base64.getUrlDecoder().decode(clientInfoJsonBase64Encoded.getBytes(StandardCharsets.UTF_8));
2727

28-
return JsonHelper.convertJsonToObject(new String(decodedInput, StandardCharset.UTF_8), ClientInfo.class);
28+
return JsonHelper.convertJsonToObject(new String(decodedInput, StandardCharsets.UTF_8), ClientInfo.class);
2929
}
3030

3131
String toAccountIdentifier() {

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

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33

44
package com.microsoft.aad.msal4j;
55

6-
import com.nimbusds.jwt.JWTParser;
7-
86
import java.net.URL;
7+
import java.nio.charset.StandardCharsets;
8+
import java.util.Base64;
99
import java.util.concurrent.CompletableFuture;
1010

1111
/**
@@ -67,11 +67,17 @@ default IAuthenticationResult parseBrokerAuthResult(String authority, String idT
6767
if (idToken != null) {
6868
builder.idToken(idToken);
6969
if (accountId != null) {
70-
String idTokenJson =
71-
JWTParser.parse(idToken).getParsedParts()[1].decodeToString();
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+
}
78+
7279
builder.accountCacheEntity(AccountCacheEntity.create(clientInfo,
73-
Authority.createAuthority(new URL(authority)), JsonHelper.convertJsonToObject(idTokenJson,
74-
IdToken.class), null));
80+
Authority.createAuthority(new URL(authority)), JsonHelper.convertJsonToObject(idTokenJson, IdToken.class), null));
7581
}
7682
}
7783
if (accessToken != null) {

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

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,10 @@
44
package com.microsoft.aad.msal4j;
55

66
import com.fasterxml.jackson.annotation.JsonProperty;
7-
import com.nimbusds.jwt.JWTClaimsSet;
8-
9-
import java.text.ParseException;
10-
import java.util.HashMap;
11-
import java.util.Map;
12-
137
import java.io.Serializable;
148

159
class IdToken implements Serializable {
1610

17-
static final String ISSUER = "iss";
18-
static final String SUBJECT = "sub";
19-
static final String AUDIENCE = "aud";
20-
static final String EXPIRATION_TIME = "exp";
21-
static final String ISSUED_AT = "issuedAt";
22-
static final String NOT_BEFORE = "nbf";
23-
static final String NAME = "name";
24-
static final String PREFERRED_USERNAME = "preferred_username";
25-
static final String OBJECT_IDENTIFIER = "oid";
26-
static final String TENANT_IDENTIFIER = "tid";
27-
static final String UPN = "upn";
28-
static final String UNIQUE_NAME = "unique_name";
29-
3011
@JsonProperty("iss")
3112
protected String issuer;
3213

@@ -62,26 +43,4 @@ class IdToken implements Serializable {
6243

6344
@JsonProperty("unique_name")
6445
protected String uniqueName;
65-
66-
static IdToken createFromJWTClaims(final JWTClaimsSet claims) throws ParseException {
67-
IdToken idToken = new IdToken();
68-
69-
idToken.issuer = claims.getStringClaim(ISSUER);
70-
idToken.subject = claims.getStringClaim(SUBJECT);
71-
idToken.audience = claims.getStringClaim(AUDIENCE);
72-
73-
idToken.expirationTime = claims.getLongClaim(EXPIRATION_TIME);
74-
idToken.issuedAt = claims.getLongClaim(ISSUED_AT);
75-
idToken.notBefore = claims.getLongClaim(NOT_BEFORE);
76-
77-
idToken.name = claims.getStringClaim(NAME);
78-
idToken.preferredUsername = claims.getStringClaim(PREFERRED_USERNAME);
79-
idToken.objectIdentifier = claims.getStringClaim(OBJECT_IDENTIFIER);
80-
idToken.tenantIdentifier = claims.getStringClaim(TENANT_IDENTIFIER);
81-
82-
idToken.upn = claims.getStringClaim(UPN);
83-
idToken.uniqueName = claims.getStringClaim(UNIQUE_NAME);
84-
85-
return idToken;
86-
}
8746
}

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

Lines changed: 51 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,76 +3,85 @@
33

44
package com.microsoft.aad.msal4j;
55

6+
import java.nio.charset.StandardCharsets;
7+
import java.security.Signature;
68
import java.util.ArrayList;
7-
import java.util.Collections;
8-
import java.util.Date;
9+
import java.util.Base64;
10+
import java.util.HashMap;
911
import java.util.List;
12+
import java.util.Map;
1013
import java.util.UUID;
1114

12-
import com.nimbusds.jose.JWSAlgorithm;
13-
import com.nimbusds.jose.JWSHeader;
14-
import com.nimbusds.jose.JWSHeader.Builder;
15-
import com.nimbusds.jose.crypto.RSASSASigner;
16-
import com.nimbusds.jose.util.Base64;
17-
import com.nimbusds.jose.util.Base64URL;
18-
import com.nimbusds.jwt.JWTClaimsSet;
19-
import com.nimbusds.jwt.SignedJWT;
20-
2115
final class JwtHelper {
2216

2317
static ClientAssertion buildJwt(String clientId, final ClientCertificate credential,
2418
final String jwtAudience, boolean sendX5c,
2519
boolean useSha1) throws MsalClientException {
26-
if (StringHelper.isBlank(clientId)) {
27-
throw new IllegalArgumentException("clientId is null or empty");
28-
}
29-
30-
if (credential == null) {
31-
throw new IllegalArgumentException("credential is null");
32-
}
3320

34-
final long time = System.currentTimeMillis();
21+
ParameterValidationUtils.validateNotBlank("clientId", clientId);
22+
ParameterValidationUtils.validateNotNull("credential", clientId);
3523

36-
final JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
37-
.audience(Collections.singletonList(jwtAudience))
38-
.issuer(clientId)
39-
.jwtID(UUID.randomUUID().toString())
40-
.notBeforeTime(new Date(time))
41-
.expirationTime(new Date(time
42-
+ Constants.AAD_JWT_TOKEN_LIFETIME_SECONDS
43-
* 1000))
44-
.subject(clientId)
45-
.build();
46-
47-
SignedJWT jwt;
4824
try {
49-
JWSHeader.Builder builder = new Builder(JWSAlgorithm.RS256);
25+
final long time = System.currentTimeMillis();
26+
27+
// Build header
28+
Map<String, Object> header = new HashMap<>();
29+
header.put("alg", "RS256");
30+
header.put("typ", "JWT");
5031

5132
if (sendX5c) {
52-
List<Base64> certs = new ArrayList<>();
33+
List<String> certs = new ArrayList<>();
5334
for (String cert : credential.getEncodedPublicKeyCertificateChain()) {
54-
certs.add(new Base64(cert));
35+
certs.add(cert);
5536
}
56-
builder.x509CertChain(certs);
37+
header.put("x5c", certs);
5738
}
5839

5940
//SHA-256 is preferred, however certain flows still require SHA-1 due to what is supported server-side. If SHA-256
6041
// is not supported or the IClientCredential.publicCertificateHash256() method is not implemented, the library will default to SHA-1.
6142
String hash256 = credential.publicCertificateHash256();
6243
if (useSha1 || hash256 == null) {
63-
builder.x509CertThumbprint(new Base64URL(credential.publicCertificateHash()));
44+
header.put("x5t", credential.publicCertificateHash());
6445
} else {
65-
builder.x509CertSHA256Thumbprint(new Base64URL(hash256));
46+
header.put("x5t#S256", hash256);
6647
}
6748

68-
jwt = new SignedJWT(builder.build(), claimsSet);
69-
final RSASSASigner signer = new RSASSASigner(credential.privateKey());
49+
// Build payload
50+
Map<String, Object> payload = new HashMap<>();
51+
payload.put("aud", jwtAudience);
52+
payload.put("iss", clientId);
53+
payload.put("jti", UUID.randomUUID().toString());
54+
payload.put("nbf", time / 1000);
55+
payload.put("exp", time / 1000 + Constants.AAD_JWT_TOKEN_LIFETIME_SECONDS);
56+
payload.put("sub", clientId);
57+
58+
// Concatenate header and payload
59+
String jsonHeader = JsonHelper.mapper.writeValueAsString(header);
60+
String jsonPayload = JsonHelper.mapper.writeValueAsString(payload);
7061

71-
jwt.sign(signer);
62+
String encodedHeader = base64UrlEncode(jsonHeader.getBytes(StandardCharsets.UTF_8));
63+
String encodedPayload = base64UrlEncode(jsonPayload.getBytes(StandardCharsets.UTF_8));
64+
65+
// Create signature
66+
String dataToSign = encodedHeader + "." + encodedPayload;
67+
68+
Signature sig = Signature.getInstance("SHA256withRSA");
69+
sig.initSign(credential.privateKey());
70+
sig.update(dataToSign.getBytes(StandardCharsets.UTF_8));
71+
byte[] signatureBytes = sig.sign();
72+
73+
String encodedSignature = base64UrlEncode(signatureBytes);
74+
75+
// Build the JWT
76+
String jwt = dataToSign + "." + encodedSignature;
77+
78+
return new ClientAssertion(jwt);
7279
} catch (final Exception e) {
7380
throw new MsalClientException(e);
7481
}
82+
}
7583

76-
return new ClientAssertion(jwt.serialize());
84+
private static String base64UrlEncode(byte[] data) {
85+
return Base64.getUrlEncoder().withoutPadding().encodeToString(data);
7786
}
78-
}
87+
}

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

Lines changed: 0 additions & 33 deletions
This file was deleted.

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,19 @@ class TokenRequestExecutor {
3131
msalRequest.requestContext().apiParameters().tenant() ;
3232
}
3333

34-
AuthenticationResult executeTokenRequest() throws ParseException, IOException {
34+
AuthenticationResult executeTokenRequest() throws IOException {
3535

3636
log.debug("Sending token request to: {}", requestAuthority.canonicalAuthorityUrl());
3737
OAuthHttpRequest oAuthHttpRequest = createOauthHttpRequest();
3838
HttpResponse oauthHttpResponse = oAuthHttpRequest.send();
3939
return createAuthenticationResultFromOauthHttpResponse(oauthHttpResponse);
4040
}
4141

42-
OAuthHttpRequest createOauthHttpRequest() throws SerializeException, MalformedURLException {
42+
OAuthHttpRequest createOauthHttpRequest() throws MalformedURLException {
4343

4444
if (requestAuthority.tokenEndpointUrl() == null) {
45-
throw new SerializeException("The endpoint URI is not specified");
45+
throw new MsalClientException("The endpoint URI is not specified",
46+
AuthenticationErrorCode.INVALID_ENDPOINT_URI);
4647
}
4748

4849
final OAuthHttpRequest oauthHttpRequest = new OAuthHttpRequest(
@@ -113,8 +114,7 @@ private void addJWTBearerAssertionParams(Map<String, List<String>> queryParamete
113114
queryParameters.put("client_assertion_type", Collections.singletonList("urn:ietf:params:oauth:client-assertion-type:jwt-bearer"));
114115
}
115116

116-
private AuthenticationResult createAuthenticationResultFromOauthHttpResponse(
117-
HttpResponse oauthHttpResponse) throws ParseException {
117+
private AuthenticationResult createAuthenticationResultFromOauthHttpResponse(HttpResponse oauthHttpResponse) {
118118
AuthenticationResult result;
119119

120120
if (oauthHttpResponse.statusCode() == HttpHelper.HTTP_STATUS_200) {

0 commit comments

Comments
 (0)