diff --git a/README.md b/README.md index d3c6455b..10cd8fb3 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Quick links: The library supports the following Java environments: - Java 8 (or higher) -Current version - 1.8.0 +Current version - 1.8.1 You can find the changes for each version in the [change log](https://github.com/AzureAD/microsoft-authentication-library-for-java/blob/master/changelog.txt). @@ -28,13 +28,13 @@ Find [the latest package in the Maven repository](https://mvnrepository.com/arti com.microsoft.azure msal4j - 1.8.0 + 1.8.1 ``` ### Gradle ``` -compile group: 'com.microsoft.azure', name: 'msal4j', version: '1.8.0' +compile group: 'com.microsoft.azure', name: 'msal4j', version: '1.8.1' ``` ## Usage diff --git a/changelog.txt b/changelog.txt index d82f356e..1da80b93 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,8 @@ +Version 1.8.1 +============= +- New ClaimsRequest class to allow ID token claims to be requested as part of any token request +- Remove use of nimbusds.oauth2.sdk CommonContentTypes + Version 1.8.0 ============= - ITenantProfile added to IAuthenticationResult for easier access to ID token claims diff --git a/pom.xml b/pom.xml index 32854b59..fc962214 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.microsoft.azure msal4j - 1.8.0 + 1.8.1 jar msal4j diff --git a/src/main/java/com/microsoft/aad/msal4j/AbstractMsalAuthorizationGrant.java b/src/main/java/com/microsoft/aad/msal4j/AbstractMsalAuthorizationGrant.java index 130b41e8..20ae1eac 100644 --- a/src/main/java/com/microsoft/aad/msal4j/AbstractMsalAuthorizationGrant.java +++ b/src/main/java/com/microsoft/aad/msal4j/AbstractMsalAuthorizationGrant.java @@ -34,4 +34,10 @@ abstract class AbstractMsalAuthorizationGrant { String getScopes() { return scopes; } + + ClaimsRequest claims; + + ClaimsRequest getClaims() { + return claims; + } } diff --git a/src/main/java/com/microsoft/aad/msal4j/AcquireTokenByAuthorizationGrantSupplier.java b/src/main/java/com/microsoft/aad/msal4j/AcquireTokenByAuthorizationGrantSupplier.java index 0d211d42..17a72f58 100644 --- a/src/main/java/com/microsoft/aad/msal4j/AcquireTokenByAuthorizationGrantSupplier.java +++ b/src/main/java/com/microsoft/aad/msal4j/AcquireTokenByAuthorizationGrantSupplier.java @@ -48,7 +48,7 @@ AuthenticationResult execute() throws Exception { (IntegratedWindowsAuthorizationGrant) authGrant; msalRequest.msalAuthorizationGrant = new OAuthAuthorizationGrant(getAuthorizationGrantIntegrated( - integratedAuthGrant.getUserName()), integratedAuthGrant.getScopes()); + integratedAuthGrant.getUserName()), integratedAuthGrant.getScopes(), integratedAuthGrant.getClaims()); } if (requestAuthority == null) { diff --git a/src/main/java/com/microsoft/aad/msal4j/AcquireTokenByInteractiveFlowSupplier.java b/src/main/java/com/microsoft/aad/msal4j/AcquireTokenByInteractiveFlowSupplier.java index 6ff3d723..88af55a3 100644 --- a/src/main/java/com/microsoft/aad/msal4j/AcquireTokenByInteractiveFlowSupplier.java +++ b/src/main/java/com/microsoft/aad/msal4j/AcquireTokenByInteractiveFlowSupplier.java @@ -149,6 +149,7 @@ private AuthenticationResult acquireTokenWithAuthorizationCode(AuthorizationResu .builder(authorizationResult.code(), interactiveRequest.interactiveRequestParameters().redirectUri()) .scopes(interactiveRequest.interactiveRequestParameters().scopes()) .codeVerifier(interactiveRequest.verifier()) + .claims(interactiveRequest.interactiveRequestParameters().claims()) .build(); AuthorizationCodeRequest authCodeRequest = new AuthorizationCodeRequest( diff --git a/src/main/java/com/microsoft/aad/msal4j/AuthorizationCodeParameters.java b/src/main/java/com/microsoft/aad/msal4j/AuthorizationCodeParameters.java index 0c7906c0..87543a7a 100644 --- a/src/main/java/com/microsoft/aad/msal4j/AuthorizationCodeParameters.java +++ b/src/main/java/com/microsoft/aad/msal4j/AuthorizationCodeParameters.java @@ -41,6 +41,11 @@ public class AuthorizationCodeParameters implements IApiParameters { */ private Set scopes; + /** + * Claims to be requested through the OIDC claims request parameter, allowing requests for standard and custom claims + */ + private ClaimsRequest claims; + /** * Code verifier used for PKCE. For more details, see https://tools.ietf.org/html/rfc7636 */ diff --git a/src/main/java/com/microsoft/aad/msal4j/AuthorizationCodeRequest.java b/src/main/java/com/microsoft/aad/msal4j/AuthorizationCodeRequest.java index 2b6cdfb2..d4236e30 100644 --- a/src/main/java/com/microsoft/aad/msal4j/AuthorizationCodeRequest.java +++ b/src/main/java/com/microsoft/aad/msal4j/AuthorizationCodeRequest.java @@ -30,6 +30,6 @@ private static AbstractMsalAuthorizationGrant createMsalGrant(AuthorizationCodeP new AuthorizationCode(parameters.authorizationCode()),parameters.redirectUri()); } - return new OAuthAuthorizationGrant(authorizationGrant, parameters.scopes()); + return new OAuthAuthorizationGrant(authorizationGrant, parameters.scopes(), parameters.claims()); } } diff --git a/src/main/java/com/microsoft/aad/msal4j/AuthorizationRequestUrlParameters.java b/src/main/java/com/microsoft/aad/msal4j/AuthorizationRequestUrlParameters.java index fc877df1..5f12ab06 100644 --- a/src/main/java/com/microsoft/aad/msal4j/AuthorizationRequestUrlParameters.java +++ b/src/main/java/com/microsoft/aad/msal4j/AuthorizationRequestUrlParameters.java @@ -81,6 +81,15 @@ private AuthorizationRequestUrlParameters(Builder builder){ requestParameters.put("claims", Collections.singletonList(builder.claimsChallenge)); } + if(builder.claimsRequest != null){ + String claimsRequest = builder.claimsRequest.formatAsJSONString(); + //If there are other claims (such as part of a claims challenge), merge them with this claims request. + if (requestParameters.get("claims") != null) { + claimsRequest = JsonHelper.mergeJSONString(claimsRequest, requestParameters.get("claims").get(0)); + } + requestParameters.put("claims", Collections.singletonList(claimsRequest)); + } + if(builder.codeChallenge != null){ this.codeChallenge = builder.codeChallenge; requestParameters.put("code_challenge", Collections.singletonList(builder.codeChallenge)); @@ -154,6 +163,7 @@ public static class Builder { private Set extraScopesToConsent; private Set claims; private String claimsChallenge; + private ClaimsRequest claimsRequest; private String codeChallenge; private String codeChallengeMethod; private String state; @@ -202,22 +212,17 @@ public Builder extraScopesToConsent(Set val){ * In cases where Azure AD tenant admin has enabled conditional access policies, and the * policy has not been met,{@link MsalServiceException} will contain claims that need be * consented to. - * - * Deprecated in favor of {@link #claimsChallenge(String)} */ - @Deprecated - public Builder claims(Set val){ - this.claims = val; + public Builder claimsChallenge(String val){ + this.claimsChallenge = val; return self(); } /** - * In cases where Azure AD tenant admin has enabled conditional access policies, and the - * policy has not been met,{@link MsalServiceException} will contain claims that need be - * consented to. + * Claims to be requested through the OIDC claims request parameter, allowing requests for standard and custom claims */ - public Builder claimsChallenge(String val){ - this.claimsChallenge = val; + public Builder claims(ClaimsRequest val){ + this.claimsRequest = val; return self(); } diff --git a/src/main/java/com/microsoft/aad/msal4j/ClaimsRequest.java b/src/main/java/com/microsoft/aad/msal4j/ClaimsRequest.java new file mode 100644 index 00000000..1b2c2bf4 --- /dev/null +++ b/src/main/java/com/microsoft/aad/msal4j/ClaimsRequest.java @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.aad.msal4j; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.Getter; +import lombok.Setter; +import java.util.ArrayList; +import java.util.List; + +/** + * Represents the claims request parameter as an object + * + * @see https://openid.net/specs/openid-connect-core-1_0-final.html#ClaimsParameter + */ +public class ClaimsRequest { + + @Getter + @Setter + List idTokenRequestedClaims = new ArrayList<>(); + + List userInfoRequestedClaims = new ArrayList<>(); + List accessTokenRequestedClaims = new ArrayList<>(); + + /** + * Inserts a claim into the list of claims to be added to the "id_token" section of an OIDC claims request + * + * @param claim the name of the claim to be requested + * @param requestedClaimAdditionalInfo additional information about the claim being requested + */ + public void requestClaimInIdToken(String claim, RequestedClaimAdditionalInfo requestedClaimAdditionalInfo) { + idTokenRequestedClaims.add(new RequestedClaim(claim, requestedClaimAdditionalInfo)); + } + + /** + * Inserts a claim into the list of claims to be added to the "access_token" section of an OIDC claims request + * + * @param claim the name of the claim to be requested + * @param requestedClaimAdditionalInfo additional information about the claim being requested + */ + protected void requestClaimInAccessToken(String claim, RequestedClaimAdditionalInfo requestedClaimAdditionalInfo) { + accessTokenRequestedClaims.add(new RequestedClaim(claim, requestedClaimAdditionalInfo)); + } + + /** + * Converts the ClaimsRequest object to a JSON-formatted String which follows the specification for the OIDC claims request parameter + * + * @return a String following JSON formatting + */ + public String formatAsJSONString() { + ObjectMapper mapper = new ObjectMapper(); + ObjectNode rootNode = mapper.createObjectNode(); + + if (!idTokenRequestedClaims.isEmpty()) { + rootNode.set("id_token", convertClaimsToObjectNode(idTokenRequestedClaims)); + } + if (!userInfoRequestedClaims.isEmpty()) { + rootNode.set("userinfo", convertClaimsToObjectNode(userInfoRequestedClaims)); + } + if (!accessTokenRequestedClaims.isEmpty()) { + rootNode.set("access_token", convertClaimsToObjectNode(accessTokenRequestedClaims)); + } + + return mapper.valueToTree(rootNode).toString(); + } + + private ObjectNode convertClaimsToObjectNode(List claims) { + ObjectMapper mapper = new ObjectMapper(); + ObjectNode claimsNode = mapper.createObjectNode(); + + for (RequestedClaim claim: claims) { + claimsNode.setAll((ObjectNode) mapper.valueToTree(claim)); + } + return claimsNode; + } +} diff --git a/src/main/java/com/microsoft/aad/msal4j/ClientAuthenticationPost.java b/src/main/java/com/microsoft/aad/msal4j/ClientAuthenticationPost.java index f511990b..d0567417 100644 --- a/src/main/java/com/microsoft/aad/msal4j/ClientAuthenticationPost.java +++ b/src/main/java/com/microsoft/aad/msal4j/ClientAuthenticationPost.java @@ -8,12 +8,9 @@ import java.util.List; import java.util.Map; -import javax.mail.internet.ContentType; - import com.nimbusds.oauth2.sdk.SerializeException; import com.nimbusds.oauth2.sdk.auth.ClientAuthentication; import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod; -import com.nimbusds.oauth2.sdk.http.CommonContentTypes; import com.nimbusds.oauth2.sdk.http.HTTPRequest; import com.nimbusds.oauth2.sdk.id.ClientID; import com.nimbusds.oauth2.sdk.util.URLUtils; @@ -40,15 +37,15 @@ public void applyTo(HTTPRequest httpRequest) throws SerializeException { if (httpRequest.getMethod() != HTTPRequest.Method.POST) throw new SerializeException("The HTTP request method must be POST"); - ContentType ct = httpRequest.getContentType(); + String ct = String.valueOf(httpRequest.getEntityContentType()); if (ct == null) throw new SerializeException("Missing HTTP Content-Type header"); - if (!ct.match(CommonContentTypes.APPLICATION_URLENCODED)) + if (!ct.equals(HTTPContentType.ApplicationURLEncoded.contentType)) throw new SerializeException( "The HTTP Content-Type header must be " - + CommonContentTypes.APPLICATION_URLENCODED); + + HTTPContentType.ApplicationURLEncoded.contentType); Map> params = httpRequest.getQueryParameters(); diff --git a/src/main/java/com/microsoft/aad/msal4j/ClientCredentialParameters.java b/src/main/java/com/microsoft/aad/msal4j/ClientCredentialParameters.java index b82dd1d1..8af1b9cd 100644 --- a/src/main/java/com/microsoft/aad/msal4j/ClientCredentialParameters.java +++ b/src/main/java/com/microsoft/aad/msal4j/ClientCredentialParameters.java @@ -26,6 +26,11 @@ public class ClientCredentialParameters implements IApiParameters { @NonNull private Set scopes; + /** + * Claims to be requested through the OIDC claims request parameter, allowing requests for standard and custom claims + */ + private ClaimsRequest claims; + private static ClientCredentialParametersBuilder builder() { return new ClientCredentialParametersBuilder(); diff --git a/src/main/java/com/microsoft/aad/msal4j/ClientCredentialRequest.java b/src/main/java/com/microsoft/aad/msal4j/ClientCredentialRequest.java index f62b5c35..ed1579db 100644 --- a/src/main/java/com/microsoft/aad/msal4j/ClientCredentialRequest.java +++ b/src/main/java/com/microsoft/aad/msal4j/ClientCredentialRequest.java @@ -5,8 +5,6 @@ import com.nimbusds.oauth2.sdk.ClientCredentialsGrant; -import java.util.Set; - class ClientCredentialRequest extends MsalRequest{ ClientCredentialRequest(ClientCredentialParameters parameters, @@ -17,6 +15,6 @@ class ClientCredentialRequest extends MsalRequest{ private static OAuthAuthorizationGrant createMsalGrant(ClientCredentialParameters parameters){ - return new OAuthAuthorizationGrant(new ClientCredentialsGrant(), parameters.scopes()); + return new OAuthAuthorizationGrant(new ClientCredentialsGrant(), parameters.scopes(), parameters.claims()); } } diff --git a/src/main/java/com/microsoft/aad/msal4j/DeviceCodeAuthorizationGrant.java b/src/main/java/com/microsoft/aad/msal4j/DeviceCodeAuthorizationGrant.java index 4528efab..7894e2de 100644 --- a/src/main/java/com/microsoft/aad/msal4j/DeviceCodeAuthorizationGrant.java +++ b/src/main/java/com/microsoft/aad/msal4j/DeviceCodeAuthorizationGrant.java @@ -23,10 +23,11 @@ class DeviceCodeAuthorizationGrant extends AbstractMsalAuthorizationGrant { * * @param scopes The resource for which the device code was acquired. */ - DeviceCodeAuthorizationGrant(DeviceCode deviceCode, final String scopes) { + DeviceCodeAuthorizationGrant(DeviceCode deviceCode, final String scopes, ClaimsRequest claims) { this.deviceCode = deviceCode; this.correlationId = deviceCode.correlationId(); this.scopes = scopes; + this.claims = claims; } /** @@ -41,6 +42,9 @@ public Map> toParameters() { outParams.put("grant_type", Collections.singletonList(GRANT_TYPE)); outParams.put("device_code", Collections.singletonList(deviceCode.deviceCode())); outParams.put("client_info", Collections.singletonList("1")); + if (claims != null) { + outParams.put("claims", Collections.singletonList(claims.formatAsJSONString())); + } return outParams; } diff --git a/src/main/java/com/microsoft/aad/msal4j/DeviceCodeFlowParameters.java b/src/main/java/com/microsoft/aad/msal4j/DeviceCodeFlowParameters.java index 930cc9ab..93772039 100644 --- a/src/main/java/com/microsoft/aad/msal4j/DeviceCodeFlowParameters.java +++ b/src/main/java/com/microsoft/aad/msal4j/DeviceCodeFlowParameters.java @@ -28,6 +28,11 @@ public class DeviceCodeFlowParameters implements IApiParameters { @NonNull private Set scopes; + /** + * Claims to be requested through the OIDC claims request parameter, allowing requests for standard and custom claims + */ + private ClaimsRequest claims; + /** * Receives the device code returned from the first step of Oauth2.0 device code flow. The * {@link DeviceCode#verificationUri} and the {@link DeviceCode#userCode} should be shown diff --git a/src/main/java/com/microsoft/aad/msal4j/DeviceCodeFlowRequest.java b/src/main/java/com/microsoft/aad/msal4j/DeviceCodeFlowRequest.java index f0473de4..8506567f 100644 --- a/src/main/java/com/microsoft/aad/msal4j/DeviceCodeFlowRequest.java +++ b/src/main/java/com/microsoft/aad/msal4j/DeviceCodeFlowRequest.java @@ -55,7 +55,7 @@ DeviceCode acquireDeviceCode(String url, } void createAuthenticationGrant(DeviceCode deviceCode) { - msalAuthorizationGrant = new DeviceCodeAuthorizationGrant(deviceCode, deviceCode.scopes()); + msalAuthorizationGrant = new DeviceCodeAuthorizationGrant(deviceCode, deviceCode.scopes(), parameters.claims()); } private String createQueryParams(String clientId) { diff --git a/src/main/java/com/microsoft/aad/msal4j/HTTPContentType.java b/src/main/java/com/microsoft/aad/msal4j/HTTPContentType.java new file mode 100644 index 00000000..b5260959 --- /dev/null +++ b/src/main/java/com/microsoft/aad/msal4j/HTTPContentType.java @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.aad.msal4j; + +/** + * Enum containing HTTP Content-Type header values + */ +enum HTTPContentType { + + ApplicationURLEncoded("application/x-www-form-urlencoded; charset=UTF-8"), + ApplicationJSON("application/json; charset=UTF-8"); + + public final String contentType; + + HTTPContentType(String contentType) { + this.contentType = contentType; + } +} diff --git a/src/main/java/com/microsoft/aad/msal4j/IApiParameters.java b/src/main/java/com/microsoft/aad/msal4j/IApiParameters.java index 676700a4..3c77debd 100644 --- a/src/main/java/com/microsoft/aad/msal4j/IApiParameters.java +++ b/src/main/java/com/microsoft/aad/msal4j/IApiParameters.java @@ -7,4 +7,6 @@ interface IApiParameters { Set scopes(); + + ClaimsRequest claims(); } diff --git a/src/main/java/com/microsoft/aad/msal4j/IntegratedWindowsAuthenticationParameters.java b/src/main/java/com/microsoft/aad/msal4j/IntegratedWindowsAuthenticationParameters.java index 85e2ebe6..a3c03d8a 100644 --- a/src/main/java/com/microsoft/aad/msal4j/IntegratedWindowsAuthenticationParameters.java +++ b/src/main/java/com/microsoft/aad/msal4j/IntegratedWindowsAuthenticationParameters.java @@ -29,6 +29,11 @@ public class IntegratedWindowsAuthenticationParameters implements IApiParameters @NonNull private Set scopes; + /** + * Claims to be requested through the OIDC claims request parameter, allowing requests for standard and custom claims + */ + private ClaimsRequest claims; + /** * Identifier of user account for which to acquire tokens for */ diff --git a/src/main/java/com/microsoft/aad/msal4j/IntegratedWindowsAuthenticationRequest.java b/src/main/java/com/microsoft/aad/msal4j/IntegratedWindowsAuthenticationRequest.java index ed9f8e34..797662cd 100644 --- a/src/main/java/com/microsoft/aad/msal4j/IntegratedWindowsAuthenticationRequest.java +++ b/src/main/java/com/microsoft/aad/msal4j/IntegratedWindowsAuthenticationRequest.java @@ -14,6 +14,6 @@ class IntegratedWindowsAuthenticationRequest extends MsalRequest{ private static AbstractMsalAuthorizationGrant createAuthenticationGrant (IntegratedWindowsAuthenticationParameters parameters){ - return new IntegratedWindowsAuthorizationGrant(parameters.scopes(), parameters.username()); + return new IntegratedWindowsAuthorizationGrant(parameters.scopes(), parameters.username(), parameters.claims()); } } diff --git a/src/main/java/com/microsoft/aad/msal4j/IntegratedWindowsAuthorizationGrant.java b/src/main/java/com/microsoft/aad/msal4j/IntegratedWindowsAuthorizationGrant.java index a0cb9603..672af4f8 100644 --- a/src/main/java/com/microsoft/aad/msal4j/IntegratedWindowsAuthorizationGrant.java +++ b/src/main/java/com/microsoft/aad/msal4j/IntegratedWindowsAuthorizationGrant.java @@ -11,9 +11,10 @@ class IntegratedWindowsAuthorizationGrant extends AbstractMsalAuthorizationGrant private final String userName; - IntegratedWindowsAuthorizationGrant(Set scopes, String userName) { + IntegratedWindowsAuthorizationGrant(Set scopes, String userName, ClaimsRequest claims) { this.userName = userName; this.scopes = String.join(" ", scopes); + this.claims = claims; } @Override diff --git a/src/main/java/com/microsoft/aad/msal4j/InteractiveRequestParameters.java b/src/main/java/com/microsoft/aad/msal4j/InteractiveRequestParameters.java index b93b66ec..4b6ba6d5 100644 --- a/src/main/java/com/microsoft/aad/msal4j/InteractiveRequestParameters.java +++ b/src/main/java/com/microsoft/aad/msal4j/InteractiveRequestParameters.java @@ -38,6 +38,11 @@ public class InteractiveRequestParameters implements IApiParameters { @NonNull private URI redirectUri; + /** + * Claims to be requested through the OIDC claims request parameter, allowing requests for standard and custom claims + */ + private ClaimsRequest claims; + /** * Scopes that the application is requesting access to and the user will consent to. */ diff --git a/src/main/java/com/microsoft/aad/msal4j/JsonHelper.java b/src/main/java/com/microsoft/aad/msal4j/JsonHelper.java index 080f07e8..36a7b025 100644 --- a/src/main/java/com/microsoft/aad/msal4j/JsonHelper.java +++ b/src/main/java/com/microsoft/aad/msal4j/JsonHelper.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; +import java.util.ArrayList; import java.util.Iterator; import java.util.Set; @@ -55,7 +56,11 @@ static void validateJsonFormat(String jsonString) { */ public static String formCapabilitiesJson(Set clientCapabilities) { if (clientCapabilities != null && !clientCapabilities.isEmpty()) { - return "{\"access_token\":{\"xms_cc\":{\"values\":[\"" + String.join("\",\"", clientCapabilities) + "\"]}}}"; + ClaimsRequest cr = new ClaimsRequest(); + RequestedClaimAdditionalInfo capabilitiesValues = new RequestedClaimAdditionalInfo(false, null, new ArrayList<>(clientCapabilities)); + cr.requestClaimInAccessToken("xms_cc", capabilitiesValues); + + return cr.formatAsJSONString(); } else { return null; diff --git a/src/main/java/com/microsoft/aad/msal4j/OAuthAuthorizationGrant.java b/src/main/java/com/microsoft/aad/msal4j/OAuthAuthorizationGrant.java index 6dad1358..fbd316e7 100644 --- a/src/main/java/com/microsoft/aad/msal4j/OAuthAuthorizationGrant.java +++ b/src/main/java/com/microsoft/aad/msal4j/OAuthAuthorizationGrant.java @@ -25,11 +25,11 @@ private OAuthAuthorizationGrant() { params.put(SCOPE_PARAM_NAME, Collections.singletonList(COMMON_SCOPES_PARAM)); } - OAuthAuthorizationGrant(final AuthorizationGrant grant, Set scopesSet) { - this(grant, scopesSet != null ? String.join(" ", scopesSet) : null); + OAuthAuthorizationGrant(final AuthorizationGrant grant, Set scopesSet, ClaimsRequest claims) { + this(grant, scopesSet != null ? String.join(" ", scopesSet) : null, claims); } - OAuthAuthorizationGrant(final AuthorizationGrant grant, String scopes) { + OAuthAuthorizationGrant(final AuthorizationGrant grant, String scopes, ClaimsRequest claims) { this(); this.grant = grant; @@ -39,6 +39,11 @@ private OAuthAuthorizationGrant() { params.put(SCOPE_PARAM_NAME, Collections.singletonList(String.join(" ",params.get(SCOPE_PARAM_NAME)) + SCOPES_DELIMITER + scopes)); } + + if (claims != null) { + this.claims = claims; + params.put("claims", Collections.singletonList(claims.formatAsJSONString())); + } } OAuthAuthorizationGrant(final AuthorizationGrant grant, @@ -56,6 +61,9 @@ public Map> toParameters() { outParams.putAll(params); outParams.put("client_info", Collections.singletonList("1")); outParams.putAll(grant.toParameters()); + if (claims != null) { + outParams.put("claims", Collections.singletonList(claims.formatAsJSONString())); + } return Collections.unmodifiableMap(outParams); } diff --git a/src/main/java/com/microsoft/aad/msal4j/OAuthHttpRequest.java b/src/main/java/com/microsoft/aad/msal4j/OAuthHttpRequest.java index 8e81e784..6b1a9a43 100644 --- a/src/main/java/com/microsoft/aad/msal4j/OAuthHttpRequest.java +++ b/src/main/java/com/microsoft/aad/msal4j/OAuthHttpRequest.java @@ -4,7 +4,6 @@ package com.microsoft.aad.msal4j; import com.nimbusds.oauth2.sdk.ParseException; -import com.nimbusds.oauth2.sdk.http.CommonContentTypes; import com.nimbusds.oauth2.sdk.http.HTTPRequest; import com.nimbusds.oauth2.sdk.http.HTTPResponse; import lombok.AccessLevel; @@ -57,7 +56,7 @@ public HTTPResponse send() throws IOException { private Map configureHttpHeaders(){ Map httpHeaders = new HashMap<>(extraHeaderParams); - httpHeaders.put("Content-Type", CommonContentTypes.APPLICATION_URLENCODED.toString()); + httpHeaders.put("Content-Type", HTTPContentType.ApplicationURLEncoded.contentType); if (this.getAuthorization() != null) { httpHeaders.put("Authorization", this.getAuthorization()); diff --git a/src/main/java/com/microsoft/aad/msal4j/OnBehalfOfParameters.java b/src/main/java/com/microsoft/aad/msal4j/OnBehalfOfParameters.java index 82be79a2..a8828c31 100644 --- a/src/main/java/com/microsoft/aad/msal4j/OnBehalfOfParameters.java +++ b/src/main/java/com/microsoft/aad/msal4j/OnBehalfOfParameters.java @@ -25,6 +25,11 @@ public class OnBehalfOfParameters implements IApiParameters { @NonNull private Set scopes; + /** + * Claims to be requested through the OIDC claims request parameter, allowing requests for standard and custom claims + */ + private ClaimsRequest claims; + @NonNull private IUserAssertion userAssertion; diff --git a/src/main/java/com/microsoft/aad/msal4j/OnBehalfOfRequest.java b/src/main/java/com/microsoft/aad/msal4j/OnBehalfOfRequest.java index 37e9b1f1..1a4cbcf9 100644 --- a/src/main/java/com/microsoft/aad/msal4j/OnBehalfOfRequest.java +++ b/src/main/java/com/microsoft/aad/msal4j/OnBehalfOfRequest.java @@ -36,6 +36,9 @@ private static OAuthAuthorizationGrant createAuthenticationGrant(OnBehalfOfParam Map> params = new HashMap<>(); params.put("scope", Collections.singletonList(String.join(" ", parameters.scopes()))); params.put("requested_token_use", Collections.singletonList("on_behalf_of")); + if (parameters.claims() != null) { + params.put("claims", Collections.singletonList(parameters.claims().formatAsJSONString())); + } return new OAuthAuthorizationGrant(jWTBearerGrant, params); } diff --git a/src/main/java/com/microsoft/aad/msal4j/Prompt.java b/src/main/java/com/microsoft/aad/msal4j/Prompt.java index 73c67079..f4315e95 100644 --- a/src/main/java/com/microsoft/aad/msal4j/Prompt.java +++ b/src/main/java/com/microsoft/aad/msal4j/Prompt.java @@ -27,8 +27,16 @@ public enum Prompt { /** * An administrator should be prompted to consent on behalf of all users in their organization. + * + * Deprecated, instead use Prompt.ADMIN_CONSENT */ - ADMING_CONSENT ("admin_consent"); + @Deprecated + ADMING_CONSENT ("admin_consent"), + + /** + * An administrator should be prompted to consent on behalf of all users in their organization. + */ + ADMIN_CONSENT ("admin_consent"); private String prompt; diff --git a/src/main/java/com/microsoft/aad/msal4j/RefreshTokenParameters.java b/src/main/java/com/microsoft/aad/msal4j/RefreshTokenParameters.java index 4c0befeb..0ca559f0 100644 --- a/src/main/java/com/microsoft/aad/msal4j/RefreshTokenParameters.java +++ b/src/main/java/com/microsoft/aad/msal4j/RefreshTokenParameters.java @@ -31,6 +31,11 @@ public class RefreshTokenParameters implements IApiParameters { @NonNull private Set scopes; + /** + * Claims to be requested through the OIDC claims request parameter, allowing requests for standard and custom claims + */ + private ClaimsRequest claims; + /** * Refresh token received from the STS */ diff --git a/src/main/java/com/microsoft/aad/msal4j/RefreshTokenRequest.java b/src/main/java/com/microsoft/aad/msal4j/RefreshTokenRequest.java index 0710998c..551b5bae 100644 --- a/src/main/java/com/microsoft/aad/msal4j/RefreshTokenRequest.java +++ b/src/main/java/com/microsoft/aad/msal4j/RefreshTokenRequest.java @@ -35,7 +35,7 @@ private static AbstractMsalAuthorizationGrant createAuthenticationGrant( RefreshTokenParameters parameters) { RefreshTokenGrant refreshTokenGrant = new RefreshTokenGrant(new RefreshToken(parameters.refreshToken())); - return new OAuthAuthorizationGrant(refreshTokenGrant, parameters.scopes()); + return new OAuthAuthorizationGrant(refreshTokenGrant, parameters.scopes(), parameters.claims()); } String getFullThumbprint() { diff --git a/src/main/java/com/microsoft/aad/msal4j/RequestedClaim.java b/src/main/java/com/microsoft/aad/msal4j/RequestedClaim.java new file mode 100644 index 00000000..075baf29 --- /dev/null +++ b/src/main/java/com/microsoft/aad/msal4j/RequestedClaim.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.aad.msal4j; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.AllArgsConstructor; +import java.util.Collections; +import java.util.Map; + +/** + * Represents an individual requested claims that's part of a complete claims request parameter + * + * @see https://openid.net/specs/openid-connect-core-1_0-final.html#ClaimsParameter + */ +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class RequestedClaim { + + @JsonIgnore + public String name; + + RequestedClaimAdditionalInfo requestedClaimAdditionalInfo; + + @JsonAnyGetter + protected Map any() { + return Collections.singletonMap(name, requestedClaimAdditionalInfo); + } +} diff --git a/src/main/java/com/microsoft/aad/msal4j/RequestedClaimAdditionalInfo.java b/src/main/java/com/microsoft/aad/msal4j/RequestedClaimAdditionalInfo.java new file mode 100644 index 00000000..7b8c0b3a --- /dev/null +++ b/src/main/java/com/microsoft/aad/msal4j/RequestedClaimAdditionalInfo.java @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.aad.msal4j; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import java.util.List; + +/** + * Represents the additional information that can be sent to an authorization server for a request claim in the claim request parameter + * + * @see https://openid.net/specs/openid-connect-core-1_0-final.html#ClaimsParameter + */ +@Getter +@Setter +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class RequestedClaimAdditionalInfo { + + @JsonInclude(JsonInclude.Include.NON_DEFAULT) + @JsonProperty("essential") + boolean essential; + + @JsonProperty("value") + String value; + + @JsonProperty("values") + List values; +} diff --git a/src/main/java/com/microsoft/aad/msal4j/SilentParameters.java b/src/main/java/com/microsoft/aad/msal4j/SilentParameters.java index 1030f8dd..da6731f0 100644 --- a/src/main/java/com/microsoft/aad/msal4j/SilentParameters.java +++ b/src/main/java/com/microsoft/aad/msal4j/SilentParameters.java @@ -28,6 +28,11 @@ public class SilentParameters implements IApiParameters { private IAccount account; + /** + * Claims to be requested through the OIDC claims request parameter, allowing requests for standard and custom claims + */ + private ClaimsRequest claims; + private String authorityUrl; private boolean forceRefresh; diff --git a/src/main/java/com/microsoft/aad/msal4j/TokenRequestExecutor.java b/src/main/java/com/microsoft/aad/msal4j/TokenRequestExecutor.java index 1e8f5366..1cca1ccd 100644 --- a/src/main/java/com/microsoft/aad/msal4j/TokenRequestExecutor.java +++ b/src/main/java/com/microsoft/aad/msal4j/TokenRequestExecutor.java @@ -5,7 +5,6 @@ import com.nimbusds.oauth2.sdk.ParseException; import com.nimbusds.oauth2.sdk.SerializeException; -import com.nimbusds.oauth2.sdk.http.CommonContentTypes; import com.nimbusds.oauth2.sdk.http.HTTPRequest; import com.nimbusds.oauth2.sdk.http.HTTPResponse; import com.nimbusds.oauth2.sdk.util.URLUtils; @@ -45,7 +44,7 @@ AuthenticationResult executeTokenRequest() throws ParseException, return createAuthenticationResultFromOauthHttpResponse(oauthHttpResponse); } - OAuthHttpRequest createOauthHttpRequest() throws SerializeException, MalformedURLException { + OAuthHttpRequest createOauthHttpRequest() throws SerializeException, MalformedURLException, ParseException { if (requestAuthority.tokenEndpointUrl() == null) { throw new SerializeException("The endpoint URI is not specified"); @@ -57,13 +56,21 @@ OAuthHttpRequest createOauthHttpRequest() throws SerializeException, MalformedUR msalRequest.headers().getReadonlyHeaderMap(), msalRequest.requestContext(), this.serviceBundle); - oauthHttpRequest.setContentType(CommonContentTypes.APPLICATION_URLENCODED); + oauthHttpRequest.setContentType(HTTPContentType.ApplicationURLEncoded.contentType); final Map> params = new HashMap<>(msalRequest.msalAuthorizationGrant().toParameters()); if (msalRequest.application().clientCapabilities() != null) { params.put("claims", Collections.singletonList(msalRequest.application().clientCapabilities())); } + if (msalRequest.msalAuthorizationGrant.getClaims() != null) { + String claimsRequest = msalRequest.msalAuthorizationGrant.getClaims().formatAsJSONString(); + if (params.get("claims") != null) { + claimsRequest = JsonHelper.mergeJSONString(params.get("claims").get(0), claimsRequest); + } + params.put("claims", Collections.singletonList(claimsRequest)); + } + oauthHttpRequest.setQuery(URLUtils.serializeParameters(params)); if (msalRequest.application().clientAuthentication() != null) { diff --git a/src/main/java/com/microsoft/aad/msal4j/UserNamePasswordParameters.java b/src/main/java/com/microsoft/aad/msal4j/UserNamePasswordParameters.java index f8b6d6a1..d97aa823 100644 --- a/src/main/java/com/microsoft/aad/msal4j/UserNamePasswordParameters.java +++ b/src/main/java/com/microsoft/aad/msal4j/UserNamePasswordParameters.java @@ -29,6 +29,11 @@ public class UserNamePasswordParameters implements IApiParameters { @NonNull private Set scopes; + /** + * Claims to be requested through the OIDC claims request parameter, allowing requests for standard and custom claims + */ + private ClaimsRequest claims; + /** * Username of the account */ diff --git a/src/main/java/com/microsoft/aad/msal4j/UserNamePasswordRequest.java b/src/main/java/com/microsoft/aad/msal4j/UserNamePasswordRequest.java index fcd37eb1..b9aa8bad 100644 --- a/src/main/java/com/microsoft/aad/msal4j/UserNamePasswordRequest.java +++ b/src/main/java/com/microsoft/aad/msal4j/UserNamePasswordRequest.java @@ -21,6 +21,6 @@ private static OAuthAuthorizationGrant createAuthenticationGrant( new ResourceOwnerPasswordCredentialsGrant(parameters.username(), new Secret(new String(parameters.password()))); - return new OAuthAuthorizationGrant(resourceOwnerPasswordCredentialsGrant, parameters.scopes()); + return new OAuthAuthorizationGrant(resourceOwnerPasswordCredentialsGrant, parameters.scopes(), parameters.claims()); } } diff --git a/src/samples/msal-b2c-web-sample/pom.xml b/src/samples/msal-b2c-web-sample/pom.xml index 6b2984fd..066c1286 100644 --- a/src/samples/msal-b2c-web-sample/pom.xml +++ b/src/samples/msal-b2c-web-sample/pom.xml @@ -23,7 +23,7 @@ com.microsoft.azure msal4j - 1.8.0 + 1.8.1 com.nimbusds diff --git a/src/samples/msal-obo-sample/pom.xml b/src/samples/msal-obo-sample/pom.xml index 14d8be6e..8f97cd3e 100644 --- a/src/samples/msal-obo-sample/pom.xml +++ b/src/samples/msal-obo-sample/pom.xml @@ -23,7 +23,7 @@ com.microsoft.azure msal4j - 1.8.0 + 1.8.1 com.nimbusds diff --git a/src/samples/msal-web-sample/pom.xml b/src/samples/msal-web-sample/pom.xml index f3f3667e..fb9aeb03 100644 --- a/src/samples/msal-web-sample/pom.xml +++ b/src/samples/msal-web-sample/pom.xml @@ -23,7 +23,7 @@ com.microsoft.azure msal4j - 1.8.0 + 1.8.1 com.nimbusds diff --git a/src/test/java/com/microsoft/aad/msal4j/ClaimsTest.java b/src/test/java/com/microsoft/aad/msal4j/ClaimsTest.java new file mode 100644 index 00000000..d434e43d --- /dev/null +++ b/src/test/java/com/microsoft/aad/msal4j/ClaimsTest.java @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.aad.msal4j; + +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; + +public class ClaimsTest { + + @Test + public void testClaimsRequest_Format() { + + List values = new ArrayList<>(); + values.add("urn:mace:incommon:iap:silver"); + values.add("urn:mace:incommon:iap:bronze"); + + ClaimsRequest cr = new ClaimsRequest(); + cr.requestClaimInAccessToken("given_name", new RequestedClaimAdditionalInfo(true, null, null)); + cr.requestClaimInAccessToken("email", null); + cr.requestClaimInIdToken("acr", new RequestedClaimAdditionalInfo(false, null, values)); + cr.requestClaimInIdToken("sub", new RequestedClaimAdditionalInfo(true, "248289761001", null)); + cr.requestClaimInIdToken("auth_time", new RequestedClaimAdditionalInfo(false, null, null)); + + Assert.assertEquals(cr.formatAsJSONString(), TestConfiguration.CLAIMS_REQUEST); + } + + @Test + public void testClaimsRequest_MergeWithClientCapabilitiesAndClaimsChallenge() throws URISyntaxException { + + List values = new ArrayList<>(); + values.add("urn:mace:incommon:iap:silver"); + values.add("urn:mace:incommon:iap:bronze"); + + ClaimsRequest cr = new ClaimsRequest(); + cr.requestClaimInAccessToken("given_name", new RequestedClaimAdditionalInfo(true, null, null)); + cr.requestClaimInAccessToken("email", null); + cr.requestClaimInIdToken("acr", new RequestedClaimAdditionalInfo(false, null, values)); + cr.requestClaimInIdToken("sub", new RequestedClaimAdditionalInfo(true, "248289761001", null)); + cr.requestClaimInIdToken("auth_time", new RequestedClaimAdditionalInfo(false, null, null)); + + PublicClientApplication pca = PublicClientApplication.builder( + "client_id"). + clientCapabilities(new HashSet<>(Collections.singletonList("llt"))). + build(); + + InteractiveRequestParameters parameters = InteractiveRequestParameters.builder(new URI("http://localhost:8080")) + .claimsChallenge("{\"id_token\":{\"auth_time\":{\"essential\":true}},\"access_token\":{\"auth_time\":{\"essential\":true},\"xms_cc\":{\"values\":[\"abc\"]}}}") + .claims(cr) + .scopes(Collections.singleton("")) + .build(); + + String clientCapabilities = pca.clientCapabilities(); + String claimsChallenge = parameters.claimsChallenge(); + String claimsRequest = parameters.claims().formatAsJSONString(); + String mergedClaimsAndCapabilities = JsonHelper.mergeJSONString(claimsRequest, clientCapabilities); + String mergedClaimsAndChallenge = JsonHelper.mergeJSONString(claimsChallenge, claimsRequest); + String mergedAll = JsonHelper.mergeJSONString(claimsChallenge, mergedClaimsAndCapabilities); + + Assert.assertEquals(clientCapabilities, TestConfiguration.CLIENT_CAPABILITIES); + Assert.assertEquals(claimsChallenge, TestConfiguration.CLAIMS_CHALLENGE); + Assert.assertEquals(claimsRequest, TestConfiguration.CLAIMS_REQUEST); + Assert.assertEquals(mergedClaimsAndCapabilities, TestConfiguration.MERGED_CLAIMS_AND_CAPABILITIES); + Assert.assertEquals(mergedClaimsAndChallenge, TestConfiguration.MERGED_CLAIMS_AND_CHALLENGE); + Assert.assertEquals(mergedAll, TestConfiguration.MERGED_CLAIMS_CAPABILITIES_AND_CHALLENGE); + } +} diff --git a/src/test/java/com/microsoft/aad/msal4j/DeviceCodeFlowTest.java b/src/test/java/com/microsoft/aad/msal4j/DeviceCodeFlowTest.java index 72df6b40..96914816 100644 --- a/src/test/java/com/microsoft/aad/msal4j/DeviceCodeFlowTest.java +++ b/src/test/java/com/microsoft/aad/msal4j/DeviceCodeFlowTest.java @@ -3,7 +3,6 @@ package com.microsoft.aad.msal4j; -import com.nimbusds.oauth2.sdk.http.CommonContentTypes; import com.nimbusds.oauth2.sdk.http.HTTPResponse; import org.easymock.Capture; import org.easymock.EasyMock; @@ -211,7 +210,7 @@ public void executeAcquireDeviceCode_AuthenticaionPendingErrorReturned_Authentic "\"correlation_id\":\"ff60101b-cb23-4a52-82cb-9966f466327a\"}"; httpResponse.setContent(content); - httpResponse.setContentType(CommonContentTypes.APPLICATION_JSON); + httpResponse.setContentType(HTTPContentType.ApplicationJSON.contentType); EasyMock.expect(request.createOauthHttpRequest()).andReturn(msalOAuthHttpRequest).times(1); EasyMock.expect(msalOAuthHttpRequest.send()).andReturn(httpResponse).times(1); diff --git a/src/test/java/com/microsoft/aad/msal4j/TestConfiguration.java b/src/test/java/com/microsoft/aad/msal4j/TestConfiguration.java index 548d2052..b27cb58c 100644 --- a/src/test/java/com/microsoft/aad/msal4j/TestConfiguration.java +++ b/src/test/java/com/microsoft/aad/msal4j/TestConfiguration.java @@ -82,4 +82,11 @@ public final class TestConfiguration { "\"trace_id\":\"0788...000\"," + "\"correlation_id\":\"3a...95a\"," + "\"suberror\":\"basic_action\"}"; + + public final static String CLAIMS_REQUEST = "{\"id_token\":{\"acr\":{\"values\":[\"urn:mace:incommon:iap:silver\",\"urn:mace:incommon:iap:bronze\"]},\"sub\":{\"essential\":true,\"value\":\"248289761001\"},\"auth_time\":{}},\"access_token\":{\"given_name\":{\"essential\":true},\"email\":null}}"; + public final static String CLAIMS_CHALLENGE = "{\"id_token\":{\"auth_time\":{\"essential\":true}},\"access_token\":{\"auth_time\":{\"essential\":true},\"xms_cc\":{\"values\":[\"abc\"]}}}"; + public final static String CLIENT_CAPABILITIES = "{\"access_token\":{\"xms_cc\":{\"values\":[\"llt\"]}}}"; + public final static String MERGED_CLAIMS_AND_CAPABILITIES = "{\"id_token\":{\"acr\":{\"values\":[\"urn:mace:incommon:iap:silver\",\"urn:mace:incommon:iap:bronze\"]},\"sub\":{\"essential\":true,\"value\":\"248289761001\"},\"auth_time\":{}},\"access_token\":{\"given_name\":{\"essential\":true},\"email\":null,\"xms_cc\":{\"values\":[\"llt\"]}}}"; + public final static String MERGED_CLAIMS_AND_CHALLENGE = "{\"id_token\":{\"auth_time\":{\"essential\":true},\"acr\":{\"values\":[\"urn:mace:incommon:iap:silver\",\"urn:mace:incommon:iap:bronze\"]},\"sub\":{\"essential\":true,\"value\":\"248289761001\"}},\"access_token\":{\"auth_time\":{\"essential\":true},\"xms_cc\":{\"values\":[\"abc\"]},\"given_name\":{\"essential\":true},\"email\":null}}"; + public final static String MERGED_CLAIMS_CAPABILITIES_AND_CHALLENGE = "{\"id_token\":{\"auth_time\":{\"essential\":true},\"acr\":{\"values\":[\"urn:mace:incommon:iap:silver\",\"urn:mace:incommon:iap:bronze\"]},\"sub\":{\"essential\":true,\"value\":\"248289761001\"}},\"access_token\":{\"auth_time\":{\"essential\":true},\"xms_cc\":{\"values\":[\"llt\"]},\"given_name\":{\"essential\":true},\"email\":null}}"; } diff --git a/src/test/java/com/microsoft/aad/msal4j/TokenRequestExecutorTest.java b/src/test/java/com/microsoft/aad/msal4j/TokenRequestExecutorTest.java index 78b3f02f..aec766bc 100644 --- a/src/test/java/com/microsoft/aad/msal4j/TokenRequestExecutorTest.java +++ b/src/test/java/com/microsoft/aad/msal4j/TokenRequestExecutorTest.java @@ -6,7 +6,6 @@ import com.nimbusds.oauth2.sdk.ParseException; import com.nimbusds.oauth2.sdk.SerializeException; import com.nimbusds.oauth2.sdk.TokenErrorResponse; -import com.nimbusds.oauth2.sdk.http.CommonContentTypes; import com.nimbusds.oauth2.sdk.http.HTTPResponse; import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; import org.easymock.EasyMock; @@ -49,7 +48,7 @@ public void executeOAuthRequest_SCBadRequestErrorInvalidGrant_InteractionRequire "\"suberror\":\"basic_action\"," + "\"claims\":\"" + claims + "\"}"; httpResponse.setContent(content); - httpResponse.setContentType(CommonContentTypes.APPLICATION_JSON); + httpResponse.setContentType(HTTPContentType.ApplicationJSON.contentType); EasyMock.expect(request.createOauthHttpRequest()).andReturn(msalOAuthHttpRequest).times(1); EasyMock.expect(msalOAuthHttpRequest.send()).andReturn(httpResponse).times(1); @@ -88,7 +87,7 @@ public void executeOAuthRequest_SCBadRequestErrorInvalidGrant_SubErrorFilteredSe "\"suberror\":\"client_mismatch\"," + "\"claims\":\"" + claims + "\"}"; httpResponse.setContent(content); - httpResponse.setContentType(CommonContentTypes.APPLICATION_JSON); + httpResponse.setContentType(HTTPContentType.ApplicationJSON.contentType); EasyMock.expect(request.createOauthHttpRequest()).andReturn(msalOAuthHttpRequest).times(1); EasyMock.expect(msalOAuthHttpRequest.send()).andReturn(httpResponse).times(1); @@ -154,7 +153,7 @@ public void testConstructor() throws MalformedURLException, @Test public void testToOAuthRequestNonEmptyCorrelationId() - throws MalformedURLException, SerializeException, URISyntaxException { + throws MalformedURLException, SerializeException, URISyntaxException, ParseException { PublicClientApplication app = PublicClientApplication.builder("id").correlationId("corr-id").build(); @@ -183,7 +182,7 @@ public void testToOAuthRequestNonEmptyCorrelationId() @Test public void testToOAuthRequestNullCorrelationId_NullClientAuth() throws MalformedURLException, SerializeException, - URISyntaxException { + URISyntaxException, ParseException { PublicClientApplication app = PublicClientApplication.builder("id").correlationId("corr-id").build();