Skip to content

Commit

Permalink
Merge pull request #626 from AzureAD/add-ciam-authority
Browse files Browse the repository at this point in the history
Support new CIAM authority
  • Loading branch information
siddhijain authored Apr 16, 2023
2 parents 891ddfe + 9d4e1dd commit a965fbb
Show file tree
Hide file tree
Showing 14 changed files with 206 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@

package com.microsoft.aad.msal4j;

import labapi.AzureEnvironment;
import labapi.B2CProvider;
import labapi.FederationProvider;
import labapi.User;
import labapi.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
Expand All @@ -16,6 +13,8 @@
import java.net.URI;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;

public class AcquireTokenInteractiveIT extends SeleniumTest {
Expand Down Expand Up @@ -73,7 +72,45 @@ public void acquireTokenInteractive_ADFSv2_Federated(String environment) {
public void acquireTokenInteractive_Ciam() {
User user = labUserProvider.getCiamUser();

assertAcquireTokenCommon(user, TestConstants.CIAM_AUTHORITY, TestConstants.GRAPH_DEFAULT_SCOPE);
Map<String, String> extraQueryParameters = new HashMap<>();
extraQueryParameters.put("dc","ESTS-PUB-EUS-AZ1-FD000-TEST1");

PublicClientApplication pca;
try {
pca = PublicClientApplication.builder(
user.getAppId()).
authority("https://" + user.getLabName() + ".ciamlogin.com/")
.build();
} catch (MalformedURLException ex) {
throw new RuntimeException(ex.getMessage());
}

IAuthenticationResult result;
try {
URI url = new URI("http://localhost:8080");

SystemBrowserOptions browserOptions =
SystemBrowserOptions
.builder()
.openBrowserAction(new SeleniumOpenBrowserAction(user, pca))
.build();

InteractiveRequestParameters parameters = InteractiveRequestParameters
.builder(url)
.scopes(Collections.singleton(TestConstants.GRAPH_DEFAULT_SCOPE))
.extraQueryParameters(extraQueryParameters)
.systemBrowserOptions(browserOptions)
.build();

result = pca.acquireToken(parameters).get();

} catch (Exception e) {
LOG.error("Error acquiring token with authCode: " + e.getMessage());
throw new RuntimeException("Error acquiring token with authCode: " + e.getMessage());
}

assertTokenResultNotNull(result);
Assert.assertEquals(user.getUpn(), result.account().username());
}

@Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import labapi.AppCredentialProvider;
import labapi.AzureEnvironment;
import labapi.LabUserProvider;
import labapi.User;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
Expand All @@ -18,6 +19,8 @@
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;

import static com.microsoft.aad.msal4j.TestConstants.KEYVAULT_DEFAULT_SCOPE;
Expand Down Expand Up @@ -62,11 +65,29 @@ public void acquireTokenClientCredentials_ClientAssertion() throws Exception {

@Test
public void acquireTokenClientCredentials_ClientSecret_Ciam() throws Exception {
String clientId = labUserProvider.getCiamUser().getAppId();

User user = labUserProvider.getCiamUser();
String clientId = user.getAppId();

Map<String, String> extraQueryParameters = new HashMap<>();
extraQueryParameters.put("dc","ESTS-PUB-EUS-AZ1-FD000-TEST1");

AppCredentialProvider appProvider = new AppCredentialProvider(AzureEnvironment.CIAM);
IClientCredential credential = ClientCredentialFactory.createFromSecret(appProvider.getOboAppPassword());

ConfidentialClientApplication cca = ConfidentialClientApplication.builder(
clientId, credential).
authority("https://" + user.getLabName() + ".ciamlogin.com/").
build();

IAuthenticationResult result = cca.acquireToken(ClientCredentialParameters
.builder(Collections.singleton(TestConstants.GRAPH_DEFAULT_SCOPE))
.extraQueryParameters(extraQueryParameters)
.build())
.get();

Assert.assertNotNull(result);
Assert.assertNotNull(result.accessToken());
assertAcquireTokenCommon(clientId, credential, TestConstants.CIAM_AUTHORITY);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,7 @@ public void DeviceCodeFlowADTest(String environment) throws Exception {
authority(cfg.tenantSpecificAuthority()).
build();

Consumer<DeviceCode> deviceCodeConsumer = (DeviceCode deviceCode) -> {
runAutomatedDeviceCodeFlow(deviceCode, user);
};
Consumer<DeviceCode> deviceCodeConsumer = (DeviceCode deviceCode) -> runAutomatedDeviceCodeFlow(deviceCode, user);

IAuthenticationResult result = pca.acquireToken(DeviceCodeFlowParameters
.builder(Collections.singleton(cfg.graphDefaultScope()),
Expand Down Expand Up @@ -119,7 +117,7 @@ public void DeviceCodeFlowCiamTest() throws Exception {

PublicClientApplication pca = PublicClientApplication.builder(
user.getAppId()).
authority(TestConstants.CIAM_AUTHORITY).
authority("https://" + user.getLabName() + ".ciamlogin.com/").
build();

Consumer<DeviceCode> deviceCodeConsumer = (DeviceCode deviceCode) -> {
Expand Down Expand Up @@ -174,7 +172,7 @@ private void runAutomatedDeviceCodeFlow(DeviceCode deviceCode, User user) {
if (isADFS2019) {
SeleniumExtensions.performADFS2019Login(seleniumDriver, user);
} else {
SeleniumExtensions.performADLogin(seleniumDriver, user);
SeleniumExtensions.performADOrCiamLogin(seleniumDriver, user);
}
} catch (Exception e) {
if (!isRunningLocally) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,11 @@ void runSeleniumAutomatedLogin(User user, AbstractClientApplicationBase app) {
break;
}
} else if (authorityType == AuthorityType.AAD) {
SeleniumExtensions.performADLogin(seleniumDriver, user);
SeleniumExtensions.performADOrCiamLogin(seleniumDriver, user);
} else if (authorityType == AuthorityType.ADFS) {
SeleniumExtensions.performADFS2019Login(seleniumDriver, user);
} else if (authorityType == AuthorityType.CIAM) {
SeleniumExtensions.performADOrCiamLogin(seleniumDriver, user);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ public class TestConstants {

public final static String REGIONAL_MICROSOFT_AUTHORITY_BASIC_HOST_EASTUS = "eastus.login.microsoft.com";

public final static String CIAM_AUTHORITY = MICROSOFT_AUTHORITY_HOST + "msidlabciam1.onmicrosoft.com";
// public final static String CIAM_AUTHORITY = MICROSOFT_AUTHORITY_HOST + "msidlabciam1.onmicrosoft.com";
public final static String CIAM_AUTHORITY = "https://msidlabciam1.ciamlogin.com/" + "msidlabciam1.onmicrosoft.com";

public final static String CIAM_TEST_AUTHORITY = "https://contoso0781.ciamlogin.com/6babcaad-604b-40ac-a9d7-9fd97c0b779f/v2.0/.well-known/openid-configuration?dc=ESTS-PUB-EUS-AZ1-FD000-TEST1&ciamhost=true";

public final static String ARLINGTON_ORGANIZATIONS_AUTHORITY = ARLINGTON_MICROSOFT_AUTHORITY_HOST + "organizations/";
public final static String ARLINGTON_TENANT_SPECIFIC_AUTHORITY = ARLINGTON_MICROSOFT_AUTHORITY_HOST + ARLINGTON_AUTHORITY_TENANT;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import org.testng.annotations.Test;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

@Test()
public class UsernamePasswordIT {
Expand Down Expand Up @@ -100,10 +102,24 @@ public void acquireTokenWithUsernamePassword_ADFSv2(String environment) throws E
@Test
public void acquireTokenWithUsernamePassword_Ciam() throws Exception {

Map<String, String> extraQueryParameters = new HashMap<>();
extraQueryParameters.put("dc","ESTS-PUB-EUS-AZ1-FD000-TEST1");

User user = labUserProvider.getCiamUser();
PublicClientApplication pca = PublicClientApplication.builder(user.getAppId())
.authority("https://" + user.getLabName() + ".ciamlogin.com/")
.build();

assertAcquireTokenCommon(user, TestConstants.CIAM_AUTHORITY, TestConstants.GRAPH_DEFAULT_SCOPE,
user.getAppId());

IAuthenticationResult result = pca.acquireToken(UserNamePasswordParameters.
builder(Collections.singleton(TestConstants.GRAPH_DEFAULT_SCOPE),
user.getUpn(),
user.getPassword().toCharArray())
.extraQueryParameters(extraQueryParameters)
.build())
.get();

Assert.assertNotNull(result.accessToken());
}

@Test
Expand All @@ -125,6 +141,7 @@ private void assertAcquireTokenCommonAAD(User user) throws Exception {

private void assertAcquireTokenCommon(User user, String authority, String scope, String appId)
throws Exception {

PublicClientApplication pca = PublicClientApplication.builder(
appId).
authority(authority).
Expand All @@ -135,6 +152,7 @@ private void assertAcquireTokenCommon(User user, String authority, String scope,
user.getUpn(),
user.getPassword().toCharArray())
.build())

.get();

assertTokenResultNotNull(result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ public static WebElement waitForElementToBeVisibleAndEnable(WebDriver driver, By
return waitForElementToBeVisibleAndEnable(driver, by, DEFAULT_TIMEOUT_IN_SEC);
}

public static void performADLogin(WebDriver driver, User user) {
LOG.info("PerformADLogin");
public static void performADOrCiamLogin(WebDriver driver, User user) {
LOG.info("performADOrCiamLogin");

UserInformationFields fields = new UserInformationFields(user);

Expand All @@ -76,7 +76,7 @@ public static void performADLogin(WebDriver driver, User user) {
LOG.info("Loggin in ... Clicking <Next> after username");
driver.findElement(new By.ById(fields.getAadSignInButtonId())).click();

if (user.getFederationProvider() == FederationProvider.ADFS_2 &&
if (user.getFederationProvider().equals(FederationProvider.ADFS_2) &&
!user.getLabName().equals(LabConstants.ARLINGTON_LAB_NAME)) {

LOG.info("Loggin in ... ADFS-V2 - Entering the username in ADFSv2 form");
Expand All @@ -96,6 +96,7 @@ public static void performADLogin(WebDriver driver, User user) {
checkAuthenticationCompletePage(driver);
return;
} catch (TimeoutException ex) {
LOG.error(ex.getMessage());
}

LOG.info("Checking optional questions");
Expand All @@ -107,6 +108,7 @@ public static void performADLogin(WebDriver driver, User user) {
LOG.info("Are you trying to sign in to ... ? click Continue");

} catch (TimeoutException ex) {
LOG.error(ex.getMessage());
}

try {
Expand All @@ -115,6 +117,7 @@ public static void performADLogin(WebDriver driver, User user) {
click();
LOG.info("Stay signed in? click NO");
} catch (TimeoutException ex) {
LOG.error(ex.getMessage());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ public T authority(String val) throws MalformedURLException {
authority = Authority.enforceTrailingSlash(val);

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


switch (Authority.detectAuthorityType(authorityURL)) {
case AAD:
Expand All @@ -366,10 +366,15 @@ public T authority(String val) throws MalformedURLException {
case ADFS:
authenticationAuthority = new ADFSAuthority(authorityURL);
break;
case CIAM:
authenticationAuthority = new CIAMAuthority(authorityURL);
break;
default:
throw new IllegalArgumentException("Unsupported authority type.");
}

Authority.validateAuthority(authenticationAuthority.canonicalAuthorityUrl());

return self();
}

Expand Down
26 changes: 19 additions & 7 deletions msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/Authority.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,22 @@ private void setCommonAuthorityProperties() {
this.host = canonicalAuthorityUrl.getAuthority().toLowerCase();
}

static Authority createAuthority(URL authorityUrl) {
validateAuthority(authorityUrl);

static Authority createAuthority(URL authorityUrl) throws MalformedURLException{
Authority createdAuthority;
AuthorityType authorityType = detectAuthorityType(authorityUrl);
if (authorityType == AuthorityType.AAD) {
return new AADAuthority(authorityUrl);
createdAuthority = new AADAuthority(authorityUrl);
} else if (authorityType == AuthorityType.B2C) {
return new B2CAuthority(authorityUrl);
createdAuthority = new B2CAuthority(authorityUrl);
} else if (authorityType == AuthorityType.ADFS) {
return new ADFSAuthority(authorityUrl);
createdAuthority = new ADFSAuthority(authorityUrl);
} else if(authorityType == AuthorityType.CIAM){
createdAuthority = new CIAMAuthority(authorityUrl);
} else {
throw new IllegalArgumentException("Unsupported Authority Type");
}
validateAuthority(createdAuthority.canonicalAuthorityUrl());
return createdAuthority;
}

static AuthorityType detectAuthorityType(URL authorityUrl) {
Expand All @@ -76,6 +79,9 @@ static AuthorityType detectAuthorityType(URL authorityUrl) {

final String path = authorityUrl.getPath().substring(1);
if (StringHelper.isBlank(path)) {
if(isCiamAuthority(authorityUrl.getHost())){
return AuthorityType.CIAM;
}
throw new IllegalArgumentException(
"authority Uri should have at least one segment in the path (i.e. https://<host>/<path>/...)");
}
Expand All @@ -87,7 +93,9 @@ static AuthorityType detectAuthorityType(URL authorityUrl) {
return AuthorityType.B2C;
} else if (isAdfsAuthority(firstPath)) {
return AuthorityType.ADFS;
} else {
} else if(isCiamAuthority(host)){
return AuthorityType.CIAM;
} else{
return AuthorityType.AAD;
}
}
Expand Down Expand Up @@ -154,6 +162,10 @@ private static boolean isB2CAuthority(final String host, final String firstPath)
return host.contains(B2C_HOST_SEGMENT) || firstPath.compareToIgnoreCase(B2C_PATH_SEGMENT) == 0;
}

private static boolean isCiamAuthority(final String host){
return host.endsWith(CIAMAuthority.CIAM_HOST_SEGMENT);
}

String deviceCodeEndpoint() {
return deviceCodeEndpoint;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
package com.microsoft.aad.msal4j;

enum AuthorityType {
AAD, ADFS, B2C
AAD, ADFS, B2C, CIAM
}
Loading

0 comments on commit a965fbb

Please sign in to comment.