From 9ca518cc2c99ed05fd1da76724399f9dfc113f72 Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Wed, 5 Jul 2023 10:12:54 +0100 Subject: [PATCH 01/24] Delete codeql.yml --- .github/workflows/codeql.yml | 46 ------------------------------------ 1 file changed, 46 deletions(-) delete mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index 4dfaa38a..00000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: "Code Scanning - Action" - -on: - push: - schedule: - - cron: '0 0 * * 0' - -jobs: - CodeQL-Build: - - strategy: - fail-fast: false - - - # CodeQL runs on ubuntu-latest, windows-latest, and macos-latest - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - # Override language selection by uncommenting this and choosing your languages - # with: - # languages: go, javascript, csharp, python, cpp, java - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below). - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 From 3c00622f7af638dcae2283709a02315db2baac41 Mon Sep 17 00:00:00 2001 From: Avery-Dunn <62066438+Avery-Dunn@users.noreply.github.com> Date: Mon, 10 Jul 2023 12:38:03 -0700 Subject: [PATCH 02/24] Test framework update (#672) * Initial working tests * Remove CIAM extra query parameter * Fix failing tests * Remove duplicate unit tests * Remove duplicate unit tests * Update tests with mocking to use Mockito * Remove testng and powermock, add junit and mockito * Remove AbstractMsalTests and PowerMockTestCase * Fix mistaken null check * Properly scope dependency --- msal4j-sdk/pom.xml | 38 +- .../AcquireTokenInteractiveIT.java | 147 +++--- .../AcquireTokenSilentIT.java | 157 ++++--- .../AuthorizationCodeIT.java | 113 ++--- .../AzureEnvironmentIT.java | 28 +- .../CachePersistenceIT.java | 58 +-- .../ClientCredentialsIT.java | 111 ++--- .../ConfidentialClientApplicationUnitT.java | 421 ------------------ .../DeviceCodeIT.java | 74 ++- .../EnvironmentsProvider.java | 2 - .../HttpClientIT.java | 27 +- .../InstanceDiscoveryTest.java | 235 ---------- .../InvalidAuthorityIT.java | 18 +- .../OAuthRequestValidationUnitT.java | 103 ----- .../OnBehalfOfIT.java | 59 +-- .../RefreshTokenIT.java | 40 +- .../SeleniumTest.java | 6 - .../TokenCacheIT.java | 43 +- .../UsernamePasswordIT.java | 82 ++-- .../infrastructure/UserInformationFields.java | 6 +- .../msal4j/AadInstanceDiscoveryProvider.java | 4 +- .../aad/msal4j/AadInstanceDiscoveryTest.java | 179 +++----- .../aad/msal4j/AbstractMsalTests.java | 9 - .../com/microsoft/aad/msal4j/AccountTest.java | 84 +--- .../aad/msal4j/AcquireTokenSilentlyTest.java | 45 +- .../aad/msal4j/AssertionCredentialTest.java | 20 - .../microsoft/aad/msal4j/AuthorityTest.java | 220 +++++---- ...AuthorizationRequestUrlParametersTest.java | 93 ++-- .../aad/msal4j/CacheFormatTests.java | 72 ++- .../com/microsoft/aad/msal4j/ClaimsTest.java | 31 +- .../msal4j/ClientCertificatePkcs12Test.java | 86 ++-- .../aad/msal4j/ClientCertificateTest.java | 64 ++- .../aad/msal4j/ClientCredentialTest.java | 35 ++ .../aad/msal4j/ClientSecretTest.java | 24 - .../aad/msal4j/DefaultHttpClientTest.java | 64 --- .../aad/msal4j/DeviceCodeFlowTest.java | 227 ---------- .../microsoft/aad/msal4j/HttpHeaderTest.java | 72 +-- .../microsoft/aad/msal4j/HttpUtilsTest.java | 22 +- .../microsoft/aad/msal4j/MexParserTest.java | 43 +- .../MsalOauthAuthorizatonGrantTest.java | 21 +- .../msal4j/OAuthRequestValidationTest.java | 186 -------- .../aad/msal4j/OauthHttpRequestTest.java | 99 ---- .../msal4j/PublicClientApplicationTest.java | 69 --- .../aad/msal4j/RequestThrottlingTest.java | 80 ++-- .../aad/msal4j/ServerTelemetryTests.java | 58 +-- .../microsoft/aad/msal4j/TelemetryTests.java | 106 ++--- .../aad/msal4j/TokenRequestExecutorTest.java | 185 ++++---- .../aad/msal4j/TokenResponseTest.java | 33 +- .../aad/msal4j/UIRequiredCacheTest.java | 79 ++-- .../aad/msal4j/WSTrustRequestTest.java | 32 +- .../aad/msal4j/WSTrustResponseTest.java | 44 +- 51 files changed, 1262 insertions(+), 2892 deletions(-) delete mode 100644 msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/ConfidentialClientApplicationUnitT.java delete mode 100644 msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/InstanceDiscoveryTest.java delete mode 100644 msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/OAuthRequestValidationUnitT.java delete mode 100644 msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AbstractMsalTests.java delete mode 100644 msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AssertionCredentialTest.java create mode 100644 msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClientCredentialTest.java delete mode 100644 msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClientSecretTest.java delete mode 100644 msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/DefaultHttpClientTest.java delete mode 100644 msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/DeviceCodeFlowTest.java delete mode 100644 msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/OAuthRequestValidationTest.java delete mode 100644 msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/OauthHttpRequestTest.java delete mode 100644 msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/PublicClientApplicationTest.java diff --git a/msal4j-sdk/pom.xml b/msal4j-sdk/pom.xml index 6ae70964..a0e984f0 100644 --- a/msal4j-sdk/pom.xml +++ b/msal4j-sdk/pom.xml @@ -68,29 +68,42 @@ test - org.testng - testng - 7.1.0 + org.junit.jupiter + junit-jupiter-api + 5.9.2 test - org.powermock - powermock-module-testng - 2.0.0 + org.junit.jupiter + junit-jupiter-params + 5.8.1 test - org.powermock - powermock-api-easymock - 2.0.0 + org.junit.jupiter + junit-jupiter-engine + 5.9.2 test - org.easymock - easymock - 4.0.2 + org.mockito + mockito-inline + 4.7.0 test + + org.mockito + mockito-junit-jupiter + 4.7.0 + test + + + net.bytebuddy + byte-buddy + 1.14.5 + test + + org.skyscreamer jsonassert @@ -156,7 +169,6 @@ - ${project.build.directory}/delombok org.projectlombok diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AcquireTokenInteractiveIT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AcquireTokenInteractiveIT.java index edce1e88..dee0c9a7 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AcquireTokenInteractiveIT.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AcquireTokenInteractiveIT.java @@ -4,10 +4,18 @@ package com.microsoft.aad.msal4j; import labapi.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.net.MalformedURLException; import java.net.URI; @@ -17,13 +25,31 @@ import java.util.Map; import java.util.concurrent.ExecutionException; -public class AcquireTokenInteractiveIT extends SeleniumTest { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class AcquireTokenInteractiveIT extends SeleniumTest { private final static Logger LOG = LoggerFactory.getLogger(AuthorizationCodeIT.class); private Config cfg; - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenInteractive_ManagedUser(String environment) { + + @BeforeAll + public void setupUserProvider() { + setUpLapUserProvider(); + } + + @AfterEach + public void stopBrowser() { + cleanUp(); + } + + @BeforeEach + public void startBrowser() { + startUpBrowser(); + } + + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenInteractive_ManagedUser(String environment) { cfg = new Config(environment); User user = labUserProvider.getDefaultUser(cfg.azureEnvironment); @@ -31,98 +57,59 @@ public void acquireTokenInteractive_ManagedUser(String environment) { } @Test() - public void acquireTokenInteractive_ADFSv2019_OnPrem() { + void acquireTokenInteractive_ADFSv2019_OnPrem() { User user = labUserProvider.getOnPremAdfsUser(FederationProvider.ADFS_2019); assertAcquireTokenCommon(user, TestConstants.ADFS_AUTHORITY, TestConstants.ADFS_SCOPE); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenInteractive_ADFSv2019_Federated(String environment) { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenInteractive_ADFSv2019_Federated(String environment) { cfg = new Config(environment); User user = labUserProvider.getFederatedAdfsUser(cfg.azureEnvironment, FederationProvider.ADFS_2019); assertAcquireTokenCommon(user, cfg.organizationsAuthority(), cfg.graphDefaultScope()); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenInteractive_ADFSv4_Federated(String environment) { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenInteractive_ADFSv4_Federated(String environment) { cfg = new Config(environment); User user = labUserProvider.getFederatedAdfsUser(cfg.azureEnvironment, FederationProvider.ADFS_4); assertAcquireTokenCommon(user, cfg.organizationsAuthority(), cfg.graphDefaultScope()); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenInteractive_ADFSv3_Federated(String environment) { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenInteractive_ADFSv3_Federated(String environment) { cfg = new Config(environment); User user = labUserProvider.getFederatedAdfsUser(cfg.azureEnvironment, FederationProvider.ADFS_3); assertAcquireTokenCommon(user, cfg.organizationsAuthority(), cfg.graphDefaultScope()); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenInteractive_ADFSv2_Federated(String environment) { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenInteractive_ADFSv2_Federated(String environment) { cfg = new Config(environment); User user = labUserProvider.getFederatedAdfsUser(cfg.azureEnvironment, FederationProvider.ADFS_2); assertAcquireTokenCommon(user, cfg.organizationsAuthority(), cfg.graphDefaultScope()); } - @Test - public void acquireTokenInteractive_Ciam() { - User user = labUserProvider.getCiamUser(); - - Map 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) - public void acquireTokenWithAuthorizationCode_B2C_Local(String environment) { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenWithAuthorizationCode_B2C_Local(String environment) { cfg = new Config(environment); User user = labUserProvider.getB2cUser(cfg.azureEnvironment, B2CProvider.LOCAL); assertAcquireTokenB2C(user, TestConstants.B2C_AUTHORITY); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenWithAuthorizationCode_B2C_LegacyFormat(String environment) { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenWithAuthorizationCode_B2C_LegacyFormat(String environment) { cfg = new Config(environment); User user = labUserProvider.getB2cUser(cfg.azureEnvironment, B2CProvider.LOCAL); @@ -130,7 +117,7 @@ public void acquireTokenWithAuthorizationCode_B2C_LegacyFormat(String environmen } @Test - public void acquireTokenInteractive_ManagedUser_InstanceAware() { + void acquireTokenInteractive_ManagedUser_InstanceAware() { cfg = new Config(AzureEnvironment.AZURE); User user = labUserProvider.getDefaultUser(AzureEnvironment.AZURE_US_GOVERNMENT); @@ -154,7 +141,7 @@ private void assertAcquireTokenCommon(User user, String authority, String scope) scope); assertTokenResultNotNull(result); - Assert.assertEquals(user.getUpn(), result.account().username()); + assertEquals(user.getUpn(), result.account().username()); } private void assertAcquireTokenB2C(User user, String authority) { @@ -187,13 +174,13 @@ private void assertAcquireTokenInstanceAware(User user) { IAuthenticationResult result = acquireTokenInteractive_instanceAware(user, pca, cfg.graphDefaultScope()); assertTokenResultNotNull(result); - Assert.assertEquals(user.getUpn(), result.account().username()); + assertEquals(user.getUpn(), result.account().username()); //This test is using a client app with the login.microsoftonline.com config to get tokens for a login.microsoftonline.us user, // so when using instance aware the result's environment will be for the user/account and not the client app - Assert.assertNotEquals(pca.authenticationAuthority.host, result.environment()); - Assert.assertEquals(result.account().environment(), result.environment()); - Assert.assertEquals(result.account().environment(), pca.getAccounts().join().iterator().next().environment()); + assertNotEquals(pca.authenticationAuthority.host, result.environment()); + assertEquals(result.account().environment(), result.environment()); + assertEquals(result.account().environment(), pca.getAccounts().join().iterator().next().environment()); IAuthenticationResult cachedResult; try { @@ -203,17 +190,7 @@ private void assertAcquireTokenInstanceAware(User user) { } //Ensure that the cached environment matches the original auth result environment (.us) instead of the client app's (.com) - Assert.assertEquals(result.account().environment(), cachedResult.environment()); - } - - //@Test - public void acquireTokensInHomeAndGuestClouds_ArlingtonAccount() throws MalformedURLException, ExecutionException, InterruptedException { - acquireTokensInHomeAndGuestClouds(AzureEnvironment.AZURE_US_GOVERNMENT); - } - - //@Test - public void acquireTokensInHomeAndGuestClouds_MooncakeAccount() throws MalformedURLException, ExecutionException, InterruptedException { - acquireTokensInHomeAndGuestClouds(AzureEnvironment.AZURE_CHINA); + assertEquals(result.account().environment(), cachedResult.environment()); } private IAuthenticationResult acquireTokenSilently(IPublicClientApplication pca, IAccount account, String scope) throws InterruptedException, ExecutionException, MalformedURLException { @@ -251,11 +228,11 @@ public void afterCacheAccess(ITokenCacheAccessContext iTokenCacheAccessContext) IAuthenticationResult result = acquireTokenInteractive(user, publicCloudPca, TestConstants.USER_READ_SCOPE); assertTokenResultNotNull(result); - Assert.assertEquals(user.getHomeUPN(), result.account().username()); + assertEquals(user.getHomeUPN(), result.account().username()); publicCloudPca.removeAccount(publicCloudPca.getAccounts().join().iterator().next()).join(); - Assert.assertEquals(publicCloudPca.getAccounts().join().size(), 0); + assertEquals(publicCloudPca.getAccounts().join().size(), 0); } private IAuthenticationResult acquireTokenInteractive( @@ -289,9 +266,9 @@ private IAuthenticationResult acquireTokenInteractive( } private void assertTokenResultNotNull(IAuthenticationResult result) { - Assert.assertNotNull(result); - Assert.assertNotNull(result.accessToken()); - Assert.assertNotNull(result.idToken()); + assertNotNull(result); + assertNotNull(result.accessToken()); + assertNotNull(result.idToken()); } private IAuthenticationResult acquireTokenInteractive_instanceAware( diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AcquireTokenSilentIT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AcquireTokenSilentIT.java index 56d5f7d5..f7eb2bf2 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AcquireTokenSilentIT.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AcquireTokenSilentIT.java @@ -4,9 +4,15 @@ package com.microsoft.aad.msal4j; import labapi.*; -import org.testng.Assert; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.api.BeforeAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.net.MalformedURLException; import java.util.*; @@ -14,18 +20,20 @@ import static com.microsoft.aad.msal4j.TestConstants.KEYVAULT_DEFAULT_SCOPE; -public class AcquireTokenSilentIT { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class AcquireTokenSilentIT { private LabUserProvider labUserProvider; private Config cfg; - @BeforeClass - public void setUp() { + @BeforeAll + void setUp() { labUserProvider = LabUserProvider.getInstance(); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenSilent_OrganizationAuthority_TokenRefreshed(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenSilent_OrganizationAuthority_TokenRefreshed(String environment) throws Exception { cfg = new Config(environment); // When using common, organization, or consumer tenants, cache has no way @@ -37,8 +45,9 @@ public void acquireTokenSilent_OrganizationAuthority_TokenRefreshed(String envir assertResultNotNull(result); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenSilent_LabAuthority_TokenNotRefreshed(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenSilent_LabAuthority_TokenNotRefreshed(String environment) throws Exception { cfg = new Config(environment); // Access token should be returned from cache, and not using refresh token @@ -58,12 +67,13 @@ public void acquireTokenSilent_LabAuthority_TokenNotRefreshed(String environment assertResultNotNull(result); // Check that access and id tokens are coming from cache - Assert.assertEquals(result.accessToken(), acquireSilentResult.accessToken()); - Assert.assertEquals(result.idToken(), acquireSilentResult.idToken()); + assertEquals(result.accessToken(), acquireSilentResult.accessToken()); + assertEquals(result.idToken(), acquireSilentResult.idToken()); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenSilent_ForceRefresh(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenSilent_ForceRefresh(String environment) throws Exception { cfg = new Config(environment); User user = labUserProvider.getDefaultUser(environment); @@ -84,8 +94,9 @@ public void acquireTokenSilent_ForceRefresh(String environment) throws Exception assertTokensAreNotEqual(result, resultAfterRefresh); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenSilent_MultipleAccountsInCache_UseCorrectAccount(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenSilent_MultipleAccountsInCache_UseCorrectAccount(String environment) throws Exception { cfg = new Config(environment); IPublicClientApplication pca = getPublicClientApplicationWithTokensInCache(); @@ -103,11 +114,12 @@ public void acquireTokenSilent_MultipleAccountsInCache_UseCorrectAccount(String IAuthenticationResult result = acquireTokenSilently(pca, account, cfg.graphDefaultScope(), false); assertResultNotNull(result); - Assert.assertEquals(result.account().username(), user.getUpn()); + assertEquals(result.account().username(), user.getUpn()); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenSilent_ADFS2019(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenSilent_ADFS2019(String environment) throws Exception { cfg = new Config(environment); UserQueryParameters query = new UserQueryParameters(); @@ -136,42 +148,19 @@ public void acquireTokenSilent_ADFS2019(String environment) throws Exception { assertTokensAreNotEqual(result, resultAfterRefresh); } - // Commented out due to unclear B2C behavior causing occasional errors - //@Test - public void acquireTokenSilent_B2C() throws Exception { - UserQueryParameters query = new UserQueryParameters(); - query.parameters.put(UserQueryParameters.USER_TYPE, UserType.B2C); - query.parameters.put(UserQueryParameters.B2C_PROVIDER, B2CProvider.LOCAL); - User user = labUserProvider.getLabUser(query); - - PublicClientApplication pca = PublicClientApplication.builder( - user.getAppId()). - b2cAuthority(TestConstants.B2C_AUTHORITY_ROPC). - build(); - - IAuthenticationResult result = acquireTokenUsernamePassword(user, pca, TestConstants.B2C_READ_SCOPE); - assertResultNotNull(result); - - IAccount account = pca.getAccounts().join().iterator().next(); - IAuthenticationResult resultAfterRefresh = acquireTokenSilently(pca, account, TestConstants.B2C_READ_SCOPE, true); - assertResultNotNull(resultAfterRefresh); - - assertTokensAreNotEqual(result, resultAfterRefresh); - } - - @Test - public void acquireTokenSilent_usingCommonAuthority_returnCachedAt() throws Exception { + void acquireTokenSilent_usingCommonAuthority_returnCachedAt() throws Exception { acquireTokenSilent_returnCachedTokens(cfg.organizationsAuthority()); } @Test - public void acquireTokenSilent_usingTenantSpecificAuthority_returnCachedAt() throws Exception { + void acquireTokenSilent_usingTenantSpecificAuthority_returnCachedAt() throws Exception { acquireTokenSilent_returnCachedTokens(cfg.tenantSpecificAuthority()); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenSilent_ConfidentialClient_acquireTokenSilent(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenSilent_ConfidentialClient_acquireTokenSilent(String environment) throws Exception { cfg = new Config(environment); IConfidentialClientApplication cca = getConfidentialClientApplications(); @@ -184,8 +173,8 @@ public void acquireTokenSilent_ConfidentialClient_acquireTokenSilent(String envi .build()) .get(); - Assert.assertNotNull(result); - Assert.assertNotNull(result.accessToken()); + assertNotNull(result); + assertNotNull(result.accessToken()); String cachedAt = result.accessToken(); @@ -195,11 +184,11 @@ public void acquireTokenSilent_ConfidentialClient_acquireTokenSilent(String envi .build()) .get(); - Assert.assertNotNull(result); - Assert.assertEquals(result.accessToken(), cachedAt); + assertNotNull(result); + assertEquals(result.accessToken(), cachedAt); } - @Test(expectedExceptions = ExecutionException.class) + @Test public void acquireTokenSilent_ConfidentialClient_acquireTokenSilentDifferentScopeThrowsException() throws Exception { cfg = new Config(AzureEnvironment.AZURE); @@ -211,18 +200,19 @@ public void acquireTokenSilent_ConfidentialClient_acquireTokenSilentDifferentSco .build()) .get(); - Assert.assertNotNull(result); - Assert.assertNotNull(result.accessToken()); + assertNotNull(result); + assertNotNull(result.accessToken()); //Acquiring token for different scope, expect exception to be thrown - cca.acquireTokenSilently(SilentParameters - .builder(Collections.singleton(cfg.graphDefaultScope())) - .build()) - .get(); + assertThrows(ExecutionException.class, () -> cca.acquireTokenSilently(SilentParameters + .builder(Collections.singleton(cfg.graphDefaultScope())) + .build()) + .get()); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenSilent_WithRefreshOn(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenSilent_WithRefreshOn(String environment) throws Exception { cfg = new Config(environment); User user = labUserProvider.getDefaultUser(cfg.azureEnvironment); @@ -236,7 +226,7 @@ public void acquireTokenSilent_WithRefreshOn(String environment) throws Exceptio assertResultNotNull(resultOriginal); IAuthenticationResult resultSilent = acquireTokenSilently(pca, resultOriginal.account(), cfg.graphDefaultScope(), false); - Assert.assertNotNull(resultSilent); + assertNotNull(resultSilent); assertTokensAreEqual(resultOriginal, resultSilent); //When this test was made, token responses did not contain the refresh_in field needed for an end-to-end test. @@ -251,8 +241,8 @@ public void acquireTokenSilent_WithRefreshOn(String environment) throws Exceptio IAuthenticationResult resultSilentWithRefreshOn = acquireTokenSilently(pca, resultOriginal.account(), cfg.graphDefaultScope(), false); //Current time is before refreshOn, so token should not have been refreshed - Assert.assertNotNull(resultSilentWithRefreshOn); - Assert.assertEquals(pca.tokenCache.accessTokens.get(key).refreshOn(), Long.toString(currTimestampSec + 60)); + assertNotNull(resultSilentWithRefreshOn); + assertEquals(pca.tokenCache.accessTokens.get(key).refreshOn(), Long.toString(currTimestampSec + 60)); assertTokensAreEqual(resultSilent, resultSilentWithRefreshOn); token = pca.tokenCache.accessTokens.get(key); @@ -261,12 +251,13 @@ public void acquireTokenSilent_WithRefreshOn(String environment) throws Exceptio resultSilentWithRefreshOn = acquireTokenSilently(pca, resultOriginal.account(), cfg.graphDefaultScope(), false); //Current time is after refreshOn, so token should be refreshed - Assert.assertNotNull(resultSilentWithRefreshOn); + assertNotNull(resultSilentWithRefreshOn); assertTokensAreNotEqual(resultSilent, resultSilentWithRefreshOn); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenSilent_TenantAsParameter(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenSilent_TenantAsParameter(String environment) throws Exception { cfg = new Config(environment); User user = labUserProvider.getDefaultUser(environment); @@ -296,8 +287,9 @@ public void acquireTokenSilent_TenantAsParameter(String environment) throws Exce assertTokensAreNotEqual(result, resultWithTenantParam); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenSilent_emptyStringScope(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenSilent_emptyStringScope(String environment) throws Exception { cfg = new Config(environment); User user = labUserProvider.getDefaultUser(environment); @@ -313,11 +305,12 @@ public void acquireTokenSilent_emptyStringScope(String environment) throws Excep IAccount account = pca.getAccounts().join().iterator().next(); IAuthenticationResult silentResult = acquireTokenSilently(pca, account, emptyScope, false); assertResultNotNull(silentResult); - Assert.assertEquals(result.accessToken(), silentResult.accessToken()); + assertEquals(result.accessToken(), silentResult.accessToken()); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenSilent_emptyScopeSet(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenSilent_emptyScopeSet(String environment) throws Exception { cfg = new Config(environment); User user = labUserProvider.getDefaultUser(environment); @@ -342,7 +335,7 @@ public void acquireTokenSilent_emptyScopeSet(String environment) throws Exceptio .get(); assertResultNotNull(silentResult); - Assert.assertEquals(result.accessToken(), silentResult.accessToken()); + assertEquals(result.accessToken(), silentResult.accessToken()); } private IConfidentialClientApplication getConfidentialClientApplications() throws Exception { @@ -368,7 +361,7 @@ private void acquireTokenSilent_returnCachedTokens(String authority) throws Exce IAuthenticationResult interactiveAuthResult = acquireTokenUsernamePassword(user, pca, cfg.graphDefaultScope()); - Assert.assertNotNull(interactiveAuthResult); + assertNotNull(interactiveAuthResult); IAuthenticationResult silentAuthResult = pca.acquireTokenSilently( SilentParameters.builder( @@ -376,8 +369,8 @@ private void acquireTokenSilent_returnCachedTokens(String authority) throws Exce .build()) .get(); - Assert.assertNotNull(silentAuthResult); - Assert.assertEquals(interactiveAuthResult.accessToken(), silentAuthResult.accessToken()); + assertNotNull(silentAuthResult); + assertEquals(interactiveAuthResult.accessToken(), silentAuthResult.accessToken()); } private IPublicClientApplication getPublicClientApplicationWithTokensInCache() @@ -414,18 +407,18 @@ private IAuthenticationResult acquireTokenUsernamePassword(User user, IPublicCli } private void assertResultNotNull(IAuthenticationResult result) { - Assert.assertNotNull(result); - Assert.assertNotNull(result.accessToken()); - Assert.assertNotNull(result.idToken()); + assertNotNull(result); + assertNotNull(result.accessToken()); + assertNotNull(result.idToken()); } private void assertTokensAreNotEqual(IAuthenticationResult result, IAuthenticationResult secondResult) { - Assert.assertNotEquals(result.accessToken(), secondResult.accessToken()); - Assert.assertNotEquals(result.idToken(), secondResult.idToken()); + assertNotEquals(result.accessToken(), secondResult.accessToken()); + assertNotEquals(result.idToken(), secondResult.idToken()); } private void assertTokensAreEqual(IAuthenticationResult result, IAuthenticationResult secondResult) { - Assert.assertEquals(result.accessToken(), secondResult.accessToken()); - Assert.assertEquals(result.idToken(), secondResult.idToken()); + assertEquals(result.accessToken(), secondResult.accessToken()); + assertEquals(result.idToken(), secondResult.idToken()); } } diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AuthorizationCodeIT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AuthorizationCodeIT.java index 26bbe6d3..8cf235a7 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AuthorizationCodeIT.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AuthorizationCodeIT.java @@ -4,10 +4,17 @@ package com.microsoft.aad.msal4j; import labapi.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.net.MalformedURLException; import java.net.URI; @@ -19,32 +26,34 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; -public class AuthorizationCodeIT extends SeleniumTest { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class AuthorizationCodeIT extends SeleniumTest { private final static Logger LOG = LoggerFactory.getLogger(AuthorizationCodeIT.class); private Config cfg; - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenWithAuthorizationCode_ManagedUser(String environment) { - cfg = new Config(environment); + @BeforeAll + public void setupUserProvider() { + setUpLapUserProvider(); + } - User user = labUserProvider.getDefaultUser(cfg.azureEnvironment); - assertAcquireTokenAAD(user, null); + @AfterEach + public void stopBrowser() { + cleanUp(); } - //TODO: Re-enable test once list of claims/capabilities and their expected behavior is known - //@Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenWithAuthorizationCode_ManagedUserWithClaimsAndCapabilities(String environment) { + @BeforeEach + public void startBrowser() { + startUpBrowser(); + } + + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + public void acquireTokenWithAuthorizationCode_ManagedUser(String environment) { cfg = new Config(environment); User user = labUserProvider.getDefaultUser(cfg.azureEnvironment); - - Map> claimsAndCapabilities = new HashMap<>(); - - claimsAndCapabilities.put("claims", Collections.singleton(TestConstants.CLAIMS)); - claimsAndCapabilities.put("clientCapabilities", TestConstants.CLIENT_CAPABILITIES_EMPTY); - - assertAcquireTokenAAD(user, claimsAndCapabilities); + assertAcquireTokenAAD(user, null); } @Test @@ -53,7 +62,8 @@ public void acquireTokenWithAuthorizationCode_ADFSv2019_OnPrem() { assertAcquireTokenADFS2019(user); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") public void acquireTokenWithAuthorizationCode_ADFSv2019_Federated(String environment) { cfg = new Config(environment); @@ -61,7 +71,8 @@ public void acquireTokenWithAuthorizationCode_ADFSv2019_Federated(String environ assertAcquireTokenAAD(user, null); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") public void acquireTokenWithAuthorizationCode_ADFSv4_Federated(String environment) { cfg = new Config(environment); @@ -70,7 +81,8 @@ public void acquireTokenWithAuthorizationCode_ADFSv4_Federated(String environmen assertAcquireTokenAAD(user, null); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") public void acquireTokenWithAuthorizationCode_ADFSv3_Federated(String environment) { cfg = new Config(environment); @@ -78,7 +90,8 @@ public void acquireTokenWithAuthorizationCode_ADFSv3_Federated(String environmen assertAcquireTokenAAD(user, null); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") public void acquireTokenWithAuthorizationCode_ADFSv2_Federated(String environment) { cfg = new Config(environment); @@ -86,7 +99,8 @@ public void acquireTokenWithAuthorizationCode_ADFSv2_Federated(String environmen assertAcquireTokenAAD(user, null); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") public void acquireTokenWithAuthorizationCode_B2C_Local(String environment) { cfg = new Config(environment); @@ -94,37 +108,6 @@ public void acquireTokenWithAuthorizationCode_B2C_Local(String environment) { assertAcquireTokenB2C(user); } - // failing on azure devOps - //@Test - // TODO Redirect URI localhost in not registered - public void acquireTokenWithAuthorizationCode_B2C_Google() { -/* LabResponse labResponse = labUserProvider.getB2cUser( - B2CIdentityProvider.GOOGLE, - false); - labUserProvider.getUserPassword(labResponse.getUser()); - - String b2CAppId = "b876a048-55a5-4fc5-9403-f5d90cb1c852"; - labResponse.setAppId(b2CAppId);*/ - User user = labUserProvider.getB2cUser(B2CProvider.GOOGLE); - assertAcquireTokenB2C(user); - } - - // TODO uncomment when lab fixes facebook test account - //@Test - // TODO Redirect URI localhost in not registered - public void acquireTokenWithAuthorizationCode_B2C_Facebook() { -/* LabResponse labResponse = labUserProvider.getB2cUser( - B2CIdentityProvider.FACEBOOK, - false); - - - String b2CAppId = "b876a048-55a5-4fc5-9403-f5d90cb1c852"; - labResponse.setAppId(b2CAppId);*/ - User user = labUserProvider.getB2cUser(B2CProvider.FACEBOOK); - - assertAcquireTokenB2C(user); - } - private void assertAcquireTokenADFS2019(User user) { PublicClientApplication pca; try { @@ -142,10 +125,10 @@ private void assertAcquireTokenADFS2019(User user) { authCode, Collections.singleton(TestConstants.ADFS_SCOPE)); - Assert.assertNotNull(result); - Assert.assertNotNull(result.accessToken()); - Assert.assertNotNull(result.idToken()); - Assert.assertEquals(user.getUpn(), result.account().username()); + assertNotNull(result); + assertNotNull(result.accessToken()); + assertNotNull(result.idToken()); + assertEquals(user.getUpn(), result.account().username()); } private void assertAcquireTokenAAD(User user, Map> parameters) { @@ -171,10 +154,10 @@ private void assertAcquireTokenAAD(User user, Map> parameter authCode, Collections.singleton(cfg.graphDefaultScope())); - Assert.assertNotNull(result); - Assert.assertNotNull(result.accessToken()); - Assert.assertNotNull(result.idToken()); - Assert.assertEquals(user.getUpn(), result.account().username()); + assertNotNull(result); + assertNotNull(result.accessToken()); + assertNotNull(result.idToken()); + assertEquals(user.getUpn(), result.account().username()); } private void assertAcquireTokenB2C(User user) { @@ -196,9 +179,9 @@ private void assertAcquireTokenB2C(User user) { String authCode = acquireAuthorizationCodeAutomated(user, cca, null); IAuthenticationResult result = acquireTokenInteractiveB2C(cca, authCode); - Assert.assertNotNull(result); - Assert.assertNotNull(result.accessToken()); - Assert.assertNotNull(result.idToken()); + assertNotNull(result); + assertNotNull(result.accessToken()); + assertNotNull(result.idToken()); } private IAuthenticationResult acquireTokenAuthorizationCodeFlow( diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AzureEnvironmentIT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AzureEnvironmentIT.java index a46c4dd0..b7d24a74 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AzureEnvironmentIT.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AzureEnvironmentIT.java @@ -4,27 +4,29 @@ package com.microsoft.aad.msal4j; import labapi.*; -import org.testng.Assert; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.BeforeAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.util.Collections; - -public class AzureEnvironmentIT { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class AzureEnvironmentIT { private LabUserProvider labUserProvider; - @BeforeClass - public void setUp() { + @BeforeAll + void setUp() { labUserProvider = LabUserProvider.getInstance(); } @Test - public void acquireTokenWithUsernamePassword_AzureChina() throws Exception { + void acquireTokenWithUsernamePassword_AzureChina() throws Exception { assertAcquireTokenCommon(AzureEnvironment.AZURE_CHINA); } @Test - public void acquireTokenWithUsernamePassword_AzureGovernment() throws Exception { + void acquireTokenWithUsernamePassword_AzureGovernment() throws Exception { assertAcquireTokenCommon(AzureEnvironment.AZURE_US_GOVERNMENT); } @@ -45,10 +47,10 @@ private void assertAcquireTokenCommon(String azureEnvironment) throws Exception .build()) .get(); - Assert.assertNotNull(result); - Assert.assertNotNull(result.accessToken()); - Assert.assertNotNull(result.idToken()); + assertNotNull(result); + assertNotNull(result.accessToken()); + assertNotNull(result.idToken()); - Assert.assertEquals(user.getUpn(), result.account().username()); + assertEquals(user.getUpn(), result.account().username()); } } diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/CachePersistenceIT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/CachePersistenceIT.java index f943a946..d6dc51b5 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/CachePersistenceIT.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/CachePersistenceIT.java @@ -4,14 +4,16 @@ import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.PlainJWT; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.IOException; import java.net.URISyntaxException; import java.util.Collections; -public class CachePersistenceIT { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class CachePersistenceIT { static class TokenPersistence implements ITokenCacheAccessAspect { String data; @@ -32,7 +34,7 @@ public void afterCacheAccess(ITokenCacheAccessContext iTokenCacheAccessContext) } @Test - public void cacheDeserializationSerializationTest() throws IOException, URISyntaxException { + void cacheDeserializationSerializationTest() throws IOException, URISyntaxException { String dataToInitCache = TestHelper.readResource(this.getClass(), "/cache_data/serialized_cache.json"); String ID_TOKEN_PLACEHOLDER = ""; @@ -50,41 +52,41 @@ public void cacheDeserializationSerializationTest() throws IOException, URISynta PublicClientApplication app = PublicClientApplication.builder("my_client_id") .setTokenCacheAccessAspect(persistenceAspect).build(); - Assert.assertEquals(app.getAccounts().join().size(), 1); - Assert.assertEquals(app.tokenCache.accounts.size(), 1); - Assert.assertEquals(app.tokenCache.accessTokens.size(), 2); - Assert.assertEquals(app.tokenCache.refreshTokens.size(), 1); - Assert.assertEquals(app.tokenCache.idTokens.size(), 1); - Assert.assertEquals(app.tokenCache.appMetadata.size(), 1); + assertEquals(app.getAccounts().join().size(), 1); + assertEquals(app.tokenCache.accounts.size(), 1); + assertEquals(app.tokenCache.accessTokens.size(), 2); + assertEquals(app.tokenCache.refreshTokens.size(), 1); + assertEquals(app.tokenCache.idTokens.size(), 1); + assertEquals(app.tokenCache.appMetadata.size(), 1); // create new instance of app to make sure in memory cache cleared app = PublicClientApplication.builder("my_client_id") .setTokenCacheAccessAspect(persistenceAspect).build(); - Assert.assertEquals(app.getAccounts().join().size(), 1); - Assert.assertEquals(app.tokenCache.accounts.size(), 1); - Assert.assertEquals(app.tokenCache.accessTokens.size(), 2); - Assert.assertEquals(app.tokenCache.refreshTokens.size(), 1); - Assert.assertEquals(app.tokenCache.idTokens.size(), 1); - Assert.assertEquals(app.tokenCache.appMetadata.size(), 1); + assertEquals(app.getAccounts().join().size(), 1); + assertEquals(app.tokenCache.accounts.size(), 1); + assertEquals(app.tokenCache.accessTokens.size(), 2); + assertEquals(app.tokenCache.refreshTokens.size(), 1); + assertEquals(app.tokenCache.idTokens.size(), 1); + assertEquals(app.tokenCache.appMetadata.size(), 1); app.removeAccount(app.getAccounts().join().iterator().next()).join(); - Assert.assertEquals(app.getAccounts().join().size(), 0); - Assert.assertEquals(app.tokenCache.accounts.size(), 0); - Assert.assertEquals(app.tokenCache.accessTokens.size(), 1); - Assert.assertEquals(app.tokenCache.refreshTokens.size(), 0); - Assert.assertEquals(app.tokenCache.idTokens.size(), 0); - Assert.assertEquals(app.tokenCache.appMetadata.size(), 1); + assertEquals(app.getAccounts().join().size(), 0); + assertEquals(app.tokenCache.accounts.size(), 0); + assertEquals(app.tokenCache.accessTokens.size(), 1); + assertEquals(app.tokenCache.refreshTokens.size(), 0); + assertEquals(app.tokenCache.idTokens.size(), 0); + assertEquals(app.tokenCache.appMetadata.size(), 1); app = PublicClientApplication.builder("my_client_id") .setTokenCacheAccessAspect(persistenceAspect).build(); - Assert.assertEquals(app.getAccounts().join().size(), 0); - Assert.assertEquals(app.tokenCache.accounts.size(), 0); - Assert.assertEquals(app.tokenCache.accessTokens.size(), 1); - Assert.assertEquals(app.tokenCache.refreshTokens.size(), 0); - Assert.assertEquals(app.tokenCache.idTokens.size(), 0); - Assert.assertEquals(app.tokenCache.appMetadata.size(), 1); + assertEquals(app.getAccounts().join().size(), 0); + assertEquals(app.tokenCache.accounts.size(), 0); + assertEquals(app.tokenCache.accessTokens.size(), 1); + assertEquals(app.tokenCache.refreshTokens.size(), 0); + assertEquals(app.tokenCache.idTokens.size(), 0); + assertEquals(app.tokenCache.appMetadata.size(), 1); } } diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/ClientCredentialsIT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/ClientCredentialsIT.java index e5c5d157..16f01193 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/ClientCredentialsIT.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/ClientCredentialsIT.java @@ -6,11 +6,12 @@ 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; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.BeforeAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.io.IOException; import java.security.KeyStoreException; @@ -25,25 +26,25 @@ import static com.microsoft.aad.msal4j.TestConstants.KEYVAULT_DEFAULT_SCOPE; -@Test -public class ClientCredentialsIT { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class ClientCredentialsIT { private IClientCertificate certificate; private LabUserProvider labUserProvider; - @BeforeClass + @BeforeAll void init() throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException, NoSuchProviderException, IOException { certificate = CertificateHelper.getClientCertificate(); labUserProvider = LabUserProvider.getInstance(); } @Test - public void acquireTokenClientCredentials_ClientCertificate() throws Exception { + void acquireTokenClientCredentials_ClientCertificate() throws Exception { String clientId = "2afb0add-2f32-4946-ac90-81a02aa4550e"; assertAcquireTokenCommon(clientId, certificate, TestConstants.MICROSOFT_AUTHORITY); } @Test - public void acquireTokenClientCredentials_ClientSecret() throws Exception { + void acquireTokenClientCredentials_ClientSecret() throws Exception { AppCredentialProvider appProvider = new AppCredentialProvider(AzureEnvironment.AZURE); final String clientId = appProvider.getLabVaultAppId(); final String password = appProvider.getLabVaultPassword(); @@ -53,7 +54,7 @@ public void acquireTokenClientCredentials_ClientSecret() throws Exception { } @Test - public void acquireTokenClientCredentials_ClientAssertion() throws Exception { + void acquireTokenClientCredentials_ClientAssertion() throws Exception { String clientId = "2afb0add-2f32-4946-ac90-81a02aa4550e"; ClientAssertion clientAssertion = getClientAssertion(clientId); @@ -64,35 +65,7 @@ public void acquireTokenClientCredentials_ClientAssertion() throws Exception { } @Test - public void acquireTokenClientCredentials_ClientSecret_Ciam() throws Exception { - - User user = labUserProvider.getCiamUser(); - String clientId = user.getAppId(); - - Map 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); - } - - @Test - public void acquireTokenClientCredentials_Callback() throws Exception { + void acquireTokenClientCredentials_Callback() throws Exception { String clientId = "2afb0add-2f32-4946-ac90-81a02aa4550e"; // Creates a valid client assertion using a callback, and uses it to build the client app and make a request @@ -116,7 +89,7 @@ public void acquireTokenClientCredentials_Callback() throws Exception { } @Test - public void acquireTokenClientCredentials_DefaultCacheLookup() throws Exception { + void acquireTokenClientCredentials_DefaultCacheLookup() throws Exception { AppCredentialProvider appProvider = new AppCredentialProvider(AzureEnvironment.AZURE); final String clientId = appProvider.getLabVaultAppId(); final String password = appProvider.getLabVaultPassword(); @@ -132,15 +105,15 @@ public void acquireTokenClientCredentials_DefaultCacheLookup() throws Exception .build()) .get(); - Assert.assertNotNull(result1); - Assert.assertNotNull(result1.accessToken()); + assertNotNull(result1); + assertNotNull(result1.accessToken()); IAuthenticationResult result2 = cca.acquireToken(ClientCredentialParameters .builder(Collections.singleton(KEYVAULT_DEFAULT_SCOPE)) .build()) .get(); - Assert.assertEquals(result1.accessToken(), result2.accessToken()); + assertEquals(result1.accessToken(), result2.accessToken()); IAuthenticationResult result3 = cca.acquireToken(ClientCredentialParameters .builder(Collections.singleton(KEYVAULT_DEFAULT_SCOPE)) @@ -148,22 +121,16 @@ public void acquireTokenClientCredentials_DefaultCacheLookup() throws Exception .build()) .get(); - Assert.assertNotNull(result3); - Assert.assertNotNull(result3.accessToken()); - Assert.assertNotEquals(result2.accessToken(), result3.accessToken()); - } - - @DataProvider(name = "regionWithAuthority") - public static Object[][] createData() { - return new Object[][]{{"westus", TestConstants.REGIONAL_MICROSOFT_AUTHORITY_BASIC_HOST_WESTUS}, - {"eastus", TestConstants.REGIONAL_MICROSOFT_AUTHORITY_BASIC_HOST_EASTUS}}; + assertNotNull(result3); + assertNotNull(result3.accessToken()); + assertNotEquals(result2.accessToken(), result3.accessToken()); } - @Test(dataProvider = "regionWithAuthority") - public void acquireTokenClientCredentials_Regional(String[] regionWithAuthority) throws Exception { + @Test + void acquireTokenClientCredentials_Regional() throws Exception { String clientId = "2afb0add-2f32-4946-ac90-81a02aa4550e"; - assertAcquireTokenCommon_withRegion(clientId, certificate, regionWithAuthority[0], regionWithAuthority[1]); + assertAcquireTokenCommon_withRegion(clientId, certificate, "westus", TestConstants.REGIONAL_MICROSOFT_AUTHORITY_BASIC_HOST_WESTUS); } private ClientAssertion getClientAssertion(String clientId) { return JwtHelper.buildJwt( @@ -184,8 +151,8 @@ private void assertAcquireTokenCommon(String clientId, IClientCredential credent .build()) .get(); - Assert.assertNotNull(result); - Assert.assertNotNull(result.accessToken()); + assertNotNull(result); + assertNotNull(result.accessToken()); } private void assertAcquireTokenCommon_withParameters(String clientId, IClientCredential credential, IClientCredential credentialParam) throws Exception { @@ -200,8 +167,8 @@ private void assertAcquireTokenCommon_withParameters(String clientId, IClientCre .build()) .get(); - Assert.assertNotNull(result); - Assert.assertNotNull(result.accessToken()); + assertNotNull(result); + assertNotNull(result.accessToken()); } private void assertAcquireTokenCommon_withRegion(String clientId, IClientCredential credential, String region, String regionalAuthority) throws Exception { @@ -221,9 +188,9 @@ private void assertAcquireTokenCommon_withRegion(String clientId, IClientCredent .build()) .get(); - Assert.assertNotNull(resultNoRegion); - Assert.assertNotNull(resultNoRegion.accessToken()); - Assert.assertEquals(resultNoRegion.environment(), TestConstants.MICROSOFT_AUTHORITY_BASIC_HOST); + assertNotNull(resultNoRegion); + assertNotNull(resultNoRegion.accessToken()); + assertEquals(TestConstants.MICROSOFT_AUTHORITY_BASIC_HOST, resultNoRegion.environment()); //Ensure regional tokens are properly cached and retrievable IAuthenticationResult resultRegion = ccaRegion.acquireToken(ClientCredentialParameters @@ -231,18 +198,18 @@ private void assertAcquireTokenCommon_withRegion(String clientId, IClientCredent .build()) .get(); - Assert.assertNotNull(resultRegion); - Assert.assertNotNull(resultRegion.accessToken()); - Assert.assertEquals(resultRegion.environment(), regionalAuthority); + assertNotNull(resultRegion); + assertNotNull(resultRegion.accessToken()); + assertEquals(resultRegion.environment(), regionalAuthority); IAuthenticationResult resultRegionCached = ccaRegion.acquireToken(ClientCredentialParameters .builder(Collections.singleton(KEYVAULT_DEFAULT_SCOPE)) .build()) .get(); - Assert.assertNotNull(resultRegionCached); - Assert.assertNotNull(resultRegionCached.accessToken()); - Assert.assertEquals(resultRegionCached.accessToken(), resultRegion.accessToken()); + assertNotNull(resultRegionCached); + assertNotNull(resultRegionCached.accessToken()); + assertEquals(resultRegionCached.accessToken(), resultRegion.accessToken()); //Tokens retrieved from regional endpoints should be interchangeable with non-regional, and vice-versa //For example, if an application doesn't configure a region but gets regional tokens added to its cache, they should be retrievable @@ -252,8 +219,8 @@ private void assertAcquireTokenCommon_withRegion(String clientId, IClientCredent .build()) .get(); - Assert.assertNotNull(resultNoRegion); - Assert.assertNotNull(resultNoRegion.accessToken()); - Assert.assertEquals(resultNoRegion.accessToken(), resultRegion.accessToken()); + assertNotNull(resultNoRegion); + assertNotNull(resultNoRegion.accessToken()); + assertEquals(resultNoRegion.accessToken(), resultRegion.accessToken()); } } diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/ConfidentialClientApplicationUnitT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/ConfidentialClientApplicationUnitT.java deleted file mode 100644 index 5624c60c..00000000 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/ConfidentialClientApplicationUnitT.java +++ /dev/null @@ -1,421 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.microsoft.aad.msal4j; - -import com.nimbusds.jose.JOSEException; -import com.nimbusds.jose.JWSAlgorithm; -import com.nimbusds.jose.JWSHeader; -import com.nimbusds.jose.crypto.RSASSASigner; -import com.nimbusds.jose.util.Base64; -import com.nimbusds.jose.util.Base64URL; -import com.nimbusds.jwt.JWTClaimsSet; -import com.nimbusds.jwt.SignedJWT; -import com.nimbusds.oauth2.sdk.auth.JWTAuthentication; -import com.nimbusds.oauth2.sdk.auth.PrivateKeyJWT; -import org.easymock.Capture; -import org.easymock.EasyMock; -import org.powermock.api.easymock.PowerMock; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.testng.PowerMockTestCase; -import org.testng.Assert; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - -import java.io.IOException; -import java.net.URI; -import java.net.URLEncoder; -import java.security.*; -import java.security.cert.CertificateException; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; - -import static com.microsoft.aad.msal4j.TestConstants.KEYVAULT_DEFAULT_SCOPE; -import static org.easymock.EasyMock.*; -import static org.testng.Assert.*; - -@PowerMockIgnore({"javax.net.ssl.*"}) -@PrepareForTest({ConfidentialClientApplication.class, - ClientCertificate.class, UserDiscoveryRequest.class, JwtHelper.class}) -public class ConfidentialClientApplicationUnitT extends PowerMockTestCase { - - private ConfidentialClientApplication app = null; - private IClientCertificate clientCertificate; - - @BeforeClass - private void init() throws - KeyStoreException, IOException, NoSuchAlgorithmException, - CertificateException, UnrecoverableKeyException, NoSuchProviderException { - - clientCertificate = CertificateHelper.getClientCertificate(); - } - - @Test - public void testAcquireTokenAuthCode_ClientCredential() throws Exception { - app = PowerMock.createPartialMock(ConfidentialClientApplication.class, - new String[]{"acquireTokenCommon"}, - ConfidentialClientApplication.builder(TestConfiguration.AAD_CLIENT_ID, - ClientCredentialFactory.createFromSecret(TestConfiguration.AAD_CLIENT_DUMMYSECRET)) - .authority(TestConfiguration.AAD_TENANT_ENDPOINT) - ); - - PowerMock.expectPrivate(app, "acquireTokenCommon", - EasyMock.isA(MsalRequest.class), - EasyMock.isA(AADAuthority.class)).andReturn( - AuthenticationResult.builder(). - accessToken("accessToken"). - expiresOn(new Date().getTime() + 100). - refreshToken("refreshToken"). - idToken("idToken").environment("environment").build()); - - PowerMock.replay(app); - - AuthorizationCodeParameters parameters = AuthorizationCodeParameters.builder - ("auth_code", - new URI(TestConfiguration.AAD_DEFAULT_REDIRECT_URI)) - .scopes(Collections.singleton("default-scope")) - .build(); - - Future result = app.acquireToken(parameters); - - IAuthenticationResult ar = result.get(); - Assert.assertNotNull(ar); - PowerMock.verifyAll(); - } - - @Test - public void testAcquireTokenAuthCode_KeyCredential() throws Exception { - app = PowerMock.createPartialMock(ConfidentialClientApplication.class, - new String[]{"acquireTokenCommon"}, - ConfidentialClientApplication.builder(TestConfiguration.AAD_CLIENT_ID, clientCertificate) - .authority(TestConfiguration.AAD_TENANT_ENDPOINT)); - - PowerMock.expectPrivate(app, "acquireTokenCommon", - EasyMock.isA(MsalRequest.class), - EasyMock.isA(AADAuthority.class)).andReturn( - AuthenticationResult.builder(). - accessToken("accessToken"). - expiresOn(new Date().getTime() + 100). - refreshToken("refreshToken"). - idToken("idToken").environment("environment").build()); - - PowerMock.replay(app); - - AuthorizationCodeParameters parameters = AuthorizationCodeParameters.builder - ("auth_code", - new URI(TestConfiguration.AAD_DEFAULT_REDIRECT_URI)) - .scopes(Collections.singleton("default-scope")) - .build(); - - Future result = app.acquireToken(parameters); - - IAuthenticationResult ar = result.get(); - Assert.assertNotNull(ar); - PowerMock.verifyAll(); - PowerMock.resetAll(app); - } - - @Test - public void testAcquireToken_KeyCred() throws Exception { - app = PowerMock.createPartialMock(ConfidentialClientApplication.class, - new String[]{"acquireTokenCommon"}, - ConfidentialClientApplication.builder(TestConfiguration.AAD_CLIENT_ID, clientCertificate) - .authority(TestConfiguration.AAD_TENANT_ENDPOINT)); - - PowerMock.expectPrivate(app, "acquireTokenCommon", - EasyMock.isA(MsalRequest.class), - EasyMock.isA(AADAuthority.class)).andReturn( - AuthenticationResult.builder(). - accessToken("accessToken"). - expiresOn(new Date().getTime() + 100). - refreshToken("refreshToken"). - idToken("idToken").environment("environment").build()); - - PowerMock.replay(app); - - ClientCredentialParameters parameters = ClientCredentialParameters.builder( - Collections.singleton(TestConfiguration.AAD_RESOURCE_ID)) - .build(); - - Future result = app.acquireToken(parameters); - - IAuthenticationResult ar = result.get(); - assertNotNull(ar); - assertFalse(StringHelper.isBlank(result.get().accessToken())); - PowerMock.verifyAll(); - PowerMock.resetAll(app); - } - - @Test - public void testClientCertificateRebuildsWhenExpired() throws Exception { - PowerMock.mockStaticPartial(JwtHelper.class, "buildJwt"); - long jwtExperiationPeriodMilli = 2000; - ClientAssertion shortExperationJwt = buildShortJwt(TestConfiguration.AAD_CLIENT_ID, - clientCertificate, - TestConfiguration.AAD_TENANT_ENDPOINT, - jwtExperiationPeriodMilli); - - PowerMock.expectPrivate( - JwtHelper.class, - "buildJwt", - EasyMock.isA(String.class), - EasyMock.isA(ClientCertificate.class), - EasyMock.isA(String.class), - EasyMock.anyBoolean()) - .andReturn(shortExperationJwt) - .times(2); // By this being called twice we ensure the client assertion is rebuilt once it has expired - - PowerMock.replay(JwtHelper.class); - app = ConfidentialClientApplication.builder(TestConfiguration.AAD_CLIENT_ID, clientCertificate) - .authority(TestConfiguration.AAD_TENANT_ENDPOINT).build(); - Thread.sleep(jwtExperiationPeriodMilli + 1000); //Have to sleep to ensure that the time period has passed - final PrivateKeyJWT clientAuthentication = (PrivateKeyJWT) app.clientAuthentication(); - assertNotNull(clientAuthentication); - PowerMock.verifyAll(); - } - - private ClientAssertion buildShortJwt(String clientId, - IClientCertificate credential, - String jwtAudience, - long jwtExperiationPeriod) { - final long time = System.currentTimeMillis(); - final JWTClaimsSet claimsSet = new JWTClaimsSet.Builder() - .audience(Collections.singletonList(jwtAudience)) - .issuer(clientId) - .jwtID(UUID.randomUUID().toString()) - .notBeforeTime(new Date(time)) - .expirationTime(new Date(time + jwtExperiationPeriod)) - .subject(clientId) - .build(); - SignedJWT jwt; - try { - JWSHeader.Builder builder = new JWSHeader.Builder(JWSAlgorithm.RS256); - - List certs = new ArrayList<>(); - for (String cert : credential.getEncodedPublicKeyCertificateChain()) { - certs.add(new Base64(cert)); - } - builder.x509CertChain(certs); - - builder.x509CertThumbprint(new Base64URL(credential.publicCertificateHash())); - - jwt = new SignedJWT(builder.build(), claimsSet); - final RSASSASigner signer = new RSASSASigner(credential.privateKey()); - jwt.sign(signer); - } catch (final Exception e) { - throw new MsalClientException(e); - } - return new ClientAssertion(jwt.serialize()); - } - - @Test - public void testClientAssertion_noException() throws Exception{ - SignedJWT jwt = createClientAssertion("issuer"); - - ClientAssertion clientAssertion = new ClientAssertion(jwt.serialize()); - - IClientCredential iClientCredential = ClientCredentialFactory.createFromClientAssertion( - clientAssertion.assertion()); - - ConfidentialClientApplication app = ConfidentialClientApplication - .builder(TestConfiguration.AAD_CLIENT_ID, iClientCredential) - .authority(TestConfiguration.AAD_TENANT_ENDPOINT) - .build(); - - Assert.assertEquals(app.clientId(),TestConfiguration.AAD_CLIENT_ID); - Assert.assertTrue(app.sendX5c()); - - } - - @Test - public void testClientAssertion_acquireToken() throws Exception{ - SignedJWT jwt = createClientAssertion("issuer"); - - ClientAssertion clientAssertion = new ClientAssertion(jwt.serialize()); - ConfidentialClientApplication app = ConfidentialClientApplication - .builder(TestConfiguration.AAD_CLIENT_ID, ClientCredentialFactory.createFromClientAssertion(clientAssertion.assertion())) - .authority(TestConfiguration.AAD_TENANT_ENDPOINT) - .build(); - - String scope = "requestedScope"; - ClientCredentialRequest clientCredentialRequest = getClientCredentialRequest(app, scope); - - IHttpClient httpClientMock = EasyMock.mock(IHttpClient.class); - Capture captureSingleArgument = newCapture(); - expect(httpClientMock.send(capture(captureSingleArgument))).andReturn(new HttpResponse()); - EasyMock.replay(httpClientMock); - - TokenRequestExecutor tokenRequestExecutor = new TokenRequestExecutor(app.authenticationAuthority, clientCredentialRequest, mockedServiceBundle(httpClientMock)); - try { - tokenRequestExecutor.executeTokenRequest(); - } catch(Exception e) { - //Ignored, we only want to check the request that was send. - } - HttpRequest value = captureSingleArgument.getValue(); - String body = value.body(); - Assert.assertTrue(body.contains("grant_type=client_credentials")); - Assert.assertTrue(body.contains("client_assertion=" + clientAssertion.assertion())); - Assert.assertTrue(body.contains("client_assertion_type=" + URLEncoder.encode(JWTAuthentication.CLIENT_ASSERTION_TYPE, "utf-8"))); - Assert.assertTrue(body.contains("scope=" + URLEncoder.encode("openid profile offline_access " + scope, "utf-8"))); - Assert.assertTrue(body.contains("client_id=" + TestConfiguration.AAD_CLIENT_ID)); - Assert.assertTrue(body.contains("test=test")); - Assert.assertTrue(body.contains("id_token_hint=token_hint_value")); - } - - private ServiceBundle mockedServiceBundle(IHttpClient httpClientMock) { - ServiceBundle serviceBundle = new ServiceBundle( - null, - httpClientMock, - new TelemetryManager(null, false)); - return serviceBundle; - } - - private ClientCredentialRequest getClientCredentialRequest(ConfidentialClientApplication app, String scope) { - Set scopes = new HashSet<>(); - scopes.add(scope); - - Map extraQueryParameters = new HashMap<>(); - extraQueryParameters.put("id_token_hint", "token_hint_value"); - extraQueryParameters.put("test", "test"); - - ClientCredentialParameters clientCredentials = ClientCredentialParameters.builder(scopes) - .tenant(IdToken.TENANT_IDENTIFIER) - .extraQueryParameters(extraQueryParameters) - .build(); - RequestContext requestContext = new RequestContext( - app, - PublicApi.ACQUIRE_TOKEN_FOR_CLIENT, - clientCredentials); - - return new ClientCredentialRequest( - clientCredentials, - app, - requestContext); - } - - @Test(expectedExceptions = MsalClientException.class) - public void testClientAssertion_throwsException() throws Exception{ - SignedJWT jwt = createClientAssertion(null); - - ClientAssertion clientAssertion = new ClientAssertion(jwt.serialize()); - - IClientCredential iClientCredential = ClientCredentialFactory.createFromClientAssertion( - clientAssertion.assertion()); - - ConfidentialClientApplication.builder(TestConfiguration.AAD_CLIENT_ID, iClientCredential).authority(TestConfiguration.AAD_TENANT_ENDPOINT).build(); - - } - - @Test - public void validateAppTokenProviderAsync() throws Exception{ - - SignedJWT jwt = createClientAssertion("issuer"); - - ClientAssertion clientAssertion = new ClientAssertion(jwt.serialize()); - - IClientCredential iClientCredential = ClientCredentialFactory.createFromClientAssertion( - clientAssertion.assertion()); - - Long refreshInSeconds = new Date().getTime() / 1000 + + 800000; - //builds client with AppTokenProvider - ConfidentialClientApplication cca = ConfidentialClientApplication. - builder(TestConfiguration.AAD_CLIENT_ID, iClientCredential) - .appTokenProvider((parameters) -> { - Assert.assertNotNull(parameters.scopes); - Assert.assertNotNull(parameters.correlationId); - Assert.assertNotNull(parameters.tenantId); - return getAppTokenProviderResult("/default", refreshInSeconds); - }) - .build(); - - IAuthenticationResult result1 = cca.acquireToken(ClientCredentialParameters - .builder(Collections.singleton(KEYVAULT_DEFAULT_SCOPE)) - .tenant("tenant1") - .build()) - .get(); - - Assert.assertNotNull(result1.accessToken()); - - Assert.assertEquals(cca.tokenCache.accessTokens.size(), 1); - //check that refreshOn is set correctly when provided by an app developer - Assert.assertNotNull(cca.tokenCache.accessTokens.values().iterator().next().refreshOn()); - Assert.assertEquals(cca.tokenCache.accessTokens.values().iterator().next().refreshOn(), refreshInSeconds.toString()); - System.out.println(cca.tokenCache.accessTokens.values().iterator().next().refreshOn()); - - //Acquire token from cache - - IAuthenticationResult result2 = cca.acquireToken(ClientCredentialParameters - .builder(Collections.singleton(KEYVAULT_DEFAULT_SCOPE)) - .build()) - .get(); - - Assert.assertEquals(result1.accessToken(), result2.accessToken()); - - Assert.assertEquals(cca.tokenCache.accessTokens.size(), 1); - - cca = ConfidentialClientApplication. - builder(TestConfiguration.AAD_CLIENT_ID, iClientCredential) - .appTokenProvider((parameters) -> { - Assert.assertNotNull(parameters.scopes); - Assert.assertNotNull(parameters.correlationId); - Assert.assertNotNull(parameters.tenantId); - return getAppTokenProviderResult("/newScope", 0L); - }) - .build(); - - IAuthenticationResult result3 = cca.acquireToken(ClientCredentialParameters - .builder(Collections.singleton("/newScope")) - .tenant("tenant1") -// .claims(new ClaimsRequest().formatAsClaimsRequest(TestConstants.CLAIMS)) - .build()) - .get(); - - Assert.assertNotEquals(result2.accessToken(), result3.accessToken()); - Assert.assertEquals(cca.tokenCache.accessTokens.size(), 1); - //check that refreshOn is set correctly when a value is not provided by an app developer - Assert.assertNotNull(cca.tokenCache.accessTokens.values().iterator().next().refreshOn()); - System.out.println(cca.tokenCache.accessTokens.values().iterator().next().refreshOn()); - } - - private CompletableFuture getAppTokenProviderResult(String differentScopesForAt, - long refreshInSeconds) - { - long currTimestampSec = new Date().getTime() / 1000; - TokenProviderResult token = new TokenProviderResult(); - token.setAccessToken(TestConstants.DEFAULT_ACCESS_TOKEN + differentScopesForAt); //Used to indicate that there is a new access token for a different set of scopes - token.setTenantId("tenantId"); - token.setExpiresInSeconds(currTimestampSec + 1000000); - token.setRefreshInSeconds(refreshInSeconds); - - return CompletableFuture.completedFuture(token); - } - - private SignedJWT createClientAssertion(String issuer) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, NoSuchProviderException, JOSEException { - IClientCertificate certificate = CertificateHelper.getClientCertificate(); - - final ClientCertificate credential = (ClientCertificate) certificate; - - final JWTClaimsSet claimsSet = new JWTClaimsSet.Builder() - .issuer(issuer) - .subject("subject") - .build(); - - SignedJWT jwt; - JWSHeader.Builder builder = new JWSHeader.Builder(JWSAlgorithm.RS256); - - List certs = new ArrayList<>(); - for (String cert : credential.getEncodedPublicKeyCertificateChain()) { - certs.add(new Base64(cert)); - } - builder.x509CertChain(certs); - - jwt = new SignedJWT(builder.build(), claimsSet); - final RSASSASigner signer = new RSASSASigner(credential.privateKey()); - - jwt.sign(signer); - return jwt; - } - -} diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/DeviceCodeIT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/DeviceCodeIT.java index 4b1d10d1..edd3c8a4 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/DeviceCodeIT.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/DeviceCodeIT.java @@ -10,30 +10,33 @@ import org.openqa.selenium.WebElement; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.testng.Assert; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; -import org.testng.util.Strings; - +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.AfterAll; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.util.Collections; import java.util.function.Consumer; -@Test -public class DeviceCodeIT { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class DeviceCodeIT { private final static Logger LOG = LoggerFactory.getLogger(DeviceCodeIT.class); private LabUserProvider labUserProvider; private WebDriver seleniumDriver; - @BeforeClass - public void setUp() { + @BeforeAll + void setUp() { labUserProvider = LabUserProvider.getInstance(); seleniumDriver = SeleniumExtensions.createDefaultWebDriver(); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void DeviceCodeFlowADTest(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void DeviceCodeFlowADTest(String environment) throws Exception { Config cfg = new Config(environment); User user = labUserProvider.getDefaultUser(cfg.azureEnvironment); @@ -51,12 +54,12 @@ public void DeviceCodeFlowADTest(String environment) throws Exception { .build()) .get(); - Assert.assertNotNull(result); - Assert.assertFalse(Strings.isNullOrEmpty(result.accessToken())); + assertNotNull(result); + assertNotNull(result.accessToken()); } @Test() - public void DeviceCodeFlowADFSv2019Test() throws Exception { + void DeviceCodeFlowADFSv2019Test() throws Exception { User user = labUserProvider.getOnPremAdfsUser(FederationProvider.ADFS_2019); @@ -75,12 +78,12 @@ public void DeviceCodeFlowADFSv2019Test() throws Exception { .build()) .get(); - Assert.assertNotNull(result); - Assert.assertFalse(Strings.isNullOrEmpty(result.accessToken())); + assertNotNull(result); + assertNotNull(result.accessToken()); } @Test() - public void DeviceCodeFlowMSATest() throws Exception { + void DeviceCodeFlowMSATest() throws Exception { User user = labUserProvider.getMSAUser(); @@ -99,39 +102,16 @@ public void DeviceCodeFlowMSATest() throws Exception { .build()) .get(); - Assert.assertNotNull(result); - Assert.assertFalse(Strings.isNullOrEmpty(result.accessToken())); + assertNotNull(result); + assertNotNull(result.accessToken()); result = pca.acquireTokenSilently(SilentParameters. builder(Collections.singleton(""), result.account()). build()) .get(); - Assert.assertNotNull(result); - Assert.assertFalse(Strings.isNullOrEmpty(result.accessToken())); - } - - @Test - public void DeviceCodeFlowCiamTest() throws Exception { - User user = labUserProvider.getCiamUser(); - - PublicClientApplication pca = PublicClientApplication.builder( - user.getAppId()). - authority("https://" + user.getLabName() + ".ciamlogin.com/"). - build(); - - Consumer deviceCodeConsumer = (DeviceCode deviceCode) -> { - runAutomatedDeviceCodeFlow(deviceCode, user); - }; - - IAuthenticationResult result = pca.acquireToken(DeviceCodeFlowParameters - .builder(Collections.singleton(""), - deviceCodeConsumer) - .build()) - .get(); - - Assert.assertNotNull(result); - Assert.assertFalse(Strings.isNullOrEmpty(result.accessToken())); + assertNotNull(result); + assertNotNull(result.accessToken()); } private void runAutomatedDeviceCodeFlow(DeviceCode deviceCode, User user) { @@ -183,8 +163,8 @@ private void runAutomatedDeviceCodeFlow(DeviceCode deviceCode, User user) { } } - @AfterClass - public void cleanUp() { + @AfterAll + void cleanUp() { if (seleniumDriver != null) { seleniumDriver.close(); } diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/EnvironmentsProvider.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/EnvironmentsProvider.java index 22b40ff2..f27c69f4 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/EnvironmentsProvider.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/EnvironmentsProvider.java @@ -4,10 +4,8 @@ package com.microsoft.aad.msal4j; import labapi.AzureEnvironment; -import org.testng.annotations.DataProvider; public class EnvironmentsProvider { - @DataProvider(name = "environments") public static Object[][] createData() { return new Object[][]{ {AzureEnvironment.AZURE}, diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/HttpClientIT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/HttpClientIT.java index 3bbbf4f7..edc82ef3 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/HttpClientIT.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/HttpClientIT.java @@ -5,28 +5,31 @@ import labapi.LabUserProvider; import labapi.User; -import org.testng.Assert; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.BeforeAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.util.Collections; -public class HttpClientIT { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class HttpClientIT { private LabUserProvider labUserProvider; - @BeforeClass - public void setUp() { + @BeforeAll + void setUp() { labUserProvider = LabUserProvider.getInstance(); } @Test - public void acquireToken_okHttpClient() throws Exception { + void acquireToken_okHttpClient() throws Exception { User user = labUserProvider.getDefaultUser(); assertAcquireTokenCommon(user, new OkHttpClientAdapter()); } @Test - public void acquireToken_apacheHttpClient() throws Exception { + void acquireToken_apacheHttpClient() throws Exception { User user = labUserProvider.getDefaultUser(); assertAcquireTokenCommon(user, new ApacheHttpClientAdapter()); } @@ -46,9 +49,9 @@ private void assertAcquireTokenCommon(User user, IHttpClient httpClient) .build()) .get(); - Assert.assertNotNull(result); - Assert.assertNotNull(result.accessToken()); - Assert.assertNotNull(result.idToken()); - Assert.assertEquals(user.getUpn(), result.account().username()); + assertNotNull(result); + assertNotNull(result.accessToken()); + assertNotNull(result.idToken()); + assertEquals(user.getUpn(), result.account().username()); } } diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/InstanceDiscoveryTest.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/InstanceDiscoveryTest.java deleted file mode 100644 index 57bc8fb3..00000000 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/InstanceDiscoveryTest.java +++ /dev/null @@ -1,235 +0,0 @@ -package com.microsoft.aad.msal4j; - -import org.easymock.Capture; -import org.easymock.EasyMock; -import org.powermock.api.easymock.PowerMock; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.testng.Assert; -import org.testng.IObjectFactory; -import org.testng.annotations.DataProvider; -import org.testng.annotations.ObjectFactory; -import org.testng.annotations.Test; - -import java.net.URI; -import java.util.Collections; -import java.util.Date; -import java.util.concurrent.CompletableFuture; - -@PrepareForTest({HttpHelper.class, PublicClientApplication.class}) -public class InstanceDiscoveryTest { - - private PublicClientApplication app; - - @ObjectFactory - public IObjectFactory getObjectFactory() { - return new org.powermock.modules.testng.PowerMockObjectFactory(); - } - - @DataProvider(name = "aadClouds") - private static Object[][] getAadClouds(){ - return new Object[][] {{"https://login.microsoftonline.com/common"} , // #Known to Microsoft - {"https://private.cloud/foo"}//Private Cloud - }; - } - - /** - * when instance_discovery flag is set to true (by default), an instance_discovery is performed for authorityType = AAD - */ - @Test( dataProvider = "aadClouds") - public void aadInstanceDiscoveryTrue(String authority) throws Exception{ - app = PowerMock.createPartialMock(PublicClientApplication.class, - new String[]{"acquireTokenCommon"}, - PublicClientApplication.builder(TestConfiguration.AAD_CLIENT_ID) - .authority(authority)); - - Capture capturedMsalRequest = Capture.newInstance(); - - PowerMock.expectPrivate(app, "acquireTokenCommon", - EasyMock.capture(capturedMsalRequest), EasyMock.isA(AADAuthority.class)).andReturn( - AuthenticationResult.builder(). - accessToken("accessToken"). - expiresOn(new Date().getTime() + 100). - refreshToken("refreshToken"). - idToken("idToken").environment("environment").build()); - - PowerMock.mockStatic(HttpHelper.class); - - HttpResponse instanceDiscoveryResponse = new HttpResponse(); - instanceDiscoveryResponse.statusCode(200); - instanceDiscoveryResponse.body(TestConfiguration.INSTANCE_DISCOVERY_RESPONSE); - - Capture capturedHttpRequest = Capture.newInstance(); - - EasyMock.expect( - HttpHelper.executeHttpRequest( - EasyMock.capture(capturedHttpRequest), - EasyMock.isA(RequestContext.class), - EasyMock.isA(ServiceBundle.class))) - .andReturn(instanceDiscoveryResponse); - - PowerMock.replay(HttpHelper.class, HttpResponse.class); - - CompletableFuture completableFuture = app.acquireToken( - AuthorizationCodeParameters.builder - ("auth_code", - new URI(TestConfiguration.AAD_DEFAULT_REDIRECT_URI)) - .scopes(Collections.singleton("default-scope")) - .build()); - - completableFuture.get(); - Assert.assertEquals(capturedHttpRequest.getValues().size(),1); - - } - - /** - * when instance_discovery flag is set to false, instance_discovery is not performed - */ - @Test (dataProvider = "aadClouds") - public void aadInstanceDiscoveryFalse(String authority) throws Exception { - - app = PowerMock.createPartialMock(PublicClientApplication.class, - new String[]{"acquireTokenCommon"}, - PublicClientApplication.builder(TestConfiguration.AAD_CLIENT_ID) - .authority(authority) - .instanceDiscovery(false)); - - Capture capturedMsalRequest = Capture.newInstance(); - - PowerMock.expectPrivate(app, "acquireTokenCommon", - EasyMock.capture(capturedMsalRequest), EasyMock.isA(AADAuthority.class)).andReturn( - AuthenticationResult.builder(). - accessToken("accessToken"). - expiresOn(new Date().getTime() + 100). - refreshToken("refreshToken"). - idToken("idToken").environment("environment").build()); - - PowerMock.mockStatic(HttpHelper.class); - - HttpResponse instanceDiscoveryResponse = new HttpResponse(); - instanceDiscoveryResponse.statusCode(200); - instanceDiscoveryResponse.body(TestConfiguration.INSTANCE_DISCOVERY_RESPONSE); - - Capture capturedHttpRequest = Capture.newInstance(); - - EasyMock.expect( - HttpHelper.executeHttpRequest( - EasyMock.capture(capturedHttpRequest), - EasyMock.isA(RequestContext.class), - EasyMock.isA(ServiceBundle.class))) - .andReturn(instanceDiscoveryResponse); - - PowerMock.replay(HttpHelper.class, HttpResponse.class); - - CompletableFuture completableFuture = app.acquireToken( - AuthorizationCodeParameters.builder - ("auth_code", - new URI(TestConfiguration.AAD_DEFAULT_REDIRECT_URI)) - .scopes(Collections.singleton("default-scope")) - .build()); - - completableFuture.get(); - Assert.assertEquals(capturedHttpRequest.getValues().size(),0); - } - - /** - * when instance_discovery flag is set to true (by default), an instance_discovery is NOT performed for adfs. - */ - @Test - public void adfsInstanceDiscoveryTrue() throws Exception{ - app = PowerMock.createPartialMock(PublicClientApplication.class, - new String[]{"acquireTokenCommon"}, - PublicClientApplication.builder(TestConstants.ADFS_APP_ID) - .authority("https://contoso.com/adfs") - .instanceDiscovery(true)); - - Capture capturedMsalRequest = Capture.newInstance(); - - PowerMock.expectPrivate(app, "acquireTokenCommon", - EasyMock.capture(capturedMsalRequest), EasyMock.isA(AADAuthority.class)).andReturn( - AuthenticationResult.builder(). - accessToken("accessToken"). - expiresOn(new Date().getTime() + 100). - refreshToken("refreshToken"). - idToken("idToken").environment("environment").build()); - - PowerMock.mockStatic(HttpHelper.class); - - HttpResponse instanceDiscoveryResponse = new HttpResponse(); - instanceDiscoveryResponse.statusCode(200); - instanceDiscoveryResponse.body(TestConfiguration.INSTANCE_DISCOVERY_RESPONSE); - - Capture capturedHttpRequest = Capture.newInstance(); - - EasyMock.expect( - HttpHelper.executeHttpRequest( - EasyMock.capture(capturedHttpRequest), - EasyMock.isA(RequestContext.class), - EasyMock.isA(ServiceBundle.class))) - .andReturn(instanceDiscoveryResponse); - - PowerMock.replay(HttpHelper.class, HttpResponse.class); - - CompletableFuture completableFuture = app.acquireToken( - AuthorizationCodeParameters.builder - ("auth_code", - new URI(TestConfiguration.AAD_DEFAULT_REDIRECT_URI)) - .scopes(Collections.singleton("default-scope")) - .build()); - - completableFuture.get(); - Assert.assertEquals(capturedHttpRequest.getValues().size(),0); - - } - - /** - * when instance_discovery flag is set to true (by default), an instance_discovery is NOT performed for b2c. - */ - @Test - public void b2cInstanceDiscoveryTrue() throws Exception{ - app = PowerMock.createPartialMock(PublicClientApplication.class, - new String[]{"acquireTokenCommon"}, - PublicClientApplication.builder(TestConstants.ADFS_APP_ID) - .b2cAuthority(TestConstants.B2C_MICROSOFTLOGIN_ROPC) - .instanceDiscovery(true)); - - Capture capturedMsalRequest = Capture.newInstance(); - - PowerMock.expectPrivate(app, "acquireTokenCommon", - EasyMock.capture(capturedMsalRequest), EasyMock.isA(AADAuthority.class)).andReturn( - AuthenticationResult.builder(). - accessToken("accessToken"). - expiresOn(new Date().getTime() + 100). - refreshToken("refreshToken"). - idToken("idToken").environment("environment").build()); - - PowerMock.mockStatic(HttpHelper.class); - - HttpResponse instanceDiscoveryResponse = new HttpResponse(); - instanceDiscoveryResponse.statusCode(200); - instanceDiscoveryResponse.body(TestConfiguration.INSTANCE_DISCOVERY_RESPONSE); - - Capture capturedHttpRequest = Capture.newInstance(); - - EasyMock.expect( - HttpHelper.executeHttpRequest( - EasyMock.capture(capturedHttpRequest), - EasyMock.isA(RequestContext.class), - EasyMock.isA(ServiceBundle.class))) - .andReturn(instanceDiscoveryResponse); - - PowerMock.replay(HttpHelper.class, HttpResponse.class); - - CompletableFuture completableFuture = app.acquireToken( - AuthorizationCodeParameters.builder - ("auth_code", - new URI(TestConfiguration.AAD_DEFAULT_REDIRECT_URI)) - .scopes(Collections.singleton("default-scope")) - .build()); - - completableFuture.get(); - Assert.assertEquals(capturedHttpRequest.getValues().size(),0); - - } - - -} diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/InvalidAuthorityIT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/InvalidAuthorityIT.java index 07be1538..08de59d3 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/InvalidAuthorityIT.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/InvalidAuthorityIT.java @@ -1,16 +1,21 @@ package com.microsoft.aad.msal4j; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.net.URI; import java.util.Collections; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -public class InvalidAuthorityIT extends SeleniumTest{ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class InvalidAuthorityIT extends SeleniumTest{ - @Test(expectedExceptions = ExecutionException.class, expectedExceptionsMessageRegExp = ".*?invalid instance.*?") - public void acquireTokenWithAuthorizationCode_InvalidAuthority() throws Exception{ + @Test + void acquireTokenWithAuthorizationCode_InvalidAuthority() throws Exception{ PublicClientApplication app; app = PublicClientApplication.builder( TestConfiguration.AAD_CLIENT_ID) @@ -21,6 +26,9 @@ public void acquireTokenWithAuthorizationCode_InvalidAuthority() throws Exceptio AuthorizationCodeParameters.builder("auth_code", new URI(TestConfiguration.AAD_DEFAULT_REDIRECT_URI)) .scopes(Collections.singleton("default-scope")) .authorizationCode("auth_code").redirectUri(new URI(TestConfiguration.AAD_DEFAULT_REDIRECT_URI)).build()); - future.get(); + + ExecutionException ex = assertThrows(ExecutionException.class, future::get); + + assertTrue(ex.getMessage().contains("invalid instance")); } } diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/OAuthRequestValidationUnitT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/OAuthRequestValidationUnitT.java deleted file mode 100644 index d4931e90..00000000 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/OAuthRequestValidationUnitT.java +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.microsoft.aad.msal4j; - -import org.apache.commons.lang3.StringUtils; -import org.testng.Assert; -import org.testng.annotations.Test; - -import java.util.*; -import java.util.concurrent.ExecutionException; - -public class OAuthRequestValidationUnitT extends OAuthRequestValidationTest { - @Test - public void oAuthRequest_for_acquireTokenByClientCertificate() throws Exception { - try { - IClientCertificate clientCertificate = CertificateHelper.getClientCertificate(); - - ConfidentialClientApplication app = ConfidentialClientApplication.builder(CLIENT_ID, clientCertificate) - .authority(AUTHORITY) - .validateAuthority(false).build(); - - // Using UserAssertion as Authorization Grants - OnBehalfOfParameters parameters = - OnBehalfOfParameters.builder(Collections.singleton(SCOPES), new UserAssertion(JWT)) - .build(); - - app.acquireToken(parameters).get(); - } catch (ExecutionException ex) { - Assert.assertTrue(ex.getCause() instanceof MsalException); - } - - Map queryParams = splitQuery(query); - Assert.assertEquals(queryParams.size(), 8); - - // validate Authorization Grants query params - Assert.assertEquals(queryParams.get("grant_type"), GRANT_TYPE_JWT); - Assert.assertEquals(queryParams.get("assertion"), JWT); - - // validate Client Authentication query params - Assert.assertFalse(StringUtils.isEmpty(queryParams.get("client_assertion"))); - - Set scopes = new HashSet<>( - Arrays.asList(queryParams.get("scope").split(AbstractMsalAuthorizationGrant.SCOPES_DELIMITER))); - - // validate custom scopes - Assert.assertTrue(scopes.contains(SCOPES)); - - // validate common scopes - Assert.assertTrue(scopes.contains(AbstractMsalAuthorizationGrant.SCOPE_OPEN_ID)); - Assert.assertTrue(scopes.contains(AbstractMsalAuthorizationGrant.SCOPE_PROFILE)); - Assert.assertTrue(scopes.contains(AbstractMsalAuthorizationGrant.SCOPE_OFFLINE_ACCESS)); - - Assert.assertEquals(queryParams.get("client_assertion_type"), CLIENT_ASSERTION_TYPE_JWT); - Assert.assertEquals(queryParams.get("requested_token_use"), ON_BEHALF_OF_USE_JWT); - - Assert.assertEquals(queryParams.get("client_info"), CLIENT_INFO_VALUE); - Assert.assertEquals(queryParams.get("client_id"), CLIENT_ID); - - } - - @Test - public void oAuthRequest_for_acquireTokenByClientAssertion() throws Exception { - - try { - IClientCertificate clientCertificate = CertificateHelper.getClientCertificate(); - - ConfidentialClientApplication app = - ConfidentialClientApplication.builder( - CLIENT_ID, - clientCertificate) - .authority(AUTHORITY) - .validateAuthority(false) - .build(); - - // Using ClientAssertion for Client Authentication and as the authorization grant - - app.acquireToken(ClientCredentialParameters.builder(Collections.singleton(SCOPES)) - .build()) - .get(); - - } catch (ExecutionException ex) { - Assert.assertTrue(ex.getCause() instanceof MsalException); - } - - Map queryParams = splitQuery(query); - - Assert.assertEquals(queryParams.size(), 6); - - // validate Authorization Grants query params - Assert.assertEquals(queryParams.get("grant_type"), CLIENT_CREDENTIALS_GRANT_TYPE); - - // validate Client Authentication query params - Assert.assertTrue(StringUtils.isNotEmpty(queryParams.get("client_assertion"))); - Assert.assertEquals(queryParams.get("client_assertion_type"), CLIENT_ASSERTION_TYPE_JWT); - - // to do validate scopes - Assert.assertEquals(queryParams.get("scope"), "https://SomeResource.azure.net openid profile offline_access"); - - Assert.assertEquals(queryParams.get("client_info"), CLIENT_INFO_VALUE); - Assert.assertEquals(queryParams.get("client_id"), CLIENT_ID); - } -} diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/OnBehalfOfIT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/OnBehalfOfIT.java index 71d706c3..bb6930bb 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/OnBehalfOfIT.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/OnBehalfOfIT.java @@ -4,18 +4,24 @@ package com.microsoft.aad.msal4j; import labapi.*; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.util.Collections; -@Test -public class OnBehalfOfIT { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class OnBehalfOfIT { private Config cfg; - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenWithOBO_Managed(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenWithOBO_Managed(String environment) throws Exception { cfg = new Config(environment); String accessToken = this.getAccessToken(); @@ -33,12 +39,13 @@ public void acquireTokenWithOBO_Managed(String environment) throws Exception { new UserAssertion(accessToken)).build()). get(); - Assert.assertNotNull(result); - Assert.assertNotNull(result.accessToken()); + assertNotNull(result); + assertNotNull(result.accessToken()); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenWithOBO_testCache(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenWithOBO_testCache(String environment) throws Exception { cfg = new Config(environment); String accessToken = this.getAccessToken(); @@ -56,8 +63,8 @@ public void acquireTokenWithOBO_testCache(String environment) throws Exception { new UserAssertion(accessToken)).build()). get(); - Assert.assertNotNull(result1); - Assert.assertNotNull(result1.accessToken()); + assertNotNull(result1); + assertNotNull(result1.accessToken()); // Same scope and userAssertion, should return cached tokens IAuthenticationResult result2 = @@ -66,7 +73,7 @@ public void acquireTokenWithOBO_testCache(String environment) throws Exception { new UserAssertion(accessToken)).build()). get(); - Assert.assertEquals(result1.accessToken(), result2.accessToken()); + assertEquals(result1.accessToken(), result2.accessToken()); // Scope 2, should return new token IAuthenticationResult result3 = @@ -75,9 +82,9 @@ public void acquireTokenWithOBO_testCache(String environment) throws Exception { new UserAssertion(accessToken)).build()). get(); - Assert.assertNotNull(result3); - Assert.assertNotNull(result3.accessToken()); - Assert.assertNotEquals(result2.accessToken(), result3.accessToken()); + assertNotNull(result3); + assertNotNull(result3.accessToken()); + assertNotEquals(result2.accessToken(), result3.accessToken()); // Scope 2, should return cached token IAuthenticationResult result4 = @@ -86,7 +93,7 @@ public void acquireTokenWithOBO_testCache(String environment) throws Exception { new UserAssertion(accessToken)).build()). get(); - Assert.assertEquals(result3.accessToken(), result4.accessToken()); + assertEquals(result3.accessToken(), result4.accessToken()); // skipCache=true, should return new token IAuthenticationResult result5 = @@ -98,10 +105,10 @@ public void acquireTokenWithOBO_testCache(String environment) throws Exception { .build()). get(); - Assert.assertNotNull(result5); - Assert.assertNotNull(result5.accessToken()); - Assert.assertNotEquals(result5.accessToken(), result4.accessToken()); - Assert.assertNotEquals(result5.accessToken(), result2.accessToken()); + assertNotNull(result5); + assertNotNull(result5.accessToken()); + assertNotEquals(result5.accessToken(), result4.accessToken()); + assertNotEquals(result5.accessToken(), result2.accessToken()); String newAccessToken = this.getAccessToken(); @@ -114,11 +121,11 @@ public void acquireTokenWithOBO_testCache(String environment) throws Exception { .build()). get(); - Assert.assertNotNull(result6); - Assert.assertNotNull(result6.accessToken()); - Assert.assertNotEquals(result6.accessToken(), result5.accessToken()); - Assert.assertNotEquals(result6.accessToken(), result4.accessToken()); - Assert.assertNotEquals(result6.accessToken(), result2.accessToken()); + assertNotNull(result6); + assertNotNull(result6.accessToken()); + assertNotEquals(result6.accessToken(), result5.accessToken()); + assertNotEquals(result6.accessToken(), result4.accessToken()); + assertNotEquals(result6.accessToken(), result2.accessToken()); } private String getAccessToken() throws Exception { diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/RefreshTokenIT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/RefreshTokenIT.java index a1e5ebfb..37984846 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/RefreshTokenIT.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/RefreshTokenIT.java @@ -5,15 +5,18 @@ import labapi.LabUserProvider; import labapi.User; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.Collections; import java.util.concurrent.ExecutionException; - -@Test() -public class RefreshTokenIT { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class RefreshTokenIT { private String refreshToken; private PublicClientApplication pca; @@ -38,8 +41,9 @@ private void setUp(String environment) throws Exception { refreshToken = result.refreshToken(); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenWithRefreshToken(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenWithRefreshToken(String environment) throws Exception { cfg = new Config(environment); setUp(environment); @@ -51,18 +55,18 @@ public void acquireTokenWithRefreshToken(String environment) throws Exception { .build()) .get(); - Assert.assertNotNull(result); - Assert.assertNotNull(result.accessToken()); - Assert.assertNotNull(result.idToken()); + assertNotNull(result); + assertNotNull(result.accessToken()); + assertNotNull(result.idToken()); } - @Test(expectedExceptions = ExecutionException.class) - public void acquireTokenWithRefreshToken_WrongScopes() throws Exception { - IAuthenticationResult result = pca.acquireToken(RefreshTokenParameters - .builder( - Collections.singleton(TestConstants.KEYVAULT_DEFAULT_SCOPE), - refreshToken) - .build()) - .get(); + @Test + void acquireTokenWithRefreshToken_WrongScopes() throws Exception { + assertThrows(IllegalArgumentException.class, () -> pca.acquireToken(RefreshTokenParameters + .builder( + Collections.singleton(TestConstants.KEYVAULT_DEFAULT_SCOPE), + refreshToken) + .build()) + .get()); } } diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/SeleniumTest.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/SeleniumTest.java index ccb218b1..f5fe21cb 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/SeleniumTest.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/SeleniumTest.java @@ -8,9 +8,6 @@ import labapi.LabUserProvider; import labapi.User; import org.openqa.selenium.WebDriver; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; abstract class SeleniumTest { @@ -18,12 +15,10 @@ abstract class SeleniumTest { WebDriver seleniumDriver; HttpListener httpListener; - @BeforeClass public void setUpLapUserProvider() { labUserProvider = LabUserProvider.getInstance(); } - @AfterMethod public void cleanUp() { seleniumDriver.quit(); if (httpListener != null) { @@ -31,7 +26,6 @@ public void cleanUp() { } } - @BeforeMethod public void startUpBrowser() { seleniumDriver = SeleniumExtensions.createDefaultWebDriver(); } diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/TokenCacheIT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/TokenCacheIT.java index 70da5288..9576eaef 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/TokenCacheIT.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/TokenCacheIT.java @@ -4,26 +4,29 @@ package com.microsoft.aad.msal4j; import labapi.*; -import org.testng.Assert; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; + +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; -public class TokenCacheIT { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class TokenCacheIT { private LabUserProvider labUserProvider; - @BeforeClass - public void setUp() { + @BeforeAll + void setUp() { labUserProvider = LabUserProvider.getInstance(); } @Test - public void singleAccountInCache_RemoveAccountTest() throws Exception { + void singleAccountInCache_RemoveAccountTest() throws Exception { User user = labUserProvider.getDefaultUser(); PublicClientApplication pca = PublicClientApplication.builder( @@ -32,7 +35,7 @@ public void singleAccountInCache_RemoveAccountTest() throws Exception { build(); // Check that cache is empty - Assert.assertEquals(pca.getAccounts().join().size(), 0); + assertEquals(pca.getAccounts().join().size(), 0); Map extraQueryParameters = new HashMap<>(); extraQueryParameters.put("test", "test"); @@ -46,16 +49,16 @@ public void singleAccountInCache_RemoveAccountTest() throws Exception { .get(); // Check that cache contains one account - Assert.assertEquals(pca.getAccounts().join().size(), 1); + assertEquals(pca.getAccounts().join().size(), 1); pca.removeAccount(pca.getAccounts().join().iterator().next()).join(); // Check that account has been removed - Assert.assertEquals(pca.getAccounts().join().size(), 0); + assertEquals(pca.getAccounts().join().size(), 0); } @Test - public void twoAccountsInCache_RemoveAccountTest() throws Exception { + void twoAccountsInCache_RemoveAccountTest() throws Exception { User managedUser = labUserProvider.getDefaultUser(); @@ -64,7 +67,7 @@ public void twoAccountsInCache_RemoveAccountTest() throws Exception { authority(TestConstants.ORGANIZATIONS_AUTHORITY). build(); - Assert.assertEquals(pca.getAccounts().join().size(), 0); + assertEquals(pca.getAccounts().join().size(), 0); pca.acquireToken(UserNamePasswordParameters. builder(Collections.singleton(TestConstants.GRAPH_DEFAULT_SCOPE), @@ -73,7 +76,7 @@ public void twoAccountsInCache_RemoveAccountTest() throws Exception { .build()) .get(); - Assert.assertEquals(pca.getAccounts().join().size(), 1); + assertEquals(pca.getAccounts().join().size(), 1); // get lab user for different account User adfsUser = labUserProvider.getFederatedAdfsUser(FederationProvider.ADFS_4); @@ -86,7 +89,7 @@ public void twoAccountsInCache_RemoveAccountTest() throws Exception { .build()) .get(); - Assert.assertEquals(pca.getAccounts().join().size(), 2); + assertEquals(pca.getAccounts().join().size(), 2); Set accounts = pca.getAccounts().join(); IAccount accountLabResponse1 = accounts.stream().filter( @@ -95,16 +98,16 @@ public void twoAccountsInCache_RemoveAccountTest() throws Exception { pca.removeAccount(accountLabResponse1).join(); - Assert.assertEquals(pca.getAccounts().join().size(), 1); + assertEquals(pca.getAccounts().join().size(), 1); IAccount accountLabResponse2 = pca.getAccounts().get().iterator().next(); // Check that the right account was left in the cache - Assert.assertEquals(accountLabResponse2.username(), adfsUser.getUpn()); + assertEquals(accountLabResponse2.username(), adfsUser.getUpn()); } @Test - public void twoAccountsInCache_SameUserDifferentTenants_RemoveAccountTest() throws Exception { + void twoAccountsInCache_SameUserDifferentTenants_RemoveAccountTest() throws Exception { UserQueryParameters query = new UserQueryParameters(); query.parameters.put(UserQueryParameters.USER_TYPE, UserType.GUEST); @@ -117,7 +120,7 @@ public void twoAccountsInCache_SameUserDifferentTenants_RemoveAccountTest() thro "/cache_data/remove-account-test-cache.json"); // check that cache is empty - Assert.assertEquals(dataToInitCache, ""); + assertEquals(dataToInitCache, ""); ITokenCacheAccessAspect persistenceAspect = new TokenPersistence(dataToInitCache); @@ -152,14 +155,14 @@ public void twoAccountsInCache_SameUserDifferentTenants_RemoveAccountTest() thro .get(); // There should be two tokens in cache, with same accounts except for tenant - Assert.assertEquals(pca2.getAccounts().join().iterator().next().getTenantProfiles().size(), 2); + assertEquals(pca2.getAccounts().join().iterator().next().getTenantProfiles().size(), 2); IAccount account = pca2.getAccounts().get().iterator().next(); // RemoveAccount should remove both cache entities pca2.removeAccount(account).join(); - Assert.assertEquals(pca.getAccounts().join().size(), 0); + assertEquals(pca.getAccounts().join().size(), 0); //clean up file TestHelper.deleteFileContent( diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/UsernamePasswordIT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/UsernamePasswordIT.java index 8b9c9fe0..049c5d40 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/UsernamePasswordIT.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/UsernamePasswordIT.java @@ -4,27 +4,32 @@ package com.microsoft.aad.msal4j; import labapi.*; -import org.testng.Assert; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.api.BeforeAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.util.Collections; import java.util.HashMap; import java.util.Map; -@Test() -public class UsernamePasswordIT { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class UsernamePasswordIT { private LabUserProvider labUserProvider; private Config cfg; - @BeforeClass - public void setUp() { + @BeforeAll + void setUp() { labUserProvider = LabUserProvider.getInstance(); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenWithUsernamePassword_Managed(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenWithUsernamePassword_Managed(String environment) throws Exception { cfg = new Config(environment); User user = labUserProvider.getDefaultUser(cfg.azureEnvironment); @@ -32,8 +37,9 @@ public void acquireTokenWithUsernamePassword_Managed(String environment) throws assertAcquireTokenCommon(user, cfg.organizationsAuthority(), cfg.graphDefaultScope(), user.getAppId()); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenWithUsernamePassword_ADFSv2019_Federated(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenWithUsernamePassword_ADFSv2019_Federated(String environment) throws Exception { cfg = new Config(environment); UserQueryParameters query = new UserQueryParameters(); @@ -47,7 +53,7 @@ public void acquireTokenWithUsernamePassword_ADFSv2019_Federated(String environm } @Test - public void acquireTokenWithUsernamePassword_ADFSv2019_OnPrem() throws Exception { + void acquireTokenWithUsernamePassword_ADFSv2019_OnPrem() throws Exception { UserQueryParameters query = new UserQueryParameters(); query.parameters.put(UserQueryParameters.FEDERATION_PROVIDER, FederationProvider.ADFS_2019); query.parameters.put(UserQueryParameters.USER_TYPE, UserType.ON_PREM); @@ -57,8 +63,9 @@ public void acquireTokenWithUsernamePassword_ADFSv2019_OnPrem() throws Exception assertAcquireTokenCommon(user, TestConstants.ADFS_AUTHORITY, TestConstants.ADFS_SCOPE, TestConstants.ADFS_APP_ID); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenWithUsernamePassword_ADFSv4(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenWithUsernamePassword_ADFSv4(String environment) throws Exception { cfg = new Config(environment); UserQueryParameters query = new UserQueryParameters(); @@ -71,8 +78,9 @@ public void acquireTokenWithUsernamePassword_ADFSv4(String environment) throws E assertAcquireTokenCommon(user, cfg.organizationsAuthority(), cfg.graphDefaultScope(), user.getAppId()); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenWithUsernamePassword_ADFSv3(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenWithUsernamePassword_ADFSv3(String environment) throws Exception { cfg = new Config(environment); UserQueryParameters query = new UserQueryParameters(); @@ -85,8 +93,9 @@ public void acquireTokenWithUsernamePassword_ADFSv3(String environment) throws E assertAcquireTokenCommon(user, cfg.organizationsAuthority(), cfg.graphDefaultScope(), user.getAppId()); } - @Test(dataProvider = "environments", dataProviderClass = EnvironmentsProvider.class) - public void acquireTokenWithUsernamePassword_ADFSv2(String environment) throws Exception { + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.EnvironmentsProvider#createData") + void acquireTokenWithUsernamePassword_ADFSv2(String environment) throws Exception { cfg = new Config(environment); UserQueryParameters query = new UserQueryParameters(); @@ -100,30 +109,7 @@ public void acquireTokenWithUsernamePassword_ADFSv2(String environment) throws E } @Test - public void acquireTokenWithUsernamePassword_Ciam() throws Exception { - - Map 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(); - - - 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 - public void acquireTokenWithUsernamePassword_AuthorityWithPort() throws Exception { + void acquireTokenWithUsernamePassword_AuthorityWithPort() throws Exception { User user = labUserProvider.getDefaultUser(); assertAcquireTokenCommon( @@ -156,11 +142,11 @@ private void assertAcquireTokenCommon(User user, String authority, String scope, .get(); assertTokenResultNotNull(result); - Assert.assertEquals(user.getUpn(), result.account().username()); + assertEquals(user.getUpn(), result.account().username()); } @Test - public void acquireTokenWithUsernamePassword_B2C_CustomAuthority() throws Exception { + void acquireTokenWithUsernamePassword_B2C_CustomAuthority() throws Exception { UserQueryParameters query = new UserQueryParameters(); query.parameters.put(UserQueryParameters.USER_TYPE, UserType.B2C); query.parameters.put(UserQueryParameters.B2C_PROVIDER, B2CProvider.LOCAL); @@ -192,7 +178,7 @@ public void acquireTokenWithUsernamePassword_B2C_CustomAuthority() throws Except } @Test - public void acquireTokenWithUsernamePassword_B2C_LoginMicrosoftOnline() throws Exception { + void acquireTokenWithUsernamePassword_B2C_LoginMicrosoftOnline() throws Exception { UserQueryParameters query = new UserQueryParameters(); query.parameters.put(UserQueryParameters.USER_TYPE, UserType.B2C); query.parameters.put(UserQueryParameters.B2C_PROVIDER, B2CProvider.LOCAL); @@ -224,8 +210,8 @@ public void acquireTokenWithUsernamePassword_B2C_LoginMicrosoftOnline() throws E } private void assertTokenResultNotNull(IAuthenticationResult result) { - Assert.assertNotNull(result); - Assert.assertNotNull(result.accessToken()); - Assert.assertNotNull(result.idToken()); + assertNotNull(result); + assertNotNull(result.accessToken()); + assertNotNull(result.idToken()); } } diff --git a/msal4j-sdk/src/integrationtest/java/infrastructure/UserInformationFields.java b/msal4j-sdk/src/integrationtest/java/infrastructure/UserInformationFields.java index 048d3b28..22e1534d 100644 --- a/msal4j-sdk/src/integrationtest/java/infrastructure/UserInformationFields.java +++ b/msal4j-sdk/src/integrationtest/java/infrastructure/UserInformationFields.java @@ -3,11 +3,9 @@ package infrastructure; -import com.microsoft.aad.msal4j.TestConstants; import labapi.FederationProvider; import labapi.LabConstants; import labapi.User; -import org.testng.util.Strings; class UserInformationFields { private final User user; @@ -19,14 +17,14 @@ class UserInformationFields { } String getPasswordInputId() { - if (Strings.isNullOrEmpty(passwordInputId)) { + if (passwordInputId == null || passwordInputId.equals("")) { determineFieldIds(); } return passwordInputId; } String getPasswordSigInButtonId() { - if (Strings.isNullOrEmpty(passwordSigInButtonId)) { + if (passwordSigInButtonId == null || passwordSigInButtonId.equals("")) { determineFieldIds(); } return passwordSigInButtonId; diff --git a/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AadInstanceDiscoveryProvider.java b/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AadInstanceDiscoveryProvider.java index a66094e9..2cbd728a 100644 --- a/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AadInstanceDiscoveryProvider.java +++ b/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AadInstanceDiscoveryProvider.java @@ -225,7 +225,7 @@ private static String getInstanceDiscoveryEndpoint(URL authorityUrl) { replace("{port}", String.valueOf(port)); } - private static AadInstanceDiscoveryResponse sendInstanceDiscoveryRequest(URL authorityUrl, + static AadInstanceDiscoveryResponse sendInstanceDiscoveryRequest(URL authorityUrl, MsalRequest msalRequest, ServiceBundle serviceBundle) { @@ -289,7 +289,7 @@ private static IHttpResponse executeRequest(String requestUrl, Map mockedInstanceDiscoveryProvider = mockStatic(AadInstanceDiscoveryProvider.class, CALLS_REAL_METHODS)) { - PowerMock.expectPrivate( - AadInstanceDiscoveryProvider.class, - "sendInstanceDiscoveryRequest", - authority, - msalRequest, - app.getServiceBundle()).andReturn(expectedResponse); - - PowerMock.replay(AadInstanceDiscoveryProvider.class); - - InstanceDiscoveryMetadataEntry entry = AadInstanceDiscoveryProvider.getMetadataEntry( - new URL(app.authority()), - false, - msalRequest, - app.getServiceBundle()); + mockedInstanceDiscoveryProvider.when(() -> AadInstanceDiscoveryProvider.sendInstanceDiscoveryRequest(authority, + msalRequest, + app.getServiceBundle())).thenReturn(expectedResponse); - PowerMock.verify(AadInstanceDiscoveryProvider.class); + InstanceDiscoveryMetadataEntry entry = AadInstanceDiscoveryProvider.getMetadataEntry( + authority, + false, + msalRequest, + app.getServiceBundle()); - Assert.assertEquals(entry.preferredNetwork(), "login.microsoftonline.com"); - Assert.assertEquals(entry.preferredCache(), "login.windows.net"); - Assert.assertEquals(entry.aliases().size(), 4); - Assert.assertTrue(entry.aliases().contains("login.microsoftonline.com")); - Assert.assertTrue(entry.aliases().contains("login.windows.net")); - Assert.assertTrue(entry.aliases().contains("login.microsoft.com")); - Assert.assertTrue(entry.aliases().contains("sts.windows.net")); + assertValidResponse(entry); + } } @Test - public void aadInstanceDiscoveryTest_responseSetByDeveloper_validResponse() throws Exception { - - String instanceDiscoveryResponse = TestHelper.readResource( - this.getClass(), - "/instance_discovery_data/aad_instance_discovery_response_valid.json"); + void aadInstanceDiscoveryTest_responseSetByDeveloper_validResponse() throws Exception { PublicClientApplication app = PublicClientApplication.builder("client_id") - .aadInstanceDiscoveryResponse(instanceDiscoveryResponse) + .aadInstanceDiscoveryResponse(instanceDiscoveryValidResponse) .build(); - AuthorizationCodeParameters parameters = AuthorizationCodeParameters.builder( - "code", new URI("http://my.redirect.com")).build(); - MsalRequest msalRequest = new AuthorizationCodeRequest( parameters, app, @@ -95,62 +89,35 @@ public void aadInstanceDiscoveryTest_responseSetByDeveloper_validResponse() thro URL authority = new URL(app.authority()); - PowerMock.mockStaticPartial( - AadInstanceDiscoveryProvider.class, - "sendInstanceDiscoveryRequest"); - - // throw exception if we try to get metadata from network. - PowerMock.expectPrivate( - AadInstanceDiscoveryProvider.class, - "sendInstanceDiscoveryRequest", - authority, - msalRequest, - app.getServiceBundle()).andThrow(new AssertionError()).anyTimes(); - - PowerMock.replay(AadInstanceDiscoveryProvider.class); - InstanceDiscoveryMetadataEntry entry = AadInstanceDiscoveryProvider.getMetadataEntry( authority, false, msalRequest, app.getServiceBundle()); - Assert.assertEquals(entry.preferredNetwork(), "login.microsoftonline.com"); - Assert.assertEquals(entry.preferredCache(), "login.windows.net"); - Assert.assertEquals(entry.aliases().size(), 4); - Assert.assertTrue(entry.aliases().contains("login.microsoftonline.com")); - Assert.assertTrue(entry.aliases().contains("login.windows.net")); - Assert.assertTrue(entry.aliases().contains("login.microsoft.com")); - Assert.assertTrue(entry.aliases().contains("sts.windows.net")); + assertValidResponse(entry); } - @Test(expectedExceptions = MsalClientException.class) - public void aadInstanceDiscoveryTest_responseSetByDeveloper_invalidJson() throws Exception { + @Test + void aadInstanceDiscoveryTest_responseSetByDeveloper_invalidJson() throws Exception { String instanceDiscoveryResponse = TestHelper.readResource( this.getClass(), "/instance_discovery_data/aad_instance_discovery_response_invalid_json.json"); - PublicClientApplication app = PublicClientApplication.builder("client_id") + assertThrows(MsalClientException.class, () -> PublicClientApplication.builder("client_id") .aadInstanceDiscoveryResponse(instanceDiscoveryResponse) - .build(); + .build()); } - @Test() - public void aadInstanceDiscoveryTest_AutoDetectRegion_NoRegionDetected() throws Exception { - - String instanceDiscoveryResponse = TestHelper.readResource( - this.getClass(), - "/instance_discovery_data/aad_instance_discovery_response_valid.json"); + @Test + void aadInstanceDiscoveryTest_AutoDetectRegion_NoRegionDetected() throws Exception { PublicClientApplication app = PublicClientApplication.builder("client_id") - .aadInstanceDiscoveryResponse(instanceDiscoveryResponse) + .aadInstanceDiscoveryResponse(instanceDiscoveryValidResponse) .autoDetectRegion(true) .build(); - AuthorizationCodeParameters parameters = AuthorizationCodeParameters.builder( - "code", new URI("http://my.redirect.com")).build(); - MsalRequest msalRequest = new AuthorizationCodeRequest( parameters, app, @@ -158,32 +125,28 @@ public void aadInstanceDiscoveryTest_AutoDetectRegion_NoRegionDetected() throws URL authority = new URL(app.authority()); - PowerMock.mockStaticPartial( - AadInstanceDiscoveryProvider.class, - "discoverRegion"); + try (MockedStatic mocked = mockStatic(AadInstanceDiscoveryProvider.class, CALLS_REAL_METHODS)) { - PowerMock.expectPrivate( - AadInstanceDiscoveryProvider.class, - "discoverRegion", - msalRequest, - app.getServiceBundle()).andThrow(new AssertionError()).anyTimes(); + mocked.when(() -> AadInstanceDiscoveryProvider.discoverRegion(msalRequest, + app.getServiceBundle())).thenReturn(null); - PowerMock.replay(AadInstanceDiscoveryProvider.class); + InstanceDiscoveryMetadataEntry entry = AadInstanceDiscoveryProvider.getMetadataEntry( + authority, + false, + msalRequest, + app.getServiceBundle()); - InstanceDiscoveryMetadataEntry entry = AadInstanceDiscoveryProvider.getMetadataEntry( - authority, - false, - msalRequest, - app.getServiceBundle()); + assertValidResponse(entry); + } + } - //Region detection will have been performed in the expected discoverRegion method, but these tests (likely) aren't - // being run in an Azure VM and instance discovery will fall back to the global endpoint (login.microsoftonline.com) - Assert.assertEquals(entry.preferredNetwork(), "login.microsoftonline.com"); - Assert.assertEquals(entry.preferredCache(), "login.windows.net"); - Assert.assertEquals(entry.aliases().size(), 4); - Assert.assertTrue(entry.aliases().contains("login.microsoftonline.com")); - Assert.assertTrue(entry.aliases().contains("login.windows.net")); - Assert.assertTrue(entry.aliases().contains("login.microsoft.com")); - Assert.assertTrue(entry.aliases().contains("sts.windows.net")); + void assertValidResponse(InstanceDiscoveryMetadataEntry entry) { + assertEquals(entry.preferredNetwork(), "login.microsoftonline.com"); + assertEquals(entry.preferredCache(), "login.windows.net"); + assertEquals(entry.aliases().size(), 4); + assertTrue(entry.aliases().contains("login.microsoftonline.com")); + assertTrue(entry.aliases().contains("login.windows.net")); + assertTrue(entry.aliases().contains("login.microsoft.com")); + assertTrue(entry.aliases().contains("sts.windows.net")); } } diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AbstractMsalTests.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AbstractMsalTests.java deleted file mode 100644 index a35079c2..00000000 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AbstractMsalTests.java +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.microsoft.aad.msal4j; - -import org.powermock.modules.testng.PowerMockTestCase; - -public class AbstractMsalTests extends PowerMockTestCase { -} diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AccountTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AccountTest.java index 14a417c0..10807817 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AccountTest.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AccountTest.java @@ -3,8 +3,10 @@ package com.microsoft.aad.msal4j; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.net.URISyntaxException; @@ -16,62 +18,8 @@ import static com.microsoft.aad.msal4j.Constants.POINT_DELIMITER; -public class AccountTest { - - // @Test - // hardcoded token secrets should not be used to not trigger CredScan - public void testMultiTenantAccount_AccessTenantProfile() throws IOException, URISyntaxException { - - ITokenCacheAccessAspect accountCache = new CachePersistenceIT.TokenPersistence( - TestHelper.readResource(this.getClass(), - "/cache_data/multi-tenant-account-cache.json")); - - PublicClientApplication app = PublicClientApplication.builder("client_id") - .setTokenCacheAccessAspect(accountCache).build(); - - Assert.assertEquals(app.getAccounts().join().size(), 3); - Iterator acctIterator = app.getAccounts().join().iterator(); - - IAccount curAccount; - while (acctIterator.hasNext()) { - curAccount = acctIterator.next(); - - switch (curAccount.username()) { - case "MultiTenantAccount": { - Assert.assertEquals(curAccount.homeAccountId(), "uid1.utid1"); - Map tenantProfiles = curAccount.getTenantProfiles(); - Assert.assertNotNull(tenantProfiles); - Assert.assertEquals(tenantProfiles.size(), 3); - Assert.assertNotNull(tenantProfiles.get("utid1")); - Assert.assertNotNull(tenantProfiles.get("utid1").getClaims()); - Assert.assertNotNull(tenantProfiles.get("utid2")); - Assert.assertNotNull(tenantProfiles.get("utid2").getClaims()); - Assert.assertNotNull(tenantProfiles.get("utid3")); - Assert.assertNotNull(tenantProfiles.get("utid3").getClaims()); - break; - } - case "SingleTenantAccount": { - Assert.assertEquals(curAccount.homeAccountId(), "uid6.utid5"); - Map tenantProfiles = curAccount.getTenantProfiles(); - Assert.assertNotNull(tenantProfiles); - Assert.assertEquals(tenantProfiles.size(), 1); - Assert.assertNotNull(tenantProfiles.get("utid5")); - Assert.assertNotNull(tenantProfiles.get("utid5").getClaims()); - break; - } - case "TenantProfileNoHome": { - Assert.assertEquals(curAccount.homeAccountId(), "uid5.utid4"); - Map tenantProfiles = curAccount.getTenantProfiles(); - Assert.assertNotNull(tenantProfiles); - Assert.assertEquals(tenantProfiles.size(), 1); - Assert.assertNotNull(tenantProfiles.get("utid4")); - Assert.assertNotNull(tenantProfiles.get("utid4").getClaims()); - break; - } - } - } - } - +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class AccountTest { String getEmptyBase64EncodedJson() { return new String(Base64.getEncoder().encode("{}".getBytes())); @@ -97,7 +45,7 @@ private String getTestIdToken(String environment, String tenant) throws IOExcept } @Test - public void multiCloudAccount_aggregatedInGetAccountsRemoveAccountApis() throws IOException, URISyntaxException { + void multiCloudAccount_aggregatedInGetAccountsRemoveAccountApis() throws IOException, URISyntaxException { String BLACK_FORESRT_TENANT = "de_tid"; String WW_TENTANT = "tid"; String BLACK_FOREST_ENV = "login.microsoftonline.de"; @@ -143,22 +91,22 @@ ITokenCacheAccessAspect init(String data) { Set accounts = pca.getAccounts().join(); - Assert.assertEquals(accounts.size(), 1); + assertEquals(accounts.size(), 1); IAccount account = accounts.iterator().next(); Map tenantProfiles = account.getTenantProfiles(); - Assert.assertEquals(tenantProfiles.size(), 2); + assertEquals(tenantProfiles.size(), 2); - Assert.assertTrue(tenantProfiles.containsKey(BLACK_FORESRT_TENANT)); - Assert.assertTrue(tenantProfiles.containsKey(WW_TENTANT)); + assertTrue(tenantProfiles.containsKey(BLACK_FORESRT_TENANT)); + assertTrue(tenantProfiles.containsKey(WW_TENTANT)); pca.removeAccount(account).join(); accounts = pca.getAccounts().join(); - Assert.assertEquals(accounts.size(), 0); + assertEquals(accounts.size(), 0); - Assert.assertEquals(pca.tokenCache.accounts.size(), 0); - Assert.assertEquals(pca.tokenCache.idTokens.size(), 0); - Assert.assertEquals(pca.tokenCache.refreshTokens.size(), 0); - Assert.assertEquals(pca.tokenCache.accessTokens.size(), 0); + assertEquals(pca.tokenCache.accounts.size(), 0); + assertEquals(pca.tokenCache.idTokens.size(), 0); + assertEquals(pca.tokenCache.refreshTokens.size(), 0); + assertEquals(pca.tokenCache.accessTokens.size(), 0); } } diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AcquireTokenSilentlyTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AcquireTokenSilentlyTest.java index db6ea553..5d0265c0 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AcquireTokenSilentlyTest.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AcquireTokenSilentlyTest.java @@ -3,18 +3,21 @@ package com.microsoft.aad.msal4j; -import org.powermock.modules.testng.PowerMockTestCase; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.Collections; -import java.util.concurrent.CompletionException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; -@Test(groups = {"checkin"}) -public class AcquireTokenSilentlyTest extends PowerMockTestCase { - @Test(expectedExceptions = MsalClientException.class, - expectedExceptionsMessageRegExp = AuthenticationErrorMessage.NO_TOKEN_IN_CACHE) - public void publicAppAcquireTokenSilently_emptyCache_MsalClientException() throws Throwable { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class AcquireTokenSilentlyTest { + + @Test + void publicAppAcquireTokenSilently_emptyCache_MsalClientException() throws Throwable { PublicClientApplication application = PublicClientApplication .builder(TestConfiguration.AAD_CLIENT_ID) @@ -22,27 +25,27 @@ public void publicAppAcquireTokenSilently_emptyCache_MsalClientException() throw SilentParameters parameters = SilentParameters.builder(Collections.singleton("scope")).build(); - try { - application.acquireTokenSilently(parameters).join(); - } catch (CompletionException ex) { - throw ex.getCause(); - } + CompletableFuture future = application.acquireTokenSilently(parameters); + + ExecutionException ex = assertThrows(ExecutionException.class, future::get); + + assertTrue(ex.getCause() instanceof MsalClientException); + assertTrue(ex.getMessage().contains(AuthenticationErrorMessage.NO_TOKEN_IN_CACHE)); } - @Test(expectedExceptions = MsalClientException.class, - expectedExceptionsMessageRegExp = AuthenticationErrorMessage.NO_TOKEN_IN_CACHE) - public void confidentialAppAcquireTokenSilently_emptyCache_MsalClientException() throws Throwable { + @Test + void confidentialAppAcquireTokenSilently_emptyCache_MsalClientException() throws Throwable { ConfidentialClientApplication application = ConfidentialClientApplication .builder(TestConfiguration.AAD_CLIENT_ID, ClientCredentialFactory.createFromSecret(TestConfiguration.AAD_CLIENT_DUMMYSECRET)) .b2cAuthority(TestConfiguration.B2C_AUTHORITY).build(); SilentParameters parameters = SilentParameters.builder(Collections.singleton("scope")).build(); + CompletableFuture future = application.acquireTokenSilently(parameters); + + ExecutionException ex = assertThrows(ExecutionException.class, future::get); - try { - application.acquireTokenSilently(parameters).join(); - } catch (CompletionException ex) { - throw ex.getCause(); - } + assertTrue(ex.getCause() instanceof MsalClientException); + assertTrue(ex.getMessage().contains(AuthenticationErrorMessage.NO_TOKEN_IN_CACHE)); } } diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AssertionCredentialTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AssertionCredentialTest.java deleted file mode 100644 index 8f7e7450..00000000 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AssertionCredentialTest.java +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.microsoft.aad.msal4j; - -import org.testng.annotations.Test; - -@Test(groups = {"checkin"}) -public class AssertionCredentialTest { - - @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "assertion") - public void testAssertionNull() { - new ClientAssertion(null); - } - - @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "assertion") - public void testAssertionEmpty() { - new ClientAssertion(""); - } -} diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AuthorityTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AuthorityTest.java index cd0a8bf4..326e933f 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AuthorityTest.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AuthorityTest.java @@ -6,197 +6,187 @@ import java.net.MalformedURLException; import java.net.URL; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@Test(groups = {"checkin"}) -@PrepareForTest({AADAuthority.class, HttpHelper.class, - JsonHelper.class, AadInstanceDiscoveryResponse.class}) -public class AuthorityTest extends AbstractMsalTests { +import static org.junit.jupiter.api.Assertions.*; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class AuthorityTest { @Test - public void testDetectAuthorityType_AAD() throws Exception { + void testDetectAuthorityType_AAD() throws Exception { URL url = new URL(TestConfiguration.AAD_TENANT_ENDPOINT); - Assert.assertEquals(Authority.detectAuthorityType(url), AuthorityType.AAD); + assertEquals(Authority.detectAuthorityType(url), AuthorityType.AAD); } @Test - public void testDetectAuthorityType_ADFS() throws Exception { + void testDetectAuthorityType_ADFS() throws Exception { URL url = new URL(TestConfiguration.ADFS_TENANT_ENDPOINT); - Assert.assertEquals(Authority.detectAuthorityType(url), AuthorityType.ADFS); + assertEquals(Authority.detectAuthorityType(url), AuthorityType.ADFS); } @Test - public void testDetectAuthorityType_B2C() throws Exception { + void testDetectAuthorityType_B2C() throws Exception { URL url = new URL(TestConfiguration.B2C_AUTHORITY); - Assert.assertEquals(Authority.detectAuthorityType(url), AuthorityType.B2C); + assertEquals(Authority.detectAuthorityType(url), AuthorityType.B2C); } - @DataProvider(name = "ciamAuthorities") - public static Object[][] createCiamAuthorityData() throws MalformedURLException { - return new Object[][]{{new URL("https://msidlabciam1.ciamlogin.com/")}, - {new URL("https://msidlabciam1.ciamlogin.com/d57fb3d4-4b5a-4144-9328-9c1f7d58179d/")}, - {new URL("https://msidlabciam1.ciamlogin.com/msidlabciam1.onmicrosoft.com/")}, - {new URL("https://msidlabciam1.ciamlogin.com/aDomain/")}}; + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.AuthorityTest#ciamAuthorities") + void testDetectAuthorityType_CIAM(URL authority) throws Exception { + assertEquals(Authority.detectAuthorityType(authority), AuthorityType.CIAM); } - @Test(dataProvider = "ciamAuthorities") - public void testDetectAuthorityType_CIAM(URL authority) throws Exception { - Assert.assertEquals(Authority.detectAuthorityType(authority), AuthorityType.CIAM); + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.AuthorityTest#validCiamAuthoritiesAndTransformedAuthority") + void testCiamAuthorityTransformation(URL authority, URL transformedAuthority) throws Exception { + assertEquals(CIAMAuthority.transformAuthority(authority), transformedAuthority); } - @DataProvider(name = "validCiamAuthoritiesAndTransformedAuthority") - public static Object[][] createCiamAndTransformedAuthorityData() throws MalformedURLException { - return new Object[][]{{new URL("https://msidlabciam1.ciamlogin.com/"),new URL("https://msidlabciam1.ciamlogin.com/msidlabciam1.onmicrosoft.com/")}, - {new URL("https://msidlabciam1.ciamlogin.com/d57fb3d4-4b5a-4144-9328-9c1f7d58179d"),new URL("https://msidlabciam1.ciamlogin.com/d57fb3d4-4b5a-4144-9328-9c1f7d58179d")}, - {new URL("https://msidlabciam1.ciamlogin.com/msidlabciam1.onmicrosoft.com"),new URL("https://msidlabciam1.ciamlogin.com/msidlabciam1.onmicrosoft.com")}, - {new URL("https://msidlabciam1.ciamlogin.com/aDomain"),new URL("https://msidlabciam1.ciamlogin.com/aDomain")}}; - } + @Test + void testB2CAuthorityConstructor_NotEnoughSegments() { + + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> + new B2CAuthority(new URL("https://something.com/somethingelse/"))); - @Test(dataProvider = "validCiamAuthoritiesAndTransformedAuthority") - public void testCiamAuthorityTransformation(URL authority, URL transformedAuthority) throws Exception{ - Assert.assertEquals(CIAMAuthority.transformAuthority(authority), transformedAuthority); + assertTrue(ex.getMessage().contains("Valid B2C 'authority' URLs should follow either of these formats")); } - @Test(expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = - "Valid B2C 'authority' URLs should follow either of these formats.*") - public void testB2CAuthorityConstructor_NotEnoughSegments() throws MalformedURLException { - new B2CAuthority(new URL("https://something.com/somethingelse/")); + @Test + void testAADAuthorityConstructor_HttpAuthority() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> + Authority.validateAuthority(new URL("http://I.com/not/h/t/t/p/s/"))); + + assertTrue(ex.getMessage().contains("authority should use the 'https' scheme")); } - @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "authority should use the 'https' scheme") - public void testAADAuthorityConstructor_HttpAuthority() throws MalformedURLException { - Authority.validateAuthority(new URL("http://I.com/not/h/t/t/p/s/")); + @Test + void testAADAuthorityConstructor_UrlHasFragment() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> + Authority.validateAuthority(new URL("https://I.com/something/#haha"))); + + assertTrue(ex.getMessage().contains("authority is invalid format (contains fragment)")); } - @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "authority is invalid format \\(contains fragment\\)") - public void testAADAuthorityConstructor_UrlHasFragment() throws MalformedURLException { - Authority.validateAuthority(new URL("https://I.com/something/#haha")); + @Test + void testAADAuthorityConstructor_AuthorityHasQuery() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> + Authority.validateAuthority(new URL("https://I.com/not/?query=not-allowed"))); + + assertTrue(ex.getMessage().contains("authority cannot contain query parameters")); } + @ParameterizedTest + @MethodSource("com.microsoft.aad.msal4j.AuthorityTest#authoritiesWithEmptyPath") + void testValidateAuthorityEmptyPathSegments(String authority) { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> + Authority.validateAuthority(new URL(authority))); - @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "authority cannot contain query parameters") - public void testAADAuthorityConstructor_AuthorityHasQuery() - throws MalformedURLException { - Authority.validateAuthority(new URL("https://I.com/not/?query=not-allowed")); + assertEquals(IllegalArgumentExceptionMessages.AUTHORITY_URI_EMPTY_PATH_SEGMENT, ex.getMessage()); } + @Test + void testValidateAuthorityEmptyPath() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> + Authority.validateAuthority(new URL("https://login.microsoftonline.com"))); + + assertEquals(IllegalArgumentExceptionMessages.AUTHORITY_URI_EMPTY_PATH, ex.getMessage()); + } @Test - public void testConstructor_AADAuthority() throws MalformedURLException { + void testConstructor_AADAuthority() throws MalformedURLException { final AADAuthority aa = new AADAuthority(new URL(TestConfiguration.AAD_TENANT_ENDPOINT)); - Assert.assertNotNull(aa); - Assert.assertEquals(aa.authority(), + assertNotNull(aa); + assertEquals(aa.authority(), TestConfiguration.AAD_TENANT_ENDPOINT); - Assert.assertEquals(aa.host(), TestConfiguration.AAD_HOST_NAME); - Assert.assertEquals(aa.tokenEndpoint(), + assertEquals(aa.host(), TestConfiguration.AAD_HOST_NAME); + assertEquals(aa.tokenEndpoint(), TestConfiguration.AAD_TENANT_ENDPOINT + "oauth2/v2.0/token"); - Assert.assertEquals(aa.selfSignedJwtAudience(), + assertEquals(aa.selfSignedJwtAudience(), TestConfiguration.AAD_TENANT_ENDPOINT + "oauth2/v2.0/token"); - Assert.assertEquals(aa.tokenEndpoint(), + assertEquals(aa.tokenEndpoint(), TestConfiguration.AAD_TENANT_ENDPOINT + "oauth2/v2.0/token"); - Assert.assertEquals(aa.authorityType(), AuthorityType.AAD); - Assert.assertFalse(aa.isTenantless()); - Assert.assertEquals(aa.deviceCodeEndpoint(), + assertEquals(aa.authorityType(), AuthorityType.AAD); + assertFalse(aa.isTenantless()); + assertEquals(aa.deviceCodeEndpoint(), TestConfiguration.AAD_TENANT_ENDPOINT + "oauth2/v2.0/devicecode"); } @Test - public void testConstructor_B2CAuthority() throws MalformedURLException { + void testConstructor_B2CAuthority() throws MalformedURLException { final B2CAuthority aa = new B2CAuthority(new URL(TestConfiguration.B2C_AUTHORITY)); - Assert.assertNotNull(aa); - Assert.assertEquals(aa.authority(), + assertNotNull(aa); + assertEquals(aa.authority(), TestConfiguration.B2C_AUTHORITY + "/"); - Assert.assertEquals(aa.host(), TestConfiguration.B2C_HOST_NAME); - Assert.assertEquals(aa.selfSignedJwtAudience(), + assertEquals(aa.host(), TestConfiguration.B2C_HOST_NAME); + assertEquals(aa.selfSignedJwtAudience(), TestConfiguration.B2C_AUTHORITY_ENDPOINT + "/oauth2/v2.0/token?p=" + TestConfiguration.B2C_SIGN_IN_POLICY); - Assert.assertEquals(aa.tokenEndpoint(), + assertEquals(aa.tokenEndpoint(), TestConfiguration.B2C_AUTHORITY_ENDPOINT + "/oauth2/v2.0/token?p=" + TestConfiguration.B2C_SIGN_IN_POLICY); - Assert.assertEquals(aa.authorityType(), AuthorityType.B2C); - Assert.assertEquals(aa.tokenEndpoint(), + assertEquals(aa.authorityType(), AuthorityType.B2C); + assertEquals(aa.tokenEndpoint(), TestConfiguration.B2C_AUTHORITY_ENDPOINT + "/oauth2/v2.0/token?p=" + TestConfiguration.B2C_SIGN_IN_POLICY); - Assert.assertFalse(aa.isTenantless()); + assertFalse(aa.isTenantless()); } @Test - public void testConstructor_ADFSAuthority() throws MalformedURLException { + void testConstructor_ADFSAuthority() throws MalformedURLException { final ADFSAuthority a = new ADFSAuthority(new URL(TestConfiguration.ADFS_TENANT_ENDPOINT)); - Assert.assertNotNull(a); - Assert.assertEquals(a.authority(), TestConfiguration.ADFS_TENANT_ENDPOINT); - Assert.assertEquals(a.host(), TestConfiguration.ADFS_HOST_NAME); - Assert.assertEquals(a.selfSignedJwtAudience(), + assertNotNull(a); + assertEquals(a.authority(), TestConfiguration.ADFS_TENANT_ENDPOINT); + assertEquals(a.host(), TestConfiguration.ADFS_HOST_NAME); + assertEquals(a.selfSignedJwtAudience(), TestConfiguration.ADFS_TENANT_ENDPOINT + ADFSAuthority.TOKEN_ENDPOINT); - Assert.assertEquals(a.authorityType(), AuthorityType.ADFS); + assertEquals(a.authorityType(), AuthorityType.ADFS); - Assert.assertEquals(a.tokenEndpoint(), + assertEquals(a.tokenEndpoint(), TestConfiguration.ADFS_TENANT_ENDPOINT + ADFSAuthority.TOKEN_ENDPOINT); - Assert.assertFalse(a.isTenantless()); + assertFalse(a.isTenantless()); } @Test - public void testB2CAuthority_SameCanonicalAuthority() throws MalformedURLException { + void testB2CAuthority_SameCanonicalAuthority() throws MalformedURLException { PublicClientApplication pca = PublicClientApplication.builder("client_id"). b2cAuthority(TestConfiguration.B2C_AUTHORITY_CUSTOM_PORT).build(); - Assert.assertEquals(pca.authenticationAuthority.authority, - TestConfiguration.B2C_AUTHORITY_CUSTOM_PORT_TAIL_SLASH); + assertEquals(TestConfiguration.B2C_AUTHORITY_CUSTOM_PORT_TAIL_SLASH, + pca.authenticationAuthority.authority); PublicClientApplication pca2 = PublicClientApplication.builder("client_id"). b2cAuthority(TestConfiguration.B2C_AUTHORITY_CUSTOM_PORT_TAIL_SLASH).build(); - Assert.assertEquals(pca2.authenticationAuthority.authority, - TestConfiguration.B2C_AUTHORITY_CUSTOM_PORT_TAIL_SLASH); + assertEquals(TestConfiguration.B2C_AUTHORITY_CUSTOM_PORT_TAIL_SLASH, + pca2.authenticationAuthority.authority); } @Test - public void testNoAuthorityPassedIn_DefaultsToCommonAuthority() { + void testNoAuthorityPassedIn_DefaultsToCommonAuthority() { PublicClientApplication pca = PublicClientApplication.builder("client_id").build(); - Assert.assertEquals(pca.authority(), TestConfiguration.AAD_COMMON_AUTHORITY); - Assert.assertNotNull(pca.authenticationAuthority); - } - - @Test - public void testDoStaticInstanceDiscovery_ValidateTrue_TrustedAuthority() - throws Exception { - final AADAuthority aa = new AADAuthority(new URL(TestConfiguration.AAD_TENANT_ENDPOINT)); - //PS Assert.assertTrue(aa.doStaticInstanceDiscovery(true)); + assertEquals(TestConfiguration.AAD_COMMON_AUTHORITY, pca.authority()); + assertNotNull(pca.authenticationAuthority); } - @Test - public void testDoStaticInstanceDiscovery_ValidateTrue_UntrustedAuthority() - throws Exception { - final AADAuthority aa = new AADAuthority(new URL(TestConfiguration.AAD_UNKNOWN_TENANT_ENDPOINT)); - //PS Assert.assertFalse(aa.doStaticInstanceDiscovery(true)); + static Object[][] validCiamAuthoritiesAndTransformedAuthority() throws MalformedURLException { + return new Object[][]{{new URL("https://msidlabciam1.ciamlogin.com/"), new URL("https://msidlabciam1.ciamlogin.com/msidlabciam1.onmicrosoft.com/")}, + {new URL("https://msidlabciam1.ciamlogin.com/d57fb3d4-4b5a-4144-9328-9c1f7d58179d"), new URL("https://msidlabciam1.ciamlogin.com/d57fb3d4-4b5a-4144-9328-9c1f7d58179d")}, + {new URL("https://msidlabciam1.ciamlogin.com/msidlabciam1.onmicrosoft.com"), new URL("https://msidlabciam1.ciamlogin.com/msidlabciam1.onmicrosoft.com")}, + {new URL("https://msidlabciam1.ciamlogin.com/aDomain"), new URL("https://msidlabciam1.ciamlogin.com/aDomain")}}; } - @Test - public void testDoStaticInstanceDiscovery_ValidateFalse_TrustedAuthority() - throws Exception { - final AADAuthority aa = new AADAuthority(new URL(TestConfiguration.AAD_UNKNOWN_TENANT_ENDPOINT)); - //PS Assert.assertTrue(aa.doStaticInstanceDiscovery(false)); + static Object[][] ciamAuthorities() throws MalformedURLException { + return new Object[][]{{new URL("https://msidlabciam1.ciamlogin.com/")}, + {new URL("https://msidlabciam1.ciamlogin.com/d57fb3d4-4b5a-4144-9328-9c1f7d58179d/")}, + {new URL("https://msidlabciam1.ciamlogin.com/msidlabciam1.onmicrosoft.com/")}, + {new URL("https://msidlabciam1.ciamlogin.com/aDomain/")}}; } - - @DataProvider(name = "authoritiesWithEmptyPath") - public static Object[][] createData() { + static Object[][] authoritiesWithEmptyPath() { return new Object[][]{{"https://login.microsoftonline.com/"}, {"https://login.microsoftonline.com//tenant"}, {"https://login.microsoftonline.com////tenant//path1"}}; } - - @Test(dataProvider = "authoritiesWithEmptyPath", expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = IllegalArgumentExceptionMessages.AUTHORITY_URI_EMPTY_PATH_SEGMENT) - public void testValidateAuthorityEmptyPathSegments(String authority) throws MalformedURLException { - Authority.validateAuthority(new URL(authority)); - } - - @Test(expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = IllegalArgumentExceptionMessages.AUTHORITY_URI_EMPTY_PATH) - public void testValidateAuthorityEmptyPath() throws MalformedURLException { - Authority.validateAuthority(new URL("https://login.microsoftonline.com")); - } } diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AuthorizationRequestUrlParametersTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AuthorizationRequestUrlParametersTest.java index 66dd4f3a..8c854be1 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AuthorizationRequestUrlParametersTest.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AuthorizationRequestUrlParametersTest.java @@ -3,18 +3,23 @@ package com.microsoft.aad.msal4j; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLDecoder; import java.util.*; -public class AuthorizationRequestUrlParametersTest { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class AuthorizationRequestUrlParametersTest { @Test - public void testBuilder_onlyRequiredParameters() throws UnsupportedEncodingException { + void testBuilder_onlyRequiredParameters() throws UnsupportedEncodingException { PublicClientApplication app = PublicClientApplication.builder("client_id").build(); String redirectUri = "http://localhost:8080"; @@ -30,23 +35,23 @@ public void testBuilder_onlyRequiredParameters() throws UnsupportedEncodingExcep .extraQueryParameters(extraParameters) .build(); - Assert.assertEquals(parameters.responseMode(), ResponseMode.FORM_POST); - Assert.assertEquals(parameters.redirectUri(), redirectUri); - Assert.assertEquals(parameters.scopes().size(), 4); - Assert.assertEquals(parameters.extraQueryParameters.size(), 2); + assertEquals(parameters.responseMode(), ResponseMode.FORM_POST); + assertEquals(parameters.redirectUri(), redirectUri); + assertEquals(parameters.scopes().size(), 4); + assertEquals(parameters.extraQueryParameters.size(), 2); - Assert.assertNull(parameters.loginHint()); - Assert.assertNull(parameters.codeChallenge()); - Assert.assertNull(parameters.codeChallengeMethod()); - Assert.assertNull(parameters.correlationId()); - Assert.assertNull(parameters.nonce()); - Assert.assertNull(parameters.prompt()); - Assert.assertNull(parameters.state()); + assertNull(parameters.loginHint()); + assertNull(parameters.codeChallenge()); + assertNull(parameters.codeChallengeMethod()); + assertNull(parameters.correlationId()); + assertNull(parameters.nonce()); + assertNull(parameters.prompt()); + assertNull(parameters.state()); URL authorizationUrl = app.getAuthorizationRequestUrl(parameters); - Assert.assertEquals(authorizationUrl.getHost(), "login.microsoftonline.com"); - Assert.assertEquals(authorizationUrl.getPath(), "/common/oauth2/v2.0/authorize"); + assertEquals(authorizationUrl.getHost(), "login.microsoftonline.com"); + assertEquals(authorizationUrl.getPath(), "/common/oauth2/v2.0/authorize"); Map queryParameters = new HashMap<>(); String query = authorizationUrl.getQuery(); @@ -59,27 +64,27 @@ public void testBuilder_onlyRequiredParameters() throws UnsupportedEncodingExcep URLDecoder.decode(pair.substring(idx + 1), "UTF-8")); } - Assert.assertEquals(queryParameters.get("scope"), "openid profile offline_access scope"); - Assert.assertEquals(queryParameters.get("response_type"), "code"); - Assert.assertEquals(queryParameters.get("redirect_uri"), "http://localhost:8080"); - Assert.assertEquals(queryParameters.get("client_id"), "client_id"); - Assert.assertEquals(queryParameters.get("response_mode"), "form_post"); - Assert.assertEquals(queryParameters.get("id_token_hint"),"test"); + assertEquals(queryParameters.get("scope"), "openid profile offline_access scope"); + assertEquals(queryParameters.get("response_type"), "code"); + assertEquals(queryParameters.get("redirect_uri"), "http://localhost:8080"); + assertEquals(queryParameters.get("client_id"), "client_id"); + assertEquals(queryParameters.get("response_mode"), "form_post"); + assertEquals(queryParameters.get("id_token_hint"),"test"); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void testBuilder_invalidRequiredParameters() { + @Test + void testBuilder_invalidRequiredParameters() { String redirectUri = ""; Set scope = Collections.singleton("scope"); - AuthorizationRequestUrlParameters parameters = + assertThrows(IllegalArgumentException.class, () -> AuthorizationRequestUrlParameters .builder(redirectUri, scope) - .build(); + .build()); } @Test - public void testBuilder_conflictingParameters() { + void testBuilder_conflictingParameters() { PublicClientApplication app = PublicClientApplication.builder("client_id").build(); String redirectUri = "http://localhost:8080"; @@ -95,7 +100,7 @@ public void testBuilder_conflictingParameters() { } @Test - public void testBuilder_optionalParameters() throws UnsupportedEncodingException { + void testBuilder_optionalParameters() throws UnsupportedEncodingException { Set clientCapabilities = new HashSet<>(); clientCapabilities.add("llt"); clientCapabilities.add("ssm"); @@ -134,23 +139,23 @@ public void testBuilder_optionalParameters() throws UnsupportedEncodingException URLDecoder.decode(pair.substring(idx + 1), "UTF-8")); } - Assert.assertEquals(queryParameters.get("scope"), + assertEquals(queryParameters.get("scope"), "openid profile offline_access scope extraScopeToConsent1 extraScopeToConsent2"); - Assert.assertEquals(queryParameters.get("response_type"), "code"); - Assert.assertEquals(queryParameters.get("redirect_uri"), "http://localhost:8080"); - Assert.assertEquals(queryParameters.get("client_id"), "client_id"); - Assert.assertEquals(queryParameters.get("prompt"), "select_account"); - Assert.assertEquals(queryParameters.get("response_mode"), "query"); - Assert.assertEquals(queryParameters.get("code_challenge"), "challenge"); - Assert.assertEquals(queryParameters.get("code_challenge_method"), "method"); - Assert.assertEquals(queryParameters.get("state"), "app_state"); - Assert.assertEquals(queryParameters.get("nonce"), "app_nonce"); - Assert.assertEquals(queryParameters.get("correlation_id"), "corr_id"); - Assert.assertEquals(queryParameters.get("login_hint"), "hint"); - Assert.assertEquals(queryParameters.get("domain_hint"), "domain_hint"); - Assert.assertEquals(queryParameters.get("claims"), "{\"id_token\":{\"auth_time\":{\"essential\":true}},\"access_token\":{\"auth_time\":{\"essential\":true},\"xms_cc\":{\"values\":[\"llt\",\"ssm\"]}}}"); + assertEquals(queryParameters.get("response_type"), "code"); + assertEquals(queryParameters.get("redirect_uri"), "http://localhost:8080"); + assertEquals(queryParameters.get("client_id"), "client_id"); + assertEquals(queryParameters.get("prompt"), "select_account"); + assertEquals(queryParameters.get("response_mode"), "query"); + assertEquals(queryParameters.get("code_challenge"), "challenge"); + assertEquals(queryParameters.get("code_challenge_method"), "method"); + assertEquals(queryParameters.get("state"), "app_state"); + assertEquals(queryParameters.get("nonce"), "app_nonce"); + assertEquals(queryParameters.get("correlation_id"), "corr_id"); + assertEquals(queryParameters.get("login_hint"), "hint"); + assertEquals(queryParameters.get("domain_hint"), "domain_hint"); + assertEquals(queryParameters.get("claims"), "{\"id_token\":{\"auth_time\":{\"essential\":true}},\"access_token\":{\"auth_time\":{\"essential\":true},\"xms_cc\":{\"values\":[\"llt\",\"ssm\"]}}}"); // CCS routing - Assert.assertEquals(queryParameters.get(HttpHeaders.X_ANCHOR_MAILBOX), String.format(HttpHeaders.X_ANCHOR_MAILBOX_UPN_FORMAT, "hint")); + assertEquals(queryParameters.get(HttpHeaders.X_ANCHOR_MAILBOX), String.format(HttpHeaders.X_ANCHOR_MAILBOX_UPN_FORMAT, "hint")); } } diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/CacheFormatTests.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/CacheFormatTests.java index 6714b82b..7adb399f 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/CacheFormatTests.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/CacheFormatTests.java @@ -7,15 +7,19 @@ import com.nimbusds.oauth2.sdk.http.HTTPResponse; import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; import net.minidev.json.JSONObject; -import org.easymock.EasyMock; import org.json.JSONException; -import org.powermock.api.easymock.PowerMock; import org.skyscreamer.jsonassert.JSONAssert; import org.skyscreamer.jsonassert.JSONCompareMode; import org.skyscreamer.jsonassert.JSONCompareResult; import org.skyscreamer.jsonassert.comparator.DefaultComparator; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; import java.io.IOException; import java.net.URI; @@ -28,7 +32,9 @@ import static com.microsoft.aad.msal4j.Constants.POINT_DELIMITER; -public class CacheFormatTests extends AbstractMsalTests { +@ExtendWith(MockitoExtension.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class CacheFormatTests { String TOKEN_RESPONSE = "/token_response.json"; String TOKEN_RESPONSE_ID_TOKEN = "/token_response_id_token.json"; @@ -53,7 +59,7 @@ public class CacheFormatTests extends AbstractMsalTests { String EXTENDED_EXPIRES_ON_PLACEHOLDER = ""; @Test - public void cacheDeserializationSerializationTest() throws IOException, URISyntaxException, JSONException { + void cacheDeserializationSerializationTest() throws IOException, URISyntaxException, JSONException { ITokenCache tokenCache = new TokenCache(null); String previouslyStoredCache = readResource("/cache_data/serialized_cache.json"); @@ -108,17 +114,17 @@ public void compareValues(String s, Object o, Object o1, JSONCompareResult jsonC } @Test - public void AADTokenCacheEntitiesFormatTest() throws JSONException, IOException, ParseException, URISyntaxException { + void AADTokenCacheEntitiesFormatTest() throws JSONException, IOException, ParseException, URISyntaxException { tokenCacheEntitiesFormatTest("/AAD_cache_data"); } @Test - public void MSATokenCacheEntitiesFormatTest() throws JSONException, IOException, ParseException, URISyntaxException { + void MSATokenCacheEntitiesFormatTest() throws JSONException, IOException, ParseException, URISyntaxException { tokenCacheEntitiesFormatTest("/MSA_cache_data"); } @Test - public void FociTokenCacheEntitiesFormatTest() throws JSONException, IOException, ParseException, URISyntaxException { + void FociTokenCacheEntitiesFormatTest() throws JSONException, IOException, ParseException, URISyntaxException { tokenCacheEntitiesFormatTest("/Foci_cache_data"); } @@ -145,30 +151,18 @@ public void tokenCacheEntitiesFormatTest(String folder) throws URISyntaxExceptio null, new TelemetryManager(null, false)); - TokenRequestExecutor request = PowerMock.createPartialMock( - TokenRequestExecutor.class, new String[]{"createOauthHttpRequest"}, - new AADAuthority(new URL(AUTHORIZE_REQUEST_URL)), msalRequest, serviceBundle); + TokenRequestExecutor request = spy(new TokenRequestExecutor( + new AADAuthority(new URL(AUTHORIZE_REQUEST_URL)), msalRequest, serviceBundle)); + OAuthHttpRequest msalOAuthHttpRequest = mock(OAuthHttpRequest.class); + HTTPResponse httpResponse = mock(HTTPResponse.class); - OAuthHttpRequest msalOAuthHttpRequest = PowerMock.createMock(OAuthHttpRequest.class); - - HTTPResponse httpResponse = PowerMock.createMock(HTTPResponse.class); - - EasyMock.expect(request.createOauthHttpRequest()).andReturn(msalOAuthHttpRequest).times(1); - EasyMock.expect(msalOAuthHttpRequest.send()).andReturn(httpResponse).times(1); - EasyMock.expect(httpResponse.getStatusCode()).andReturn(200).times(1); - EasyMock.expect(httpResponse.getContentAsJSONObject()) - .andReturn( - JSONObjectUtils.parse(tokenResponse)) - .times(1); - httpResponse.ensureStatusCode(200); - EasyMock.expectLastCall(); - - PowerMock.replay(request, msalOAuthHttpRequest, httpResponse); + doReturn(msalOAuthHttpRequest).when(request).createOauthHttpRequest(); + doReturn(httpResponse).when(msalOAuthHttpRequest).send(); + doReturn(200).when(httpResponse).getStatusCode(); + doReturn(JSONObjectUtils.parse(tokenResponse)).when(httpResponse).getContentAsJSONObject(); final AuthenticationResult result = request.executeTokenRequest(); - PowerMock.verifyAll(); - TokenCache tokenCache = new TokenCache(); tokenCache.saveTokens(request, result, "login.microsoftonline.com"); @@ -183,11 +177,11 @@ public void tokenCacheEntitiesFormatTest(String folder) throws URISyntaxExceptio private void validateAccessTokenCacheEntity(String folder, String tokenResponse, TokenCache tokenCache) throws IOException, URISyntaxException, ParseException, JSONException { - Assert.assertEquals(tokenCache.accessTokens.size(), 1); + assertEquals(tokenCache.accessTokens.size(), 1); String keyActual = tokenCache.accessTokens.keySet().stream().findFirst().get(); String keyExpected = readResource(folder + AT_CACHE_ENTITY_KEY); - Assert.assertEquals(keyActual, keyExpected); + assertEquals(keyActual, keyExpected); String valueActual = JsonHelper.mapper.writeValueAsString(tokenCache.accessTokens.get(keyActual)); String valueExpected = readResource(folder + AT_CACHE_ENTITY); @@ -204,11 +198,11 @@ private void validateAccessTokenCacheEntity(String folder, String tokenResponse, private void validateRefreshTokenCacheEntity(String folder, TokenCache tokenCache) throws IOException, URISyntaxException, JSONException { - Assert.assertEquals(tokenCache.refreshTokens.size(), 1); + assertEquals(tokenCache.refreshTokens.size(), 1); String actualKey = tokenCache.refreshTokens.keySet().stream().findFirst().get(); String keyExpected = readResource(folder + RT_CACHE_ENTITY_KEY); - Assert.assertEquals(actualKey, keyExpected); + assertEquals(actualKey, keyExpected); String actualValue = JsonHelper.mapper.writeValueAsString(tokenCache.refreshTokens.get(actualKey)); String valueExpected = readResource(folder + RT_CACHE_ENTITY); @@ -240,11 +234,11 @@ public void compareValues(String s, Object o, Object o1, JSONCompareResult jsonC private void validateIdTokenCacheEntity(String folder, TokenCache tokenCache) throws IOException, URISyntaxException, JSONException { - Assert.assertEquals(tokenCache.idTokens.size(), 1); + assertEquals(tokenCache.idTokens.size(), 1); String actualKey = tokenCache.idTokens.keySet().stream().findFirst().get(); String keyExpected = readResource(folder + ID_TOKEN_CACHE_ENTITY_KEY); - Assert.assertEquals(actualKey, keyExpected); + assertEquals(actualKey, keyExpected); String actualValue = JsonHelper.mapper.writeValueAsString(tokenCache.idTokens.get(actualKey)); String valueExpected = readResource(folder + ID_TOKEN_CACHE_ENTITY); @@ -255,11 +249,11 @@ private void validateIdTokenCacheEntity(String folder, TokenCache tokenCache) private void validateAccountCacheEntity(String folder, TokenCache tokenCache) throws IOException, URISyntaxException, JSONException { - Assert.assertEquals(tokenCache.accounts.size(), 1); + assertEquals(tokenCache.accounts.size(), 1); String actualKey = tokenCache.accounts.keySet().stream().findFirst().get(); String keyExpected = readResource(folder + ACCOUNT_CACHE_ENTITY_KEY); - Assert.assertEquals(actualKey, keyExpected); + assertEquals(actualKey, keyExpected); String actualValue = JsonHelper.mapper.writeValueAsString(tokenCache.accounts.get(actualKey)); String valueExpected = readResource(folder + ACCOUNT_CACHE_ENTITY); @@ -274,11 +268,11 @@ private void validateAppMetadataCacheEntity(String folder, TokenCache tokenCache return; } - Assert.assertEquals(tokenCache.appMetadata.size(), 1); + assertEquals(tokenCache.appMetadata.size(), 1); String actualKey = tokenCache.appMetadata.keySet().stream().findFirst().get(); String keyExpected = readResource(folder + APP_METADATA_ENTITY_KEY); - Assert.assertEquals(actualKey, keyExpected); + assertEquals(actualKey, keyExpected); String actualValue = JsonHelper.mapper.writeValueAsString(tokenCache.appMetadata.get(actualKey)); String valueExpected = readResource(folder + APP_METADATA_CACHE_ENTITY); diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClaimsTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClaimsTest.java index 60eb99e8..708ea306 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClaimsTest.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClaimsTest.java @@ -3,9 +3,9 @@ package com.microsoft.aad.msal4j; -import org.testng.Assert; -import org.testng.annotations.Test; - +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; @@ -13,10 +13,11 @@ import java.util.HashSet; import java.util.List; -public class ClaimsTest { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class ClaimsTest { @Test - public void testClaimsRequest_Format() { + void testClaimsRequest_Format() { List values = new ArrayList<>(); values.add("urn:mace:incommon:iap:silver"); @@ -29,11 +30,11 @@ public void testClaimsRequest_Format() { cr.requestClaimInIdToken("sub", new RequestedClaimAdditionalInfo(true, "248289761001", null)); cr.requestClaimInIdToken("auth_time", new RequestedClaimAdditionalInfo(false, null, null)); - Assert.assertEquals(cr.formatAsJSONString(), TestConfiguration.CLAIMS_REQUEST); + assertEquals(cr.formatAsJSONString(), TestConfiguration.CLAIMS_REQUEST); } @Test - public void testClaimsRequest_MergeWithClientCapabilitiesAndClaimsChallenge() throws URISyntaxException { + void testClaimsRequest_MergeWithClientCapabilitiesAndClaimsChallenge() throws URISyntaxException { List values = new ArrayList<>(); values.add("urn:mace:incommon:iap:silver"); @@ -64,18 +65,18 @@ public void testClaimsRequest_MergeWithClientCapabilitiesAndClaimsChallenge() th 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); + assertEquals(clientCapabilities, TestConfiguration.CLIENT_CAPABILITIES); + assertEquals(claimsChallenge, TestConfiguration.CLAIMS_CHALLENGE); + assertEquals(claimsRequest, TestConfiguration.CLAIMS_REQUEST); + assertEquals(mergedClaimsAndCapabilities, TestConfiguration.MERGED_CLAIMS_AND_CAPABILITIES); + assertEquals(mergedClaimsAndChallenge, TestConfiguration.MERGED_CLAIMS_AND_CHALLENGE); + assertEquals(mergedAll, TestConfiguration.MERGED_CLAIMS_CAPABILITIES_AND_CHALLENGE); } @Test - public void testClaimsRequest_StringToClaimsRequest() { + void testClaimsRequest_StringToClaimsRequest() { ClaimsRequest cr = ClaimsRequest.formatAsClaimsRequest(TestConfiguration.CLAIMS_CHALLENGE); - Assert.assertEquals(cr.formatAsJSONString(), TestConfiguration.CLAIMS_CHALLENGE); + assertEquals(cr.formatAsJSONString(), TestConfiguration.CLAIMS_CHALLENGE); } } diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClientCertificatePkcs12Test.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClientCertificatePkcs12Test.java index 112a8f11..5af514ac 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClientCertificatePkcs12Test.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClientCertificatePkcs12Test.java @@ -3,70 +3,76 @@ package com.microsoft.aad.msal4j; -import org.easymock.EasyMock; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; import java.security.KeyStore; import java.security.KeyStoreSpi; import java.util.Arrays; import java.util.Collections; -import static org.testng.AssertJUnit.assertEquals; - -@Test -public class ClientCertificatePkcs12Test extends AbstractMsalTests { +@ExtendWith(MockitoExtension.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class ClientCertificatePkcs12Test { private KeyStoreSpi keyStoreSpi; private KeyStore keystore; - @BeforeMethod - public void setUp() throws Exception { - keyStoreSpi = EasyMock.createMock(KeyStoreSpi.class); + @BeforeEach + void setUp() throws Exception { + keyStoreSpi = mock(KeyStoreSpi.class); keystore = new KeyStore(keyStoreSpi, null, "PKCS12") {}; keystore.load(null); } - @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "certificate not loaded from input stream") - public void testNoEntries() throws Exception { - EasyMock.expect(keyStoreSpi.engineAliases()) - .andReturn(Collections.enumeration(Collections.emptyList())).times(1); - EasyMock.replay(keyStoreSpi); + @Test + void testNoEntries() { + doReturn(Collections.enumeration(Collections.emptyList())).when(keyStoreSpi).engineAliases(); + + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> ClientCertificate.getPrivateKeyAlias(keystore)); - ClientCertificate.getPrivateKeyAlias(keystore); + assertTrue(ex.getMessage().contains("certificate not loaded from input stream")); } - @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "certificate not loaded from input stream") - public void testNoPrivateKey() throws Exception { - EasyMock.expect(keyStoreSpi.engineAliases()) - .andReturn(Collections.enumeration(Arrays.asList("CA_cert1", "CA_cert2"))).times(1); - EasyMock.expect(keyStoreSpi.engineEntryInstanceOf("CA_cert1", KeyStore.PrivateKeyEntry.class)).andReturn(false).times(1); - EasyMock.expect(keyStoreSpi.engineEntryInstanceOf("CA_cert2", KeyStore.PrivateKeyEntry.class)).andReturn(false).times(1); - EasyMock.replay(keyStoreSpi); + @Test + void testNoPrivateKey() { + doReturn(Collections.enumeration(Arrays.asList("CA_cert1", "CA_cert2"))).when(keyStoreSpi).engineAliases(); + doReturn(false).when(keyStoreSpi).engineEntryInstanceOf("CA_cert1", KeyStore.PrivateKeyEntry.class); + doReturn(false).when(keyStoreSpi).engineEntryInstanceOf("CA_cert2", KeyStore.PrivateKeyEntry.class); + + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> ClientCertificate.getPrivateKeyAlias(keystore)); - ClientCertificate.getPrivateKeyAlias(keystore); + assertTrue(ex.getMessage().contains("certificate not loaded from input stream")); } - @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "more than one certificate alias found in input stream") - public void testMultiplePrivateKeyAliases() throws Exception { - EasyMock.expect(keyStoreSpi.engineAliases()) - .andReturn(Collections.enumeration(Arrays.asList("private_key1", "private_key2", "CA_cert"))).times(1); - EasyMock.expect(keyStoreSpi.engineEntryInstanceOf("private_key1", KeyStore.PrivateKeyEntry.class)).andReturn(true).times(1); - EasyMock.expect(keyStoreSpi.engineEntryInstanceOf("private_key2", KeyStore.PrivateKeyEntry.class)).andReturn(true).times(1); - EasyMock.expect(keyStoreSpi.engineEntryInstanceOf("CA_cert", KeyStore.PrivateKeyEntry.class)).andReturn(false).times(1); - EasyMock.replay(keyStoreSpi); + @Test + void testMultiplePrivateKeyAliases() { + doReturn(Collections.enumeration(Arrays.asList("private_key1", "private_key2", "CA_cert"))).when(keyStoreSpi).engineAliases(); + doReturn(true).when(keyStoreSpi).engineEntryInstanceOf("private_key1", KeyStore.PrivateKeyEntry.class); + doReturn(true).when(keyStoreSpi).engineEntryInstanceOf("private_key2", KeyStore.PrivateKeyEntry.class); + lenient().doReturn(false).when(keyStoreSpi).engineEntryInstanceOf("CA_cert", KeyStore.PrivateKeyEntry.class); + + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> ClientCertificate.getPrivateKeyAlias(keystore)); - ClientCertificate.getPrivateKeyAlias(keystore); + assertTrue(ex.getMessage().contains("more than one certificate alias found in input stream")); } @Test - public void testMultipleEntriesButOnlyOnePrivateKey() throws Exception { - EasyMock.expect(keyStoreSpi.engineAliases()) - .andReturn(Collections.enumeration(Arrays.asList("CA_cert1", "private_key", "CA_cert2"))).times(1); - EasyMock.expect(keyStoreSpi.engineEntryInstanceOf("CA_cert1", KeyStore.PrivateKeyEntry.class)).andReturn(false).times(1); - EasyMock.expect(keyStoreSpi.engineEntryInstanceOf("private_key", KeyStore.PrivateKeyEntry.class)).andReturn(true).times(1); - EasyMock.expect(keyStoreSpi.engineEntryInstanceOf("CA_cert2", KeyStore.PrivateKeyEntry.class)).andReturn(false).times(1); - EasyMock.replay(keyStoreSpi); + void testMultipleEntriesButOnlyOnePrivateKey() throws Exception { + + doReturn(Collections.enumeration(Arrays.asList("CA_cert1", "private_key", "CA_cert2"))).when(keyStoreSpi).engineAliases(); + doReturn(false).when(keyStoreSpi).engineEntryInstanceOf("CA_cert1", KeyStore.PrivateKeyEntry.class); + doReturn(true).when(keyStoreSpi).engineEntryInstanceOf("private_key", KeyStore.PrivateKeyEntry.class); + doReturn(false).when(keyStoreSpi).engineEntryInstanceOf("CA_cert2", KeyStore.PrivateKeyEntry.class); String privateKeyAlias = ClientCertificate.getPrivateKeyAlias(keystore); assertEquals("private_key", privateKeyAlias); diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClientCertificateTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClientCertificateTest.java index c54aef87..7241a141 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClientCertificateTest.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClientCertificateTest.java @@ -3,54 +3,48 @@ package com.microsoft.aad.msal4j; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import java.math.BigInteger; import java.security.PrivateKey; import java.security.interfaces.RSAPrivateKey; -import org.easymock.EasyMock; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.testng.annotations.Test; - -@Test(groups = {"checkin"}) -@PrepareForTest({RSAPrivateKey.class}) -public class ClientCertificateTest extends AbstractMsalTests { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class ClientCertificateTest { - @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "PrivateKey is null or empty") - public void testNullKey() { - ClientCertificate.create((PrivateKey) null, null); - } + @Test + void testNullKey() { + NullPointerException ex = assertThrows(NullPointerException.class, () -> ClientCertificate.create((PrivateKey) null, null)); - @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "certificate key size must be at least 2048") - public void testInvalidKeysize() { - final RSAPrivateKey key = EasyMock.createMock(RSAPrivateKey.class); - final BigInteger modulus = EasyMock.createMock(BigInteger.class); - EasyMock.expect(modulus.bitLength()).andReturn(2047).times(1); - EasyMock.expect(key.getModulus()).andReturn(modulus).times(1); - EasyMock.replay(modulus, key); - ClientCertificate.create(key, null); + assertEquals("PrivateKey is null or empty", ex.getMessage()); } @Test - public void testGetClient() { - final RSAPrivateKey key = EasyMock.createMock(RSAPrivateKey.class); - final BigInteger modulus = EasyMock.createMock(BigInteger.class); - EasyMock.expect(modulus.bitLength()).andReturn(2048).times(1); - EasyMock.expect(key.getModulus()).andReturn(modulus).times(1); - EasyMock.replay(modulus, key); - final ClientCertificate kc = ClientCertificate.create(key, null); - assertNotNull(kc); + void testInvalidKeysize() { + final RSAPrivateKey key = mock(RSAPrivateKey.class); + final BigInteger modulus = mock(BigInteger.class); + doReturn(2047).when(modulus).bitLength(); + doReturn(modulus).when(key).getModulus(); + + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> ClientCertificate.create(key, null)); + + assertEquals("certificate key size must be at least 2048", ex.getMessage()); } @Test - public void testGetKey() { - final RSAPrivateKey key = EasyMock.createMock(RSAPrivateKey.class); - final BigInteger modulus = EasyMock.createMock(BigInteger.class); - EasyMock.expect(modulus.bitLength()).andReturn(2048).times(1); - EasyMock.expect(key.getModulus()).andReturn(modulus).times(1); - EasyMock.replay(modulus, key); + void testGetClient() { + final RSAPrivateKey key = mock(RSAPrivateKey.class); + final BigInteger modulus = mock(BigInteger.class); + doReturn(2048).when(modulus).bitLength(); + doReturn(modulus).when(key).getModulus(); + final ClientCertificate kc = ClientCertificate.create(key, null); assertNotNull(kc); } diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClientCredentialTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClientCredentialTest.java new file mode 100644 index 00000000..b3e73cbe --- /dev/null +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClientCredentialTest.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.aad.msal4j; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class ClientCredentialTest { + + @Test + void testAssertionNullAndEmpty() { + assertThrows(NullPointerException.class, () -> + new ClientAssertion("")); + + assertThrows(NullPointerException.class, () -> + new ClientAssertion(null)); + } + + @Test + void testSecretNullAndEmpty() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> + new ClientSecret("")); + + assertTrue(ex.getMessage().contains("clientSecret is null or empty")); + + assertThrows(IllegalArgumentException.class, () -> + new ClientSecret(null)); + + assertTrue(ex.getMessage().contains("clientSecret is null or empty")); + } +} diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClientSecretTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClientSecretTest.java deleted file mode 100644 index d058c8cf..00000000 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ClientSecretTest.java +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.microsoft.aad.msal4j; - -import org.testng.annotations.Test; - -/** - * - */ -public class ClientSecretTest { - - @Test(expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = "clientSecret is null or empty") - public void testConstructorNullClientId() { - new ClientSecret(null); - } - - @Test(expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = "clientSecret is null or empty") - public void testConstructorEmptyClientId() { - new ClientSecret(""); - } -} diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/DefaultHttpClientTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/DefaultHttpClientTest.java deleted file mode 100644 index 12ea22eb..00000000 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/DefaultHttpClientTest.java +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.microsoft.aad.msal4j; - -import org.apache.commons.io.IOUtils; -import org.easymock.EasyMock; -import org.powermock.api.easymock.PowerMock; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.testng.PowerMockTestCase; -import org.testng.Assert; -import org.testng.annotations.Test; - -import javax.net.ssl.HttpsURLConnection; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.powermock.api.easymock.PowerMock.expectPrivate; - -@PrepareForTest({DefaultHttpClient.class}) -public class DefaultHttpClientTest extends PowerMockTestCase { - - @Test - public void ValidNotOkHttpResponse() throws Exception { - String TEST_URL = "https://somehost.com"; - - HttpsURLConnection mockCon = PowerMock.createMock(HttpsURLConnection.class); - - EasyMock.expect(mockCon.getResponseCode()) - .andReturn(HttpURLConnection.HTTP_INTERNAL_ERROR).times(1); - - String errorResponse = "Error Message"; - InputStream inputStream = IOUtils.toInputStream(errorResponse, "UTF-8"); - EasyMock.expect(mockCon.getErrorStream()).andReturn(inputStream).times(1); - - Map> expectedHeaders = new HashMap<>(); - expectedHeaders.put("header1", Arrays.asList("val1", "val2")); - - EasyMock.expect(mockCon.getHeaderFields()).andReturn(expectedHeaders).times(1); - - mockCon.setReadTimeout(0); - mockCon.setConnectTimeout(0); - - DefaultHttpClient httpClient = - PowerMock.createPartialMock(DefaultHttpClient.class, "openConnection"); - - expectPrivate(httpClient, "openConnection", EasyMock.isA(URL.class)).andReturn(mockCon); - - PowerMock.replayAll(mockCon, httpClient); - - - HttpRequest httpRequest = new HttpRequest(HttpMethod.GET, TEST_URL); - IHttpResponse response = httpClient.send(httpRequest); - - - Assert.assertEquals(response.body(), errorResponse); - Assert.assertEquals(response.headers(), expectedHeaders); - } -} diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/DeviceCodeFlowTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/DeviceCodeFlowTest.java deleted file mode 100644 index 1ac60c59..00000000 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/DeviceCodeFlowTest.java +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.microsoft.aad.msal4j; - -import com.nimbusds.oauth2.sdk.http.HTTPResponse; -import org.easymock.Capture; -import org.easymock.EasyMock; -import org.powermock.api.easymock.PowerMock; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.testng.PowerMockTestCase; -import org.testng.Assert; -import org.testng.IObjectFactory; -import org.testng.annotations.ObjectFactory; -import org.testng.annotations.Test; - -import java.net.URL; -import java.net.URLEncoder; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Consumer; - - -@Test(groups = {"checkin"}) -@PrepareForTest({HttpHelper.class, PublicClientApplication.class}) -public class DeviceCodeFlowTest extends PowerMockTestCase { - private PublicClientApplication app = null; - - @ObjectFactory - public IObjectFactory getObjectFactory() { - return new org.powermock.modules.testng.PowerMockObjectFactory(); - } - - public static Map getQueryMap(String query) { - Map map = new HashMap<>(); - for (String param : query.split("&")) { - map.put(param.split("=")[0], param.split("=")[1]); - } - return map; - } - - String deviceCodeJsonResponse = "{\n" + - " \"user_code\": \"DW83JNP2P\",\n" + - " \"device_code\": \"DAQABAAEAAADRNYRQ3dhRFEeqWvq-yi6QodK2pb1iAA\",\n" + - " \"verification_uri\": \"https://aka.ms/devicelogin\",\n" + - " \"expires_in\": 900,\n" + - " \"interval\": 5,\n" + - " \"message\": \"To sign in, use a web browser to open the page https://aka.ms/devicelogin and enter the code DW83JNP2P to authenticate.\"\n" + - "}"; - - @SuppressWarnings("unchecked") - @Test - public void deviceCodeFlowTest() throws Exception { - app = PowerMock.createPartialMock(PublicClientApplication.class, - new String[]{"acquireTokenCommon"}, - PublicClientApplication.builder(TestConfiguration.AAD_CLIENT_ID) - .authority(TestConfiguration.AAD_TENANT_ENDPOINT)); - - Capture capturedMsalRequest = Capture.newInstance(); - - PowerMock.expectPrivate(app, "acquireTokenCommon", - EasyMock.capture(capturedMsalRequest), EasyMock.isA(AADAuthority.class)).andReturn( - AuthenticationResult.builder(). - accessToken("accessToken"). - expiresOn(new Date().getTime() + 100). - refreshToken("refreshToken"). - idToken("idToken").environment("environment").build()); - - PowerMock.mockStatic(HttpHelper.class); - - HttpResponse instanceDiscoveryResponse = new HttpResponse(); - instanceDiscoveryResponse.statusCode(200); - instanceDiscoveryResponse.body(TestConfiguration.INSTANCE_DISCOVERY_RESPONSE); - - EasyMock.expect( - HttpHelper.executeHttpRequest( - EasyMock.isA(HttpRequest.class), - EasyMock.isA(RequestContext.class), - EasyMock.isA(ServiceBundle.class))) - .andReturn(instanceDiscoveryResponse); - - HttpResponse deviceCodeResponse = new HttpResponse(); - deviceCodeResponse.statusCode(200); - deviceCodeResponse.body(deviceCodeJsonResponse); - - Capture capturedHttpRequest = Capture.newInstance(); - - EasyMock.expect( - HttpHelper.executeHttpRequest( - EasyMock.capture(capturedHttpRequest), - EasyMock.isA(RequestContext.class), - EasyMock.isA(ServiceBundle.class))) - .andReturn(deviceCodeResponse); - - PowerMock.replay(HttpHelper.class, HttpResponse.class); - - AtomicReference deviceCodeCorrelationId = new AtomicReference<>(); - - Consumer deviceCodeConsumer = (DeviceCode deviceCode) -> { - - // validate returned Device Code object - Assert.assertNotNull(deviceCode); - Assert.assertEquals(deviceCode.userCode(), "DW83JNP2P"); - Assert.assertEquals(deviceCode.deviceCode(), "DAQABAAEAAADRNYRQ3dhRFEeqWvq-yi6QodK2pb1iAA"); - Assert.assertEquals(deviceCode.verificationUri(), "https://aka.ms/devicelogin"); - Assert.assertEquals(deviceCode.expiresIn(), 900); - Assert.assertEquals(deviceCode.interval(), 5); - Assert.assertEquals(deviceCode.message(), "To sign in, use a web browser" + - " to open the page https://aka.ms/devicelogin and enter the code DW83JNP2P to authenticate."); - Assert.assertNotNull(deviceCode.correlationId()); - - deviceCodeCorrelationId.set(deviceCode.correlationId()); - }; - - PowerMock.replay(app); - - IAuthenticationResult authResult = app.acquireToken( - DeviceCodeFlowParameters.builder(Collections.singleton(TestConfiguration.AAD_RESOURCE_ID), deviceCodeConsumer) - .build()) - .get(); - - // validate HTTP GET request used to get device code - URL url = capturedHttpRequest.getValue().url(); - Assert.assertEquals(url.getAuthority(), TestConfiguration.AAD_PREFERRED_NETWORK_ENV_ALIAS); - Assert.assertEquals(url.getPath(), - "/" + TestConfiguration.AAD_TENANT_NAME + "/" + AADAuthority.DEVICE_CODE_ENDPOINT); - - String expectedScope = URLEncoder.encode(AbstractMsalAuthorizationGrant.COMMON_SCOPES_PARAM + - AbstractMsalAuthorizationGrant.SCOPES_DELIMITER + TestConfiguration.AAD_RESOURCE_ID, "UTF-8"); - String expectedBody = String.format("scope=%s&client_id=%s", expectedScope, TestConfiguration.AAD_CLIENT_ID); - - String body = capturedHttpRequest.getValue().body(); - Assert.assertEquals(body, expectedBody); - - // make sure same correlation id is used for acquireDeviceCode and acquireTokenByDeviceCode calls - Assert.assertEquals(capturedMsalRequest.getValue().headers().getReadonlyHeaderMap(). - get(HttpHeaders.CORRELATION_ID_HEADER_NAME), deviceCodeCorrelationId.get()); - Assert.assertNotNull(authResult); - - PowerMock.verify(); - } - - @Test(expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = "Invalid authority type. Device Flow is not supported by B2C authority.") - public void executeAcquireDeviceCode_B2CAuthorityUsed_IllegalArgumentExceptionThrown() - throws Exception { - - app = PublicClientApplication.builder("client_id") - .b2cAuthority(TestConfiguration.B2C_AUTHORITY) - .validateAuthority(false).build(); - - app.acquireToken - (DeviceCodeFlowParameters - .builder(Collections.singleton(TestConfiguration.AAD_RESOURCE_ID), (DeviceCode deviceCode) -> { - }) - .build()); - } - - @Test - public void executeAcquireDeviceCode_AuthenticaionPendingErrorReturned_AuthenticationExceptionThrown() - throws Exception { - - TelemetryManager telemetryManager = new TelemetryManager(null, false); - - AtomicReference> futureReference = - new AtomicReference<>(); - - Consumer deviceCodeConsumer = (DeviceCode deviceCode) -> { - }; - - app = PublicClientApplication.builder("client_id") - .authority(TestConfiguration.AAD_TENANT_ENDPOINT) - .validateAuthority(false) - .correlationId("corr_id") - .build(); - - DeviceCodeFlowParameters parameters = - DeviceCodeFlowParameters.builder(Collections.singleton("default-scope"), deviceCodeConsumer) - .build(); - - final DeviceCodeFlowRequest dcr = new DeviceCodeFlowRequest( - parameters, - futureReference, - app, - new RequestContext(app, PublicApi.ACQUIRE_TOKEN_BY_DEVICE_CODE_FLOW, parameters)); - - - TokenRequestExecutor request = PowerMock.createPartialMock( - TokenRequestExecutor.class, new String[]{"createOauthHttpRequest"}, - new AADAuthority(new URL(TestConstants.ORGANIZATIONS_AUTHORITY)), - dcr, new ServiceBundle(null, null, telemetryManager)); - - OAuthHttpRequest msalOAuthHttpRequest = PowerMock.createMock(OAuthHttpRequest.class); - - HTTPResponse httpResponse = new HTTPResponse(HTTPResponse.SC_BAD_REQUEST); - - String content = "{\"error\":\"authorization_pending\"," + - "\"error_description\":\"AADSTS70016: Pending end-user authorization.\\r\\n" + - "Trace ID: 6c9dd244-0c65-4ea6-b121-0afd1c640200\\r\\n" + - "Correlation ID: ff60101b-cb23-4a52-82cb-9966f466327a\\r\\n" + - "Timestamp: 2018-03-14 20:15:43Z\"," + - "\"error_codes\":[70016],\"timestamp\":\"2018-03-14 20:15:43Z\"," + - "\"trace_id\":\"6c9dd244-0c65-4ea6-b121-0afd1c640200\"," + - "\"correlation_id\":\"ff60101b-cb23-4a52-82cb-9966f466327a\"}"; - - httpResponse.setContent(content); - httpResponse.setContentType(HTTPContentType.ApplicationJSON.contentType); - - EasyMock.expect(request.createOauthHttpRequest()).andReturn(msalOAuthHttpRequest).times(1); - EasyMock.expect(msalOAuthHttpRequest.send()).andReturn(httpResponse).times(1); - - PowerMock.replay(request, msalOAuthHttpRequest); - - try { - request.executeTokenRequest(); - Assert.fail("Expected MsalException was not thrown"); - } catch (MsalServiceException ex) { - - Assert.assertEquals(ex.errorCode(), AuthenticationErrorCode.AUTHORIZATION_PENDING); - } - PowerMock.verifyAll(); - } -} \ No newline at end of file diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/HttpHeaderTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/HttpHeaderTest.java index 435dffe1..fb4f4757 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/HttpHeaderTest.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/HttpHeaderTest.java @@ -3,18 +3,24 @@ package com.microsoft.aad.msal4j; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.api.BeforeAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import java.util.Collections; import java.util.HashMap; import java.util.Map; -@Test(groups = {"checkin"}) -public class HttpHeaderTest { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class HttpHeaderTest { @Test - public void testHttpHeaderConstructor() { + void testHttpHeaderConstructor() { PublicClientApplication app = PublicClientApplication .builder("client-id") @@ -34,17 +40,17 @@ public void testHttpHeaderConstructor() { Map httpHeaderMap = httpHeaders.getReadonlyHeaderMap(); - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.PRODUCT_HEADER_NAME), HttpHeaders.PRODUCT_HEADER_VALUE); - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.PRODUCT_VERSION_HEADER_NAME), HttpHeaders.PRODUCT_VERSION_HEADER_VALUE); - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.OS_HEADER_NAME), HttpHeaders.OS_HEADER_VALUE); - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.CPU_HEADER_NAME), HttpHeaders.CPU_HEADER_VALUE); - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.APPLICATION_NAME_HEADER_NAME), "app-name"); - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.APPLICATION_VERSION_HEADER_NAME), "app-version"); - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.CORRELATION_ID_HEADER_NAME), "correlation-id"); + assertEquals(httpHeaderMap.get(HttpHeaders.PRODUCT_HEADER_NAME), HttpHeaders.PRODUCT_HEADER_VALUE); + assertEquals(httpHeaderMap.get(HttpHeaders.PRODUCT_VERSION_HEADER_NAME), HttpHeaders.PRODUCT_VERSION_HEADER_VALUE); + assertEquals(httpHeaderMap.get(HttpHeaders.OS_HEADER_NAME), HttpHeaders.OS_HEADER_VALUE); + assertEquals(httpHeaderMap.get(HttpHeaders.CPU_HEADER_NAME), HttpHeaders.CPU_HEADER_VALUE); + assertEquals(httpHeaderMap.get(HttpHeaders.APPLICATION_NAME_HEADER_NAME), "app-name"); + assertEquals(httpHeaderMap.get(HttpHeaders.APPLICATION_VERSION_HEADER_NAME), "app-version"); + assertEquals(httpHeaderMap.get(HttpHeaders.CORRELATION_ID_HEADER_NAME), "correlation-id"); } @Test - public void testHttpHeaderConstructor_valuesNotSet() { + void testHttpHeaderConstructor_valuesNotSet() { PublicClientApplication app = PublicClientApplication .builder("client-id") @@ -61,17 +67,17 @@ public void testHttpHeaderConstructor_valuesNotSet() { Map httpHeaderMap = httpHeaders.getReadonlyHeaderMap(); - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.PRODUCT_HEADER_NAME), HttpHeaders.PRODUCT_HEADER_VALUE); - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.PRODUCT_VERSION_HEADER_NAME), HttpHeaders.PRODUCT_VERSION_HEADER_VALUE); - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.OS_HEADER_NAME), HttpHeaders.OS_HEADER_VALUE); - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.CPU_HEADER_NAME), HttpHeaders.CPU_HEADER_VALUE); - Assert.assertNull(httpHeaderMap.get(HttpHeaders.APPLICATION_NAME_HEADER_NAME)); - Assert.assertNull(httpHeaderMap.get(HttpHeaders.APPLICATION_VERSION_HEADER_NAME)); - Assert.assertNotNull(httpHeaderMap.get(HttpHeaders.CORRELATION_ID_HEADER_NAME)); + assertEquals(httpHeaderMap.get(HttpHeaders.PRODUCT_HEADER_NAME), HttpHeaders.PRODUCT_HEADER_VALUE); + assertEquals(httpHeaderMap.get(HttpHeaders.PRODUCT_VERSION_HEADER_NAME), HttpHeaders.PRODUCT_VERSION_HEADER_VALUE); + assertEquals(httpHeaderMap.get(HttpHeaders.OS_HEADER_NAME), HttpHeaders.OS_HEADER_VALUE); + assertEquals(httpHeaderMap.get(HttpHeaders.CPU_HEADER_NAME), HttpHeaders.CPU_HEADER_VALUE); + assertNull(httpHeaderMap.get(HttpHeaders.APPLICATION_NAME_HEADER_NAME)); + assertNull(httpHeaderMap.get(HttpHeaders.APPLICATION_VERSION_HEADER_NAME)); + assertNotNull(httpHeaderMap.get(HttpHeaders.CORRELATION_ID_HEADER_NAME)); } @Test - public void testHttpHeaderConstructor_userIdentifierUPN() { + void testHttpHeaderConstructor_userIdentifierUPN() { PublicClientApplication app = PublicClientApplication .builder("client-id") @@ -93,11 +99,11 @@ public void testHttpHeaderConstructor_userIdentifierUPN() { Map httpHeaderMap = httpHeaders.getReadonlyHeaderMap(); String expectedValue = String.format(HttpHeaders.X_ANCHOR_MAILBOX_UPN_FORMAT, upn); - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.X_ANCHOR_MAILBOX), expectedValue); + assertEquals(httpHeaderMap.get(HttpHeaders.X_ANCHOR_MAILBOX), expectedValue); } @Test - public void testHttpHeaderConstructor_userIdentifierHomeAccountId() { + void testHttpHeaderConstructor_userIdentifierHomeAccountId() { PublicClientApplication app = PublicClientApplication .builder("client-id") @@ -118,11 +124,11 @@ public void testHttpHeaderConstructor_userIdentifierHomeAccountId() { Map httpHeaderMap = httpHeaders.getReadonlyHeaderMap(); - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.X_ANCHOR_MAILBOX), "oid:userObjectId@userTenantId"); + assertEquals(httpHeaderMap.get(HttpHeaders.X_ANCHOR_MAILBOX), "oid:userObjectId@userTenantId"); } @Test - public void testHttpHeaderConstructor_extraHttpHeadersOverwriteLibraryHeaders() { + void testHttpHeaderConstructor_extraHttpHeadersOverwriteLibraryHeaders() { PublicClientApplication app = PublicClientApplication .builder("client-id") @@ -154,17 +160,17 @@ public void testHttpHeaderConstructor_extraHttpHeadersOverwriteLibraryHeaders() Map httpHeaderMap = httpHeaders.getReadonlyHeaderMap(); // Standard headers - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.PRODUCT_HEADER_NAME), HttpHeaders.PRODUCT_HEADER_VALUE); - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.PRODUCT_VERSION_HEADER_NAME), HttpHeaders.PRODUCT_VERSION_HEADER_VALUE); - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.OS_HEADER_NAME), HttpHeaders.OS_HEADER_VALUE); - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.CPU_HEADER_NAME), HttpHeaders.CPU_HEADER_VALUE); - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.APPLICATION_VERSION_HEADER_NAME), "app-version"); - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.CORRELATION_ID_HEADER_NAME), "correlation-id"); + assertEquals(httpHeaderMap.get(HttpHeaders.PRODUCT_HEADER_NAME), HttpHeaders.PRODUCT_HEADER_VALUE); + assertEquals(httpHeaderMap.get(HttpHeaders.PRODUCT_VERSION_HEADER_NAME), HttpHeaders.PRODUCT_VERSION_HEADER_VALUE); + assertEquals(httpHeaderMap.get(HttpHeaders.OS_HEADER_NAME), HttpHeaders.OS_HEADER_VALUE); + assertEquals(httpHeaderMap.get(HttpHeaders.CPU_HEADER_NAME), HttpHeaders.CPU_HEADER_VALUE); + assertEquals(httpHeaderMap.get(HttpHeaders.APPLICATION_VERSION_HEADER_NAME), "app-version"); + assertEquals(httpHeaderMap.get(HttpHeaders.CORRELATION_ID_HEADER_NAME), "correlation-id"); // Overwritten standard header - Assert.assertEquals(httpHeaderMap.get(HttpHeaders.APPLICATION_NAME_HEADER_NAME), uniqueAppName); + assertEquals(httpHeaderMap.get(HttpHeaders.APPLICATION_NAME_HEADER_NAME), uniqueAppName); // Extra header - Assert.assertEquals(httpHeaderMap.get(uniqueHeaderKey), uniqueHeaderValue); + assertEquals(httpHeaderMap.get(uniqueHeaderKey), uniqueHeaderValue); } } diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/HttpUtilsTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/HttpUtilsTest.java index 46b3da59..901fb358 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/HttpUtilsTest.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/HttpUtilsTest.java @@ -3,8 +3,10 @@ package com.microsoft.aad.msal4j; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import java.util.Arrays; import java.util.Collections; @@ -12,26 +14,26 @@ import java.util.List; import java.util.Map; -@Test(groups = {"checkin"}) -public class HttpUtilsTest { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class HttpUtilsTest { private final String COOKIE_HEADER_NAME = "Set-Cookie"; private final String COOKIE_HEADER_VALUE_1 = "298zf09hf012fh2"; private final String COOKIE_HEADER_VALUE_2 = "u32t4o3tb3gg43"; @Test - public void testHttpUtils_singleValueHeader() { + void testHttpUtils_singleValueHeader() { Map> singleValuedHeader = new HashMap>() {{ put(COOKIE_HEADER_NAME, Collections.singletonList(COOKIE_HEADER_VALUE_1)); }}; String headerValue = HttpUtils.headerValue(singleValuedHeader, COOKIE_HEADER_NAME); - Assert.assertEquals(headerValue, COOKIE_HEADER_VALUE_1); + assertEquals(headerValue, COOKIE_HEADER_VALUE_1); } @Test - public void testHttpUtils_multiValueHeader() { + void testHttpUtils_multiValueHeader() { Map> multiValuedHeader = new HashMap>() {{ put(COOKIE_HEADER_NAME, Arrays.asList(COOKIE_HEADER_VALUE_1, COOKIE_HEADER_VALUE_2)); @@ -39,17 +41,17 @@ public void testHttpUtils_multiValueHeader() { String headerValue = HttpUtils.headerValue(multiValuedHeader, COOKIE_HEADER_NAME); String expectedValue = COOKIE_HEADER_VALUE_1 + "," + COOKIE_HEADER_VALUE_2; - Assert.assertEquals(headerValue, expectedValue); + assertEquals(headerValue, expectedValue); } @Test - public void testHttpUtils_HeaderValueNull() { + void testHttpUtils_HeaderValueNull() { Map> nullValuedHeader = new HashMap>() {{ put(COOKIE_HEADER_NAME, null); }}; String headerValue = HttpUtils.headerValue(nullValuedHeader, COOKIE_HEADER_NAME); - Assert.assertNull(headerValue); + assertNull(headerValue); } } diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/MexParserTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/MexParserTest.java index 948d6a36..131357ad 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/MexParserTest.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/MexParserTest.java @@ -6,26 +6,33 @@ import java.io.BufferedReader; import java.io.FileReader; -import org.testng.Assert; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -@Test(groups = {"checkin"}) -public class MexParserTest { - - @BeforeTest - public void setup() { +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.AfterAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class MexParserTest { + + @BeforeAll + void setup() { System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl"); } - @AfterTest - public void cleanup() { + @AfterAll + void cleanup() { System.clearProperty("javax.xml.parsers.DocumentBuilderFactory"); } @Test - public void testMexParsing() throws Exception { + void testMexParsingWs13() throws Exception { StringBuilder sb = new StringBuilder(); try (BufferedReader br = new BufferedReader(new FileReader( @@ -41,12 +48,12 @@ public void testMexParsing() throws Exception { } BindingPolicy endpoint = MexParser.getWsTrustEndpointFromMexResponse(sb.toString(), false); - Assert.assertEquals(endpoint.getUrl(), + assertEquals(endpoint.getUrl(), "https://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed"); } @Test - public void testMexParsingWs2005() throws Exception { + void testMexParsingWs2005() throws Exception { StringBuilder sb = new StringBuilder(); try (BufferedReader br = new BufferedReader(new FileReader( @@ -62,11 +69,11 @@ public void testMexParsingWs2005() throws Exception { } BindingPolicy endpoint = MexParser.getWsTrustEndpointFromMexResponse(sb .toString(), false); - Assert.assertEquals(endpoint.getUrl(), "https://msft.sts.microsoft.com/adfs/services/trust/2005/usernamemixed"); + assertEquals(endpoint.getUrl(), "https://msft.sts.microsoft.com/adfs/services/trust/2005/usernamemixed"); } @Test - public void testMexParsingIntegrated() throws Exception { + void testMexParsingIntegrated() throws Exception { StringBuilder sb = new StringBuilder(); try (BufferedReader br = new BufferedReader(new FileReader( @@ -82,7 +89,7 @@ public void testMexParsingIntegrated() throws Exception { } BindingPolicy endpoint = MexParser.getPolicyFromMexResponseForIntegrated(sb .toString(), false); - Assert.assertEquals(endpoint.getUrl(), + assertEquals(endpoint.getUrl(), "https://msft.sts.microsoft.com/adfs/services/trust/13/windowstransport"); } -} +} \ No newline at end of file diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/MsalOauthAuthorizatonGrantTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/MsalOauthAuthorizatonGrantTest.java index e465b409..3fcc6cd0 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/MsalOauthAuthorizatonGrantTest.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/MsalOauthAuthorizatonGrantTest.java @@ -5,32 +5,31 @@ import com.nimbusds.oauth2.sdk.AuthorizationCode; import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; -/** - * - */ -public class MsalOauthAuthorizatonGrantTest { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class MsalOauthAuthorizatonGrantTest { @Test - public void testConstructor() { + void testConstructor() { final OAuthAuthorizationGrant grant = new OAuthAuthorizationGrant(null, new HashMap<>()); - Assert.assertNotNull(grant); + assertNotNull(grant); } @Test - public void testToParameters() throws URISyntaxException { + void testToParameters() throws URISyntaxException { final OAuthAuthorizationGrant grant = new OAuthAuthorizationGrant( new AuthorizationCodeGrant(new AuthorizationCode("grant"), new URI("http://microsoft.com")), null); - Assert.assertNotNull(grant); - Assert.assertNotNull(grant.toParameters()); + assertNotNull(grant); + assertNotNull(grant.toParameters()); } } diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/OAuthRequestValidationTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/OAuthRequestValidationTest.java deleted file mode 100644 index 9e3bf1ed..00000000 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/OAuthRequestValidationTest.java +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.microsoft.aad.msal4j; - -import static com.microsoft.aad.msal4j.TestConfiguration.INSTANCE_DISCOVERY_RESPONSE; -import static org.powermock.api.support.membermodification.MemberMatcher.method; -import static org.powermock.api.support.membermodification.MemberModifier.replace; - -import com.nimbusds.jose.JOSEException; -import com.nimbusds.jose.JWSAlgorithm; -import com.nimbusds.jose.JWSHeader; -import com.nimbusds.jose.JWSSigner; -import com.nimbusds.jose.crypto.RSASSASigner; -import com.nimbusds.jwt.JWTClaimsSet; -import com.nimbusds.jwt.SignedJWT; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.testng.Assert; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -import java.io.UnsupportedEncodingException; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.net.URLDecoder; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; -import java.util.*; -import java.util.concurrent.ExecutionException; - -import org.easymock.EasyMock; -import org.powermock.api.easymock.PowerMock; - -@PowerMockIgnore({"javax.net.ssl.*"}) -@PrepareForTest({com.microsoft.aad.msal4j.OAuthHttpRequest.class, HttpHelper.class}) -public class OAuthRequestValidationTest extends AbstractMsalTests { - - final static String AUTHORITY = "https://loginXXX.windows.net/path/"; - - final static String CLIENT_ID = "ClientId"; - private final static String CLIENT_DUMMYSECRET = "ClientDummyPsw"; - - final static String SCOPES = "https://SomeResource.azure.net"; - private final static String DEFAULT_SCOPES = "openid profile offline_access"; - - final static String GRANT_TYPE_JWT = "urn:ietf:params:oauth:grant-type:jwt-bearer"; - final static String CLIENT_ASSERTION_TYPE_JWT = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"; - final static String ON_BEHALF_OF_USE_JWT = "on_behalf_of"; - - final static String CLIENT_CREDENTIALS_GRANT_TYPE = "client_credentials"; - - final static String CLIENT_INFO_VALUE = "1"; - - final static String JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva" + - "G4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"; - - static String query; - - @SuppressWarnings("unchecked") - @BeforeMethod - public void init() throws Exception { - - PowerMock.mockStatic(HttpHelper.class); - HttpResponse httpResponse = new HttpResponse(); - httpResponse.body(INSTANCE_DISCOVERY_RESPONSE); - httpResponse.statusCode(HttpHelper.HTTP_STATUS_200); - EasyMock.expect( - HttpHelper.executeHttpRequest( - EasyMock.isA(HttpRequest.class), - EasyMock.isA(RequestContext.class), - EasyMock.isA(ServiceBundle.class))) - .andReturn(httpResponse); - - PowerMock.replay(HttpHelper.class); - - replace(method(OAuthHttpRequest.class, "send")). - with(new InvocationHandler() { - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - query = ((OAuthHttpRequest) proxy).getQuery(); - throw new MsalException("", AuthenticationErrorCode.UNKNOWN); - } - }); - } - - public static Map splitQuery(String query) throws UnsupportedEncodingException { - Map query_pairs = new LinkedHashMap<>(); - String[] pairs = query.split("&"); - for (String pair : pairs) { - int idx = pair.indexOf("="); - query_pairs.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8")); - } - return query_pairs; - } - - private String getRSAjwt() throws NoSuchAlgorithmException, JOSEException { - // RSA signatures require a public and private RSA key pair, the public key - // must be made known to the JWS recipient in order to verify the signatures - KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA"); - keyGenerator.initialize(2048); - - KeyPair kp = keyGenerator.genKeyPair(); - RSAPublicKey publicKey = (RSAPublicKey) kp.getPublic(); - RSAPrivateKey privateKey = (RSAPrivateKey) kp.getPrivate(); - - // Create RSA-signer with the private key - JWSSigner signer = new RSASSASigner(privateKey); - - // Prepare JWT with claims set - JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder(); - builder.issuer("alice"); - builder.subject("alice"); - List aud = new ArrayList(); - aud.add("https://app-one.com"); - aud.add("https://app-two.com"); - builder.audience(aud); - // Set expiration in 10 minutes - builder.expirationTime(new Date(new Date().getTime() + 1000 * 60 * 10)); - builder.notBeforeTime(new Date()); - builder.issueTime(new Date()); - builder.jwtID(UUID.randomUUID().toString()); - - JWTClaimsSet jwtClaims = builder.build(); - - SignedJWT signedJWT = new SignedJWT( - new JWSHeader(JWSAlgorithm.RS256), - jwtClaims); - - // Compute the RSA signature - signedJWT.sign(signer); - - return signedJWT.serialize(); - } - - @Test - public void oAuthRequest_for_acquireTokenByUserAssertion() throws Exception { - ConfidentialClientApplication app = - ConfidentialClientApplication.builder(CLIENT_ID, ClientCredentialFactory.createFromSecret(CLIENT_DUMMYSECRET)) - .authority(AUTHORITY) - .validateAuthority(false).build(); - - try { - // Using UserAssertion as Authorization Grants - OnBehalfOfParameters parameters = - OnBehalfOfParameters.builder(Collections.singleton(SCOPES), new UserAssertion(JWT)) - .build(); - - app.acquireToken(parameters).get(); - - } catch (ExecutionException ex) { - Assert.assertTrue(ex.getCause() instanceof MsalException); - } - - Map queryParams = splitQuery(query); - Assert.assertEquals(7, queryParams.size()); - - // validate Authorization Grants query params - Assert.assertEquals(GRANT_TYPE_JWT, queryParams.get("grant_type")); - Assert.assertEquals(JWT, queryParams.get("assertion")); - - // validate Client Authentication query params - Assert.assertEquals(CLIENT_ID, queryParams.get("client_id")); - Assert.assertEquals(CLIENT_DUMMYSECRET, queryParams.get("client_secret")); - - - Set scopes = new HashSet<>( - Arrays.asList(queryParams.get("scope").split(AbstractMsalAuthorizationGrant.SCOPES_DELIMITER))); - - // validate custom scopes - Assert.assertTrue(scopes.contains(SCOPES)); - - // validate common scopes - Assert.assertTrue(scopes.contains(AbstractMsalAuthorizationGrant.SCOPE_OPEN_ID)); - Assert.assertTrue(scopes.contains(AbstractMsalAuthorizationGrant.SCOPE_PROFILE)); - Assert.assertTrue(scopes.contains(AbstractMsalAuthorizationGrant.SCOPE_OFFLINE_ACCESS)); - - Assert.assertEquals("on_behalf_of", queryParams.get("requested_token_use")); - - Assert.assertEquals(CLIENT_INFO_VALUE, queryParams.get("client_info")); - } -} - diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/OauthHttpRequestTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/OauthHttpRequestTest.java deleted file mode 100644 index 8ef4f776..00000000 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/OauthHttpRequestTest.java +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.microsoft.aad.msal4j; - -import com.nimbusds.oauth2.sdk.http.HTTPRequest.Method; -import com.nimbusds.oauth2.sdk.http.HTTPResponse; -import org.easymock.EasyMock; -import org.powermock.api.easymock.PowerMock; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.reflect.Whitebox; -import org.testng.Assert; -import org.testng.annotations.Test; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.testng.Assert.assertNotNull; - -@Test(groups = {"checkin"}) -@PrepareForTest({OAuthHttpRequest.class}) -public class OauthHttpRequestTest extends AbstractMsalTests { - - @Test - public void testConstructor() throws MalformedURLException { - final OAuthHttpRequest request = new OAuthHttpRequest( - Method.POST, - new URL("http://login.windows.net"), - null, - null, - null); - assertNotNull(request); - } - - @Test(expectedExceptions = IOException.class, expectedExceptionsMessageRegExp = "Couldn't parse Content-Type header: Invalid Content-Type value: Invalid content type string") - public void testCreateResponseContentTypeParsingFailure() throws Exception { - - final OAuthHttpRequest request = new OAuthHttpRequest( - Method.GET, - new URL("https://" + TestConfiguration.AAD_HOST_NAME), - null, - null, - null); - - final HttpResponse httpResponse = PowerMock - .createMock(HttpResponse.class); - - EasyMock.expect(httpResponse.statusCode()).andReturn(200).times(1); - - Map> headers = new HashMap<>(); - headers.put("Location", Collections.singletonList("https://location.pl")); - headers.put("Content-Type", Collections.singletonList("invalid-content")); - - EasyMock.expect(httpResponse.headers()).andReturn(headers).times(3); - EasyMock.expect(httpResponse.body()).andReturn("").times(1); - PowerMock.replay(httpResponse); - - final HTTPResponse response = Whitebox.invokeMethod(request, - "createOauthHttpResponseFromHttpResponse", httpResponse); - } - - @Test - public void testCreateResponse() throws Exception { - final OAuthHttpRequest request = new OAuthHttpRequest( - Method.GET, - new URL("https://" + TestConfiguration.AAD_HOST_NAME), - null, - null, - null); - - final HttpResponse httpResponse = PowerMock - .createMock(HttpResponse.class); - - EasyMock.expect(httpResponse.statusCode()).andReturn(200).times(1); - - Map> headers = new HashMap<>(); - headers.put("Location", Collections.singletonList("https://location.pl")); - headers.put("Content-Type", Collections.singletonList("application/x-www-form-urlencoded")); - - EasyMock.expect(httpResponse.headers()).andReturn(headers).times(3); - EasyMock.expect(httpResponse.body()).andReturn("").times(1); - PowerMock.replay(httpResponse); - - final HTTPResponse response = Whitebox.invokeMethod(request, - "createOauthHttpResponseFromHttpResponse", httpResponse); - - Assert.assertNotNull(response); - Assert.assertEquals(response.getLocation().getAuthority(), - "location.pl"); - Assert.assertEquals(response.getLocation().getScheme(), "https"); - Assert.assertNull(response.getContent()); - PowerMock.verifyAll(); - } -} diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/PublicClientApplicationTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/PublicClientApplicationTest.java deleted file mode 100644 index 16adab0e..00000000 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/PublicClientApplicationTest.java +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.microsoft.aad.msal4j; - -import org.easymock.EasyMock; -import org.powermock.api.easymock.PowerMock; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.testng.PowerMockTestCase; -import org.testng.Assert; -import org.testng.annotations.Test; - -import java.util.Collections; -import java.util.Date; -import java.util.Map; -import java.util.concurrent.Future; - -@PowerMockIgnore({"javax.net.ssl.*"}) -@Test(groups = {"checkin"}) -@PrepareForTest({PublicClientApplication.class, - ClientCertificate.class, UserDiscoveryRequest.class}) -public class PublicClientApplicationTest extends PowerMockTestCase { - - private PublicClientApplication app = null; - - @SuppressWarnings("unchecked") - @Test - public void testAcquireToken_Username_Password() throws Exception { - app = PowerMock.createPartialMock(PublicClientApplication.class, - new String[]{"acquireTokenCommon"}, - PublicClientApplication.builder(TestConfiguration.AAD_CLIENT_ID) - .authority(TestConfiguration.AAD_TENANT_ENDPOINT)); - - PowerMock.expectPrivate(app, "acquireTokenCommon", - EasyMock.isA(MsalRequest.class), - EasyMock.isA(AADAuthority.class)) - .andReturn(AuthenticationResult.builder(). - accessToken("accessToken"). - expiresOn(new Date().getTime() + 100). - refreshToken("refreshToken"). - idToken("idToken").environment("environment").build() - ); - - UserDiscoveryResponse response = EasyMock - .createMock(UserDiscoveryResponse.class); - EasyMock.expect(response.isAccountFederated()).andReturn(false); - - PowerMock.mockStatic(UserDiscoveryRequest.class); - EasyMock.expect( - UserDiscoveryRequest.execute( - EasyMock.isA(String.class), - EasyMock.isA(Map.class), - EasyMock.isA(RequestContext.class), - EasyMock.isA(ServiceBundle.class))).andReturn(response); - - PowerMock.replay(app, response, UserDiscoveryRequest.class); - - Future result = app.acquireToken( - UserNamePasswordParameters - .builder(Collections.singleton("scopes"), "username", "password".toCharArray()) - .build()); - - IAuthenticationResult ar = result.get(); - Assert.assertNotNull(ar); - PowerMock.verifyAll(); - PowerMock.resetAll(app); - } -} diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/RequestThrottlingTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/RequestThrottlingTest.java index cd04b926..990b59b4 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/RequestThrottlingTest.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/RequestThrottlingTest.java @@ -4,27 +4,49 @@ package com.microsoft.aad.msal4j; import com.nimbusds.oauth2.sdk.http.HTTPResponse; -import org.easymock.EasyMock; -import org.powermock.api.easymock.PowerMock; -import org.testng.Assert; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import java.net.URI; import java.net.URISyntaxException; import java.util.*; -import static org.easymock.EasyMock.anyObject; - -public class RequestThrottlingTest extends AbstractMsalTests { +@ExtendWith(MockitoExtension.class) +@TestInstance(TestInstance.Lifecycle.PER_METHOD) +class RequestThrottlingTest { public final Integer THROTTLE_IN_SEC = 1; + public TokenEndpointResponseType responseType; + IHttpClient httpClientMock = mock(IHttpClient.class); + - @BeforeMethod + @BeforeEach void init() { ThrottlingCache.DEFAULT_THROTTLING_TIME_SEC = THROTTLE_IN_SEC; } + @AfterEach + void check() throws Exception { + + //throttlingTest() makes three non-throttled calls, so for a test without a retry there should be + // 3 invocations of httpClientMock.send(), and 6 invocations if the calls are set to retry + if (responseType == TokenEndpointResponseType.STATUS_CODE_500) { + verify(httpClientMock, times(6)).send(any()); + } else { + verify(httpClientMock, times(3)).send(any()); + } + } + private AuthorizationCodeParameters getAcquireTokenApiParameters(String scope) throws URISyntaxException { return AuthorizationCodeParameters .builder("auth_code", @@ -66,9 +88,9 @@ private enum TokenEndpointResponseType { } private PublicClientApplication getClientApplicationMockedWithOneTokenEndpointResponse( - TokenEndpointResponseType responseType) + TokenEndpointResponseType type) throws Exception { - IHttpClient httpClientMock = EasyMock.createMock(IHttpClient.class); + responseType = type; HttpResponse httpResponse = new HttpResponse(); Map> headers = new HashMap<>(); @@ -102,17 +124,9 @@ private PublicClientApplication getClientApplicationMockedWithOneTokenEndpointRe headers.put("Content-Type", Arrays.asList("application/json")); httpResponse.addHeaders(headers); - if (responseType == TokenEndpointResponseType.STATUS_CODE_500) { - // expected to called two times due to retry logic - EasyMock.expect(httpClientMock.send(anyObject())).andReturn(httpResponse).times(2); - } else { - EasyMock.expect(httpClientMock.send(anyObject())).andReturn(httpResponse).times(1); - } - - PublicClientApplication app = getPublicClientApp(httpClientMock); + doReturn(httpResponse).when(httpClientMock).send(any()); - PowerMock.replayAll(httpClientMock); - return app; + return getPublicClientApp(httpClientMock); } private void throttlingTest(TokenEndpointResponseType tokenEndpointResponseType) throws Exception { @@ -125,11 +139,9 @@ private void throttlingTest(TokenEndpointResponseType tokenEndpointResponseType) app.acquireToken(getAcquireTokenApiParameters("scope1")).join(); } catch (Exception ex) { if (!(ex.getCause() instanceof MsalServiceException)) { - Assert.fail("Unexpected exception"); + fail("Unexpected exception"); } } - PowerMock.verifyAll(); - PowerMock.resetAll(); // repeat same request #1, should be throttled try { @@ -137,7 +149,7 @@ private void throttlingTest(TokenEndpointResponseType tokenEndpointResponseType) app.acquireToken(getAcquireTokenApiParameters("scope1")).join(); } catch (Exception ex) { if (!(ex.getCause() instanceof MsalThrottlingException)) { - Assert.fail("Unexpected exception"); + fail("Unexpected exception"); } } @@ -147,11 +159,9 @@ private void throttlingTest(TokenEndpointResponseType tokenEndpointResponseType) app.acquireToken(getAcquireTokenApiParameters("scope2")).join(); } catch (Exception ex) { if (!(ex.getCause() instanceof MsalServiceException)) { - Assert.fail("Unexpected exception"); + fail("Unexpected exception"); } } - PowerMock.verifyAll(); - PowerMock.resetAll(); // repeat request #1, should not be throttled after // throttling for this request got expired @@ -161,37 +171,35 @@ private void throttlingTest(TokenEndpointResponseType tokenEndpointResponseType) app.acquireToken(getAcquireTokenApiParameters("scope1")).join(); } catch (Exception ex) { if (!(ex.getCause() instanceof MsalServiceException)) { - Assert.fail("Unexpected exception"); + fail("Unexpected exception"); } } - PowerMock.verifyAll(); - PowerMock.resetAll(); } @Test - public void STSResponseContains_RetryAfterHeader() throws Exception { + void STSResponseContains_RetryAfterHeader() throws Exception { throttlingTest(TokenEndpointResponseType.RETRY_AFTER_HEADER); } @Test - public void STSResponseContains_StatusCode429() throws Exception { + void STSResponseContains_StatusCode429() throws Exception { throttlingTest(TokenEndpointResponseType.STATUS_CODE_429); } @Test - public void STSResponseContains_StatusCode429_RetryAfterHeader() throws Exception { + void STSResponseContains_StatusCode429_RetryAfterHeader() throws Exception { // using big value for DEFAULT_THROTTLING_TIME_SEC to make sure that RetryAfterHeader value used instead ThrottlingCache.DEFAULT_THROTTLING_TIME_SEC = 1000; throttlingTest(TokenEndpointResponseType.STATUS_CODE_429_RETRY_AFTER_HEADER); } @Test - public void STSResponseContains_StatusCode500() throws Exception { + void STSResponseContains_StatusCode500() throws Exception { throttlingTest(TokenEndpointResponseType.STATUS_CODE_500); } @Test - public void STSResponseContains_StatusCode500_RetryAfterHeader() throws Exception { + void STSResponseContains_StatusCode500_RetryAfterHeader() throws Exception { // using big value for DEFAULT_THROTTLING_TIME_SEC to make sure that RetryAfterHeader value used instead ThrottlingCache.DEFAULT_THROTTLING_TIME_SEC = 1000; throttlingTest(TokenEndpointResponseType.STATUS_CODE_500_RETRY_AFTER_HEADER); diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ServerTelemetryTests.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ServerTelemetryTests.java index 6d826cf5..ae9c2e65 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ServerTelemetryTests.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ServerTelemetryTests.java @@ -3,8 +3,11 @@ package com.microsoft.aad.msal4j; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -16,6 +19,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ServerTelemetryTests { private static final String SCHEMA_VERSION = "5"; @@ -42,28 +46,28 @@ public void serverTelemetryHeaders_correctSchema() { List currentRequestHeader = Arrays.asList(headers.get(CURRENT_REQUEST_HEADER_NAME).split("\\|")); // ["5", "831,"] - Assert.assertEquals(currentRequestHeader.size(), 2); - Assert.assertEquals(currentRequestHeader.get(0), SCHEMA_VERSION); + assertEquals(currentRequestHeader.size(), 2); + assertEquals(currentRequestHeader.get(0), SCHEMA_VERSION); // ["831", ""] List secondSegment = Arrays.asList(currentRequestHeader.get(1).split(",")); - Assert.assertEquals(secondSegment.get(0), String.valueOf(PublicApi.ACQUIRE_TOKEN_BY_AUTHORIZATION_CODE.getApiId())); - Assert.assertEquals(secondSegment.get(1), ""); + assertEquals(secondSegment.get(0), String.valueOf(PublicApi.ACQUIRE_TOKEN_BY_AUTHORIZATION_CODE.getApiId())); + assertEquals(secondSegment.get(1), ""); // Previous request test List previousRequestHeader = Arrays.asList(headers.get(LAST_REQUEST_HEADER_NAME).split("\\|")); // ["5","0","831,936732c6-74b9-4783-aad9-fa205eae8763","invalid_grant"] - Assert.assertEquals(previousRequestHeader.size(), 4); - Assert.assertEquals(previousRequestHeader.get(0), SCHEMA_VERSION); - Assert.assertEquals(previousRequestHeader.get(1), "0"); - Assert.assertEquals(previousRequestHeader.get(3), ERROR); + assertEquals(previousRequestHeader.size(), 4); + assertEquals(previousRequestHeader.get(0), SCHEMA_VERSION); + assertEquals(previousRequestHeader.get(1), "0"); + assertEquals(previousRequestHeader.get(3), ERROR); List thirdSegment = Arrays.asList(previousRequestHeader.get(2).split(",")); - Assert.assertEquals(thirdSegment.get(0), PUBLIC_API_ID); - Assert.assertEquals(thirdSegment.get(1), correlationId); + assertEquals(thirdSegment.get(0), PUBLIC_API_ID); + assertEquals(thirdSegment.get(1), correlationId); } @Test @@ -76,7 +80,7 @@ public void serverTelemetryHeaders_previewsRequestNull() { Map headers = serverSideTelemetry.getServerTelemetryHeaderMap(); - Assert.assertEquals(headers.get(LAST_REQUEST_HEADER_NAME), "5|3|||"); + assertEquals(headers.get(LAST_REQUEST_HEADER_NAME), "5|3|||"); } @Test @@ -95,7 +99,7 @@ public void serverTelemetryHeader_testMaximumHeaderSize() { byte[] lastRequestBytes = lastRequest.getBytes(StandardCharsets.UTF_8); - Assert.assertTrue(lastRequestBytes.length <= 350); + assertTrue(lastRequestBytes.length <= 350); } @Test @@ -124,30 +128,30 @@ public void serverTelemetryHeaders_multipleThreadsWrite() { List previousRequestHeader = Arrays.asList(headers.get(LAST_REQUEST_HEADER_NAME).split("\\|")); - Assert.assertEquals(previousRequestHeader.get(1), "10"); + assertEquals(previousRequestHeader.get(1), "10"); List thirdSegment = Arrays.asList(previousRequestHeader.get(2).split(",")); - Assert.assertEquals(thirdSegment.size(), 12); + assertEquals(thirdSegment.size(), 12); List fourthSegment = Arrays.asList(previousRequestHeader.get(3).split(",")); - Assert.assertEquals(fourthSegment.size(), 6); + assertEquals(fourthSegment.size(), 6); - Assert.assertTrue(headers.get(LAST_REQUEST_HEADER_NAME).getBytes(StandardCharsets.UTF_8).length < 350); + assertTrue(headers.get(LAST_REQUEST_HEADER_NAME).getBytes(StandardCharsets.UTF_8).length < 350); // Not all requests fit into first header, so they would get dispatched in the next request Map secondRequest = serverSideTelemetry.getServerTelemetryHeaderMap(); previousRequestHeader = Arrays.asList(secondRequest.get(LAST_REQUEST_HEADER_NAME).split("\\|")); - Assert.assertEquals(previousRequestHeader.get(1), "0"); + assertEquals(previousRequestHeader.get(1), "0"); thirdSegment = Arrays.asList(previousRequestHeader.get(2).split(",")); - Assert.assertEquals(thirdSegment.size(), 8); + assertEquals(thirdSegment.size(), 8); fourthSegment = Arrays.asList(previousRequestHeader.get(3).split(",")); - Assert.assertEquals(fourthSegment.size(), 4); + assertEquals(fourthSegment.size(), 4); - Assert.assertTrue(secondRequest.get(LAST_REQUEST_HEADER_NAME).getBytes(StandardCharsets.UTF_8).length < 350); + assertTrue(secondRequest.get(LAST_REQUEST_HEADER_NAME).getBytes(StandardCharsets.UTF_8).length < 350); } @@ -160,7 +164,7 @@ public void serverTelemetryHeaders_testRegionTelemetry() throws Exception { Map headers = serverSideTelemetry.getServerTelemetryHeaderMap(); - Assert.assertEquals(headers.get(CURRENT_REQUEST_HEADER_NAME), "5|831,,,0,0|"); + assertEquals(headers.get(CURRENT_REQUEST_HEADER_NAME), "5|831,,,0,0|"); serverSideTelemetry.getCurrentRequest().regionUsed("westus"); serverSideTelemetry.getCurrentRequest().regionSource(RegionTelemetry.REGION_SOURCE_IMDS.telemetryValue); @@ -168,14 +172,14 @@ public void serverTelemetryHeaders_testRegionTelemetry() throws Exception { headers = serverSideTelemetry.getServerTelemetryHeaderMap(); - Assert.assertEquals(headers.get(CURRENT_REQUEST_HEADER_NAME), "5|831,,westus,4,4|"); + assertEquals(headers.get(CURRENT_REQUEST_HEADER_NAME), "5|831,,westus,4,4|"); serverSideTelemetry.getCurrentRequest().regionUsed("centralus"); serverSideTelemetry.getCurrentRequest().regionSource(RegionTelemetry.REGION_SOURCE_ENV_VARIABLE.telemetryValue); serverSideTelemetry.getCurrentRequest().regionOutcome(RegionTelemetry.REGION_OUTCOME_DEVELOPER_AUTODETECT_MISMATCH.telemetryValue); headers = serverSideTelemetry.getServerTelemetryHeaderMap(); - Assert.assertEquals(headers.get(CURRENT_REQUEST_HEADER_NAME), "5|831,,centralus,3,3|"); + assertEquals(headers.get(CURRENT_REQUEST_HEADER_NAME), "5|831,,centralus,3,3|"); PublicClientApplication pca = PublicClientApplication.builder( "client"). @@ -191,11 +195,11 @@ public void serverTelemetryHeaders_testRegionTelemetry() throws Exception { .build()) .get(); - Assert.fail("Expected MsalException was not thrown"); + fail("Expected MsalException was not thrown"); } catch (Exception ex) { headers = pca.getServiceBundle().getServerSideTelemetry().getServerTelemetryHeaderMap(); - Assert.assertEquals(headers.get(CURRENT_REQUEST_HEADER_NAME), "5|300,,,1,2|"); + assertEquals(headers.get(CURRENT_REQUEST_HEADER_NAME), "5|300,,,0,0|"); } } diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/TelemetryTests.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/TelemetryTests.java index 7f159d36..1b299ae0 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/TelemetryTests.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/TelemetryTests.java @@ -3,9 +3,15 @@ package com.microsoft.aad.msal4j; -import org.testng.Assert; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.AfterEach; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; import java.net.URI; import java.net.URISyntaxException; @@ -14,8 +20,8 @@ import java.util.List; import java.util.function.Consumer; -@Test(groups = {"checkin"}) -public class TelemetryTests { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class TelemetryTests { private List> eventsReceived = new ArrayList<>(); private String tenantId = "tenantId123"; @@ -34,22 +40,22 @@ private class MyTelemetryConsumer { }; } - @AfterMethod - private void cleanUp() { + @AfterEach + void cleanUp() { eventsReceived.clear(); } @Test - public void telemetryConsumerRegistration_ConsumerNotNullTest() { + void telemetryConsumerRegistration_ConsumerNotNullTest() { PublicClientApplication app = PublicClientApplication.builder("a1b2c3") .telemetryConsumer(new MyTelemetryConsumer().telemetryConsumer) .build(); - Assert.assertNotNull(app.telemetryConsumer()); + assertNotNull(app.telemetryConsumer()); } @Test - public void telemetryManagerFlush_EventCountTest() { + void telemetryManagerFlush_EventCountTest() { Consumer>> telemetryConsumer = new MyTelemetryConsumer().telemetryConsumer; TelemetryManager telemetryManager = new TelemetryManager(telemetryConsumer, false); @@ -68,11 +74,11 @@ public void telemetryManagerFlush_EventCountTest() { telemetryManager.flush(reqId, clientId); // 1 Default event, 1 API event, 1 Http event - Assert.assertEquals(eventsReceived.size(), 3); + assertEquals(eventsReceived.size(), 3); } @Test - public void onSendFailureTrue_SkipEventsIfSuccessfulTest() { + void onSendFailureTrue_SkipEventsIfSuccessfulTest() { Consumer>> telemetryConsumer = new MyTelemetryConsumer().telemetryConsumer; // Only send on failure @@ -93,7 +99,7 @@ public void onSendFailureTrue_SkipEventsIfSuccessfulTest() { telemetryManager.flush(reqId, clientId); // API event was successful, so count should be 0 - Assert.assertEquals(eventsReceived.size(), 0); + assertEquals(eventsReceived.size(), 0); eventsReceived.clear(); String reqId2 = telemetryManager.generateRequestId(); @@ -110,27 +116,27 @@ public void onSendFailureTrue_SkipEventsIfSuccessfulTest() { telemetryManager.flush(reqId2, clientId); // API event failed, so count should be 3 (1 default, 1 Api, 1 http) - Assert.assertEquals(eventsReceived.size(), 3); + assertEquals(eventsReceived.size(), 3); } @Test - public void telemetryInternalApi_ScrubTenantFromUriTest() throws Exception { - Assert.assertEquals(Event.scrubTenant(new URI("https://login.microsoftonline.com/common/oauth2/v2.0/token")), + void telemetryInternalApi_ScrubTenantFromUriTest() throws Exception { + assertEquals(Event.scrubTenant(new URI("https://login.microsoftonline.com/common/oauth2/v2.0/token")), "https://login.microsoftonline.com//oauth2/v2.0/token"); - Assert.assertEquals(Event.scrubTenant(new URI("https://login.microsoftonline.com/common")), + assertEquals(Event.scrubTenant(new URI("https://login.microsoftonline.com/common")), "https://login.microsoftonline.com/"); - Assert.assertEquals(Event.scrubTenant(new URI("https://login.microsoftonline.com/tfp/msidlabb2c.onmicrosoft.com/B2C_1_ROPC_Auth")), + assertEquals(Event.scrubTenant(new URI("https://login.microsoftonline.com/tfp/msidlabb2c.onmicrosoft.com/B2C_1_ROPC_Auth")), "https://login.microsoftonline.com/tfp//B2C_1_ROPC_Auth"); - Assert.assertNull(Event.scrubTenant(new URI("https://msidlabb2c.b2clogin.com/tfp/msidlabb2c.onmicrosoft.com/B2C_1_ROPC_Auth"))); + assertNull(Event.scrubTenant(new URI("https://msidlabb2c.b2clogin.com/tfp/msidlabb2c.onmicrosoft.com/B2C_1_ROPC_Auth"))); - Assert.assertNull(Event.scrubTenant(new URI("https://login.contoso.com/adfs"))); + assertNull(Event.scrubTenant(new URI("https://login.contoso.com/adfs"))); } @Test - public void telemetryContainsDefaultEventTest() { + void telemetryContainsDefaultEventTest() { Consumer>> telemetryConsumer = new MyTelemetryConsumer().telemetryConsumer; // Only send on failure @@ -149,11 +155,11 @@ public void telemetryContainsDefaultEventTest() { telemetryManager.flush(reqId, clientId); - Assert.assertEquals(eventsReceived.get(0).get("event_name"), "msal.default_event"); + assertEquals(eventsReceived.get(0).get("event_name"), "msal.default_event"); } @Test - public void telemetryFlushEventWithoutStopping_OrphanedEventIncludedTest() { + void telemetryFlushEventWithoutStopping_OrphanedEventIncludedTest() { Consumer>> telemetryConsumer = new MyTelemetryConsumer().telemetryConsumer; TelemetryManager telemetryManager = new TelemetryManager(telemetryConsumer, false); @@ -171,12 +177,12 @@ public void telemetryFlushEventWithoutStopping_OrphanedEventIncludedTest() { telemetryManager.stopEvent(reqId, apiEvent1); telemetryManager.flush(reqId, clientId); - Assert.assertEquals(eventsReceived.size(), 3); - Assert.assertTrue(eventsReceived.stream().anyMatch(event -> event.get("event_name").equals("msal.http_event"))); + assertEquals(eventsReceived.size(), 3); + assertTrue(eventsReceived.stream().anyMatch(event -> event.get("event_name").equals("msal.http_event"))); } @Test - public void telemetryStopEventWithoutStarting_NoExceptionThrownTest() { + void telemetryStopEventWithoutStarting_NoExceptionThrownTest() { Consumer>> telemetryConsumer = new MyTelemetryConsumer().telemetryConsumer; TelemetryManager telemetryManager = new TelemetryManager(telemetryConsumer, false); @@ -196,12 +202,12 @@ public void telemetryStopEventWithoutStarting_NoExceptionThrownTest() { telemetryManager.flush(reqId, clientId); - Assert.assertEquals(eventsReceived.size(), 2); - Assert.assertFalse(eventsReceived.stream().anyMatch(event -> event.get("event_name").equals("msal.http_event"))); + assertEquals(eventsReceived.size(), 2); + assertFalse(eventsReceived.stream().anyMatch(event -> event.get("event_name").equals("msal.http_event"))); } @Test - public void piiLoggingEnabled_ApiEventHashTest() { + void piiLoggingEnabled_ApiEventHashTest() { Consumer>> telemetryConsumer = new MyTelemetryConsumer().telemetryConsumer; TelemetryManager telemetryManager = new TelemetryManager(telemetryConsumer, false); @@ -215,12 +221,12 @@ public void piiLoggingEnabled_ApiEventHashTest() { apiEvent.setWasSuccessful(true); telemetryManager.stopEvent(reqId, apiEvent); - Assert.assertNotNull(apiEvent.get("msal.tenant_id")); - Assert.assertNotEquals(apiEvent.get("msal.tenant_id"), tenantId); + assertNotNull(apiEvent.get("msal.tenant_id")); + assertNotEquals(apiEvent.get("msal.tenant_id"), tenantId); } @Test - public void piiLoggingEnabledFalse_TenantIdUserIdSetToNullTest() { + void piiLoggingEnabledFalse_TenantIdUserIdSetToNullTest() { Consumer>> telemetryConsumer = new MyTelemetryConsumer().telemetryConsumer; TelemetryManager telemetryManager = new TelemetryManager(telemetryConsumer, false); @@ -234,11 +240,11 @@ public void piiLoggingEnabledFalse_TenantIdUserIdSetToNullTest() { apiEvent.setWasSuccessful(true); telemetryManager.stopEvent(reqId, apiEvent); - Assert.assertNull(apiEvent.get("msal.tenant_id")); + assertNull(apiEvent.get("msal.tenant_id")); } @Test - public void authorityNotInTrustedHostList_AuthorityIsNullTest() throws URISyntaxException { + void authorityNotInTrustedHostList_AuthorityIsNullTest() throws URISyntaxException { Consumer>> telemetryConsumer = new MyTelemetryConsumer().telemetryConsumer; TelemetryManager telemetryManager = new TelemetryManager(telemetryConsumer, false); @@ -250,7 +256,7 @@ public void authorityNotInTrustedHostList_AuthorityIsNullTest() throws URISyntax apiEvent.setWasSuccessful(true); telemetryManager.stopEvent(reqId, apiEvent); - Assert.assertEquals(apiEvent.get("msal.authority"), "https://login.microsoftonline.com"); + assertEquals(apiEvent.get("msal.authority"), "https://login.microsoftonline.com"); ApiEvent apiEvent2 = new ApiEvent(false); @@ -259,40 +265,40 @@ public void authorityNotInTrustedHostList_AuthorityIsNullTest() throws URISyntax apiEvent2.setWasSuccessful(true); telemetryManager.stopEvent(reqId, apiEvent2); - Assert.assertNull(apiEvent2.get("msal.authority")); + assertNull(apiEvent2.get("msal.authority")); } @Test - public void xmsCliTelemetryTest_CorrectFormatTest() { + void xmsCliTelemetryTest_CorrectFormatTest() { String responseHeader = "1,0,0,,"; XmsClientTelemetryInfo info = XmsClientTelemetryInfo.parseXmsTelemetryInfo(responseHeader); - Assert.assertEquals(info.getServerErrorCode(), "0"); - Assert.assertEquals(info.getServerSubErrorCode(), "0"); - Assert.assertEquals(info.getTokenAge(), ""); - Assert.assertEquals(info.getSpeInfo(), ""); + assertEquals(info.getServerErrorCode(), "0"); + assertEquals(info.getServerSubErrorCode(), "0"); + assertEquals(info.getTokenAge(), ""); + assertEquals(info.getSpeInfo(), ""); } @Test - public void xmsCliTelemetryTest_IncorrectFormatTest() { + void xmsCliTelemetryTest_IncorrectFormatTest() { String responseHeader = "1,2,3,4,5,6"; XmsClientTelemetryInfo info = XmsClientTelemetryInfo.parseXmsTelemetryInfo(responseHeader); - Assert.assertNull(info.getServerErrorCode()); - Assert.assertNull(info.getServerSubErrorCode()); - Assert.assertNull(info.getTokenAge()); - Assert.assertNull(info.getSpeInfo()); + assertNull(info.getServerErrorCode()); + assertNull(info.getServerSubErrorCode()); + assertNull(info.getTokenAge()); + assertNull(info.getSpeInfo()); } @Test - public void xmsCliTelemetryTest_IncorrectHeaderTest() { + void xmsCliTelemetryTest_IncorrectHeaderTest() { String responseHeader = "3,0,0,,"; XmsClientTelemetryInfo info = XmsClientTelemetryInfo.parseXmsTelemetryInfo(responseHeader); - Assert.assertNull(info); + assertNull(info); } - private ApiEvent createApiEvent(Boolean logPii) { + ApiEvent createApiEvent(Boolean logPii) { ApiEvent apiEvent1; try { apiEvent1 = new ApiEvent(logPii); @@ -305,7 +311,7 @@ private ApiEvent createApiEvent(Boolean logPii) { return apiEvent1; } - private HttpEvent createHttpEvent() { + HttpEvent createHttpEvent() { HttpEvent httpEvent1; try { httpEvent1 = new HttpEvent(); diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/TokenRequestExecutorTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/TokenRequestExecutorTest.java index efe3ac80..d430e304 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/TokenRequestExecutorTest.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/TokenRequestExecutorTest.java @@ -5,14 +5,22 @@ import com.nimbusds.oauth2.sdk.ParseException; import com.nimbusds.oauth2.sdk.SerializeException; -import com.nimbusds.oauth2.sdk.TokenErrorResponse; import com.nimbusds.oauth2.sdk.http.HTTPResponse; import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; -import org.easymock.EasyMock; -import org.powermock.api.easymock.PowerMock; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; import java.io.IOException; import java.net.MalformedURLException; @@ -22,18 +30,18 @@ import java.util.Collections; import java.util.HashMap; -@Test(groups = {"checkin"}) -@PrepareForTest(TokenErrorResponse.class) -public class TokenRequestExecutorTest extends AbstractMsalTests { +@ExtendWith(MockitoExtension.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class TokenRequestExecutorTest { @Test - public void executeOAuthRequest_SCBadRequestErrorInvalidGrant_InteractionRequiredException() + void executeOAuthRequest_SCBadRequestErrorInvalidGrant_InteractionRequiredException() throws SerializeException, ParseException, MsalException, IOException, URISyntaxException { TokenRequestExecutor request = createMockedTokenRequest(); - OAuthHttpRequest msalOAuthHttpRequest = PowerMock.createMock(OAuthHttpRequest.class); + OAuthHttpRequest msalOAuthHttpRequest = mock(OAuthHttpRequest.class); HTTPResponse httpResponse = new HTTPResponse(HTTPResponse.SC_BAD_REQUEST); @@ -50,29 +58,26 @@ public void executeOAuthRequest_SCBadRequestErrorInvalidGrant_InteractionRequire httpResponse.setContent(content); httpResponse.setContentType(HTTPContentType.ApplicationJSON.contentType); - EasyMock.expect(request.createOauthHttpRequest()).andReturn(msalOAuthHttpRequest).times(1); - EasyMock.expect(msalOAuthHttpRequest.send()).andReturn(httpResponse).times(1); - PowerMock.replay(request, msalOAuthHttpRequest); + doReturn(msalOAuthHttpRequest).when(request).createOauthHttpRequest(); + doReturn(httpResponse).when(msalOAuthHttpRequest).send(); try { request.executeTokenRequest(); - Assert.fail("Expected MsalServiceException was not thrown"); + fail("Expected MsalServiceException was not thrown"); } catch (MsalInteractionRequiredException ex) { - Assert.assertEquals(claims.replace("\\", ""), ex.claims()); - Assert.assertEquals(ex.reason(), InteractionRequiredExceptionReason.BASIC_ACTION); + assertEquals(claims.replace("\\", ""), ex.claims()); + assertEquals(ex.reason(), InteractionRequiredExceptionReason.BASIC_ACTION); } - PowerMock.verifyAll(); } @Test - public void executeOAuthRequest_SCBadRequestErrorInvalidGrant_SubErrorFilteredServiceExceptionThrown() + void executeOAuthRequest_SCBadRequestErrorInvalidGrant_SubErrorFilteredServiceExceptionThrown() throws SerializeException, ParseException, MsalException, IOException, URISyntaxException { TokenRequestExecutor request = createMockedTokenRequest(); - OAuthHttpRequest msalOAuthHttpRequest = PowerMock - .createMock(OAuthHttpRequest.class); + OAuthHttpRequest msalOAuthHttpRequest = mock(OAuthHttpRequest.class); HTTPResponse httpResponse = new HTTPResponse(HTTPResponse.SC_BAD_REQUEST); @@ -89,19 +94,16 @@ public void executeOAuthRequest_SCBadRequestErrorInvalidGrant_SubErrorFilteredSe httpResponse.setContent(content); httpResponse.setContentType(HTTPContentType.ApplicationJSON.contentType); - EasyMock.expect(request.createOauthHttpRequest()).andReturn(msalOAuthHttpRequest).times(1); - EasyMock.expect(msalOAuthHttpRequest.send()).andReturn(httpResponse).times(1); - - PowerMock.replay(request, msalOAuthHttpRequest); + doReturn(msalOAuthHttpRequest).when(request).createOauthHttpRequest(); + doReturn(httpResponse).when(msalOAuthHttpRequest).send(); try { request.executeTokenRequest(); - Assert.fail("Expected MsalServiceException was not thrown"); + fail("Expected MsalServiceException was not thrown"); } catch (MsalServiceException ex) { - Assert.assertEquals(claims.replace("\\", ""), ex.claims()); - Assert.assertTrue(!(ex instanceof MsalInteractionRequiredException)); + assertEquals(claims.replace("\\", ""), ex.claims()); + assertTrue(!(ex instanceof MsalInteractionRequiredException)); } - PowerMock.verifyAll(); } private TokenRequestExecutor createMockedTokenRequest() throws URISyntaxException, MalformedURLException { @@ -121,15 +123,12 @@ private TokenRequestExecutor createMockedTokenRequest() throws URISyntaxExceptio new DefaultHttpClient(null, null, null, null), new TelemetryManager(null, false)); - return PowerMock.createPartialMock( - TokenRequestExecutor.class, new String[]{"createOauthHttpRequest"}, - new AADAuthority(new URL(TestConstants.ORGANIZATIONS_AUTHORITY)), - refreshTokenRequest, - serviceBundle); + return spy(new TokenRequestExecutor( + new AADAuthority(new URL(TestConstants.ORGANIZATIONS_AUTHORITY)), refreshTokenRequest, serviceBundle)); } @Test - public void testConstructor() throws MalformedURLException, + void testConstructor() throws MalformedURLException, URISyntaxException { PublicClientApplication app = PublicClientApplication.builder("id").correlationId("corr-id").build(); @@ -148,11 +147,11 @@ public void testConstructor() throws MalformedURLException, new AADAuthority(new URL(TestConstants.ORGANIZATIONS_AUTHORITY)), acr, new ServiceBundle(null, null, null)); - Assert.assertNotNull(request); + assertNotNull(request); } @Test - public void testToOAuthRequestNonEmptyCorrelationId() + void testToOAuthRequestNonEmptyCorrelationId() throws MalformedURLException, SerializeException, URISyntaxException, ParseException { PublicClientApplication app = PublicClientApplication.builder("id").correlationId("corr-id").build(); @@ -171,16 +170,16 @@ public void testToOAuthRequestNonEmptyCorrelationId() new AADAuthority(new URL(TestConstants.ORGANIZATIONS_AUTHORITY)), acr, new ServiceBundle(null, null, null)); - Assert.assertNotNull(request); + assertNotNull(request); OAuthHttpRequest req = request.createOauthHttpRequest(); - Assert.assertNotNull(req); - Assert.assertEquals( + assertNotNull(req); + assertEquals( "corr-id", req.getExtraHeaderParams().get(HttpHeaders.CORRELATION_ID_HEADER_NAME)); } @Test - public void testToOAuthRequestNullCorrelationId_NullClientAuth() + void testToOAuthRequestNullCorrelationId_NullClientAuth() throws MalformedURLException, SerializeException, URISyntaxException, ParseException { @@ -200,13 +199,13 @@ public void testToOAuthRequestNullCorrelationId_NullClientAuth() new AADAuthority(new URL(TestConstants.ORGANIZATIONS_AUTHORITY)), acr, new ServiceBundle(null, null, null)); - Assert.assertNotNull(request); + assertNotNull(request); final OAuthHttpRequest req = request.createOauthHttpRequest(); - Assert.assertNotNull(req); + assertNotNull(req); } @Test - public void testExecuteOAuth_Success() throws SerializeException, ParseException, MsalException, + void testExecuteOAuth_Success() throws SerializeException, ParseException, MsalException, IOException, URISyntaxException { PublicClientApplication app = PublicClientApplication.builder("id").correlationId("corr-id").build(); @@ -226,45 +225,33 @@ public void testExecuteOAuth_Success() throws SerializeException, ParseException null, new TelemetryManager(null, false)); - final TokenRequestExecutor request = PowerMock.createPartialMock( - TokenRequestExecutor.class, new String[]{"createOauthHttpRequest"}, - new AADAuthority(new URL(TestConstants.ORGANIZATIONS_AUTHORITY)), acr, serviceBundle); - - final OAuthHttpRequest msalOAuthHttpRequest = PowerMock - .createMock(OAuthHttpRequest.class); - - final HTTPResponse httpResponse = PowerMock - .createMock(HTTPResponse.class); - - EasyMock.expect(request.createOauthHttpRequest()) - .andReturn(msalOAuthHttpRequest).times(1); - EasyMock.expect(msalOAuthHttpRequest.send()).andReturn(httpResponse) - .times(1); - EasyMock.expect(httpResponse.getContentAsJSONObject()) - .andReturn( - JSONObjectUtils - .parse(TestConfiguration.TOKEN_ENDPOINT_OK_RESPONSE)) - .times(1); - httpResponse.ensureStatusCode(200); - EasyMock.expectLastCall(); + final TokenRequestExecutor request = spy(new TokenRequestExecutor( + new AADAuthority(new URL(TestConstants.ORGANIZATIONS_AUTHORITY)), acr, serviceBundle)); + + final OAuthHttpRequest msalOAuthHttpRequest = mock(OAuthHttpRequest.class); + + final HTTPResponse httpResponse = mock(HTTPResponse.class); + + doReturn(msalOAuthHttpRequest).when(request).createOauthHttpRequest(); + doReturn(httpResponse).when(msalOAuthHttpRequest).send(); + doReturn(JSONObjectUtils.parse(TestConfiguration.TOKEN_ENDPOINT_OK_RESPONSE)).when(httpResponse).getContentAsJSONObject(); - EasyMock.expect(httpResponse.getStatusCode()).andReturn(200).times(1); + httpResponse.ensureStatusCode(200); - PowerMock.replay(request, msalOAuthHttpRequest, httpResponse); + doReturn(200).when(httpResponse).getStatusCode(); final AuthenticationResult result = request.executeTokenRequest(); - PowerMock.verifyAll(); - Assert.assertNotNull(result.account()); - Assert.assertNotNull(result.account().homeAccountId()); - Assert.assertEquals(result.account().username(), "idlab@msidlab4.onmicrosoft.com"); + assertNotNull(result.account()); + assertNotNull(result.account().homeAccountId()); + assertEquals(result.account().username(), "idlab@msidlab4.onmicrosoft.com"); - Assert.assertFalse(StringHelper.isBlank(result.accessToken())); - Assert.assertFalse(StringHelper.isBlank(result.refreshToken())); + assertFalse(StringHelper.isBlank(result.accessToken())); + assertFalse(StringHelper.isBlank(result.refreshToken())); } - @Test(expectedExceptions = MsalException.class) - public void testExecuteOAuth_Failure() throws SerializeException, + @Test + void testExecuteOAuth_Failure() throws SerializeException, ParseException, MsalException, IOException, URISyntaxException { PublicClientApplication app = PublicClientApplication.builder("id").correlationId("corr-id").build(); @@ -284,41 +271,27 @@ public void testExecuteOAuth_Failure() throws SerializeException, null, new TelemetryManager(null, false)); - final TokenRequestExecutor request = PowerMock.createPartialMock( - TokenRequestExecutor.class, new String[]{"createOauthHttpRequest"}, - new AADAuthority(new URL(TestConstants.ORGANIZATIONS_AUTHORITY)), acr, serviceBundle); - final OAuthHttpRequest msalOAuthHttpRequest = PowerMock - .createMock(OAuthHttpRequest.class); - - final HTTPResponse httpResponse = PowerMock - .createMock(HTTPResponse.class); - EasyMock.expect(request.createOauthHttpRequest()) - .andReturn(msalOAuthHttpRequest).times(1); - EasyMock.expect(msalOAuthHttpRequest.send()).andReturn(httpResponse) - .times(1); - EasyMock.expect(httpResponse.getStatusCode()).andReturn(402).times(3); - EasyMock.expect(httpResponse.getStatusMessage()).andReturn("403 Forbidden"); - EasyMock.expect(httpResponse.getHeaderMap()).andReturn(new HashMap<>()); - EasyMock.expect(httpResponse.getContent()).andReturn(TestConfiguration.HTTP_ERROR_RESPONSE); + final TokenRequestExecutor request = spy(new TokenRequestExecutor( + new AADAuthority(new URL(TestConstants.ORGANIZATIONS_AUTHORITY)), acr, serviceBundle)); + final OAuthHttpRequest msalOAuthHttpRequest = mock(OAuthHttpRequest.class); - final ErrorResponse errorResponse = PowerMock.createMock(ErrorResponse.class); + final HTTPResponse httpResponse = mock(HTTPResponse.class); + doReturn(msalOAuthHttpRequest).when(request).createOauthHttpRequest(); + doReturn(httpResponse).when(msalOAuthHttpRequest).send(); + lenient().doReturn(402).when(httpResponse).getStatusCode(); + doReturn("403 Forbidden").when(httpResponse).getStatusMessage(); + doReturn(new HashMap<>()).when(httpResponse).getHeaderMap(); + doReturn(TestConfiguration.HTTP_ERROR_RESPONSE).when(httpResponse).getContent(); - EasyMock.expect(errorResponse.error()).andReturn("invalid_request"); + final ErrorResponse errorResponse = mock(ErrorResponse.class); - EasyMock.expect(httpResponse.getHeaderValue("User-Agent")).andReturn(null); - EasyMock.expect(httpResponse.getHeaderValue("x-ms-request-id")).andReturn(null); - EasyMock.expect(httpResponse.getHeaderValue("x-ms-clitelem")).andReturn(null); - EasyMock.expect(httpResponse.getStatusCode()).andReturn(402).times(1); + lenient().doReturn("invalid_request").when(errorResponse).error(); + lenient().doReturn(null).when(httpResponse).getHeaderValue("User-Agent"); + lenient().doReturn(null).when(httpResponse).getHeaderValue("x-ms-request-id"); + lenient().doReturn(null).when(httpResponse).getHeaderValue("x-ms-clitelem"); + doReturn(402).when(httpResponse).getStatusCode(); - PowerMock.replay(request, msalOAuthHttpRequest, httpResponse, - TokenErrorResponse.class, errorResponse); - try { - request.executeTokenRequest(); - PowerMock.verifyAll(); - } finally { - PowerMock.reset(request, msalOAuthHttpRequest, httpResponse, - TokenErrorResponse.class, errorResponse); - } + assertThrows(MsalException.class, request::executeTokenRequest); } } \ No newline at end of file diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/TokenResponseTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/TokenResponseTest.java index 2eaa76f8..0744c224 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/TokenResponseTest.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/TokenResponseTest.java @@ -11,11 +11,14 @@ import com.nimbusds.oauth2.sdk.token.RefreshToken; import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; import com.nimbusds.openid.connect.sdk.token.OIDCTokens; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; -@Test(groups = {"checkin"}) -public class TokenResponseTest extends AbstractMsalTests { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class TokenResponseTest { private final String idToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1THdqcHdBSk9NOW4tQSJ9." + "eyJhdWQiOiIyMTZlZjgxZC1mM2IyLTQ3ZDQtYWQyMS1hNGRmNDliNTZkZWUiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5l" @@ -39,11 +42,11 @@ public void testConstructor() throws ParseException { final TokenResponse response = new TokenResponse( new BearerAccessToken("access_token"), new RefreshToken( "refresh_token"), idToken, null, null, expiresIn, extExpiresIn, null, refreshIn); - Assert.assertNotNull(response); + assertNotNull(response); OIDCTokens tokens = response.getOIDCTokens(); - Assert.assertNotNull(tokens); + assertNotNull(tokens); final JWT jwt = tokens.getIDToken(); - Assert.assertTrue(jwt.getJWTClaimsSet().getClaims().size() >= 0); + assertTrue(jwt.getJWTClaimsSet().getClaims().size() >= 0); } @Test @@ -52,12 +55,12 @@ public void testParseJsonObject() final TokenResponse response = TokenResponse .parseJsonObject(JSONObjectUtils .parse(TestConfiguration.TOKEN_ENDPOINT_OK_RESPONSE)); - Assert.assertNotNull(response); + assertNotNull(response); OIDCTokens tokens = response.getOIDCTokens(); - Assert.assertNotNull(tokens); - Assert.assertNotNull(tokens.getIDToken()); - Assert.assertFalse(StringHelper.isBlank(tokens.getIDTokenString())); - Assert.assertFalse(StringHelper.isBlank(response.getScope())); + assertNotNull(tokens); + assertNotNull(tokens.getIDToken()); + assertFalse(StringHelper.isBlank(tokens.getIDTokenString())); + assertFalse(StringHelper.isBlank(response.getScope())); } @Test @@ -67,10 +70,10 @@ public void testEmptyIdToken() { new RefreshToken("refresh_token"), "", null, null, expiresIn, extExpiresIn, null, refreshIn); - Assert.assertNotNull(response); + assertNotNull(response); OIDCTokens tokens = response.getOIDCTokens(); - Assert.assertNotNull(tokens); + assertNotNull(tokens); final AccessToken accessToken = tokens.getAccessToken(); - Assert.assertNotNull(accessToken); + assertNotNull(accessToken); } } diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/UIRequiredCacheTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/UIRequiredCacheTest.java index 8c51897d..00e29882 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/UIRequiredCacheTest.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/UIRequiredCacheTest.java @@ -4,21 +4,27 @@ package com.microsoft.aad.msal4j; import com.nimbusds.oauth2.sdk.http.HTTPResponse; -import org.easymock.EasyMock; -import org.powermock.api.easymock.PowerMock; -import org.testng.Assert; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.BeforeAll; +import org.mockito.junit.jupiter.MockitoExtension; import java.util.*; -import static org.easymock.EasyMock.anyObject; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; -public class UIRequiredCacheTest extends AbstractMsalTests { +@ExtendWith(MockitoExtension.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class UIRequiredCacheTest { - public final Integer CACHING_TIME_SEC = 2; + final Integer CACHING_TIME_SEC = 2; - @BeforeClass + @BeforeAll void init() { InteractionRequiredCache.DEFAULT_CACHING_TIME_SEC = CACHING_TIME_SEC; } @@ -68,37 +74,35 @@ private HttpResponse getHttpResponse(int statusCode, String body) { private PublicClientApplication getApp_MockedWith_InvalidGrantTokenEndpointResponse() throws Exception { - IHttpClient httpClientMock = EasyMock.createMock(IHttpClient.class); + IHttpClient httpClientMock = mock(IHttpClient.class); HttpResponse httpResponse = getHttpResponse(400, TestConfiguration.TOKEN_ENDPOINT_INVALID_GRANT_ERROR_RESPONSE); - EasyMock.expect(httpClientMock.send(anyObject())).andReturn(httpResponse).times(1); - PowerMock.replayAll(httpClientMock); + doReturn(httpResponse).when(httpClientMock).send(any()); return getPublicClientApp(httpClientMock); } private PublicClientApplication getApp_MockedWith_OKTokenEndpointResponse_InvalidGrantTokenEndpointResponse() throws Exception { - IHttpClient httpClientMock = EasyMock.createMock(IHttpClient.class); + IHttpClient httpClientMock = mock(IHttpClient.class); HttpResponse httpResponse = getHttpResponse(HTTPResponse.SC_OK, TestConfiguration.TOKEN_ENDPOINT_OK_RESPONSE); - EasyMock.expect(httpClientMock.send(anyObject())).andReturn(httpResponse).times(1); + lenient().doReturn(httpResponse).when(httpClientMock).send(any()); httpResponse = getHttpResponse(HTTPResponse.SC_UNAUTHORIZED, TestConfiguration.TOKEN_ENDPOINT_INVALID_GRANT_ERROR_RESPONSE); - EasyMock.expect(httpClientMock.send(anyObject())).andReturn(httpResponse).times(1); + lenient().doReturn(httpResponse).when(httpClientMock).send(any()); PublicClientApplication app = getPublicClientApp(httpClientMock); - PowerMock.replayAll(httpClientMock); return app; } @Test - public void RefreshTokenRequest_STSResponseInvalidGrantError_repeatedRequestsServedFromCache() throws Exception { + void RefreshTokenRequest_STSResponseInvalidGrantError_repeatedRequestsServedFromCache() throws Exception { InteractionRequiredCache.clear(); // refresh token request #1 to token endpoint @@ -109,11 +113,9 @@ public void RefreshTokenRequest_STSResponseInvalidGrantError_repeatedRequestsSer app.acquireToken(getAcquireTokenApiParameters("scope1")).join(); } catch (Exception ex) { if (!(ex.getCause() instanceof MsalInteractionRequiredException)) { - Assert.fail("Unexpected exception"); + fail("Unexpected exception"); } } - PowerMock.verifyAll(); - PowerMock.resetAll(); // repeat same request #1, cached response should be returned try { @@ -121,7 +123,7 @@ public void RefreshTokenRequest_STSResponseInvalidGrantError_repeatedRequestsSer app.acquireToken(getAcquireTokenApiParameters("scope1")).join(); } catch (Exception ex) { if (!(ex.getCause() instanceof MsalInteractionRequiredException)) { - Assert.fail("Unexpected exception"); + fail("Unexpected exception"); } } @@ -132,11 +134,9 @@ public void RefreshTokenRequest_STSResponseInvalidGrantError_repeatedRequestsSer app.acquireToken(getAcquireTokenApiParameters("scope2")).join(); } catch (Exception ex) { if (!(ex.getCause() instanceof MsalInteractionRequiredException)) { - Assert.fail("Unexpected exception"); + fail("Unexpected exception"); } } - PowerMock.verifyAll(); - PowerMock.resetAll(); // repeat request #1, should not be served from cache (cache entry should be expired) // request to token endpoint should be sent @@ -146,15 +146,13 @@ public void RefreshTokenRequest_STSResponseInvalidGrantError_repeatedRequestsSer app.acquireToken(getAcquireTokenApiParameters("scope1")).join(); } catch (Exception ex) { if (!(ex.getCause() instanceof MsalServiceException)) { - Assert.fail("Unexpected exception"); + fail("Unexpected exception"); } } - PowerMock.verifyAll(); - PowerMock.resetAll(); } @Test - public void SilentRequest_STSResponseInvalidGrantError_repeatedRequestsServedFromCache() throws Exception { + void SilentRequest_STSResponseInvalidGrantError_repeatedRequestsServedFromCache() throws Exception { InteractionRequiredCache.clear(); PublicClientApplication @@ -170,22 +168,7 @@ public void SilentRequest_STSResponseInvalidGrantError_repeatedRequestsServedFro app.acquireTokenSilently(silentParameters).join(); } catch (Exception ex) { if (!(ex.getCause() instanceof MsalInteractionRequiredException)) { - Assert.fail("Unexpected exception"); - } - } - PowerMock.verifyAll(); - PowerMock.resetAll(); - - // repeat same silent #1, cached response should be returned - try { - SilentParameters silentParameters = SilentParameters.builder( - Collections.singleton("scope1"), - app.getAccounts().join().iterator().next()) - .build(); - app.acquireTokenSilently(silentParameters).join(); - } catch (Exception ex) { - if (!(ex.getCause() instanceof MsalInteractionRequiredException)) { - Assert.fail("Unexpected exception"); + fail("Unexpected exception"); } } @@ -201,11 +184,9 @@ public void SilentRequest_STSResponseInvalidGrantError_repeatedRequestsServedFro app.acquireTokenSilently(silentParameters).join(); } catch (Exception ex) { if (!(ex.getCause() instanceof MsalInteractionRequiredException)) { - Assert.fail("Unexpected exception"); + fail("Unexpected exception"); } } - PowerMock.verifyAll(); - PowerMock.resetAll(); // repeat request #1, should not be served from cache (cache entry should be expired) // request to token endpoint should be sent @@ -220,10 +201,8 @@ public void SilentRequest_STSResponseInvalidGrantError_repeatedRequestsServedFro app.acquireTokenSilently(silentParameters).join(); } catch (Exception ex) { if (!(ex.getCause() instanceof MsalServiceException)) { - Assert.fail("Unexpected exception"); + fail("Unexpected exception"); } } - PowerMock.verifyAll(); - PowerMock.resetAll(); } } diff --git a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/WSTrustRequestTest.java b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/WSTrustRequestTest.java index 151b7804..dd020db8 100644 --- a/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/WSTrustRequestTest.java +++ b/msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/WSTrustRequestTest.java @@ -4,43 +4,45 @@ package com.microsoft.aad.msal4j; import org.apache.commons.text.StringEscapeUtils; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; -@Test(groups = {"checkin"}) -public class WSTrustRequestTest { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class WSTrustRequestTest { @Test - public void buildMessage_cloudAudienceUrnNotNull() throws Exception { + void buildMessage_cloudAudienceUrnNotNull() throws Exception { String msg = WSTrustRequest.buildMessage("address", "username", "password", WSTrustVersion.WSTRUST2005, "cloudAudienceUrn").toString(); - Assert.assertTrue(msg.contains("cloudAudienceUrn")); + assertTrue(msg.contains("cloudAudienceUrn")); } @Test - public void buildMessage_cloudAudienceUrnNull() throws Exception { + void buildMessage_cloudAudienceUrnNull() throws Exception { String msg = WSTrustRequest.buildMessage("address", "username", "password", WSTrustVersion.WSTRUST2005, null).toString(); - Assert.assertTrue(msg.contains("" + WSTrustRequest.DEFAULT_APPLIES_TO + "")); + assertTrue(msg.contains("" + WSTrustRequest.DEFAULT_APPLIES_TO + "")); } @Test - public void buildMessage_cloudAudienceUrnEmpty() throws Exception { + void buildMessage_cloudAudienceUrnEmpty() throws Exception { String msg = WSTrustRequest.buildMessage("address", "username", "password", WSTrustVersion.WSTRUST2005, "").toString(); - Assert.assertTrue(msg.contains("" + WSTrustRequest.DEFAULT_APPLIES_TO + "")); + assertTrue(msg.contains("" + WSTrustRequest.DEFAULT_APPLIES_TO + "")); } @Test - public void buildMessage_integrated() throws Exception { + void buildMessage_integrated() throws Exception { String msg = WSTrustRequest.buildMessage("address", null, null, WSTrustVersion.WSTRUST13, "cloudAudienceUrn").toString(); - Assert.assertTrue(msg.contains("cloudAudienceUrn")); - Assert.assertTrue(!msg.contains("cloudAudienceUrn")); + assertTrue(!msg.contains(" Date: Mon, 10 Jul 2023 14:58:37 -0700 Subject: [PATCH 03/24] Update CIAM tests (#673) --- .../AcquireTokenInteractiveIT.java | 44 +++++++++++++++++++ .../ClientCredentialsIT.java | 25 +++++++++++ .../TestConstants.java | 1 + .../UsernamePasswordIT.java | 21 +++++++++ .../java/labapi/LabConstants.java | 2 +- 5 files changed, 92 insertions(+), 1 deletion(-) diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AcquireTokenInteractiveIT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AcquireTokenInteractiveIT.java index dee0c9a7..fe2d0b25 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AcquireTokenInteractiveIT.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AcquireTokenInteractiveIT.java @@ -124,6 +124,50 @@ void acquireTokenInteractive_ManagedUser_InstanceAware() { assertAcquireTokenInstanceAware(user); } + @Test + void acquireTokenInteractive_Ciam() { + User user = labUserProvider.getCiamUser(); + + Map extraQueryParameters = new HashMap<>(); + + 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.USER_READ_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); + assertEquals(user.getUpn(), result.account().username()); + } + private void assertAcquireTokenCommon(User user, String authority, String scope) { PublicClientApplication pca; try { diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/ClientCredentialsIT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/ClientCredentialsIT.java index 16f01193..de536eed 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/ClientCredentialsIT.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/ClientCredentialsIT.java @@ -6,6 +6,7 @@ import labapi.AppCredentialProvider; import labapi.AzureEnvironment; import labapi.LabUserProvider; +import labapi.User; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.BeforeAll; @@ -64,6 +65,29 @@ void acquireTokenClientCredentials_ClientAssertion() throws Exception { assertAcquireTokenCommon(clientId, credential, TestConstants.MICROSOFT_AUTHORITY); } + @Test + void acquireTokenClientCredentials_ClientSecret_Ciam() throws Exception { + + User user = labUserProvider.getCiamUser(); + String clientId = user.getAppId(); + + 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.DEFAULT_SCOPE)) + .build()) + .get(); + + assertNotNull(result); + assertNotNull(result.accessToken()); + } + @Test void acquireTokenClientCredentials_Callback() throws Exception { String clientId = "2afb0add-2f32-4946-ac90-81a02aa4550e"; @@ -132,6 +156,7 @@ void acquireTokenClientCredentials_Regional() throws Exception { assertAcquireTokenCommon_withRegion(clientId, certificate, "westus", TestConstants.REGIONAL_MICROSOFT_AUTHORITY_BASIC_HOST_WESTUS); } + private ClientAssertion getClientAssertion(String clientId) { return JwtHelper.buildJwt( clientId, diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/TestConstants.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/TestConstants.java index d11fcdf8..23f6e621 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/TestConstants.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/TestConstants.java @@ -13,6 +13,7 @@ public class TestConstants { public final static String MSIDLAB_VAULT_URL = "https://msidlabs.vault.azure.net/"; public final static String GRAPH_DEFAULT_SCOPE = "https://graph.windows.net/.default"; public final static String USER_READ_SCOPE = "user.read"; + public final static String DEFAULT_SCOPE = ".default"; public final static String B2C_LAB_SCOPE = "https://msidlabb2c.onmicrosoft.com/msaapp/user_impersonation"; public final static String B2C_CONFIDENTIAL_CLIENT_APP_SECRETID = "MSIDLABB2C-MSAapp-AppSecret"; public final static String B2C_CONFIDENTIAL_CLIENT_LAB_APP_ID = "MSIDLABB2C-MSAapp-AppID"; diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/UsernamePasswordIT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/UsernamePasswordIT.java index 049c5d40..415b2ac9 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/UsernamePasswordIT.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/UsernamePasswordIT.java @@ -119,6 +119,27 @@ void acquireTokenWithUsernamePassword_AuthorityWithPort() throws Exception { user.getAppId()); } + @Test + void acquireTokenWithUsernamePassword_Ciam() throws Exception { + + Map extraQueryParameters = new HashMap<>(); + + User user = labUserProvider.getCiamUser(); + PublicClientApplication pca = PublicClientApplication.builder(user.getAppId()) + .authority("https://" + user.getLabName() + ".ciamlogin.com/") + .build(); + + + IAuthenticationResult result = pca.acquireToken(UserNamePasswordParameters. + builder(Collections.singleton(TestConstants.USER_READ_SCOPE), + user.getUpn(), + user.getPassword().toCharArray()) + .extraQueryParameters(extraQueryParameters) + .build()) + .get(); + + assertNotNull(result.accessToken()); + } private void assertAcquireTokenCommonAAD(User user) throws Exception { assertAcquireTokenCommon(user, cfg.organizationsAuthority(), cfg.graphDefaultScope(), diff --git a/msal4j-sdk/src/integrationtest/java/labapi/LabConstants.java b/msal4j-sdk/src/integrationtest/java/labapi/LabConstants.java index 569acafd..79397eb9 100644 --- a/msal4j-sdk/src/integrationtest/java/labapi/LabConstants.java +++ b/msal4j-sdk/src/integrationtest/java/labapi/LabConstants.java @@ -14,7 +14,7 @@ public class LabConstants { public final static String USER_MSA_USERNAME_URL = "https://msidlabs.vault.azure.net/secrets/MSA-MSIDLAB4-UserName"; public final static String USER_MSA_PASSWORD_URL = "https://msidlabs.vault.azure.net/secrets/MSA-MSIDLAB4-Password"; public final static String OBO_APP_PASSWORD_URL = "https://msidlabs.vault.azure.net/secrets/TodoListServiceV2-OBO"; - public final static String CIAM_KEY_VAULT_SECRET_KEY = "https://msidlabs.vault.azure.net/secrets/MSIDLABCIAM1-cc"; + public final static String CIAM_KEY_VAULT_SECRET_KEY = "https://msidlabs.vault.azure.net/secrets/MSIDLABCIAM2-cc"; public final static String ARLINGTON_APP_ID = "cb7faed4-b8c0-49ee-b421-f5ed16894c83"; public final static String ARLINGTON_OBO_APP_ID = "c0555d2d-02f2-4838-802e-3463422e571d"; From 0efcce174d0c0d2ba2251822b4117c63ae55e0f9 Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Tue, 11 Jul 2023 16:24:16 +0100 Subject: [PATCH 04/24] Bump guava from 31.1-jre to 32.0.0-jre in /msal4j-sdk (#671) Bumps [guava](https://github.com/google/guava) from 31.1-jre to 32.0.0-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Avery-Dunn --- msal4j-sdk/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msal4j-sdk/pom.xml b/msal4j-sdk/pom.xml index a0e984f0..2e6f4c89 100644 --- a/msal4j-sdk/pom.xml +++ b/msal4j-sdk/pom.xml @@ -131,7 +131,7 @@ com.google.guava guava - 31.1-jre + 32.0.0-jre test From 6dc951b0ee828ebe91506b1370ec60b3f6102931 Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Tue, 11 Jul 2023 16:25:11 +0100 Subject: [PATCH 05/24] Delete contributing.md (#667) Co-authored-by: Avery-Dunn --- msal4j-sdk/contributing.md | 122 ------------------------------------- 1 file changed, 122 deletions(-) delete mode 100644 msal4j-sdk/contributing.md diff --git a/msal4j-sdk/contributing.md b/msal4j-sdk/contributing.md deleted file mode 100644 index 82ba843b..00000000 --- a/msal4j-sdk/contributing.md +++ /dev/null @@ -1,122 +0,0 @@ -# CONTRIBUTING - -Microsoft Authentication Library for Java welcomes new contributors. This document will guide you -through the process. - -### CONTRIBUTOR LICENSE AGREEMENT - -Please visit [https://cla.microsoft.com/](https://cla.microsoft.com/) and sign the Contributor License -Agreement. You only need to do that once. We can not look at your code until you've submitted this request. - - -### FORK - -Fork the project [on GitHub](https://github.com/AzureAD/microsoft-authentication-library-for-java) and check out -your copy. - -Example for MSAL Java: - -``` -$ git clone git@github.com:username/microsoft-authentication-library-for-java.git -$ cd microsoft-authentication-library-for-java -$ git remote add upstream git@github.com:AzureAD/microsoft-authentication-library-for-java.git -``` - -Now decide if you want your feature or bug fix to go into the dev branch -or the master branch. **All bug fixes and new features should go into the dev branch.** - -The master branch is effectively frozen; patches that change the SDKs -protocols or API surface area or affect the run-time behavior of the SDK will be rejected. - -Some of our SDKs have bundled dependencies that are not part of the project proper. Any changes to files in those directories or its subdirectories should be sent to their respective -projects. Do not send your patch to us, we cannot accept it. - -In case of doubt, open an issue in the [issue tracker](https://github.com/AzureAD/microsoft-authentication-library-for-java/issues). - -Especially do so if you plan to work on a major change in functionality. Nothing is more -frustrating than seeing your hard work go to waste because your vision -does not align with our goals for the SDK. - - -### BRANCH - -Okay, so you have decided on the proper branch. Create a feature branch -and start hacking: - -``` -$ git checkout -b my-feature-branch -``` - -### COMMIT - -Make sure git knows your name and email address: - -``` -$ git config --global user.name "J. Random User" -$ git config --global user.email "j.random.user@example.com" -``` - -Writing good commit logs is important. A commit log should describe what -changed and why. Follow these guidelines when writing one: - -1. The first line should be 50 characters or less and contain a short - description of the change prefixed with the name of the changed - subsystem (e.g. "net: add localAddress and localPort to Socket"). -2. Keep the second line blank. -3. Wrap all other lines at 72 columns. - -A good commit log looks like this: - -``` -fix: explaining the commit in one line - -Body of commit message is a few lines of text, explaining things -in more detail, possibly giving some background about the issue -being fixed, etc etc. - -The body of the commit message can be several paragraphs, and -please do proper word-wrap and keep columns shorter than about -72 characters or so. That way `git log` will show things -nicely even when it is indented. -``` - -The header line should be meaningful; it is what other people see when they -run `git shortlog` or `git log --oneline`. - -Check the output of `git log --oneline files_that_you_changed` to find out -what directories your changes touch. - - -### REBASE - -Use `git rebase` (not `git merge`) to sync your work from time to time. - -``` -$ git fetch upstream -$ git rebase upstream/v0.1 # or upstream/master -``` - - -### TEST - -Bug fixes and features should come with tests. Add your tests in the -test directory. This varies by repository but often follows the same convention of /src/test. Look at other tests to see how they should be -structured (license boilerplate, common includes, etc.). - - -Make sure that all tests pass. - - -### PUSH - -``` -$ git push origin my-feature-branch -``` - -Go to https://github.com/username/microsoft-authentication-library-for-java.git and select your feature branch. Click -the 'Pull Request' button and fill out the form. - -Pull requests are usually reviewed within a few days. If there are comments -to address, apply your changes in a separate commit and push that to your -feature branch. Post a comment in the pull request afterwards; GitHub does -not send out notifications when you add commits. From 3d1ca7c16a88100676e0df9bcc1cc0b534754ef9 Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Tue, 11 Jul 2023 16:25:22 +0100 Subject: [PATCH 06/24] Create Contributing.md (#668) Co-authored-by: Avery-Dunn --- Contributing.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Contributing.md diff --git a/Contributing.md b/Contributing.md new file mode 100644 index 00000000..fb5cdf20 --- /dev/null +++ b/Contributing.md @@ -0,0 +1,18 @@ +# CONTRIBUTING + +Microsoft Authentication Library for Java welcomes new contributors. This document will guide you +through the process. + +## CONTRIBUTOR LICENSE AGREEMENT + +Please visit [https://cla.microsoft.com/](https://cla.microsoft.com/) and sign the Contributor License +Agreement. You only need to do that once. We can not look at your code until you've submitted this request. + + +## Build + +Use Java8. + +## Test + +Unit tests should run as expected. Integration tests require certificate / secrets which are deployed on CI. External contributors are not able to run integration tests manually. From 8bf42f2efa3bf9d70f036ac946347f8950c6b487 Mon Sep 17 00:00:00 2001 From: Avery-Dunn <62066438+Avery-Dunn@users.noreply.github.com> Date: Tue, 11 Jul 2023 09:54:22 -0700 Subject: [PATCH 07/24] Version changes for 1.13.9 (#674) --- README.md | 6 +++--- msal4j-sdk/README.md | 6 +++--- msal4j-sdk/bnd.bnd | 2 +- msal4j-sdk/changelog.txt | 5 +++++ msal4j-sdk/pom.xml | 2 +- msal4j-sdk/src/samples/msal-b2c-web-sample/pom.xml | 2 +- msal4j-sdk/src/samples/msal-obo-sample/pom.xml | 2 +- msal4j-sdk/src/samples/msal-web-sample/pom.xml | 2 +- 8 files changed, 16 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 00e86f3d..1b4780d0 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.13.8 +Current version - 1.13.9 You can find the changes for each version in the [change log](https://github.com/AzureAD/microsoft-authentication-library-for-java/blob/main/msal4j-sdk/changelog.txt). @@ -28,13 +28,13 @@ Find [the latest package in the Maven repository](https://mvnrepository.com/arti com.microsoft.azure msal4j - 1.13.8 + 1.13.9 ``` ### Gradle ```gradle -implementation group: 'com.microsoft.azure', name: 'com.microsoft.aad.msal4j', version: '1.13.8' +implementation group: 'com.microsoft.azure', name: 'com.microsoft.aad.msal4j', version: '1.13.9' ``` ## Usage diff --git a/msal4j-sdk/README.md b/msal4j-sdk/README.md index e1f75061..e503ef86 100644 --- a/msal4j-sdk/README.md +++ b/msal4j-sdk/README.md @@ -16,7 +16,7 @@ Quick links: The library supports the following Java environments: - Java 8 (or higher) -Current version - 1.13.8 +Current version - 1.13.9 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.13.8 + 1.13.9 ``` ### Gradle ```gradle -compile group: 'com.microsoft.azure', name: 'msal4j', version: '1.13.8' +compile group: 'com.microsoft.azure', name: 'msal4j', version: '1.13.9' ``` ## Usage diff --git a/msal4j-sdk/bnd.bnd b/msal4j-sdk/bnd.bnd index d7cdd81e..81a498af 100644 --- a/msal4j-sdk/bnd.bnd +++ b/msal4j-sdk/bnd.bnd @@ -1,2 +1,2 @@ -Export-Package: com.microsoft.aad.msal4j;version="1.13.8" +Export-Package: com.microsoft.aad.msal4j;version="1.13.9" Automatic-Module-Name: com.microsoft.aad.msal4j diff --git a/msal4j-sdk/changelog.txt b/msal4j-sdk/changelog.txt index 647918fd..8e0c0591 100644 --- a/msal4j-sdk/changelog.txt +++ b/msal4j-sdk/changelog.txt @@ -1,3 +1,8 @@ +Version 1.13.9 +============= +- Update automated tests to use JUnit 5/Mockito instead of TestNG/Powermock +- Fix issue with interactive flow on macOS/Linux/Unix systems + Version 1.13.8 ============= - Added support for CIAM authority diff --git a/msal4j-sdk/pom.xml b/msal4j-sdk/pom.xml index 2e6f4c89..cc2b0aba 100644 --- a/msal4j-sdk/pom.xml +++ b/msal4j-sdk/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.microsoft.azure msal4j - 1.13.8 + 1.13.9 jar msal4j diff --git a/msal4j-sdk/src/samples/msal-b2c-web-sample/pom.xml b/msal4j-sdk/src/samples/msal-b2c-web-sample/pom.xml index 44fb595f..bb553488 100644 --- a/msal4j-sdk/src/samples/msal-b2c-web-sample/pom.xml +++ b/msal4j-sdk/src/samples/msal-b2c-web-sample/pom.xml @@ -23,7 +23,7 @@ com.microsoft.azure msal4j - 1.13.8 + 1.13.9 com.nimbusds diff --git a/msal4j-sdk/src/samples/msal-obo-sample/pom.xml b/msal4j-sdk/src/samples/msal-obo-sample/pom.xml index 83de76a6..54178923 100644 --- a/msal4j-sdk/src/samples/msal-obo-sample/pom.xml +++ b/msal4j-sdk/src/samples/msal-obo-sample/pom.xml @@ -23,7 +23,7 @@ com.microsoft.azure msal4j - 1.13.8 + 1.13.9 com.nimbusds diff --git a/msal4j-sdk/src/samples/msal-web-sample/pom.xml b/msal4j-sdk/src/samples/msal-web-sample/pom.xml index 4c5eb86e..03efd6fc 100644 --- a/msal4j-sdk/src/samples/msal-web-sample/pom.xml +++ b/msal4j-sdk/src/samples/msal-web-sample/pom.xml @@ -23,7 +23,7 @@ com.microsoft.azure msal4j - 1.13.8 + 1.13.9 com.nimbusds From 1dfb59cc05209d2c94b260e24f1533cfa690d984 Mon Sep 17 00:00:00 2001 From: Ric Emery Date: Wed, 26 Jul 2023 14:33:12 -0700 Subject: [PATCH 08/24] Add space between command and arguments when executing linux command to open browser. Refs #682 (#683) Co-authored-by: Ric Emery --- .../aad/msal4j/AcquireTokenByInteractiveFlowSupplier.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AcquireTokenByInteractiveFlowSupplier.java b/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AcquireTokenByInteractiveFlowSupplier.java index 8029c5d8..72f3f3a0 100644 --- a/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AcquireTokenByInteractiveFlowSupplier.java +++ b/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AcquireTokenByInteractiveFlowSupplier.java @@ -182,7 +182,7 @@ private static void openDefaultSystemBrowserInLinux(URL url){ if (openToolPath != null) { Runtime runtime = Runtime.getRuntime(); try { - runtime.exec(openTool + url); + runtime.exec(openTool + " " + url); } catch (IOException e) { throw new RuntimeException(e); } From efee88f08c3d4adc90bcaac0279993f3650b99a1 Mon Sep 17 00:00:00 2001 From: Avery-Dunn <62066438+Avery-Dunn@users.noreply.github.com> Date: Thu, 3 Aug 2023 11:05:03 -0700 Subject: [PATCH 09/24] Assorted fixes (#684) * Remove default timeouts and improve exception messages * Fix NPE for on-prem ADFS scenario * Log MSAL message but re-throw exception * Update vulnerable test dependency --- msal4j-sdk/pom.xml | 2 +- .../HttpClientIT.java | 33 +++++++++++++++++-- .../TokenCacheIT.java | 26 +++++++++++++++ ...AcquireTokenByInteractiveFlowSupplier.java | 7 ++-- .../aad/msal4j/AuthenticationErrorCode.java | 12 ++++++- .../aad/msal4j/DefaultHttpClient.java | 21 +++++++++--- .../com/microsoft/aad/msal4j/TokenCache.java | 2 +- 7 files changed, 92 insertions(+), 11 deletions(-) diff --git a/msal4j-sdk/pom.xml b/msal4j-sdk/pom.xml index cc2b0aba..9a3c8e3e 100644 --- a/msal4j-sdk/pom.xml +++ b/msal4j-sdk/pom.xml @@ -131,7 +131,7 @@ com.google.guava guava - 32.0.0-jre + 32.1.1-jre test diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/HttpClientIT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/HttpClientIT.java index edc82ef3..66f55986 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/HttpClientIT.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/HttpClientIT.java @@ -8,10 +8,13 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.BeforeAll; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; import java.util.Collections; +import java.util.concurrent.ExecutionException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; @TestInstance(TestInstance.Lifecycle.PER_CLASS) class HttpClientIT { @@ -34,6 +37,14 @@ void acquireToken_apacheHttpClient() throws Exception { assertAcquireTokenCommon(user, new ApacheHttpClientAdapter()); } + @Test + void acquireToken_readTimeout() throws Exception { + User user = labUserProvider.getDefaultUser(); + + //Set a 1ms read timeout, which will almost certainly occur before the service can respond + assertAcquireTokenCommon_WithTimeout(user, 1); + } + private void assertAcquireTokenCommon(User user, IHttpClient httpClient) throws Exception { PublicClientApplication pca = PublicClientApplication.builder( @@ -54,4 +65,22 @@ private void assertAcquireTokenCommon(User user, IHttpClient httpClient) assertNotNull(result.idToken()); assertEquals(user.getUpn(), result.account().username()); } + + private void assertAcquireTokenCommon_WithTimeout(User user, int readTimeout) + throws Exception { + PublicClientApplication pca = PublicClientApplication.builder( + user.getAppId()). + authority(TestConstants.ORGANIZATIONS_AUTHORITY). + readTimeoutForDefaultHttpClient(readTimeout). + build(); + + ExecutionException ex = assertThrows(ExecutionException.class, () -> pca.acquireToken(UserNamePasswordParameters. + builder(Collections.singleton(TestConstants.GRAPH_DEFAULT_SCOPE), + user.getUpn(), + user.getPassword().toCharArray()) + .build()) + .get()); + + assertEquals("com.microsoft.aad.msal4j.MsalClientException: java.net.SocketTimeoutException: Read timed out", ex.getMessage()); + } } diff --git a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/TokenCacheIT.java b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/TokenCacheIT.java index 9576eaef..d1192f2c 100644 --- a/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/TokenCacheIT.java +++ b/msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/TokenCacheIT.java @@ -9,6 +9,7 @@ import org.junit.jupiter.api.TestInstance; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.util.Collections; import java.util.HashMap; @@ -170,6 +171,31 @@ void twoAccountsInCache_SameUserDifferentTenants_RemoveAccountTest() throws Exce "/cache_data/remove-account-test-cache.json"); } + @Test + void retrieveAccounts_ADFSOnPrem() throws Exception { + UserQueryParameters query = new UserQueryParameters(); + query.parameters.put(UserQueryParameters.FEDERATION_PROVIDER, FederationProvider.ADFS_2019); + query.parameters.put(UserQueryParameters.USER_TYPE, UserType.ON_PREM); + + User user = labUserProvider.getLabUser(query); + + PublicClientApplication pca = PublicClientApplication.builder( + TestConstants.ADFS_APP_ID). + authority(TestConstants.ADFS_AUTHORITY). + build(); + + pca.acquireToken(UserNamePasswordParameters. + builder(Collections.singleton(TestConstants.ADFS_SCOPE), + user.getUpn(), + user.getPassword().toCharArray()) + .build()) + .get(); + + assertNotNull(pca.getAccounts().join().iterator().next()); + assertEquals(pca.getAccounts().join().size(), 1); + } + + private static class TokenPersistence implements ITokenCacheAccessAspect { String data; diff --git a/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AcquireTokenByInteractiveFlowSupplier.java b/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AcquireTokenByInteractiveFlowSupplier.java index 72f3f3a0..485bc4f9 100644 --- a/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AcquireTokenByInteractiveFlowSupplier.java +++ b/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AcquireTokenByInteractiveFlowSupplier.java @@ -209,8 +209,11 @@ private AuthorizationResult getAuthorizationResultFromHttpListener() { expirationTime = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()) + 1; } - while (result == null && !interactiveRequest.futureReference().get().isCancelled() && - TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()) < expirationTime) { + while (result == null && !interactiveRequest.futureReference().get().isCancelled()) { + if (TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()) > expirationTime) { + LOG.warn(String.format("Listener timed out after %S seconds, no authorization code was returned from the server during that time.", timeFromParameters)); + break; + } result = authorizationResultQueue.poll(100, TimeUnit.MILLISECONDS); } diff --git a/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AuthenticationErrorCode.java b/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AuthenticationErrorCode.java index 78f5260c..22e8299f 100644 --- a/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AuthenticationErrorCode.java +++ b/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AuthenticationErrorCode.java @@ -115,9 +115,19 @@ public class AuthenticationErrorCode { * A JWT parsing failure, indicating the JWT provided to MSAL is of invalid format. */ public final static String INVALID_JWT = "invalid_jwt"; + /** * Indicates that a Broker implementation is missing from the device, such as when an app developer * does not include one of our broker packages as a dependency in their project, or otherwise cannot - * be accessed by MSAL Java*/ + * be accessed by MSAL Java + */ public final static String MISSING_BROKER = "missing_broker"; + + /** + * Indicates that a timeout occurred during an HTTP call. If this was thrown in relation to a connection timeout error, + * there is likely a network issue preventing the library from reaching a service, such as being blocked by a firewall. + * If this was thrown in relation to a read timeout error, there is likely an issue in the service itself causing a + * slow response, and this may be resolvable by increasing timeouts. For more details, see https://aka.ms/msal4j-http-client + */ + public final static String HTTP_TIMEOUT = "http_timeout"; } diff --git a/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/DefaultHttpClient.java b/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/DefaultHttpClient.java index a563b369..ee60eccc 100644 --- a/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/DefaultHttpClient.java +++ b/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/DefaultHttpClient.java @@ -1,25 +1,30 @@ package com.microsoft.aad.msal4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLSocketFactory; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; +import java.net.ConnectException; import java.net.HttpURLConnection; import java.net.Proxy; +import java.net.SocketTimeoutException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Map; class DefaultHttpClient implements IHttpClient { + private final static Logger LOG = LoggerFactory.getLogger(DefaultHttpClient.class); private final Proxy proxy; private final SSLSocketFactory sslSocketFactory; - public int DEFAULT_CONNECT_TIMEOUT = 10000; - public int DEFAULT_READ_TIMEOUT = 15000; - private int connectTimeout = DEFAULT_CONNECT_TIMEOUT; - private int readTimeout = DEFAULT_READ_TIMEOUT; + //By default, rely on the timeout behavior of the services requests are sent to + private int connectTimeout = 0; + private int readTimeout = 0; DefaultHttpClient(Proxy proxy, SSLSocketFactory sslSocketFactory, Integer connectTimeout, Integer readTimeout) { this.proxy = proxy; @@ -117,6 +122,14 @@ private HttpResponse readResponseFromConnection(final HttpsURLConnection conn) t httpResponse.addHeaders(conn.getHeaderFields()); httpResponse.body(inputStreamToString(is)); return httpResponse; + } catch (SocketTimeoutException readException) { + LOG.error("Timeout while waiting for response from service. If custom timeouts were set, increasing them may resolve this issue. See https://aka.ms/msal4j-http-client for more information and solutions."); + + throw readException; + } catch (ConnectException timeoutException) { + LOG.error("Exception while connecting to service, there may be network issues preventing MSAL Java from connecting. See https://aka.ms/msal4j-http-client for more information and solutions."); + + throw timeoutException; } finally { if (is != null) { is.close(); diff --git a/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/TokenCache.java b/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/TokenCache.java index d12dc186..b5032d7c 100644 --- a/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/TokenCache.java +++ b/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/TokenCache.java @@ -346,7 +346,7 @@ Set getAccounts(String clientId) { ((Account) rootAccounts.get(accCached.homeAccountId())).tenantProfiles.put(accCached.realm(), profile); } - if (accCached.homeAccountId().contains(accCached.localAccountId())) { + if (accCached.localAccountId() != null && accCached.homeAccountId().contains(accCached.localAccountId())) { ((Account) rootAccounts.get(accCached.homeAccountId())).username(accCached.username()); } } From feabcde3f3dfba58b96958288be0106cbbd8c773 Mon Sep 17 00:00:00 2001 From: Maximilian Pfeffer Date: Mon, 7 Aug 2023 00:11:48 +0200 Subject: [PATCH 10/24] Issue-679: Fix for Account Cache; .contains() was not possible and you had to iterate through all elements as workaround. (#681) --- msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/Account.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/Account.java b/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/Account.java index 926419e4..1c541d21 100644 --- a/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/Account.java +++ b/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/Account.java @@ -4,6 +4,7 @@ package com.microsoft.aad.msal4j; import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; import lombok.experimental.Accessors; @@ -17,6 +18,7 @@ @Accessors(fluent = true) @Getter @Setter +@EqualsAndHashCode(of = {"homeAccountId"}) @AllArgsConstructor class Account implements IAccount { From ef40ea036c825c664c51af383a4a4c564b5b6428 Mon Sep 17 00:00:00 2001 From: Avery-Dunn <62066438+Avery-Dunn@users.noreply.github.com> Date: Mon, 7 Aug 2023 09:48:45 -0700 Subject: [PATCH 11/24] Version changes for 1.13.10 (#685) --- README.md | 6 +++--- msal4j-sdk/README.md | 6 +++--- msal4j-sdk/bnd.bnd | 2 +- msal4j-sdk/changelog.txt | 7 +++++++ msal4j-sdk/pom.xml | 2 +- msal4j-sdk/src/samples/msal-b2c-web-sample/pom.xml | 2 +- msal4j-sdk/src/samples/msal-obo-sample/pom.xml | 2 +- msal4j-sdk/src/samples/msal-web-sample/pom.xml | 2 +- 8 files changed, 18 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 1b4780d0..5e99abf0 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.13.9 +Current version - 1.13.10 You can find the changes for each version in the [change log](https://github.com/AzureAD/microsoft-authentication-library-for-java/blob/main/msal4j-sdk/changelog.txt). @@ -28,13 +28,13 @@ Find [the latest package in the Maven repository](https://mvnrepository.com/arti com.microsoft.azure msal4j - 1.13.9 + 1.13.10 ``` ### Gradle ```gradle -implementation group: 'com.microsoft.azure', name: 'com.microsoft.aad.msal4j', version: '1.13.9' +implementation group: 'com.microsoft.azure', name: 'com.microsoft.aad.msal4j', version: '1.13.10' ``` ## Usage diff --git a/msal4j-sdk/README.md b/msal4j-sdk/README.md index e503ef86..dce0869b 100644 --- a/msal4j-sdk/README.md +++ b/msal4j-sdk/README.md @@ -16,7 +16,7 @@ Quick links: The library supports the following Java environments: - Java 8 (or higher) -Current version - 1.13.9 +Current version - 1.13.10 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.13.9 + 1.13.10 ``` ### Gradle ```gradle -compile group: 'com.microsoft.azure', name: 'msal4j', version: '1.13.9' +compile group: 'com.microsoft.azure', name: 'msal4j', version: '1.13.10' ``` ## Usage diff --git a/msal4j-sdk/bnd.bnd b/msal4j-sdk/bnd.bnd index 81a498af..d3b2aa1a 100644 --- a/msal4j-sdk/bnd.bnd +++ b/msal4j-sdk/bnd.bnd @@ -1,2 +1,2 @@ -Export-Package: com.microsoft.aad.msal4j;version="1.13.9" +Export-Package: com.microsoft.aad.msal4j;version="1.13.10" Automatic-Module-Name: com.microsoft.aad.msal4j diff --git a/msal4j-sdk/changelog.txt b/msal4j-sdk/changelog.txt index 8e0c0591..380e95a4 100644 --- a/msal4j-sdk/changelog.txt +++ b/msal4j-sdk/changelog.txt @@ -1,3 +1,10 @@ +Version 1.13.10 +============= +- Remove default HTTP timeout (#664) +- Add equals/hash logic to Account class based on homeAccountID (#681) +- Fix issue with command to open default browser on Linux (#683) +- Handle null pointer exception in certain ADFS scenarios (#669) + Version 1.13.9 ============= - Update automated tests to use JUnit 5/Mockito instead of TestNG/Powermock diff --git a/msal4j-sdk/pom.xml b/msal4j-sdk/pom.xml index 9a3c8e3e..ef8e12b5 100644 --- a/msal4j-sdk/pom.xml +++ b/msal4j-sdk/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.microsoft.azure msal4j - 1.13.9 + 1.13.10 jar msal4j diff --git a/msal4j-sdk/src/samples/msal-b2c-web-sample/pom.xml b/msal4j-sdk/src/samples/msal-b2c-web-sample/pom.xml index bb553488..775c4e14 100644 --- a/msal4j-sdk/src/samples/msal-b2c-web-sample/pom.xml +++ b/msal4j-sdk/src/samples/msal-b2c-web-sample/pom.xml @@ -23,7 +23,7 @@ com.microsoft.azure msal4j - 1.13.9 + 1.13.10 com.nimbusds diff --git a/msal4j-sdk/src/samples/msal-obo-sample/pom.xml b/msal4j-sdk/src/samples/msal-obo-sample/pom.xml index 54178923..86615a41 100644 --- a/msal4j-sdk/src/samples/msal-obo-sample/pom.xml +++ b/msal4j-sdk/src/samples/msal-obo-sample/pom.xml @@ -23,7 +23,7 @@ com.microsoft.azure msal4j - 1.13.9 + 1.13.10 com.nimbusds diff --git a/msal4j-sdk/src/samples/msal-web-sample/pom.xml b/msal4j-sdk/src/samples/msal-web-sample/pom.xml index 03efd6fc..2d06caed 100644 --- a/msal4j-sdk/src/samples/msal-web-sample/pom.xml +++ b/msal4j-sdk/src/samples/msal-web-sample/pom.xml @@ -23,7 +23,7 @@ com.microsoft.azure msal4j - 1.13.9 + 1.13.10 com.nimbusds From 4dc7a5e3c29e3995c585648b86cb3a04aef3c39f Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Wed, 9 Aug 2023 15:38:51 +0100 Subject: [PATCH 12/24] Move changelog --- msal4j-sdk/changelog.txt => changelog.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename msal4j-sdk/changelog.txt => changelog.txt (100%) diff --git a/msal4j-sdk/changelog.txt b/changelog.txt similarity index 100% rename from msal4j-sdk/changelog.txt rename to changelog.txt From 255644875cf9c76baf834edfedfad604bea14895 Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Wed, 9 Aug 2023 15:40:12 +0100 Subject: [PATCH 13/24] Move changelog to root --- msal4j-sdk/changelog.txt => changelog.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename msal4j-sdk/changelog.txt => changelog.txt (100%) diff --git a/msal4j-sdk/changelog.txt b/changelog.txt similarity index 100% rename from msal4j-sdk/changelog.txt rename to changelog.txt From ddc953f78ba61ae447250764bf83047789a43122 Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Tue, 12 Sep 2023 17:29:18 +0100 Subject: [PATCH 14/24] Update issue templates (#707) --- .github/ISSUE_TEMPLATE/bug_report.md | 125 +++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..d788b3f9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,125 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +name: Bug report +description: Broken or unintended behavior with one of our libraries. +title: '[Bug] ' +labels: ["untriaged", "needs attention"] +body: +- type: markdown + attributes: + value: | + ## Before submitting your issue + Please make sure that your question or issue is not already covered in existing issues + + **Logs and network traces** + Without logs or traces, it is unlikely that the team can investigate your issue. Capturing logs is described in our [Docs](https://learn.microsoft.com/azure/active-directory/develop/msal-logging-java). + +- type: markdown + attributes: + value: | + ## Issue details + +- type: input + attributes: + label: Library version used + description: "Please enter the version of the library where you ran into the issue (e.g. 1.13.10)." + validations: + required: true + +- type: input + attributes: + label: Java version + description: "Please enter the Java SDK and Framework version your application is developed in." + validations: + required: true + +- type: dropdown + attributes: + label: Scenario + description: "Are you using PublicClientApplication, ConfidentialClientApplication or ManagedIdentityApplication?" + multiple: true + options: + - "PublicClient - desktop app" + - "PublicClient - mobile app" + - "ConfidentialClient - web site (AcquireTokenByAuthCode)" + - "ConfidentialClient - web api (AcquireTokenOnBehalfOf)" + - "ConfidentialClient - service to service (AcquireTokenForClient)" + - "ManagedIdentityClient - managed identity" + - "Other - please specify" + validations: + required: true + +- type: dropdown + attributes: + label: Is this a new or an existing app? + description: "Is this a new or existing app?" + multiple: false + options: + - "The app is in production, and I have upgraded to a new version of MSAL" + - "The app is in production, I haven't upgraded MSAL, but started seeing this issue" + - "This is a new app or experiment" + validations: + required: false + +- type: textarea + attributes: + label: Issue description and reproduction steps + description: "Briefly explain the issue you are seeing along with any error messages or stack trace. Provide a link to one of the [standard samples](https://learn.microsoft.com/azure/active-directory/develop/sample-v2-code?tabs=apptype) and steps to reproduce the behavior. Make sure to provide verbose level log messages from MSAL, if available. [Learn more](https://learn.microsoft.com/azure/active-directory/develop/msal-logging-dotnet)" + validations: + required: true + +- type: textarea + attributes: + label: Relevant code snippets + description: "Provide relevant code snippets that can be used to reproduce the issue." + render: csharp + validations: + required: false + +- type: textarea + attributes: + label: Expected behavior + description: "Describe what you expect the behavior to be." + validations: + required: false + +- type: dropdown + attributes: + label: Identity provider + options: + - Microsoft Entra ID (Work and School accounts and Personal Microsoft accounts) + - Azure B2C Basic Policy + - Azure B2C Custom Policy + - Azure Active Directory Federation Services (ADFS) + - Microsoft Entra External ID + - Other + validations: + required: true + +- type: input + attributes: + label: Regression + description: "If this behavior worked before, enter the last working version(s) of MSAL." + placeholder: "MSAL version: " + +- type: textarea + attributes: + label: Solution and workarounds + description: "Possible solution or workarounds, if you know of any." + validations: + required: false + +- type: markdown + attributes: + value: "## Security Reporting" +- type: markdown + attributes: + value: | + If you find a security issue with our libraries or services [please report it to the Microsoft Security Response Center (MSRC)](https://aka.ms/report-security-issue) with as much detail as possible. Your submission may be eligible for a bounty through the [Microsoft Bounty](http://aka.ms/bugbounty) program. Please do not post security issues to GitHub Issues or any other public site. We will contact you shortly upon receiving the information. We encourage you to get notifications of when security incidents occur by visiting [this page](https://www.microsoft.com/msrc/technical-security-notifications) and subscribing to Security Advisory Alerts. From afc8a15a133230c7e771320b9af06a599183ac53 Mon Sep 17 00:00:00 2001 From: Avery-Dunn <62066438+Avery-Dunn@users.noreply.github.com> Date: Thu, 21 Sep 2023 09:28:53 -0700 Subject: [PATCH 15/24] Re-add lombok source line (#705) --- msal4j-sdk/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/msal4j-sdk/pom.xml b/msal4j-sdk/pom.xml index ef8e12b5..bd92dd15 100644 --- a/msal4j-sdk/pom.xml +++ b/msal4j-sdk/pom.xml @@ -169,6 +169,7 @@ + ${project.build.directory}/delombok org.projectlombok From f31cd8b50a987a144d9dbb85e1e29d6a37e3edd3 Mon Sep 17 00:00:00 2001 From: Avery-Dunn <62066438+Avery-Dunn@users.noreply.github.com> Date: Fri, 22 Sep 2023 14:44:24 -0700 Subject: [PATCH 16/24] Version changes for release 1.13.11 (#714) --- README.md | 6 +++--- changelog.txt | 4 ++++ msal4j-sdk/README.md | 6 +++--- msal4j-sdk/bnd.bnd | 2 +- msal4j-sdk/pom.xml | 2 +- msal4j-sdk/src/samples/msal-b2c-web-sample/pom.xml | 2 +- msal4j-sdk/src/samples/msal-obo-sample/pom.xml | 2 +- msal4j-sdk/src/samples/msal-web-sample/pom.xml | 2 +- 8 files changed, 15 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 5e99abf0..0ddb3d98 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.13.10 +Current version - 1.13.11 You can find the changes for each version in the [change log](https://github.com/AzureAD/microsoft-authentication-library-for-java/blob/main/msal4j-sdk/changelog.txt). @@ -28,13 +28,13 @@ Find [the latest package in the Maven repository](https://mvnrepository.com/arti com.microsoft.azure msal4j - 1.13.10 + 1.13.11 ``` ### Gradle ```gradle -implementation group: 'com.microsoft.azure', name: 'com.microsoft.aad.msal4j', version: '1.13.10' +implementation group: 'com.microsoft.azure', name: 'com.microsoft.aad.msal4j', version: '1.13.11' ``` ## Usage diff --git a/changelog.txt b/changelog.txt index 380e95a4..24639066 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +Version 1.13.11 +============= +- Hotfix for internal docs generation issue (#705) + Version 1.13.10 ============= - Remove default HTTP timeout (#664) diff --git a/msal4j-sdk/README.md b/msal4j-sdk/README.md index dce0869b..474499bc 100644 --- a/msal4j-sdk/README.md +++ b/msal4j-sdk/README.md @@ -16,7 +16,7 @@ Quick links: The library supports the following Java environments: - Java 8 (or higher) -Current version - 1.13.10 +Current version - 1.13.11 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.13.10 + 1.13.11 ``` ### Gradle ```gradle -compile group: 'com.microsoft.azure', name: 'msal4j', version: '1.13.10' +compile group: 'com.microsoft.azure', name: 'msal4j', version: '1.13.11' ``` ## Usage diff --git a/msal4j-sdk/bnd.bnd b/msal4j-sdk/bnd.bnd index d3b2aa1a..0a14dff8 100644 --- a/msal4j-sdk/bnd.bnd +++ b/msal4j-sdk/bnd.bnd @@ -1,2 +1,2 @@ -Export-Package: com.microsoft.aad.msal4j;version="1.13.10" +Export-Package: com.microsoft.aad.msal4j;version="1.13.11" Automatic-Module-Name: com.microsoft.aad.msal4j diff --git a/msal4j-sdk/pom.xml b/msal4j-sdk/pom.xml index bd92dd15..847b32e7 100644 --- a/msal4j-sdk/pom.xml +++ b/msal4j-sdk/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.microsoft.azure msal4j - 1.13.10 + 1.13.11 jar msal4j diff --git a/msal4j-sdk/src/samples/msal-b2c-web-sample/pom.xml b/msal4j-sdk/src/samples/msal-b2c-web-sample/pom.xml index 775c4e14..416d4d36 100644 --- a/msal4j-sdk/src/samples/msal-b2c-web-sample/pom.xml +++ b/msal4j-sdk/src/samples/msal-b2c-web-sample/pom.xml @@ -23,7 +23,7 @@ com.microsoft.azure msal4j - 1.13.10 + 1.13.11 com.nimbusds diff --git a/msal4j-sdk/src/samples/msal-obo-sample/pom.xml b/msal4j-sdk/src/samples/msal-obo-sample/pom.xml index 86615a41..860ebce8 100644 --- a/msal4j-sdk/src/samples/msal-obo-sample/pom.xml +++ b/msal4j-sdk/src/samples/msal-obo-sample/pom.xml @@ -23,7 +23,7 @@ com.microsoft.azure msal4j - 1.13.10 + 1.13.11 com.nimbusds diff --git a/msal4j-sdk/src/samples/msal-web-sample/pom.xml b/msal4j-sdk/src/samples/msal-web-sample/pom.xml index 2d06caed..bb6760fb 100644 --- a/msal4j-sdk/src/samples/msal-web-sample/pom.xml +++ b/msal4j-sdk/src/samples/msal-web-sample/pom.xml @@ -23,7 +23,7 @@ com.microsoft.azure msal4j - 1.13.10 + 1.13.11 com.nimbusds From 746631ef43cd01c9774e65525dfd2a857d4eb629 Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Fri, 29 Sep 2023 11:45:31 +0100 Subject: [PATCH 17/24] Update bug report --- .github/ISSUE_TEMPLATE/bug_report.yaml | 125 +++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yaml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 00000000..d788b3f9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,125 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +name: Bug report +description: Broken or unintended behavior with one of our libraries. +title: '[Bug] ' +labels: ["untriaged", "needs attention"] +body: +- type: markdown + attributes: + value: | + ## Before submitting your issue + Please make sure that your question or issue is not already covered in existing issues + + **Logs and network traces** + Without logs or traces, it is unlikely that the team can investigate your issue. Capturing logs is described in our [Docs](https://learn.microsoft.com/azure/active-directory/develop/msal-logging-java). + +- type: markdown + attributes: + value: | + ## Issue details + +- type: input + attributes: + label: Library version used + description: "Please enter the version of the library where you ran into the issue (e.g. 1.13.10)." + validations: + required: true + +- type: input + attributes: + label: Java version + description: "Please enter the Java SDK and Framework version your application is developed in." + validations: + required: true + +- type: dropdown + attributes: + label: Scenario + description: "Are you using PublicClientApplication, ConfidentialClientApplication or ManagedIdentityApplication?" + multiple: true + options: + - "PublicClient - desktop app" + - "PublicClient - mobile app" + - "ConfidentialClient - web site (AcquireTokenByAuthCode)" + - "ConfidentialClient - web api (AcquireTokenOnBehalfOf)" + - "ConfidentialClient - service to service (AcquireTokenForClient)" + - "ManagedIdentityClient - managed identity" + - "Other - please specify" + validations: + required: true + +- type: dropdown + attributes: + label: Is this a new or an existing app? + description: "Is this a new or existing app?" + multiple: false + options: + - "The app is in production, and I have upgraded to a new version of MSAL" + - "The app is in production, I haven't upgraded MSAL, but started seeing this issue" + - "This is a new app or experiment" + validations: + required: false + +- type: textarea + attributes: + label: Issue description and reproduction steps + description: "Briefly explain the issue you are seeing along with any error messages or stack trace. Provide a link to one of the [standard samples](https://learn.microsoft.com/azure/active-directory/develop/sample-v2-code?tabs=apptype) and steps to reproduce the behavior. Make sure to provide verbose level log messages from MSAL, if available. [Learn more](https://learn.microsoft.com/azure/active-directory/develop/msal-logging-dotnet)" + validations: + required: true + +- type: textarea + attributes: + label: Relevant code snippets + description: "Provide relevant code snippets that can be used to reproduce the issue." + render: csharp + validations: + required: false + +- type: textarea + attributes: + label: Expected behavior + description: "Describe what you expect the behavior to be." + validations: + required: false + +- type: dropdown + attributes: + label: Identity provider + options: + - Microsoft Entra ID (Work and School accounts and Personal Microsoft accounts) + - Azure B2C Basic Policy + - Azure B2C Custom Policy + - Azure Active Directory Federation Services (ADFS) + - Microsoft Entra External ID + - Other + validations: + required: true + +- type: input + attributes: + label: Regression + description: "If this behavior worked before, enter the last working version(s) of MSAL." + placeholder: "MSAL version: " + +- type: textarea + attributes: + label: Solution and workarounds + description: "Possible solution or workarounds, if you know of any." + validations: + required: false + +- type: markdown + attributes: + value: "## Security Reporting" +- type: markdown + attributes: + value: | + If you find a security issue with our libraries or services [please report it to the Microsoft Security Response Center (MSRC)](https://aka.ms/report-security-issue) with as much detail as possible. Your submission may be eligible for a bounty through the [Microsoft Bounty](http://aka.ms/bugbounty) program. Please do not post security issues to GitHub Issues or any other public site. We will contact you shortly upon receiving the information. We encourage you to get notifications of when security incidents occur by visiting [this page](https://www.microsoft.com/msrc/technical-security-notifications) and subscribing to Security Advisory Alerts. From 681328689e48cbdbbefeb4cf40c9db0a3d9e2ae7 Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Fri, 29 Sep 2023 11:48:56 +0100 Subject: [PATCH 18/24] Delete .github/ISSUE_TEMPLATE/bug_report.md --- .github/ISSUE_TEMPLATE/bug_report.md | 125 --------------------------- 1 file changed, 125 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index d788b3f9..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -name: Bug report -description: Broken or unintended behavior with one of our libraries. -title: '[Bug] ' -labels: ["untriaged", "needs attention"] -body: -- type: markdown - attributes: - value: | - ## Before submitting your issue - Please make sure that your question or issue is not already covered in existing issues - - **Logs and network traces** - Without logs or traces, it is unlikely that the team can investigate your issue. Capturing logs is described in our [Docs](https://learn.microsoft.com/azure/active-directory/develop/msal-logging-java). - -- type: markdown - attributes: - value: | - ## Issue details - -- type: input - attributes: - label: Library version used - description: "Please enter the version of the library where you ran into the issue (e.g. 1.13.10)." - validations: - required: true - -- type: input - attributes: - label: Java version - description: "Please enter the Java SDK and Framework version your application is developed in." - validations: - required: true - -- type: dropdown - attributes: - label: Scenario - description: "Are you using PublicClientApplication, ConfidentialClientApplication or ManagedIdentityApplication?" - multiple: true - options: - - "PublicClient - desktop app" - - "PublicClient - mobile app" - - "ConfidentialClient - web site (AcquireTokenByAuthCode)" - - "ConfidentialClient - web api (AcquireTokenOnBehalfOf)" - - "ConfidentialClient - service to service (AcquireTokenForClient)" - - "ManagedIdentityClient - managed identity" - - "Other - please specify" - validations: - required: true - -- type: dropdown - attributes: - label: Is this a new or an existing app? - description: "Is this a new or existing app?" - multiple: false - options: - - "The app is in production, and I have upgraded to a new version of MSAL" - - "The app is in production, I haven't upgraded MSAL, but started seeing this issue" - - "This is a new app or experiment" - validations: - required: false - -- type: textarea - attributes: - label: Issue description and reproduction steps - description: "Briefly explain the issue you are seeing along with any error messages or stack trace. Provide a link to one of the [standard samples](https://learn.microsoft.com/azure/active-directory/develop/sample-v2-code?tabs=apptype) and steps to reproduce the behavior. Make sure to provide verbose level log messages from MSAL, if available. [Learn more](https://learn.microsoft.com/azure/active-directory/develop/msal-logging-dotnet)" - validations: - required: true - -- type: textarea - attributes: - label: Relevant code snippets - description: "Provide relevant code snippets that can be used to reproduce the issue." - render: csharp - validations: - required: false - -- type: textarea - attributes: - label: Expected behavior - description: "Describe what you expect the behavior to be." - validations: - required: false - -- type: dropdown - attributes: - label: Identity provider - options: - - Microsoft Entra ID (Work and School accounts and Personal Microsoft accounts) - - Azure B2C Basic Policy - - Azure B2C Custom Policy - - Azure Active Directory Federation Services (ADFS) - - Microsoft Entra External ID - - Other - validations: - required: true - -- type: input - attributes: - label: Regression - description: "If this behavior worked before, enter the last working version(s) of MSAL." - placeholder: "MSAL version: " - -- type: textarea - attributes: - label: Solution and workarounds - description: "Possible solution or workarounds, if you know of any." - validations: - required: false - -- type: markdown - attributes: - value: "## Security Reporting" -- type: markdown - attributes: - value: | - If you find a security issue with our libraries or services [please report it to the Microsoft Security Response Center (MSRC)](https://aka.ms/report-security-issue) with as much detail as possible. Your submission may be eligible for a bounty through the [Microsoft Bounty](http://aka.ms/bugbounty) program. Please do not post security issues to GitHub Issues or any other public site. We will contact you shortly upon receiving the information. We encourage you to get notifications of when security incidents occur by visiting [this page](https://www.microsoft.com/msrc/technical-security-notifications) and subscribing to Security Advisory Alerts. From 041bd0117d125415077a119783eb9e2a7354bb84 Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Fri, 29 Sep 2023 11:52:42 +0100 Subject: [PATCH 19/24] Update bug_report.yaml --- .github/ISSUE_TEMPLATE/bug_report.yaml | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index d788b3f9..439b5ef8 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -1,14 +1,5 @@ ---- name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -name: Bug report -description: Broken or unintended behavior with one of our libraries. +description: Broken or unintended behavior with MSAL4J library title: '[Bug] ' labels: ["untriaged", "needs attention"] body: @@ -19,7 +10,7 @@ body: Please make sure that your question or issue is not already covered in existing issues **Logs and network traces** - Without logs or traces, it is unlikely that the team can investigate your issue. Capturing logs is described in our [Docs](https://learn.microsoft.com/azure/active-directory/develop/msal-logging-java). + Without logs or traces, it is unlikely that the team can investigate your issue. Capturing logs is described in our [Docs](https://learn.microsoft.com/azure/active-directory/develop/msal-logging-java). - type: markdown attributes: @@ -29,14 +20,14 @@ body: - type: input attributes: label: Library version used - description: "Please enter the version of the library where you ran into the issue (e.g. 1.13.10)." + description: "Enter the version of the library where you ran into the issue (e.g. 1.13.10)." validations: required: true - type: input attributes: label: Java version - description: "Please enter the Java SDK and Framework version your application is developed in." + description: "Enter the Java SDK and Framework version your application is developed in." validations: required: true @@ -46,8 +37,7 @@ body: description: "Are you using PublicClientApplication, ConfidentialClientApplication or ManagedIdentityApplication?" multiple: true options: - - "PublicClient - desktop app" - - "PublicClient - mobile app" + - "PublicClient (AcquireTokenInteractive, AcquireTokenByUsernamePassword)" - "ConfidentialClient - web site (AcquireTokenByAuthCode)" - "ConfidentialClient - web api (AcquireTokenOnBehalfOf)" - "ConfidentialClient - service to service (AcquireTokenForClient)" From 09c82224a500a55179ce72afa7ac97f59183658e Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Fri, 29 Sep 2023 11:55:01 +0100 Subject: [PATCH 20/24] Create FeatureRequest.yaml --- .github/ISSUE_TEMPLATE/FeatureRequest.yaml | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/FeatureRequest.yaml diff --git a/.github/ISSUE_TEMPLATE/FeatureRequest.yaml b/.github/ISSUE_TEMPLATE/FeatureRequest.yaml new file mode 100644 index 00000000..3ecb4027 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/FeatureRequest.yaml @@ -0,0 +1,48 @@ +name: Feature request +description: Suggest a new feature for MSAL.NET. +labels: ["feature request", "untriaged", "needs attention"] +title : '[Feature Request] ' +body: +- type: markdown + attributes: + value: | + ## Before submitting your feature request + Please make sure that your question or issue is not already covered in [MSAL documentation](https://learn.microsoft.com/entra/msal/dotnet/) or [samples](https://learn.microsoft.com/azure/active-directory/develop/sample-v2-code?tabs=apptype). + +- type: markdown + attributes: + value: | + ## Feature request for MSAL.NET + +- type: dropdown + attributes: + label: MSAL client type + description: Are you using PublicClientApplication (desktop and mobile apps), ConfidentialClientApplication (web apps, web APIs, service-to-service) or ManagedIdentityApplication? + multiple: true + options: + - "Public" + - "Confidential" + - "Managed identity" + validations: + required: true + +- type: textarea + attributes: + label: Problem Statement + description: "Describe the problem or context for this feature request." + validations: + required: true + +- type: textarea + attributes: + label: Proposed solution + description: "Describe the solution you'd like." + validations: + required: false + +- type: textarea + attributes: + label: Alternatives + description: "Describe alternatives you've considered." + validations: + required: false From 2edc49bc392d64ce388649a4688d52f2ca52b946 Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Fri, 29 Sep 2023 11:56:36 +0100 Subject: [PATCH 21/24] Update FeatureRequest.yaml --- .github/ISSUE_TEMPLATE/FeatureRequest.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/FeatureRequest.yaml b/.github/ISSUE_TEMPLATE/FeatureRequest.yaml index 3ecb4027..a112882e 100644 --- a/.github/ISSUE_TEMPLATE/FeatureRequest.yaml +++ b/.github/ISSUE_TEMPLATE/FeatureRequest.yaml @@ -1,5 +1,5 @@ name: Feature request -description: Suggest a new feature for MSAL.NET. +description: Suggest a new feature for MSAL Java labels: ["feature request", "untriaged", "needs attention"] title : '[Feature Request] ' body: @@ -7,17 +7,17 @@ body: attributes: value: | ## Before submitting your feature request - Please make sure that your question or issue is not already covered in [MSAL documentation](https://learn.microsoft.com/entra/msal/dotnet/) or [samples](https://learn.microsoft.com/azure/active-directory/develop/sample-v2-code?tabs=apptype). + Please make sure that your question or issue is not already covered in [MSAL documentation](https://learn.microsoft.com/entra/msal/java/) or [samples](https://learn.microsoft.com/azure/active-directory/develop/sample-v2-code?tabs=apptype). - type: markdown attributes: value: | - ## Feature request for MSAL.NET + ## Feature request for MSAL Java - type: dropdown attributes: label: MSAL client type - description: Are you using PublicClientApplication (desktop and mobile apps), ConfidentialClientApplication (web apps, web APIs, service-to-service) or ManagedIdentityApplication? + description: Are you using PublicClientApplication (desktop / CLI apps), ConfidentialClientApplication (web apps, web APIs, service-to-service) or ManagedIdentityApplication? multiple: true options: - "Public" From 39eb7d8f8a4394165b919187af984daac67cbcf7 Mon Sep 17 00:00:00 2001 From: akulyakhtin Date: Fri, 6 Oct 2023 20:36:35 +0300 Subject: [PATCH 22/24] Set default throttling time to 5 sec (#721) Co-authored-by: Kulyakhtin, Alexander (Ext) --- .../src/main/java/com/microsoft/aad/msal4j/ThrottlingCache.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/ThrottlingCache.java b/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/ThrottlingCache.java index 89e1f348..9c8a0584 100644 --- a/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/ThrottlingCache.java +++ b/msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/ThrottlingCache.java @@ -12,7 +12,7 @@ class ThrottlingCache { static final int MAX_THROTTLING_TIME_SEC = 3600; - static int DEFAULT_THROTTLING_TIME_SEC = 120; + static int DEFAULT_THROTTLING_TIME_SEC = 5; static final int CACHE_SIZE_LIMIT_TO_TRIGGER_EXPIRED_ENTITIES_REMOVAL = 100; // request hash to expiration timestamp From 6fc2c6c197acb1d5336971edb09fcd09f21f91ff Mon Sep 17 00:00:00 2001 From: Avery-Dunn Date: Sun, 8 Oct 2023 16:37:51 -0700 Subject: [PATCH 23/24] Ensure correlation ID is never null --- .../aad/msal4jbrokers/MsalRuntimeBroker.java | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/msal4j-brokers/src/main/java/com/microsoft/aad/msal4jbrokers/MsalRuntimeBroker.java b/msal4j-brokers/src/main/java/com/microsoft/aad/msal4jbrokers/MsalRuntimeBroker.java index 786f7245..916a4a14 100644 --- a/msal4j-brokers/src/main/java/com/microsoft/aad/msal4jbrokers/MsalRuntimeBroker.java +++ b/msal4j-brokers/src/main/java/com/microsoft/aad/msal4jbrokers/MsalRuntimeBroker.java @@ -13,6 +13,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -34,12 +35,13 @@ public class MsalRuntimeBroker implements IBroker { @Override public CompletableFuture acquireToken(PublicClientApplication application, SilentParameters parameters) { + String correlationID = application.correlationId() == null ? generateCorrelationID() : application.correlationId(); Account accountResult = null; //If request has an account ID, MSALRuntime likely has data cached for that account that we can retrieve if (parameters.account() != null) { try { - accountResult = ((ReadAccountResult) interop.readAccountById(parameters.account().homeAccountId().split("\\.")[0], application.correlationId()).get()).getAccount(); + accountResult = ((ReadAccountResult) interop.readAccountById(parameters.account().homeAccountId().split("\\.")[0], correlationID).get()).getAccount(); } catch (InterruptedException | ExecutionException ex) { throw new MsalClientException(String.format("MSALRuntime async operation interrupted when waiting for result: %s", ex.getMessage()), AuthenticationErrorCode.MSALRUNTIME_INTEROP_ERROR); } @@ -62,8 +64,8 @@ public CompletableFuture acquireToken(PublicClientApplica AuthParameters authParameters = authParamsBuilder.build(); if (accountResult == null) { - return interop.signInSilently(authParameters, application.correlationId()) - .thenCompose(acctResult -> interop.acquireTokenSilently(authParameters, application.correlationId(), ((AuthResult) acctResult).getAccount())) + return interop.signInSilently(authParameters, correlationID) + .thenCompose(acctResult -> interop.acquireTokenSilently(authParameters, correlationID, ((AuthResult) acctResult).getAccount())) .thenApply(authResult -> parseBrokerAuthResult( application.authority(), ((AuthResult) authResult).getIdToken(), @@ -73,7 +75,7 @@ public CompletableFuture acquireToken(PublicClientApplica ((AuthResult) authResult).getAccessTokenExpirationTime(), ((AuthResult) authResult).isPopAuthorization())); } else { - return interop.acquireTokenSilently(authParameters, application.correlationId(), accountResult) + return interop.acquireTokenSilently(authParameters, correlationID, accountResult) .thenApply(authResult -> parseBrokerAuthResult(application.authority(), ((AuthResult) authResult).getIdToken(), ((AuthResult) authResult).getAccessToken(), @@ -89,6 +91,8 @@ public CompletableFuture acquireToken(PublicClientApplica @Override public CompletableFuture acquireToken(PublicClientApplication application, InteractiveRequestParameters parameters) { + String correlationID = application.correlationId() == null ? generateCorrelationID() : application.correlationId(); + try { AuthParameters.AuthParametersBuilder authParamsBuilder = new AuthParameters. AuthParametersBuilder(application.clientId(), @@ -106,8 +110,8 @@ public CompletableFuture acquireToken(PublicClientApplica AuthParameters authParameters = authParamsBuilder.build(); - return interop.signInInteractively(parameters.windowHandle(), authParameters, application.correlationId(), parameters.loginHint()) - .thenCompose(acctResult -> interop.acquireTokenInteractively(parameters.windowHandle(), authParameters, application.correlationId(), ((AuthResult) acctResult).getAccount())) + return interop.signInInteractively(parameters.windowHandle(), authParameters, correlationID, parameters.loginHint()) + .thenCompose(acctResult -> interop.acquireTokenInteractively(parameters.windowHandle(), authParameters, correlationID, ((AuthResult) acctResult).getAccount())) .thenApply(authResult -> parseBrokerAuthResult( application.authority(), ((AuthResult) authResult).getIdToken(), @@ -127,6 +131,8 @@ public CompletableFuture acquireToken(PublicClientApplica @Deprecated @Override public CompletableFuture acquireToken(PublicClientApplication application, UserNamePasswordParameters parameters) { + String correlationID = application.correlationId() == null ? generateCorrelationID() : application.correlationId(); + try { AuthParameters.AuthParametersBuilder authParamsBuilder = new AuthParameters. AuthParametersBuilder(application.clientId(), @@ -143,8 +149,8 @@ public CompletableFuture acquireToken(PublicClientApplica AuthParameters authParameters = authParamsBuilder.build(); - return interop.signInSilently(authParameters, application.correlationId()) - .thenCompose(acctResult -> interop.acquireTokenSilently(authParameters, application.correlationId(), ((AuthResult) acctResult).getAccount())) + return interop.signInSilently(authParameters, correlationID) + .thenCompose(acctResult -> interop.acquireTokenSilently(authParameters, correlationID, ((AuthResult) acctResult).getAccount())) .thenApply(authResult -> parseBrokerAuthResult( application.authority(), ((AuthResult) authResult).getIdToken(), @@ -160,11 +166,13 @@ public CompletableFuture acquireToken(PublicClientApplica @Override public void removeAccount(PublicClientApplication application, IAccount msalJavaAccount) { + String correlationID = application.correlationId() == null ? generateCorrelationID() : application.correlationId(); + try { - Account msalRuntimeAccount = ((ReadAccountResult) interop.readAccountById(msalJavaAccount.homeAccountId().split("\\.")[0], application.correlationId()).get()).getAccount(); + Account msalRuntimeAccount = ((ReadAccountResult) interop.readAccountById(msalJavaAccount.homeAccountId().split("\\.")[0], correlationID).get()).getAccount(); if (msalRuntimeAccount != null) { - interop.signOutSilently(application.clientId(), application.correlationId(), msalRuntimeAccount); + interop.signOutSilently(application.clientId(), correlationID, msalRuntimeAccount); } } catch (MsalInteropException interopException) { throw new MsalClientException(interopException.getErrorMessage(), AuthenticationErrorCode.MSALRUNTIME_INTEROP_ERROR); @@ -233,4 +241,9 @@ public void enableBrokerPIILogging(boolean enablePII) { throw new MsalClientException(String.format("Error occurred when calling MSALRuntime PII logging API: %s", ex.getMessage()), AuthenticationErrorCode.MSALRUNTIME_INTEROP_ERROR); } } + + //Generates a random correlation ID, used when a correlation ID was not set at the application level + private String generateCorrelationID() { + return UUID.randomUUID().toString(); + } } From b315b3e970a6b2dce3d0c34fe0070c8389f67b5f Mon Sep 17 00:00:00 2001 From: Avery-Dunn Date: Fri, 20 Oct 2023 15:28:03 -0700 Subject: [PATCH 24/24] Rename MsalRuntimeBroker and add builder pattern for better API consistency --- .../{MsalRuntimeBroker.java => Broker.java} | 28 +++++++++++++++++-- .../test/java/test/ProofOfPossessionTest.java | 12 ++++---- 2 files changed, 30 insertions(+), 10 deletions(-) rename msal4j-brokers/src/main/java/com/microsoft/aad/msal4jbrokers/{MsalRuntimeBroker.java => Broker.java} (95%) diff --git a/msal4j-brokers/src/main/java/com/microsoft/aad/msal4jbrokers/MsalRuntimeBroker.java b/msal4j-brokers/src/main/java/com/microsoft/aad/msal4jbrokers/Broker.java similarity index 95% rename from msal4j-brokers/src/main/java/com/microsoft/aad/msal4jbrokers/MsalRuntimeBroker.java rename to msal4j-brokers/src/main/java/com/microsoft/aad/msal4jbrokers/Broker.java index 916a4a14..30cdd7d9 100644 --- a/msal4j-brokers/src/main/java/com/microsoft/aad/msal4jbrokers/MsalRuntimeBroker.java +++ b/msal4j-brokers/src/main/java/com/microsoft/aad/msal4jbrokers/Broker.java @@ -17,12 +17,14 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -public class MsalRuntimeBroker implements IBroker { - private static final Logger LOG = LoggerFactory.getLogger(MsalRuntimeBroker.class); +public class Broker implements IBroker { + private static final Logger LOG = LoggerFactory.getLogger(Broker.class); private static MsalRuntimeInterop interop; private static Boolean brokerAvailable; + private boolean supportWindows; + static { try { //MsalRuntimeInterop performs various initialization steps in a similar static block, @@ -107,7 +109,7 @@ public CompletableFuture acquireToken(PublicClientApplica parameters.proofOfPossession().getUri(), parameters.proofOfPossession().getNonce()); } - + AuthParameters authParameters = authParamsBuilder.build(); return interop.signInInteractively(parameters.windowHandle(), authParameters, correlationID, parameters.loginHint()) @@ -246,4 +248,24 @@ public void enableBrokerPIILogging(boolean enablePII) { private String generateCorrelationID() { return UUID.randomUUID().toString(); } + + public static class Builder { + private boolean supportWindows = false; + + public Builder() { + } + + public Builder supportWindows(boolean val) { + supportWindows = val; + return this; + } + + public Broker build() { + return new Broker(this); + } + } + + private Broker(Builder builder) { + supportWindows = builder.supportWindows; + } } diff --git a/msal4j-brokers/src/test/java/test/ProofOfPossessionTest.java b/msal4j-brokers/src/test/java/test/ProofOfPossessionTest.java index 07fd5224..2f613958 100644 --- a/msal4j-brokers/src/test/java/test/ProofOfPossessionTest.java +++ b/msal4j-brokers/src/test/java/test/ProofOfPossessionTest.java @@ -1,14 +1,12 @@ package test; import com.microsoft.aad.msal4j.*; -import com.microsoft.aad.msal4jbrokers.MsalRuntimeBroker; +import com.microsoft.aad.msal4jbrokers.Broker; import infrastructure.SeleniumExtensions; import labapi.LabUserProvider; import labapi.User; import org.openqa.selenium.WebDriver; import org.testng.Assert; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; import java.net.MalformedURLException; import java.net.URI; @@ -35,7 +33,7 @@ public void setUp() { public void acquirePopToken_WithBroker() throws Exception { User user = labUserProvider.getDefaultUser(); - MsalRuntimeBroker broker = new MsalRuntimeBroker(); + Broker broker = new Broker.Builder().supportWindows(true).build(); PublicClientApplication pca = createPublicClientApp(user, broker); @@ -75,7 +73,7 @@ public void acquirePopToken_BrowserAndBroker() throws Exception { seleniumDriver.quit(); //Then, get a PoP token silently, using the cache that contains the non-PoP token - MsalRuntimeBroker broker = new MsalRuntimeBroker(); + Broker broker = new Broker.Builder().supportWindows(true).build(); PublicClientApplication pcaWithBroker = createPublicClientApp(user, broker, pcaWithoutBroker.tokenCache().serialize()); @@ -93,7 +91,7 @@ private PublicClientApplication createPublicClientApp(User user) throws Malforme .build(); } - private PublicClientApplication createPublicClientApp(User user, MsalRuntimeBroker broker) throws MalformedURLException { + private PublicClientApplication createPublicClientApp(User user, Broker broker) throws MalformedURLException { return PublicClientApplication.builder(user.getAppId()) .authority(MICROSOFT_AUTHORITY_ORGANIZATIONS) .correlationId(UUID.randomUUID().toString()) @@ -101,7 +99,7 @@ private PublicClientApplication createPublicClientApp(User user, MsalRuntimeBrok .build(); } - private PublicClientApplication createPublicClientApp(User user, MsalRuntimeBroker broker, String cache) throws MalformedURLException { + private PublicClientApplication createPublicClientApp(User user, Broker broker, String cache) throws MalformedURLException { return PublicClientApplication.builder(user.getAppId()) .authority(MICROSOFT_AUTHORITY_ORGANIZATIONS) .correlationId(UUID.randomUUID().toString())