From 8e378b5ff52bf30053a9cfa597831019b1dbce37 Mon Sep 17 00:00:00 2001 From: Pasindu Yeshan Date: Mon, 9 Dec 2024 23:26:16 +0530 Subject: [PATCH] Add unit tests for PasswordExpiryEventListener --- .../pom.xml | 5 + .../expiry/PasswordPolicyUtilsTest.java | 79 +++---- .../PasswordExpiryEventListenerTest.java | 199 ++++++++++++++++++ .../src/test/resources/testng.xml | 1 + 4 files changed, 246 insertions(+), 38 deletions(-) create mode 100644 components/org.wso2.carbon.identity.password.expiry/src/test/java/org/wso2/carbon/identity/password/expiry/listener/PasswordExpiryEventListenerTest.java diff --git a/components/org.wso2.carbon.identity.password.expiry/pom.xml b/components/org.wso2.carbon.identity.password.expiry/pom.xml index 559afadc2b..4d87e016b1 100644 --- a/components/org.wso2.carbon.identity.password.expiry/pom.xml +++ b/components/org.wso2.carbon.identity.password.expiry/pom.xml @@ -89,6 +89,11 @@ mockito-inline test + + org.wso2.carbon.identity.framework + org.wso2.carbon.identity.testutil + test + org.wso2.carbon.identity.organization.management.core org.wso2.carbon.identity.organization.management.service diff --git a/components/org.wso2.carbon.identity.password.expiry/src/test/java/org/wso2/carbon/identity/password/expiry/PasswordPolicyUtilsTest.java b/components/org.wso2.carbon.identity.password.expiry/src/test/java/org/wso2/carbon/identity/password/expiry/PasswordPolicyUtilsTest.java index 47b67ee71e..c3081debe7 100644 --- a/components/org.wso2.carbon.identity.password.expiry/src/test/java/org/wso2/carbon/identity/password/expiry/PasswordPolicyUtilsTest.java +++ b/components/org.wso2.carbon.identity.password.expiry/src/test/java/org/wso2/carbon/identity/password/expiry/PasswordPolicyUtilsTest.java @@ -288,17 +288,17 @@ public void testIsPasswordExpiredWithoutRules(Integer daysAgo, boolean expectedE public Object[][] passwordExpiryTestCases() { return new Object[][] { // {daysAgo, roles, groups, skipIfNoApplicableRules, expectedExpired, description}. - {55, new String[]{ROLE_MAP.get("employee"), ROLE_MAP.get("manager")}, new String[]{}, false, false, + {55, new String[]{"employee", "manager"}, new String[]{}, false, false, "Not expired: 3rd rule (60) applies"}, - {55, new String[]{ROLE_MAP.get("employee"), ROLE_MAP.get("manager"), ROLE_MAP.get("contractor")}, + {55, new String[]{"employee", "manager", "contractor"}, new String[]{}, false, true, "Expired: 2nd rule (40) applies"}, - {35, new String[]{ROLE_MAP.get("employee"), ROLE_MAP.get("contractor")}, new String[]{}, false, false, + {35, new String[]{"employee", "contractor"}, new String[]{}, false, false, "Not expired: 2nd rule (40) applies"}, - {35, new String[]{ROLE_MAP.get("employee"), ROLE_MAP.get("contractor")}, new String[]{"admin"}, false, + {35, new String[]{"employee", "contractor"}, new String[]{"admin"}, false, false, "Not expired: 1st rule (skip) applies."}, - {35, new String[]{ROLE_MAP.get("employee")}, new String[]{}, false, true, + {35, new String[]{"employee"}, new String[]{}, false, true, "Expired: Default expiry policy applies."}, - {35, new String[]{ROLE_MAP.get("employee")}, new String[]{}, true, false, + {35, new String[]{"employee"}, new String[]{}, true, false, "Not expired: Default expiry policy applies - skip if no rules applicable."}, }; } @@ -319,13 +319,7 @@ public void testIsPasswordExpiredWithRules(int daysAgo, String[] roles, String[] mockPasswordExpiryEnabled(identityGovernanceService, PasswordPolicyConstants.TRUE); - List userGroups = new ArrayList<>(); - Arrays.stream(groups).forEach(groupName -> { - Group groupObj = new Group(); - groupObj.setGroupID(GROUP_MAP.get(groupName)); - userGroups.add(groupObj); - }); - when(abstractUserStoreManager.getGroupListOfUser(userId, null, null)).thenReturn(userGroups); + when(abstractUserStoreManager.getGroupListOfUser(userId, null, null)).thenReturn(getGroups(groups)); // Mock last password update time. Long updateTime = getUpdateTime(daysAgo); @@ -363,7 +357,8 @@ public Object[][] passwordExpiryTimeTestCases() { @Test(dataProvider = "passwordExpiryTimeTestCases") public void testGetUserPasswordExpiryTime(Integer daysAgo, String[] roles, String[] groups, Integer expiryDays, String description) - throws IdentityGovernanceException, UserStoreException, PostAuthenticationFailedException { + throws IdentityGovernanceException, UserStoreException, PostAuthenticationFailedException, + IdentityRoleManagementException { when(IdentityTenantUtil.getTenantId(anyString())).thenReturn(3); when(realmService.getTenantUserRealm(anyInt())).thenReturn(userRealm); @@ -391,8 +386,12 @@ public void testGetUserPasswordExpiryTime(Integer daysAgo, String[] roles, Strin new String[]{PasswordPolicyConstants.CONNECTOR_CONFIG_SKIP_IF_NO_APPLICABLE_RULES}, tenantDomain)).thenReturn(getSkipIfNoRulesApplicableProperty(PasswordPolicyConstants.FALSE)); - List roleIds = Arrays.stream(roles).map(ROLE_MAP::get).collect(Collectors.toList()); - List groupIds = Arrays.stream(groups).map(GROUP_MAP::get).collect(Collectors.toList()); + // Mock user roles. + when(roleManagementService.getRoleListOfUser(userId, tenantDomain)).thenReturn(getRoles(roles)); + + // Mock user groups. + when(abstractUserStoreManager.getGroupListOfUser(userId, null, null)) + .thenReturn(getGroups(groups)); long testStartTime = System.currentTimeMillis(); Optional expiryTime = @@ -417,9 +416,9 @@ public void testGetUserPasswordExpiryTime() throws IdentityGovernanceException, UserStoreException, PostAuthenticationFailedException { // Case 1: Password expiry disabled. - mockPasswordExpiryEnabled(identityGovernanceService, PasswordPolicyConstants.FALSE); - Optional expiryTime = - PasswordPolicyUtils.getUserPasswordExpiryTime(tenantDomain, tenantAwareUsername); + Optional expiryTime = PasswordPolicyUtils.getUserPasswordExpiryTime( + tenantDomain, tenantAwareUsername, false, null, + null, null); Assert.assertFalse(expiryTime.isPresent()); // Case 2: Password expiry enabled, but no rules. @@ -435,20 +434,9 @@ public void testGetUserPasswordExpiryTime() Long updateTime = System.currentTimeMillis() - getDaysTimeInMillis(20); mockLastPasswordUpdateTime(updateTime, abstractUserStoreManager); - // Mock empty password expiry rules. - ConnectorConfig connectorConfig = new ConnectorConfig(); - connectorConfig.setProperties( new Property[0]); - when(identityGovernanceService.getConnectorWithConfigs(tenantDomain, - PasswordPolicyConstants.CONNECTOR_CONFIG_NAME)).thenReturn(connectorConfig); - - when(identityGovernanceService.getConfiguration( - new String[]{PasswordPolicyConstants.CONNECTOR_CONFIG_PASSWORD_EXPIRY_IN_DAYS}, - tenantDomain)).thenReturn(getPasswordExpiryInDaysProperty()); - when(identityGovernanceService.getConfiguration( - new String[]{PasswordPolicyConstants.CONNECTOR_CONFIG_SKIP_IF_NO_APPLICABLE_RULES}, - tenantDomain)).thenReturn(getSkipIfNoRulesApplicableProperty(PasswordPolicyConstants.FALSE)); - - expiryTime = PasswordPolicyUtils.getUserPasswordExpiryTime(tenantDomain, tenantAwareUsername); + expiryTime = PasswordPolicyUtils.getUserPasswordExpiryTime( + tenantDomain, tenantAwareUsername, true, false, + Collections.emptyList(), DEFAULT_EXPIRY_DAYS); long expectedExpiryTime = updateTime + getDaysTimeInMillis(DEFAULT_EXPIRY_DAYS); Assert.assertTrue(Math.abs(expiryTime.get() - expectedExpiryTime) <= TIME_TOLERANCE_MS); @@ -458,14 +446,18 @@ public void testGetUserPasswordExpiryTime() new String[]{PasswordPolicyConstants.CONNECTOR_CONFIG_SKIP_IF_NO_APPLICABLE_RULES}, tenantDomain)).thenReturn(getSkipIfNoRulesApplicableProperty(PasswordPolicyConstants.TRUE)); - expiryTime = PasswordPolicyUtils.getUserPasswordExpiryTime(tenantDomain, tenantAwareUsername); + expiryTime = PasswordPolicyUtils.getUserPasswordExpiryTime(tenantDomain, tenantAwareUsername, + true, true, Collections.emptyList(), + DEFAULT_EXPIRY_DAYS); Assert.assertFalse(expiryTime.isPresent()); // Case 4: UserStoreException. when(abstractUserStoreManager.getUserIDFromUserName(tenantAwareUsername)).thenThrow( new org.wso2.carbon.user.core.UserStoreException()); try { - PasswordPolicyUtils.getUserPasswordExpiryTime(tenantDomain, tenantAwareUsername); + PasswordPolicyUtils.getUserPasswordExpiryTime(tenantDomain, tenantAwareUsername, + true, true, Collections.emptyList(), + DEFAULT_EXPIRY_DAYS); Assert.fail("Expected PostAuthenticationFailedException was not thrown"); } catch (Exception e) { Assert.assertTrue(e instanceof PostAuthenticationFailedException); @@ -538,17 +530,28 @@ private static Long getUpdateTime(Integer daysAgo) { return daysAgo != null ? System.currentTimeMillis() - getDaysTimeInMillis(daysAgo) : null; } - private List getRoles(String[] roleIds) { + private List getRoles(String[] roleNames) { List userRoles = new ArrayList<>(); - for (String roleId : roleIds) { + for (String roleId : roleNames) { RoleBasicInfo roleInfo = new RoleBasicInfo(); - roleInfo.setId(roleId); + roleInfo.setId(ROLE_MAP.get(roleId)); userRoles.add(roleInfo); } return userRoles; } + private static List getGroups(String[] groupNames) { + + List userGroups = new ArrayList<>(); + Arrays.stream(groupNames).forEach(groupName -> { + Group groupObj = new Group(); + groupObj.setGroupID(GROUP_MAP.get(groupName)); + userGroups.add(groupObj); + }); + return userGroups; + } + private Property[] getPasswordExpiryRulesProperties() { Property expiryRule1 = new Property(); diff --git a/components/org.wso2.carbon.identity.password.expiry/src/test/java/org/wso2/carbon/identity/password/expiry/listener/PasswordExpiryEventListenerTest.java b/components/org.wso2.carbon.identity.password.expiry/src/test/java/org/wso2/carbon/identity/password/expiry/listener/PasswordExpiryEventListenerTest.java new file mode 100644 index 0000000000..d6dcfc22cc --- /dev/null +++ b/components/org.wso2.carbon.identity.password.expiry/src/test/java/org/wso2/carbon/identity/password/expiry/listener/PasswordExpiryEventListenerTest.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.password.expiry.listener; + +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.identity.application.authentication.framework.exception.PostAuthenticationFailedException; +import org.wso2.carbon.identity.password.expiry.constants.PasswordPolicyConstants; +import org.wso2.carbon.identity.password.expiry.util.PasswordPolicyUtils; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.common.testng.WithCarbonHome; +import org.wso2.carbon.user.core.UserStoreException; +import org.wso2.carbon.user.core.UserStoreManager; +import org.wso2.carbon.user.core.model.UserClaimSearchEntry; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; + +/** + * Unit test cases for PasswordExpiryEventListener. + */ +@WithCarbonHome +public class PasswordExpiryEventListenerTest { + + private static final String TENANT_DOMAIN = "test.com"; + private PasswordExpiryEventListener passwordExpiryEventListener; + + @Mock + PrivilegedCarbonContext privilegedCarbonContext; + @Mock + UserStoreManager userStoreManager; + + private MockedStatic mockedPrivilegedCarbonContext; + private MockedStatic mockedPasswordPolicyUtils; + + @BeforeMethod + public void setUp() { + + MockitoAnnotations.openMocks(this); + passwordExpiryEventListener = new PasswordExpiryEventListener(); + + mockedPrivilegedCarbonContext.when(PrivilegedCarbonContext::getThreadLocalCarbonContext) + .thenReturn(privilegedCarbonContext); + + when(privilegedCarbonContext.getTenantDomain()).thenReturn(TENANT_DOMAIN); + } + + @BeforeClass + public void init() { + + mockedPrivilegedCarbonContext = mockStatic(PrivilegedCarbonContext.class); + mockedPasswordPolicyUtils = mockStatic(PasswordPolicyUtils.class); + } + + @AfterClass + public void close() { + + mockedPrivilegedCarbonContext.close(); + mockedPasswordPolicyUtils.close(); + } + + @Test + public void testGetExecutionOrderId() { + + Assert.assertEquals(passwordExpiryEventListener.getExecutionOrderId(), 99); // TODO: Change the order id accordingly. + } + + @Test + public void testDoPostGetUserClaimValuesWithPasswordExpiryClaim() throws UserStoreException { + + String username = "testUser"; + String[] claims; + Map claimMap = new HashMap<>(); + String profileName = "default"; + + // Case 1: When claims contains PASSWORD_EXPIRY_TIME_CLAIM. + claims = new String[]{PasswordPolicyConstants.PASSWORD_EXPIRY_TIME_CLAIM}; + + mockedPasswordPolicyUtils.when(() -> PasswordPolicyUtils.getUserPasswordExpiryTime( + eq(TENANT_DOMAIN), eq(username))).thenReturn(Optional.of(1000L)); + + passwordExpiryEventListener.doPostGetUserClaimValues(username, claims, profileName, claimMap, userStoreManager); + Assert.assertNotNull(claimMap.get(PasswordPolicyConstants.PASSWORD_EXPIRY_TIME_CLAIM)); + + // Case 2: PostAuthenticationFailedException is thrown. + mockedPasswordPolicyUtils.when(() -> + PasswordPolicyUtils.getUserPasswordExpiryTime(eq(TENANT_DOMAIN), eq(username))) + .thenThrow(new PostAuthenticationFailedException("test-error", "test-error")); + try { + passwordExpiryEventListener.doPostGetUserClaimValues(username, claims, profileName, claimMap, userStoreManager); + } catch (Exception e) { + Assert.assertTrue(e instanceof UserStoreException); + } + } + + @Test + public void testDoPostGetUserClaimValuesWithoutPasswordExpiryClaim() throws UserStoreException { + + String username = "testUser"; + String[] claims; + Map claimMap = new HashMap<>(); + String profileName = "default"; + claims = new String[]{"claim1", "claim2"}; + + passwordExpiryEventListener.doPostGetUserClaimValues(username, claims, profileName, claimMap, userStoreManager); + Assert.assertFalse(claimMap.containsKey(PasswordPolicyConstants.PASSWORD_EXPIRY_TIME_CLAIM)); + } + + @Test + public void testDoPostGetUsersClaimValuesWithPasswordExpiryClaim() throws UserStoreException { + + String[] userNames = new String[]{"testUser1", "testUser2"}; + String[] claims = new String[]{PasswordPolicyConstants.PASSWORD_EXPIRY_TIME_CLAIM}; + String profileName = "default"; + + UserClaimSearchEntry[] userClaimSearchEntries = new UserClaimSearchEntry[2]; + userClaimSearchEntries[0] = new UserClaimSearchEntry(); + userClaimSearchEntries[0].setUserName("testUser1"); + userClaimSearchEntries[1] = new UserClaimSearchEntry(); + userClaimSearchEntries[1].setUserName("testUser1"); + + mockedPasswordPolicyUtils.when(() -> + PasswordPolicyUtils.isPasswordExpiryEnabled(TENANT_DOMAIN)).thenReturn(true); + mockedPasswordPolicyUtils.when(() -> + PasswordPolicyUtils.isSkipIfNoApplicableRulesEnabled(TENANT_DOMAIN)).thenReturn(false); + mockedPasswordPolicyUtils.when(() -> + PasswordPolicyUtils.getPasswordExpiryInDays(TENANT_DOMAIN)).thenReturn(30); + mockedPasswordPolicyUtils.when(() -> + PasswordPolicyUtils.getPasswordExpiryRules(TENANT_DOMAIN)).thenReturn(Collections.emptyList()); + mockedPasswordPolicyUtils.when(() -> PasswordPolicyUtils.getUserPasswordExpiryTime( + eq(TENANT_DOMAIN), anyString(), eq(true), eq(false), any(), eq(30))) + .thenReturn(Optional.of(1000L)); + + passwordExpiryEventListener.doPostGetUsersClaimValues(userNames, claims, profileName, userClaimSearchEntries); + Assert.assertNotNull( + userClaimSearchEntries[0].getClaims().get(PasswordPolicyConstants.PASSWORD_EXPIRY_TIME_CLAIM)); + Assert.assertNotNull( + userClaimSearchEntries[1].getClaims().get(PasswordPolicyConstants.PASSWORD_EXPIRY_TIME_CLAIM)); + + // Case 2: PostAuthenticationFailedException is thrown. + mockedPasswordPolicyUtils.when(() -> PasswordPolicyUtils.getUserPasswordExpiryTime( + eq(TENANT_DOMAIN), anyString(), eq(true), eq(false), any(), eq(30))) + .thenThrow(new PostAuthenticationFailedException("test-error", "test-error")); + try { + passwordExpiryEventListener.doPostGetUsersClaimValues(userNames, claims, + profileName, userClaimSearchEntries); + } catch (Exception e) { + Assert.assertTrue(e instanceof UserStoreException); + } + } + + @Test + public void testDoPostGetUsersClaimValuesWithoutPasswordExpiryClaims() throws UserStoreException { + + String[] userNames = new String[]{"testUser1", "testUser2"}; + String[] claims = new String[]{"claim1", "claim2"}; + String profileName = "default"; + + UserClaimSearchEntry[] userClaimSearchEntries = new UserClaimSearchEntry[2]; + userClaimSearchEntries[0] = new UserClaimSearchEntry(); + userClaimSearchEntries[0].setUserName("testUser1"); + userClaimSearchEntries[1] = new UserClaimSearchEntry(); + userClaimSearchEntries[1].setUserName("testUser1"); + + passwordExpiryEventListener.doPostGetUsersClaimValues(userNames, claims, profileName, userClaimSearchEntries); + Assert.assertNull(userClaimSearchEntries[0].getClaims()); + Assert.assertNull(userClaimSearchEntries[1].getClaims()); + } +} diff --git a/components/org.wso2.carbon.identity.password.expiry/src/test/resources/testng.xml b/components/org.wso2.carbon.identity.password.expiry/src/test/resources/testng.xml index 2aac16e379..ed19db6cef 100644 --- a/components/org.wso2.carbon.identity.password.expiry/src/test/resources/testng.xml +++ b/components/org.wso2.carbon.identity.password.expiry/src/test/resources/testng.xml @@ -14,6 +14,7 @@ +