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 @@
+