Skip to content

Commit

Permalink
Merge pull request #6074 from lashinijay/password-generation
Browse files Browse the repository at this point in the history
Update random password generation for provisioned users and clearing password after it's usage
  • Loading branch information
lashinijay authored Nov 8, 2024
2 parents 4a30de8 + d4717d4 commit fa9ca08
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ private void handleUserProvisioning(String username, UserStoreManager userStoreM
.get(FrameworkConstants.ATTRIBUTE_SYNC_METHOD).toString();
String idp = attributes.remove(FrameworkConstants.IDP_ID);
String subjectVal = attributes.remove(FrameworkConstants.ASSOCIATED_ID);
char[] password;

Map<String, String> userClaims = prepareClaimMappings(attributes);

Expand Down Expand Up @@ -297,12 +298,7 @@ tobeDeleted claims (claims came from federated idp as null). If there is a match
}
}
} else {
String password = generatePassword();
String passwordFromUser = userClaims.get(FrameworkConstants.PASSWORD);
if (StringUtils.isNotEmpty(passwordFromUser)) {
password = passwordFromUser;
}

password = resolvePassword(userClaims);
// Check for inconsistencies in username attribute and the username claim.
if (userClaims.containsKey(USERNAME_CLAIM) && !userClaims.get(USERNAME_CLAIM).equals(username)) {
// If so update the username claim with the username attribute.
Expand All @@ -324,7 +320,7 @@ tobeDeleted claims (claims came from federated idp as null). If there is a match
if (FrameworkUtils.isJITProvisionEnhancedFeatureEnabled()) {
setJitProvisionedSource(tenantDomain, idp, userClaims);
}
userStoreManager.addUser(username, password, null, userClaims, null);
userStoreManager.addUser(username, String.valueOf(password), null, userClaims, null);
} catch (UserStoreException e) {
// Add user operation will fail if a user operation workflow is already defined for the same user.
if (USER_WORKFLOW_ENGAGED_ERROR_CODE.equals(e.getErrorCode())) {
Expand All @@ -339,6 +335,7 @@ tobeDeleted claims (claims came from federated idp as null). If there is a match
} finally {
UserCoreUtil.removeSkipPasswordPatternValidationThreadLocal();
UserCoreUtil.removeSkipUsernamePatternValidationThreadLocal();
Arrays.fill(password, '\0');
}

if (userWorkflowEngaged ||
Expand All @@ -360,6 +357,18 @@ tobeDeleted claims (claims came from federated idp as null). If there is a match
}
}

protected char[] resolvePassword(Map<String, String> userClaims) {

char[] passwordFromUser = null;
if (userClaims.get(FrameworkConstants.PASSWORD) != null) {
passwordFromUser = userClaims.get(FrameworkConstants.PASSWORD).toCharArray();
}
if (passwordFromUser == null || passwordFromUser.length == 0) {
return generatePassword();
}
return passwordFromUser;
}

private void handleV1Roles(String username, UserStoreManager userStoreManager, UserRealm realm,
List<String> roles, List<String> idpToLocalRoleMapping)
throws UserStoreException, FrameworkException {
Expand Down Expand Up @@ -718,7 +727,7 @@ private String getUserStoreDomain(String userStoreDomain, UserRealm realm)
*
* @return
*/
protected String generatePassword() {
protected char[] generatePassword() {

// Pick from some letters that won't be easily mistaken for each other.
// So, for example, omit o O and 0, 1 l and L.
Expand All @@ -737,30 +746,14 @@ protected String generatePassword() {
for (int i = 0; i < passwordLength - mandatoryCharactersCount; i++) {
pw.append(characters.charAt(secureRandom.nextInt(characters.length())));
}
pw.append(digits.charAt(secureRandom.nextInt(digits.length())));
pw.append(lowercaseLetters.charAt(secureRandom.nextInt(lowercaseLetters.length())));
pw.append(uppercaseLetters.charAt(secureRandom.nextInt(uppercaseLetters.length())));
pw.append(specialCharacters.charAt(secureRandom.nextInt(specialCharacters.length())));
return pw.toString();
}

/**
* remove user store domain from names except the domain 'Internal'
*
* @param names
* @return
*/
private List<String> removeDomainFromNamesExcludeInternal(List<String> names, int tenantId) {
List<String> nameList = new ArrayList<String>();
for (String name : names) {
String userStoreDomain = IdentityUtil.extractDomainFromName(name);
if (UserCoreConstants.INTERNAL_DOMAIN.equalsIgnoreCase(userStoreDomain)) {
nameList.add(name);
} else {
nameList.add(UserCoreUtil.removeDomainFromName(name));
}
}
return nameList;
pw.insert(secureRandom.nextInt(pw.length()), digits.charAt(secureRandom.nextInt(digits.length())));
pw.insert(secureRandom.nextInt(pw.length()), lowercaseLetters.charAt(secureRandom.nextInt(
lowercaseLetters.length())));
pw.insert(secureRandom.nextInt(pw.length()), uppercaseLetters.charAt(secureRandom.nextInt(
uppercaseLetters.length())));
pw.insert(secureRandom.nextInt(pw.length()), specialCharacters.charAt(secureRandom.nextInt(
specialCharacters.length())));
return pw.toString().toCharArray();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,13 @@
import org.testng.annotations.Test;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.identity.application.authentication.framework.exception.FrameworkException;
import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants;
import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils;
import org.wso2.carbon.identity.application.authentication.framwork.test.utils.CommonTestUtils;

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

import static org.mockito.Mockito.mockStatic;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
Expand Down Expand Up @@ -72,15 +76,26 @@ public void testAssociateUserEmptyInputs(String subject,
String idp) throws Exception {

try (MockedStatic<FrameworkUtils> frameworkUtils = mockStatic(FrameworkUtils.class)) {
frameworkUtils.when(() -> FrameworkUtils.startTenantFlow("tenantDomain")).thenAnswer(invocation -> null);
provisioningHandler.associateUser("dummy_user_name", "DUMMY_DOMAIN", "dummy.com", subject, idp);
frameworkUtils.when(() -> FrameworkUtils.startTenantFlow("tenantDomain"))
.thenAnswer(invocation -> null);
provisioningHandler.associateUser("dummy_user_name", "DUMMY_DOMAIN",
"dummy.com", subject, idp);
}
}

@Test
public void testGeneratePassword() throws Exception {
String randomPassword = provisioningHandler.generatePassword();
char[] randomPassword = provisioningHandler.generatePassword();
assertNotNull(randomPassword);
assertEquals(randomPassword.length(), 12);
assertEquals(randomPassword.length, 12);
}

@Test
public void testResolvePassword() throws Exception {

Map<String, String> userClaims = new HashMap<>();
userClaims.put(FrameworkConstants.PASSWORD, "dummy_password");
char[] resolvedPassword = provisioningHandler.resolvePassword(userClaims);
assertEquals(resolvedPassword, "dummy_password".toCharArray());
}
}

0 comments on commit fa9ca08

Please sign in to comment.