Skip to content

Commit 35aa889

Browse files
authored
Merge pull request #851 from AzureAD/avdunn/ciam-custom
Add support for CIAM custom authority
2 parents 260656e + 7e7ea1c commit 35aa889

File tree

14 files changed

+201
-17
lines changed

14 files changed

+201
-17
lines changed

msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AuthorizationCodeIT.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,45 @@ public void acquireTokenWithAuthorizationCode_B2C_Local(String environment) {
9090
assertAcquireTokenB2C(user);
9191
}
9292

93+
@Test
94+
public void acquireTokenWithAuthorizationCode_CiamCud() throws Exception {
95+
String authorityCud = "https://login.msidlabsciam.com/fe362aec-5d43-45d1-b730-9755e60dc3b9/v2.0/";
96+
User user = labUserProvider.getCiamCudUser();
97+
98+
PublicClientApplication pca = PublicClientApplication.builder(
99+
user.getAppId()).
100+
oidcAuthority(authorityCud).
101+
build();
102+
103+
assertEquals("https://login.msidlabsciam.com/fe362aec-5d43-45d1-b730-9755e60dc3b9/v2.0/.well-known/openid-configuration",
104+
pca.authenticationAuthority.canonicalAuthorityUrl.toString());
105+
assertEquals("https://login.msidlabsciam.com/fe362aec-5d43-45d1-b730-9755e60dc3b9/oauth2/v2.0/authorize",
106+
pca.authenticationAuthority.authorizationEndpoint);
107+
108+
String authCode = acquireAuthorizationCodeAutomated(user, pca, null);
109+
110+
IAuthenticationResult result = pca.acquireToken(AuthorizationCodeParameters
111+
.builder(authCode,
112+
new URI(TestConstants.LOCALHOST + httpListener.port()))
113+
.scopes(Collections.singleton("user.read"))
114+
.build())
115+
.get();
116+
117+
assertNotNull(result);
118+
assertNotNull(result.accessToken());
119+
assertNotNull(result.idToken());
120+
assertEquals(user.getUpn(), result.account().username());
121+
122+
IAuthenticationResult resultSilent = pca.acquireTokenSilently(SilentParameters
123+
.builder(Collections.singleton("user.read"), result.account())
124+
.build())
125+
.get();
126+
127+
assertNotNull(resultSilent);
128+
assertEquals(resultSilent.accessToken(), result.accessToken());
129+
assertEquals(resultSilent.account().username(), result.account().username());
130+
}
131+
93132
private void assertAcquireTokenADFS2019(User user) {
94133
PublicClientApplication pca;
95134
try {
@@ -261,6 +300,8 @@ private String buildAuthenticationCodeURL(AbstractClientApplicationBase app, Map
261300
scope = TestConstants.B2C_LAB_SCOPE;
262301
} else if (authorityType == AuthorityType.ADFS) {
263302
scope = TestConstants.ADFS_SCOPE;
303+
} else if (authorityType == AuthorityType.OIDC) {
304+
scope = TestConstants.USER_READ_SCOPE;
264305
} else {
265306
throw new RuntimeException("Authority type not recognized");
266307
}

msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/ClientCredentialsIT.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,25 @@ void acquireTokenClientCredentials_ClientSecret_Ciam() throws Exception {
8888
assertNotNull(result.accessToken());
8989
}
9090

91+
@Test
92+
void acquireTokenClientCredentials_Certificate_CiamCud() throws Exception {
93+
String authorityCud = "https://login.msidlabsciam.com/fe362aec-5d43-45d1-b730-9755e60dc3b9/v2.0/";
94+
String clientId = "b244c86f-ed88-45bf-abda-6b37aa482c79";
95+
96+
ConfidentialClientApplication cca = ConfidentialClientApplication.builder(
97+
clientId, CertificateHelper.getClientCertificate())
98+
.oidcAuthority(authorityCud)
99+
.build();
100+
101+
IAuthenticationResult result = cca.acquireToken(ClientCredentialParameters
102+
.builder(Collections.singleton(TestConstants.DEFAULT_SCOPE))
103+
.build())
104+
.get();
105+
106+
assertNotNull(result);
107+
assertNotNull(result.accessToken());
108+
}
109+
91110
@Test
92111
void acquireTokenClientCredentials_Callback() throws Exception {
93112
String clientId = TestConstants.MSIDLAB_CLIENT_ID;

msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/SeleniumTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ void runSeleniumAutomatedLogin(User user, AbstractClientApplicationBase app) {
4848
SeleniumExtensions.performADOrCiamLogin(seleniumDriver, user);
4949
} else if (authorityType == AuthorityType.ADFS) {
5050
SeleniumExtensions.performADFS2019Login(seleniumDriver, user);
51-
} else if (authorityType == AuthorityType.CIAM) {
51+
} else if (authorityType == AuthorityType.CIAM || authorityType == AuthorityType.OIDC) {
5252
SeleniumExtensions.performADOrCiamLogin(seleniumDriver, user);
5353
}
5454
}

msal4j-sdk/src/integrationtest/java/labapi/FederationProvider.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public class FederationProvider {
99
public static final String ADFS_4 = "adfsv4";
1010
public static final String ADFS_2019 = "adfsv2019";
1111
public static final String CIAM = "ciam";
12+
public static final String CIAMCUD = "ciamcud";
1213

1314
}
1415

msal4j-sdk/src/integrationtest/java/labapi/LabUserProvider.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,14 @@ public User getCiamUser() {
113113
return getLabUser(query);
114114
}
115115

116+
public User getCiamCudUser() {
117+
UserQueryParameters query = new UserQueryParameters();
118+
query.parameters.put(UserQueryParameters.FEDERATION_PROVIDER, FederationProvider.CIAMCUD);
119+
query.parameters.put(UserQueryParameters.SIGN_IN_AUDIENCE, "azureadmyorg");
120+
121+
return getLabUser(query);
122+
}
123+
116124
public User getLabUser(UserQueryParameters userQuery) {
117125
if (userCache.containsKey(userQuery)) {
118126
return userCache.get(userQuery);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,4 +372,4 @@ private static void validate(AadInstanceDiscoveryResponse aadInstanceDiscoveryRe
372372
throw new MsalServiceException(aadInstanceDiscoveryResponse);
373373
}
374374
}
375-
}
375+
}

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

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

66
import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
7-
import lombok.AccessLevel;
87
import lombok.Getter;
98
import lombok.experimental.Accessors;
10-
import org.slf4j.Logger;
119

1210
import javax.net.ssl.SSLSocketFactory;
1311
import java.net.MalformedURLException;
1412
import java.net.Proxy;
1513
import java.net.URL;
1614
import java.util.Collections;
17-
import java.util.HashMap;
18-
import java.util.List;
1915
import java.util.Set;
2016
import java.util.concurrent.CompletableFuture;
2117
import java.util.concurrent.ExecutorService;
22-
import java.util.function.Consumer;
2318

2419
import static com.microsoft.aad.msal4j.ParameterValidationUtils.validateNotBlank;
2520
import static com.microsoft.aad.msal4j.ParameterValidationUtils.validateNotNull;
@@ -283,6 +278,24 @@ public T b2cAuthority(String val) throws MalformedURLException {
283278
return self();
284279
}
285280

281+
/**
282+
* Set a known authority corresponding to a generic OpenIdConnect Identity Provider.
283+
* MSAL will append ".well-known/openid-configuration" to the authority to retrieve the OIDC metadata and determine the endpoints.
284+
*
285+
* @param val a string value of authority
286+
* @return instance of the Builder on which method was called
287+
*/
288+
public T oidcAuthority(String val) throws MalformedURLException {
289+
authority = Authority.enforceTrailingSlash(val);
290+
URL authorityURL = new URL(authority);
291+
292+
authenticationAuthority = new OidcAuthority(authorityURL);
293+
294+
Authority.validateAuthority(authenticationAuthority.canonicalAuthorityUrl());
295+
296+
return self();
297+
}
298+
286299
/**
287300
* Set a boolean value telling the application if the authority needs to be verified
288301
* against a list of known authorities. Authority is only validated when:
@@ -550,5 +563,11 @@ public T correlationId(String val) {
550563
authenticationAuthority.host,
551564
aadAadInstanceDiscoveryResponse);
552565
}
566+
567+
if (authenticationAuthority.authorityType == AuthorityType.OIDC) {
568+
((OidcAuthority) authenticationAuthority).setAuthorityProperties(
569+
OidcDiscoveryProvider.performOidcDiscovery(
570+
(OidcAuthority) authenticationAuthority, this));
571+
}
553572
}
554573
}

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
/**
1414
* Represents Authentication Authority responsible for issuing access tokens.
1515
*/
16-
1716
@Accessors(fluent = true)
1817
@Getter(AccessLevel.PACKAGE)
1918
abstract class Authority {
@@ -63,7 +62,7 @@ static Authority createAuthority(URL authorityUrl) throws MalformedURLException{
6362
createdAuthority = new B2CAuthority(authorityUrl);
6463
} else if (authorityType == AuthorityType.ADFS) {
6564
createdAuthority = new ADFSAuthority(authorityUrl);
66-
} else if(authorityType == AuthorityType.CIAM){
65+
} else if (authorityType == AuthorityType.CIAM) {
6766
createdAuthority = new CIAMAuthority(authorityUrl);
6867
} else {
6968
throw new IllegalArgumentException("Unsupported Authority Type");
@@ -79,7 +78,7 @@ static AuthorityType detectAuthorityType(URL authorityUrl) {
7978

8079
final String path = authorityUrl.getPath().substring(1);
8180
if (StringHelper.isBlank(path)) {
82-
if(isCiamAuthority(authorityUrl.getHost())){
81+
if (isCiamAuthority(authorityUrl.getHost())) {
8382
return AuthorityType.CIAM;
8483
}
8584
throw new IllegalArgumentException(

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
package com.microsoft.aad.msal4j;
55

66
enum AuthorityType {
7-
AAD, ADFS, B2C, CIAM
7+
AAD, ADFS, B2C, CIAM, OIDC
88
}

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import java.net.MalformedURLException;
77
import java.net.URL;
88

9-
public class CIAMAuthority extends Authority{
9+
public class CIAMAuthority extends Authority {
1010

1111
public static final String CIAM_HOST_SEGMENT = ".ciamlogin.com";
1212

@@ -23,20 +23,22 @@ public class CIAMAuthority extends Authority{
2323
CIAMAuthority(URL authorityUrl) throws MalformedURLException {
2424
super(transformAuthority(authorityUrl), AuthorityType.CIAM);
2525
setAuthorityProperties();
26-
this.authority = String.format(CIAM_AUTHORITY_FORMAT,host,tenant);
26+
this.authority = String.format(CIAM_AUTHORITY_FORMAT, host, tenant);
2727
}
2828

29-
/** This method takes a CIAM authority string of format "tenant.ciamlogin.com" or "https://tenant.ciamlogin.com"
30-
and converts it into a full authority url with a path segment of format "/tenant.onmicrosoft.com"
29+
/**
30+
* This method takes a CIAM authority string of format "tenant.ciamlogin.com" or "https://tenant.ciamlogin.com"
31+
* and converts it into a full authority url with a path segment of format "/tenant.onmicrosoft.com"
32+
*
3133
* @param originalAuthority authority to be transformed
3234
* @return full CIAM authority with path
3335
*/
3436
protected static URL transformAuthority(URL originalAuthority) throws MalformedURLException {
3537
String host = originalAuthority.getHost() + originalAuthority.getPath();
3638
String transformedAuthority = originalAuthority.toString();
37-
if(originalAuthority.getPath().equals("/")){
39+
if (originalAuthority.getPath().equals("/")) {
3840
int ciamHostIndex = host.indexOf(CIAMAuthority.CIAM_HOST_SEGMENT);
39-
String tenant = host.substring(0 , ciamHostIndex);
41+
String tenant = host.substring(0, ciamHostIndex);
4042
transformedAuthority = originalAuthority + tenant + ".onmicrosoft.com/";
4143
}
4244
return new URL(transformedAuthority);

0 commit comments

Comments
 (0)