Skip to content

Commit 70d4312

Browse files
authored
Merge pull request #927 from AzureAD/avdunn/nimbus-http
Remove usage of com.nimbusds.oauth2's HTTP classes
2 parents 3699125 + 962405a commit 70d4312

18 files changed

+221
-413
lines changed

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

-3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
package com.microsoft.aad.msal4j;
55

6-
import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
7-
86
import javax.net.ssl.SSLSocketFactory;
97
import java.net.MalformedURLException;
108
import java.net.Proxy;
@@ -29,7 +27,6 @@ public abstract class AbstractClientApplicationBase extends AbstractApplicationB
2927
private String applicationName;
3028
private String applicationVersion;
3129
private AadInstanceDiscoveryResponse aadAadInstanceDiscoveryResponse;
32-
protected abstract ClientAuthentication clientAuthentication();
3330
private String clientCapabilities;
3431
private boolean autoDetectRegion;
3532
protected String azureRegion;

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

-60
This file was deleted.

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

+18-57
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,8 @@
33

44
package com.microsoft.aad.msal4j;
55

6-
import com.nimbusds.oauth2.sdk.ParseException;
7-
import com.nimbusds.oauth2.sdk.auth.*;
8-
import com.nimbusds.oauth2.sdk.id.ClientID;
96
import org.slf4j.LoggerFactory;
107

11-
import java.util.*;
128
import java.util.concurrent.CompletableFuture;
139
import java.util.function.Function;
1410

