Skip to content

Commit 5516914

Browse files
Avery-Dunnsiddhijainbs-rscsDidunAyodejidsmith270
authoredMay 5, 2022
Release 1.12.0 (#507)
* Initial commit * fix: Correct scope for test dependency in POM The `azure-security-keyvault-secrets` test dependency was include twice and without the correct `test` scope. * Updated keyvault secrets version * Allow client assertion to be a callback and a per-request parameter (#482) * Allow creating a client assertion from a callback * Allow client credentials as a per-request parameter * Minor changes to fix build issues * Bump version numbers for 1.11.3 release (#484) * Revert unintentional commit * Add client_id to http request * Retrigger the build * Moving code to be executed for all client_Assertion requests * Update README.md * Update README.md * Update README.md * Update README.md * Cause the User Principal to be Serializable when held in the HttpSession as an attribute. This allows the J2EE web.xml "distributable" tag to work. https://access.redhat.com/documentation/en-us/red_hat_jboss_enterprise_application_platform/7.0/html/development_guide/clustering_in_web_applications * Update oauth2-oidc-sdk dependency * Changes in the relevant classes * Update error message when Authority does not contain path * Update IllegalArgumentExceptionMessages.java fix typo * Fix java.io.IOException: too many bytes written (#453) Current implementation relies on system location for getting bytes, and if it is not "UTF-8" underlying outputstream will error with ```java.io.IOException: too many bytes written``` Also fixed minor bug with wrong message being output * Add trailing slash to authorities in silent calls (#431) * Add trailing slash to authorities in silent calls * Move trailing slash helper method to Authority class * Silent calls now use cached environment info (#427) * issue #428 resolution * Fixed failing tests * Updated vulnerable libraries' versions * Revert some changes from the old PR * Update regional endpoints (#504) * Minor fixes/enhancements * Update regional endpoint formatting * Changelog and version changes for 1.12 release (#506) Co-authored-by: siddhijain <[email protected]> Co-authored-by: B. Schellhaas <[email protected]> Co-authored-by: DidunAyodeji <[email protected]> Co-authored-by: Dave Smith (Middleware Support) <[email protected]> Co-authored-by: Matt Mazzola <[email protected]> Co-authored-by: Marcelo Castro <[email protected]>
1 parent cd0feeb commit 5516914

26 files changed

+178
-68
lines changed
 

‎README.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@
44
--------------------|-----------------|---------------
55
[![Build status](https://identitydivision.visualstudio.com/IDDP/_apis/build/status/CI/Java/MSAL%20Java%20CI%20Build?branchName=main)](https://identitydivision.visualstudio.com/IDDP/_build/latest?definitionId=762) | [![Build status](https://identitydivision.visualstudio.com/IDDP/_apis/build/status/CI/Java/MSAL%20Java%20CI%20Build?branchName=dev)](https://identitydivision.visualstudio.com/IDDP/_build/latest?definitionId=762)| [![Javadocs](http://javadoc.io/badge/com.microsoft.azure/msal4j.svg)](http://javadoc.io/doc/com.microsoft.azure/msal4j)
66

7-
The Microsoft Authentication Library for Java (MSAL4J) enables applications to integrate with the [Microsoft identity platform](https://aka.ms/aaddevv2). It allows you to sign in users or apps with Microsoft identities (Azure AD, Microsoft accounts and Azure AD B2C accounts) and obtain tokens to call Microsoft APIs such as [Microsoft Graph](https://graph.microsoft.io/) or your own APIs registered with the Microsoft identity platform. It is built using industry standard OAuth2 and OpenID Connect protocols.
7+
The Microsoft Authentication Library for Java (MSAL4J) enables applications to integrate with the [Microsoft identity platform](https://docs.microsoft.com/en-us/azure/active-directory/develop/). It allows you to sign in users or apps with Microsoft identities (Azure AD, Microsoft accounts and Azure AD B2C accounts) and obtain tokens to call Microsoft APIs such as [Microsoft Graph](https://graph.microsoft.io/) or your own APIs registered with the Microsoft identity platform. It is built using industry standard OAuth2 and OpenID Connect protocols.
88

99
Quick links:
1010

11-
| [Getting Started](https://docs.microsoft.com/azure/active-directory/develop/quickstart-v2-java-webapp) | [Docs](https://github.com/AzureAD/microsoft-authentication-library-for-java/wiki) | [Samples](https://aka.ms/aaddevsamplesv2) | [Support](README.md#community-help-and-support) | [Feedback](https://forms.office.com/r/6AhHwQp3pe)
11+
| [Getting Started](https://docs.microsoft.com/en-us/azure/active-directory/develop/web-app-quickstart?pivots=devlang-java) | [Home](https://github.com/AzureAD/microsoft-authentication-library-for-java/wiki) | [Samples](https://github.com/Azure-Samples/ms-identity-msal-java-samples) | [Support](README.md#community-help-and-support) | [Feedback](https://forms.office.com/r/6AhHwQp3pe)
1212
| --- | --- | --- | --- | --- |
1313

1414
## Install
1515

1616
The library supports the following Java environments:
1717
- Java 8 (or higher)
1818

19-
Current version - 1.11.3
19+
Current version - 1.12.0
2020

2121
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).
2222

@@ -28,12 +28,12 @@ Find [the latest package in the Maven repository](https://mvnrepository.com/arti
2828
<dependency>
2929
<groupId>com.microsoft.azure</groupId>
3030
<artifactId>msal4j</artifactId>
31-
<version>1.11.3</version>
31+
<version>1.12.0</version>
3232
</dependency>
3333
```
3434
### Gradle
3535

36-
compile group: 'com.microsoft.azure', name: 'msal4j', version: '1.11.3'
36+
compile group: 'com.microsoft.azure', name: 'msal4j', version: '1.12.0'
3737

3838
## Usage
3939

@@ -58,7 +58,7 @@ This project has adopted the Microsoft Open Source Code of Conduct. For more inf
5858

5959
## Samples and Documentation
6060

61-
We provide a [full suite of sample applications](https://aka.ms/aaddevsamplesv2) and [documentation](https://aka.ms/aaddevv2) to help you get started with learning the Microsoft identity platform.
61+
We provide a [full suite of sample applications](https://aka.ms/aaddevsamplesv2) and [documentation](https://docs.microsoft.com/en-us/azure/active-directory/develop/) to help you get started with learning the Microsoft identity platform.
6262

6363
## Community Help and Support
6464

‎changelog.txt

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
Version 1.12.0
2+
=============
3+
- Updates several dependencies to avoid security vulnerabilities
4+
- Improves serialization of ID tokens and authentication results
5+
- Various bug fixes related to authority paths, regional endpoints, and unclear logs
6+
17
Version 1.11.3
28
=============
39
- Allow client assertions as callbacks and as per-request parameters

‎pom.xml

+9-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<modelVersion>4.0.0</modelVersion>
44
<groupId>com.microsoft.azure</groupId>
55
<artifactId>msal4j</artifactId>
6-
<version>1.11.3</version>
6+
<version>1.12.0</version>
77
<packaging>jar</packaging>
88
<name>msal4j</name>
99
<description>
@@ -36,12 +36,17 @@
3636
<dependency>
3737
<groupId>com.nimbusds</groupId>
3838
<artifactId>oauth2-oidc-sdk</artifactId>
39-
<version>9.22.1</version>
39+
<version>9.32</version>
40+
</dependency>
41+
<dependency>
42+
<groupId>net.minidev</groupId>
43+
<artifactId>json-smart</artifactId>
44+
<version>2.4.8</version>
4045
</dependency>
4146
<dependency>
4247
<groupId>org.slf4j</groupId>
4348
<artifactId>slf4j-api</artifactId>
44-
<version>1.7.28</version>
49+
<version>1.7.36</version>
4550
</dependency>
4651
<dependency>
4752
<groupId>org.projectlombok</groupId>
@@ -52,7 +57,7 @@
5257
<dependency>
5358
<groupId>com.fasterxml.jackson.core</groupId>
5459
<artifactId>jackson-databind</artifactId>
55-
<version>2.12.1</version>
60+
<version>2.13.2.1</version>
5661
</dependency>
5762

5863
<!-- test dependencies -->

‎src/integrationtest/java/com.microsoft.aad.msal4j/AcquireTokenInteractiveIT.java

+19-3
Original file line numberDiff line numberDiff line change
@@ -167,19 +167,35 @@ private void assertAcquireTokenInstanceAware(User user) {
167167
Assert.assertNotEquals(pca.authenticationAuthority.host, result.environment());
168168
Assert.assertEquals(result.account().environment(), result.environment());
169169
Assert.assertEquals(result.account().environment(), pca.getAccounts().join().iterator().next().environment());
170+
171+
IAuthenticationResult cachedResult;
172+
try {
173+
cachedResult = acquireTokenSilently(pca, result.account(), cfg.graphDefaultScope());
174+
} catch (Exception ex) {
175+
throw new RuntimeException(ex.getMessage());
176+
}
177+
178+
//Ensure that the cached environment matches the original auth result environment (.us) instead of the client app's (.com)
179+
Assert.assertEquals(result.account().environment(), cachedResult.environment());
170180
}
171181

172182
@Test
173183
public void acquireTokensInHomeAndGuestClouds_ArlingtonAccount() throws MalformedURLException, ExecutionException, InterruptedException {
174-
acquireTokensInHomeAndGuestClouds(AzureEnvironment.AZURE_US_GOVERNMENT, TestConstants.AUTHORITY_ARLINGTON);
184+
acquireTokensInHomeAndGuestClouds(AzureEnvironment.AZURE_US_GOVERNMENT);
175185
}
176186

177187
@Test
178188
public void acquireTokensInHomeAndGuestClouds_MooncakeAccount() throws MalformedURLException, ExecutionException, InterruptedException {
179-
acquireTokensInHomeAndGuestClouds(AzureEnvironment.AZURE_CHINA, TestConstants.AUTHORITY_MOONCAKE);
189+
acquireTokensInHomeAndGuestClouds(AzureEnvironment.AZURE_CHINA);
190+
}
191+
192+
private IAuthenticationResult acquireTokenSilently(IPublicClientApplication pca, IAccount account, String scope) throws InterruptedException, ExecutionException, MalformedURLException {
193+
return pca.acquireTokenSilently(SilentParameters.builder(Collections.singleton(scope), account)
194+
.build())
195+
.get();
180196
}
181197

182-
public void acquireTokensInHomeAndGuestClouds(String homeCloud, String homeCloudAuthority) throws MalformedURLException, ExecutionException, InterruptedException {
198+
public void acquireTokensInHomeAndGuestClouds(String homeCloud) throws MalformedURLException {
183199

184200
User user = labUserProvider.getUserByGuestHomeAzureEnvironments
185201
(AzureEnvironment.AZURE, homeCloud);

‎src/integrationtest/java/com.microsoft.aad.msal4j/DeviceCodeIT.java

+37-5
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public void DeviceCodeFlowADTest(String environment) throws Exception {
4444
build();
4545

4646
Consumer<DeviceCode> deviceCodeConsumer = (DeviceCode deviceCode) -> {
47-
runAutomatedDeviceCodeFlow(deviceCode, user, environment);
47+
runAutomatedDeviceCodeFlow(deviceCode, user);
4848
};
4949

5050
IAuthenticationResult result = pca.acquireToken(DeviceCodeFlowParameters
@@ -57,8 +57,8 @@ public void DeviceCodeFlowADTest(String environment) throws Exception {
5757
Assert.assertFalse(Strings.isNullOrEmpty(result.accessToken()));
5858
}
5959

60-
@Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class)
61-
public void DeviceCodeFlowADFSv2019Test(String environment) throws Exception {
60+
@Test()
61+
public void DeviceCodeFlowADFSv2019Test() throws Exception {
6262

6363
User user = labUserProvider.getOnPremAdfsUser(FederationProvider.ADFS_2019);
6464

@@ -68,7 +68,7 @@ public void DeviceCodeFlowADFSv2019Test(String environment) throws Exception {
6868
build();
6969

7070
Consumer<DeviceCode> deviceCodeConsumer = (DeviceCode deviceCode) -> {
71-
runAutomatedDeviceCodeFlow(deviceCode, user, environment);
71+
runAutomatedDeviceCodeFlow(deviceCode, user);
7272
};
7373

7474
IAuthenticationResult result = pca.acquireToken(DeviceCodeFlowParameters
@@ -81,7 +81,39 @@ public void DeviceCodeFlowADFSv2019Test(String environment) throws Exception {
8181
Assert.assertFalse(Strings.isNullOrEmpty(result.accessToken()));
8282
}
8383

84-
private void runAutomatedDeviceCodeFlow(DeviceCode deviceCode, User user, String environment) {
84+
@Test()
85+
public void DeviceCodeFlowMSATest() throws Exception {
86+
87+
User user = labUserProvider.getMSAUser();
88+
89+
PublicClientApplication pca = PublicClientApplication.builder(
90+
user.getAppId()).
91+
authority(TestConstants.CONSUMERS_AUTHORITY).
92+
build();
93+
94+
Consumer<DeviceCode> deviceCodeConsumer = (DeviceCode deviceCode) -> {
95+
runAutomatedDeviceCodeFlow(deviceCode, user);
96+
};
97+
98+
IAuthenticationResult result = pca.acquireToken(DeviceCodeFlowParameters
99+
.builder(Collections.singleton(""),
100+
deviceCodeConsumer)
101+
.build())
102+
.get();
103+
104+
Assert.assertNotNull(result);
105+
Assert.assertFalse(Strings.isNullOrEmpty(result.accessToken()));
106+
107+
result = pca.acquireTokenSilently(SilentParameters.
108+
builder(Collections.singleton(""), result.account()).
109+
build())
110+
.get();
111+
112+
Assert.assertNotNull(result);
113+
Assert.assertFalse(Strings.isNullOrEmpty(result.accessToken()));
114+
}
115+
116+
private void runAutomatedDeviceCodeFlow(DeviceCode deviceCode, User user) {
85117
boolean isRunningLocally = true;//!Strings.isNullOrEmpty(
86118
//System.getenv(TestConstants.LOCAL_FLAG_ENV_VAR));
87119

‎src/integrationtest/java/com.microsoft.aad.msal4j/OAuthRequestValidationUnitT.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public void oAuthRequest_for_acquireTokenByClientCertificate() throws Exception
3131
}
3232

3333
Map<String, String> queryParams = splitQuery(query);
34-
Assert.assertEquals(queryParams.size(), 7);
34+
Assert.assertEquals(queryParams.size(), 8);
3535

3636
// validate Authorization Grants query params
3737
Assert.assertEquals(queryParams.get("grant_type"), GRANT_TYPE_JWT);
@@ -55,6 +55,8 @@ public void oAuthRequest_for_acquireTokenByClientCertificate() throws Exception
5555
Assert.assertEquals(queryParams.get("requested_token_use"), ON_BEHALF_OF_USE_JWT);
5656

5757
Assert.assertEquals(queryParams.get("client_info"), CLIENT_INFO_VALUE);
58+
Assert.assertEquals(queryParams.get("client_id"), CLIENT_ID);
59+
5860
}
5961

6062
@Test
@@ -83,7 +85,7 @@ public void oAuthRequest_for_acquireTokenByClientAssertion() throws Exception {
8385

8486
Map<String, String> queryParams = splitQuery(query);
8587

86-
Assert.assertEquals(queryParams.size(), 5);
88+
Assert.assertEquals(queryParams.size(), 6);
8789

8890
// validate Authorization Grants query params
8991
Assert.assertEquals(queryParams.get("grant_type"), CLIENT_CREDENTIALS_GRANT_TYPE);
@@ -96,5 +98,6 @@ public void oAuthRequest_for_acquireTokenByClientAssertion() throws Exception {
9698
Assert.assertEquals(queryParams.get("scope"), "https://SomeResource.azure.net openid profile offline_access");
9799

98100
Assert.assertEquals(queryParams.get("client_info"), CLIENT_INFO_VALUE);
101+
Assert.assertEquals(queryParams.get("client_id"), CLIENT_ID);
99102
}
100103
}

‎src/integrationtest/java/com.microsoft.aad.msal4j/TestConstants.java

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public class TestConstants {
2525

2626
public final static String ORGANIZATIONS_AUTHORITY = MICROSOFT_AUTHORITY_HOST + "organizations/";
2727
public final static String COMMON_AUTHORITY = MICROSOFT_AUTHORITY_HOST + "common/";
28+
public final static String CONSUMERS_AUTHORITY = MICROSOFT_AUTHORITY_HOST + "consumers/";
2829
public final static String COMMON_AUTHORITY_WITH_PORT = MICROSOFT_AUTHORITY_HOST_WITH_PORT + "msidlab4.onmicrosoft.com";
2930
public final static String MICROSOFT_AUTHORITY = MICROSOFT_AUTHORITY_HOST + "microsoft.onmicrosoft.com";
3031
public final static String TENANT_SPECIFIC_AUTHORITY = MICROSOFT_AUTHORITY_HOST + MICROSOFT_AUTHORITY_TENANT;

‎src/integrationtest/java/labapi/LabUserProvider.java

+7
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ public User getB2cUser(String azureEnvironment, String b2cProvider) {
7878
return getLabUser(query);
7979
}
8080

81+
public User getMSAUser() {
82+
UserQueryParameters query = new UserQueryParameters();
83+
query.parameters.put(UserQueryParameters.USER_TYPE, UserType.MSA);
84+
85+
return getLabUser(query);
86+
}
87+
8188
public User getUserByAzureEnvironment(String azureEnvironment) {
8289

8390
UserQueryParameters query = new UserQueryParameters();

‎src/main/java/com/microsoft/aad/msal4j/AadInstanceDiscoveryProvider.java

+21-8
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ class AadInstanceDiscoveryProvider {
2222
private final static String DEFAULT_TRUSTED_HOST = "login.microsoftonline.com";
2323
private final static String AUTHORIZE_ENDPOINT_TEMPLATE = "https://{host}/{tenant}/oauth2/v2.0/authorize";
2424
private final static String INSTANCE_DISCOVERY_ENDPOINT_TEMPLATE = "https://{host}:{port}/common/discovery/instance";
25-
private final static String INSTANCE_DISCOVERY_ENDPOINT_TEMPLATE_WITH_REGION = "https://{region}.{host}:{port}/common/discovery/instance";
25+
private final static String INSTANCE_DISCOVERY_ENDPOINT_TEMPLATE_WITH_REGION = "https://{region}.r.{host}:{port}/common/discovery/instance";
26+
private final static String INSTANCE_DISCOVERY_SOVEREIGN_ENDPOINT_TEMPLATE_WITH_REGION = "https://{region}.{host}:{port}/common/discovery/instance";
2627
private final static String INSTANCE_DISCOVERY_REQUEST_PARAMETERS_TEMPLATE = "?api-version=1.1&authorization_endpoint={authorizeEndpoint}";
2728
private final static String REGION_NAME = "REGION_NAME";
2829
private final static int PORT_NOT_SET = -1;
@@ -31,19 +32,24 @@ class AadInstanceDiscoveryProvider {
3132
private final static String IMDS_ENDPOINT = "https://169.254.169.254/metadata/instance/compute/location?" + DEFAULT_API_VERSION + "&format=text";
3233

3334
final static TreeSet<String> TRUSTED_HOSTS_SET = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
35+
final static TreeSet<String> TRUSTED_SOVEREIGN_HOSTS_SET = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
3436

3537
private final static Logger log = LoggerFactory.getLogger(HttpHelper.class);
3638

3739
static ConcurrentHashMap<String, InstanceDiscoveryMetadataEntry> cache = new ConcurrentHashMap<>();
3840

3941
static {
40-
TRUSTED_HOSTS_SET.addAll(Arrays.asList(
41-
"login.windows.net",
42+
TRUSTED_SOVEREIGN_HOSTS_SET.addAll(Arrays.asList(
4243
"login.chinacloudapi.cn",
4344
"login-us.microsoftonline.com",
4445
"login.microsoftonline.de",
45-
"login.microsoftonline.com",
4646
"login.microsoftonline.us"));
47+
48+
TRUSTED_HOSTS_SET.addAll(Arrays.asList(
49+
"login.windows.net",
50+
"login.microsoftonline.com"));
51+
52+
TRUSTED_HOSTS_SET.addAll(TRUSTED_SOVEREIGN_HOSTS_SET);
4753
}
4854

4955
static InstanceDiscoveryMetadataEntry getMetadataEntry(URL authorityUrl,
@@ -133,10 +139,17 @@ private static String getInstanceDiscoveryEndpointWithRegion(URL authorityUrl, S
133139
authorityUrl.getDefaultPort() :
134140
authorityUrl.getPort();
135141

136-
return INSTANCE_DISCOVERY_ENDPOINT_TEMPLATE_WITH_REGION.
137-
replace("{region}", region).
138-
replace("{host}", discoveryHost).
139-
replace("{port}", String.valueOf(port));
142+
if (TRUSTED_SOVEREIGN_HOSTS_SET.contains(authorityUrl.getHost())) {
143+
return INSTANCE_DISCOVERY_SOVEREIGN_ENDPOINT_TEMPLATE_WITH_REGION.
144+
replace("{region}", region).
145+
replace("{host}", discoveryHost).
146+
replace("{port}", String.valueOf(port));
147+
} else {
148+
return INSTANCE_DISCOVERY_ENDPOINT_TEMPLATE_WITH_REGION.
149+
replace("{region}", region).
150+
replace("{host}", discoveryHost).
151+
replace("{port}", String.valueOf(port));
152+
}
140153
}
141154

142155

‎src/main/java/com/microsoft/aad/msal4j/AbstractClientApplicationBase.java

+4-13
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
* Abstract class containing common methods and properties to both {@link PublicClientApplication}
2929
* and {@link ConfidentialClientApplication}.
3030
*/
31-
abstract class AbstractClientApplicationBase implements IClientApplicationBase {
31+
public abstract class AbstractClientApplicationBase implements IClientApplicationBase {
3232

3333
protected Logger log;
3434
protected Authority authenticationAuthority;
@@ -300,16 +300,7 @@ ServiceBundle getServiceBundle() {
300300
return serviceBundle;
301301
}
302302

303-
protected static String enforceTrailingSlash(String authority) {
304-
authority = authority.toLowerCase();
305-
306-
if (!authority.endsWith("/")) {
307-
authority += "/";
308-
}
309-
return authority;
310-
}
311-
312-
abstract static class Builder<T extends Builder<T>> {
303+
public abstract static class Builder<T extends Builder<T>> {
313304
// Required parameters
314305
private String clientId;
315306

@@ -358,7 +349,7 @@ public Builder(String clientId) {
358349
* @throws MalformedURLException if val is malformed URL
359350
*/
360351
public T authority(String val) throws MalformedURLException {
361-
authority = enforceTrailingSlash(val);
352+
authority = Authority.enforceTrailingSlash(val);
362353

363354
URL authorityURL = new URL(authority);
364355
Authority.validateAuthority(authorityURL);
@@ -378,7 +369,7 @@ public T authority(String val) throws MalformedURLException {
378369
}
379370

380371
public T b2cAuthority(String val) throws MalformedURLException {
381-
authority = enforceTrailingSlash(val);
372+
authority = Authority.enforceTrailingSlash(val);
382373

383374
URL authorityURL = new URL(authority);
384375
Authority.validateAuthority(authorityURL);

‎src/main/java/com/microsoft/aad/msal4j/AcquireTokenSilentSupplier.java

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

44
package com.microsoft.aad.msal4j;
55

6+
import java.net.URL;
67
import java.util.Date;
78

89
class AcquireTokenSilentSupplier extends AuthenticationResultSupplier {
@@ -69,6 +70,14 @@ AuthenticationResult execute() throws Exception {
6970
}
7071

7172
if (!StringHelper.isBlank(res.refreshToken())) {
73+
//There are certain scenarios where the cached authority may differ from the client app's authority,
74+
// such as when a request is instance aware. Unless overridden by SilentParameters.authorityUrl, the
75+
// cached authority should be used in the token refresh request
76+
if (silentRequest.parameters().authorityUrl() == null && !res.account().environment().equals(requestAuthority.host)) {
77+
requestAuthority = Authority.createAuthority(new URL(requestAuthority.authority().replace(requestAuthority.host(),
78+
res.account().environment())));
79+
}
80+
7281
RefreshTokenRequest refreshTokenRequest = new RefreshTokenRequest(
7382
RefreshTokenParameters.builder(silentRequest.parameters().scopes(), res.refreshToken()).build(),
7483
silentRequest.application(),

‎src/main/java/com/microsoft/aad/msal4j/Authority.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ static void validateAuthority(URL authorityUrl) {
117117

118118
if (segments.length == 0) {
119119
throw new IllegalArgumentException(
120-
IllegalArgumentExceptionMessages.AUTHORITY_URI_EMPTY_PATH_SEGMENT);
120+
IllegalArgumentExceptionMessages.AUTHORITY_URI_MISSING_PATH_SEGMENT);
121121
}
122122

123123
for (String segment : segments) {
@@ -151,4 +151,13 @@ private static boolean isB2CAuthority(final String firstPath) {
151151
String deviceCodeEndpoint() {
152152
return deviceCodeEndpoint;
153153
}
154+
155+
protected static String enforceTrailingSlash(String authority) {
156+
authority = authority.toLowerCase();
157+
158+
if (!authority.endsWith("/")) {
159+
authority += "/";
160+
}
161+
return authority;
162+
}
154163
}

‎src/main/java/com/microsoft/aad/msal4j/AuthorizationResponseHandler.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ private void send302Response(HttpExchange httpExchange, String redirectUri) thro
102102
private void send200Response(HttpExchange httpExchange, String response) throws IOException {
103103
httpExchange.sendResponseHeaders(200, response.length());
104104
OutputStream os = httpExchange.getResponseBody();
105-
os.write(response.getBytes());
105+
os.write(response.getBytes("UTF-8"));
106106
os.close();
107107
}
108108

@@ -117,6 +117,6 @@ private String getErrorResponseMessage() {
117117
if (systemBrowserOptions == null || systemBrowserOptions.htmlMessageError() == null) {
118118
return DEFAULT_FAILURE_MESSAGE;
119119
}
120-
return systemBrowserOptions().htmlMessageSuccess();
120+
return systemBrowserOptions().htmlMessageError();
121121
}
122122
}

‎src/main/java/com/microsoft/aad/msal4j/ClientAuthenticationPost.java

+6-4
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@
33

44
package com.microsoft.aad.msal4j;
55

6-
import java.util.Collections;
7-
import java.util.HashMap;
8-
import java.util.List;
9-
import java.util.Map;
6+
import java.util.*;
107

118
import com.nimbusds.oauth2.sdk.SerializeException;
129
import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
@@ -22,6 +19,11 @@ protected ClientAuthenticationPost(ClientAuthenticationMethod method,
2219
super(method, clientID);
2320
}
2421

22+
@Override
23+
public Set<String> getFormParameterNames() {
24+
return Collections.unmodifiableSet(new HashSet(Arrays.asList("client_assertion", "client_assertion_type", "client_id")));
25+
}
26+
2527
Map<String, List<String>> toParameters() {
2628

2729
Map<String, List<String>> params = new HashMap<>();

‎src/main/java/com/microsoft/aad/msal4j/CustomJWTAuthentication.java

+7-5
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,7 @@
1212
import com.nimbusds.oauth2.sdk.id.ClientID;
1313
import com.nimbusds.oauth2.sdk.util.URLUtils;
1414

15-
import java.net.URLEncoder;
16-
import java.util.Collections;
17-
import java.util.HashMap;
18-
import java.util.List;
19-
import java.util.Map;
15+
import java.util.*;
2016

2117
public class CustomJWTAuthentication extends ClientAuthentication {
2218
private ClientAssertion clientAssertion;
@@ -26,6 +22,12 @@ protected CustomJWTAuthentication(ClientAuthenticationMethod method, ClientAsser
2622
this.clientAssertion = clientAssertion;
2723
}
2824

25+
@Override
26+
public Set<String> getFormParameterNames() {
27+
return Collections.unmodifiableSet(new HashSet(Arrays.asList("client_assertion", "client_assertion_type", "client_id")));
28+
29+
}
30+
2931
@Override
3032
public void applyTo(HTTPRequest httpRequest) {
3133
if (httpRequest.getMethod() != HTTPRequest.Method.POST) {

‎src/main/java/com/microsoft/aad/msal4j/IAuthenticationResult.java

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

44
package com.microsoft.aad.msal4j;
55

6+
import java.io.Serializable;
7+
68
/**
79
* Interface representing the results of token acquisition operation.
810
*/
9-
public interface IAuthenticationResult {
11+
public interface IAuthenticationResult extends Serializable {
1012

1113
/**
1214
* @return access token

‎src/main/java/com/microsoft/aad/msal4j/IdToken.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
import java.util.HashMap;
1111
import java.util.Map;
1212

13-
class IdToken {
13+
import java.io.Serializable;
14+
15+
class IdToken implements Serializable {
1416

1517
static final String ISSUER = "iss";
1618
static final String SUBJECT = "sub";

‎src/main/java/com/microsoft/aad/msal4j/IllegalArgumentExceptionMessages.java

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ class IllegalArgumentExceptionMessages {
77

88
final static String AUTHORITY_URI_EMPTY_PATH_SEGMENT = "Authority Uri should not have empty path segments";
99

10+
final static String AUTHORITY_URI_MISSING_PATH_SEGMENT = "Authority Uri must have at least one path segment. This is usually 'common' or the application's tenant id.";
11+
1012
final static String AUTHORITY_URI_EMPTY_PATH = "Authority Uri should have at least one segment in the path";
1113

1214
}

‎src/main/java/com/microsoft/aad/msal4j/Prompt.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,12 @@ public enum Prompt {
3636
/**
3737
* An administrator should be prompted to consent on behalf of all users in their organization.
3838
*/
39-
ADMIN_CONSENT("admin_consent");
39+
ADMIN_CONSENT("admin_consent"),
40+
41+
/**
42+
* User will not be shown an interactive prompt
43+
*/
44+
NONE("none");
4045

4146
private String prompt;
4247

‎src/main/java/com/microsoft/aad/msal4j/SilentRequest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class SilentRequest extends MsalRequest {
2828
this.assertion = assertion;
2929
this.requestAuthority = StringHelper.isBlank(parameters.authorityUrl()) ?
3030
application.authenticationAuthority :
31-
Authority.createAuthority(new URL(parameters.authorityUrl()));
31+
Authority.createAuthority(new URL(Authority.enforceTrailingSlash(parameters.authorityUrl())));
3232

3333
if (parameters.forceRefresh()) {
3434
application.getServiceBundle().getServerSideTelemetry().getCurrentRequest().cacheInfo(

‎src/main/java/com/microsoft/aad/msal4j/TokenCache.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,6 @@ AuthenticationResult getCachedAuthenticationResult(
584584
String clientId) {
585585

586586
AuthenticationResult.AuthenticationResultBuilder builder = AuthenticationResult.builder();
587-
builder.environment(authority.host());
588587

589588
Set<String> environmentAliases = AadInstanceDiscoveryProvider.getAliases(account.environment());
590589

@@ -622,11 +621,14 @@ AuthenticationResult getCachedAuthenticationResult(
622621

623622
if (atCacheEntity.isPresent()) {
624623
builder.
624+
environment(atCacheEntity.get().environment).
625625
accessToken(atCacheEntity.get().secret).
626626
expiresOn(Long.parseLong(atCacheEntity.get().expiresOn()));
627627
if (atCacheEntity.get().refreshOn() != null) {
628628
builder.refreshOn(Long.parseLong(atCacheEntity.get().refreshOn()));
629629
}
630+
} else {
631+
builder.environment(authority.host());
630632
}
631633
idTokenCacheEntity.ifPresent(tokenCacheEntity -> builder.idToken(tokenCacheEntity.secret));
632634
rtCacheEntity.ifPresent(refreshTokenCacheEntity ->

‎src/main/java/com/microsoft/aad/msal4j/TokenRequestExecutor.java

+8-6
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,7 @@
1616

1717
import java.io.IOException;
1818
import java.net.MalformedURLException;
19-
import java.util.Collections;
20-
import java.util.Date;
21-
import java.util.HashMap;
22-
import java.util.List;
23-
import java.util.Map;
19+
import java.util.*;
2420

2521
@Getter(AccessLevel.PACKAGE)
2622
class TokenRequestExecutor {
@@ -71,8 +67,14 @@ OAuthHttpRequest createOauthHttpRequest() throws SerializeException, MalformedUR
7167
}
7268

7369
oauthHttpRequest.setQuery(URLUtils.serializeParameters(params));
74-
70+
7571
if (msalRequest.application().clientAuthentication() != null) {
72+
73+
Map<String, List<String>> queryParameters = oauthHttpRequest.getQueryParameters();
74+
String clientID = msalRequest.application().clientId();
75+
queryParameters.put("client_id", Arrays.asList(clientID));
76+
oauthHttpRequest.setQuery(URLUtils.serializeParameters(queryParameters));
77+
7678
// If the client application has a client assertion to apply to the request, check if a new client assertion
7779
// was supplied as a request parameter. If so, use the request's assertion instead of the application's
7880
if (msalRequest instanceof ClientCredentialRequest && ((ClientCredentialRequest) msalRequest).parameters.clientCredential() != null) {

‎src/samples/msal-b2c-web-sample/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<dependency>
2424
<groupId>com.microsoft.azure</groupId>
2525
<artifactId>msal4j</artifactId>
26-
<version>1.11.3</version>
26+
<version>1.12.0</version>
2727
</dependency>
2828
<dependency>
2929
<groupId>com.nimbusds</groupId>

‎src/samples/msal-obo-sample/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<dependency>
2424
<groupId>com.microsoft.azure</groupId>
2525
<artifactId>msal4j</artifactId>
26-
<version>1.11.3</version>
26+
<version>1.12.0</version>
2727
</dependency>
2828
<dependency>
2929
<groupId>com.nimbusds</groupId>

‎src/samples/msal-web-sample/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<dependency>
2424
<groupId>com.microsoft.azure</groupId>
2525
<artifactId>msal4j</artifactId>
26-
<version>1.11.3</version>
26+
<version>1.12.0</version>
2727
</dependency>
2828
<dependency>
2929
<groupId>com.nimbusds</groupId>

‎src/test/java/com/microsoft/aad/msal4j/AuthorityTest.java

-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,6 @@ public void testDoStaticInstanceDiscovery_ValidateFalse_TrustedAuthority()
158158
@DataProvider(name = "authoritiesWithEmptyPath")
159159
public static Object[][] createData() {
160160
return new Object[][]{{"https://login.microsoftonline.com/"},
161-
{"https://login.microsoftonline.com//"},
162161
{"https://login.microsoftonline.com//tenant"},
163162
{"https://login.microsoftonline.com////tenant//path1"}};
164163
}

0 commit comments

Comments
 (0)
Please sign in to comment.