@@ -23,10 +19,9 @@
2319
*/
2420
public class ConfidentialClientApplication extends AbstractClientApplicationBase implements IConfidentialClientApplication {
2521

26-
private ClientAuthentication clientAuthentication;
27-
28-
private boolean clientCertAuthentication = false;
2922
private ClientCertificate clientCertificate;
23+
String assertion;
24+
String secret;
3025

3126
/** AppTokenProvider creates a Credential from a function that provides access tokens. The function
3227
must be concurrency safe. This is intended only to allow the Azure SDK to cache MSI tokens. It isn't
@@ -87,65 +82,31 @@ private void initClientAuthentication(IClientCredential clientCredential) {
8782
validateNotNull("clientCredential", clientCredential);
8883

8984
if (clientCredential instanceof ClientSecret) {
90-
clientAuthentication = new ClientSecretPost(
91-
new ClientID(clientId()),
92-
new Secret(((ClientSecret) clientCredential).clientSecret()));
85+
this.secret = ((ClientSecret) clientCredential).clientSecret();
9386
} else if (clientCredential instanceof ClientCertificate) {
94-
this.clientCertAuthentication = true;
9587
this.clientCertificate = (ClientCertificate) clientCredential;
96-
clientAuthentication = buildValidClientCertificateAuthority();
88+
this.assertion = getAssertionString(clientCredential);
9789
} else if (clientCredential instanceof ClientAssertion) {
98-
clientAuthentication = createClientAuthFromClientAssertion((ClientAssertion) clientCredential);
90+
this.assertion = getAssertionString(clientCredential);
9991
} else {
10092
throw new IllegalArgumentException("Unsupported client credential");
10193
}
10294
}
10395

104-
@Override
105-
protected ClientAuthentication clientAuthentication() {
106-
if (clientCertAuthentication) {
107-
final Date currentDateTime = new Date(System.currentTimeMillis());
108-
final Date expirationTime = ((PrivateKeyJWT) clientAuthentication).getJWTAuthenticationClaimsSet().getExpirationTime();
109-
if (expirationTime.before(currentDateTime)) {
110-
clientAuthentication = buildValidClientCertificateAuthority();
111-
}
112-
}
113-
return clientAuthentication;
114-
}
96+
String getAssertionString(IClientCredential clientCredential) {
97+
if (clientCredential instanceof ClientCertificate) {
98+
boolean useSha1 = Authority.detectAuthorityType(this.authenticationAuthority.canonicalAuthorityUrl()) == AuthorityType.ADFS;
11599

116-
private ClientAuthentication buildValidClientCertificateAuthority() {
117-
//The library originally used SHA-1 for thumbprints as other algorithms were not supported server-side.
118-
//When this was written support for SHA-256 had been added, however ADFS scenarios still only allowed SHA-1.
119-
boolean useSha1 = Authority.detectAuthorityType(this.authenticationAuthority.canonicalAuthorityUrl()) == AuthorityType.ADFS;
120-
121-
ClientAssertion clientAssertion = JwtHelper.buildJwt(
122-
clientId(),
123-
clientCertificate,
124-
this.authenticationAuthority.selfSignedJwtAudience(),
125-
sendX5c,
126-
useSha1);
127-
return createClientAuthFromClientAssertion(clientAssertion);
128-
}
129-
130-
protected ClientAuthentication createClientAuthFromClientAssertion(
131-
final ClientAssertion clientAssertion) {
132-
final Map<String, List<String>> map = new HashMap<>();
133-
try {
134-
135-
map.put("client_assertion_type", Collections.singletonList(ClientAssertion.assertionType));
136-
map.put("client_assertion", Collections.singletonList(clientAssertion.assertion()));
137-
return PrivateKeyJWT.parse(map);
138-
} catch (final ParseException e) {
139-
//This library is not supposed to validate Issuer and subject values.
140-
//The next lines of code ensures that exception is not thrown.
141-
if (e.getMessage().contains("Issuer and subject in client JWT assertion must designate the same client identifier")) {
142-
return new CustomJWTAuthentication(
143-
ClientAuthenticationMethod.PRIVATE_KEY_JWT,
144-
clientAssertion,
145-
new ClientID(clientId())
146-
);
147-
}
148-
throw new MsalClientException(e);
100+
return JwtHelper.buildJwt(
101+
clientId(),
102+
clientCertificate,
103+
this.authenticationAuthority.selfSignedJwtAudience(),
104+
sendX5c,
105+
useSha1).assertion();
106+
} else if (clientCredential instanceof ClientAssertion) {
107+
return ((ClientAssertion) clientCredential).assertion();
108+
} else {
109+
throw new IllegalArgumentException("Unsupported client credential");
149110
}
150111
}
151112

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

+13-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
package com.microsoft.aad.msal4j;
55

6+
import com.azure.json.JsonProviders;
7+
import com.azure.json.JsonReader;
8+
9+
import java.io.IOException;
610
import java.util.Arrays;
711
import java.util.HashMap;
812
import java.util.List;
@@ -46,14 +50,22 @@ public void addHeaders(Map<String, List<String>> responseHeaders) {
4650
}
4751
}
4852

49-
private void addHeader(final String name, final String... values) {
53+
void addHeader(final String name, final String... values) {
5054
if (values != null && values.length > 0) {
5155
headers.put(name, Arrays.asList(values));
5256
} else {
5357
headers.remove(name);
5458
}
5559
}
5660

61+
List<String> getHeader(String key) {
62+
return headers.get(key);
63+
}
64+
65+
Map<String, String> getBodyAsMap() {
66+
return JsonHelper.convertJsonToMap(this.body);
67+
}
68+
5769
public int statusCode() {
5870
return this.statusCode;
5971
}

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

+11
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import java.io.IOException;
1818
import java.util.ArrayList;
1919
import java.util.Iterator;
20+
import java.util.Map;
2021
import java.util.Set;
2122

2223
class JsonHelper {
@@ -51,6 +52,16 @@ static <T extends JsonSerializable<T>> T convertJsonStringToJsonSerializableObje
5152
}
5253
}
5354

55+
//Converts a JSON string to a Map<String, String>
56+
static Map<String, String> convertJsonToMap(String jsonString) {
57+
try (JsonReader reader = JsonProviders.createReader(jsonString)) {
58+
reader.nextToken();
59+
return reader.readMap(JsonReader::getString);
60+
} catch (IOException e) {
61+
throw new MsalClientException("Could not parse JSON from HttpResponse body: " + e.getMessage(), AuthenticationErrorCode.INVALID_JSON);
62+
}
63+
}
64+
5465
/**
5566
* Throws exception if given String does not follow JSON syntax
5667
*/

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

+6-33
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
package com.microsoft.aad.msal4j;
55

6-
import com.nimbusds.oauth2.sdk.http.HTTPResponse;
7-
86
import java.util.Arrays;
97
import java.util.HashSet;
108
import java.util.Set;
@@ -14,37 +12,6 @@ class MsalServiceExceptionFactory {
1412
private MsalServiceExceptionFactory() {
1513
}
1614

17-
static MsalServiceException fromHttpResponse(HTTPResponse httpResponse) {
18-
19-
String responseContent = httpResponse.getContent();
20-
if (responseContent == null || StringHelper.isBlank(responseContent)) {
21-
return new MsalServiceException(
22-
String.format(
23-
"Unknown Service Exception. Service returned status code %s",
24-
httpResponse.getStatusCode()),
25-
AuthenticationErrorCode.UNKNOWN);
26-
}
27-
28-
ErrorResponse errorResponse = JsonHelper.convertJsonToObject(
29-
responseContent,
30-
ErrorResponse.class);
31-
32-
errorResponse.statusCode(httpResponse.getStatusCode());
33-
errorResponse.statusMessage(httpResponse.getStatusMessage());
34-
35-
if (errorResponse.error() != null &&
36-
errorResponse.error().equalsIgnoreCase(AuthenticationErrorCode.INVALID_GRANT)) {
37-
38-
if (isInteractionRequired(errorResponse.subError)) {
39-
return new MsalInteractionRequiredException(errorResponse, httpResponse.getHeaderMap());
40-
}
41-
}
42-
43-
return new MsalServiceException(
44-
errorResponse,
45-
httpResponse.getHeaderMap());
46-
}
47-
4815
static MsalServiceException fromHttpResponse(IHttpResponse response) {
4916
String responseBody = response.body();
5017
if (StringHelper.isBlank(responseBody)) {
@@ -59,6 +26,12 @@ static MsalServiceException fromHttpResponse(IHttpResponse response) {
5926
responseBody,
6027
ErrorResponse.class);
6128

29+
if (errorResponse.error() != null &&
30+
errorResponse.error().equalsIgnoreCase(AuthenticationErrorCode.INVALID_GRANT) && isInteractionRequired(errorResponse.subError)) {
31+
return new MsalInteractionRequiredException(errorResponse, response.headers());
32+
}
33+
34+
6235
if (!StringHelper.isBlank(errorResponse.error()) && !StringHelper.isBlank(errorResponse.errorDescription)) {
6336

6437
errorResponse.statusCode(response.statusCode());

0 commit comments

Comments
 (0)