Skip to content

Commit

Permalink
Make user service use a random password (#3077)
Browse files Browse the repository at this point in the history
Uses Passay to generate a random password for service accounts where
each password is between 8 and 16 characters and has at least 1 of each:
lower case letter, upper case letter, digit, special symbol.

Signed-off-by: Stephen Crawford <[email protected]>
  • Loading branch information
stephen-crawford authored Aug 4, 2023
1 parent 527495d commit 1822e13
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 4 deletions.
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,9 @@ dependencies {
implementation 'com.flipkart.zjsonpatch:zjsonpatch:0.4.14'
implementation 'org.apache.commons:commons-collections4:4.4'

//Password generation
implementation 'org.passay:passay:1.6.3'

//JSON path
implementation 'com.jayway.jsonpath:json-path:2.8.0'
implementation 'net.minidev:json-smart:2.4.11'
Expand Down
29 changes: 25 additions & 4 deletions src/main/java/org/opensearch/security/user/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.stream.Collectors;

import com.fasterxml.jackson.core.JsonProcessingException;
Expand All @@ -31,6 +33,7 @@
import org.opensearch.action.support.WriteRequest;
import org.opensearch.client.Client;
import org.opensearch.cluster.service.ClusterService;
import org.opensearch.common.Randomness;
import org.opensearch.common.inject.Inject;
import org.opensearch.common.settings.Settings;
import org.opensearch.common.xcontent.XContentHelper;
Expand All @@ -43,6 +46,9 @@
import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration;
import org.opensearch.security.support.ConfigConstants;
import org.opensearch.security.support.SecurityJsonNode;
import org.passay.CharacterRule;
import org.passay.EnglishCharacterData;
import org.passay.PasswordGenerator;

import static org.opensearch.security.dlic.rest.support.Utils.hash;

Expand Down Expand Up @@ -204,13 +210,28 @@ private void verifyServiceAccount(SecurityJsonNode securityJsonNode, String acco
}

/**
* This will be swapped in for a real solution once one is decided on.
* Use Passay to generate an 8 - 16 character password with 1+ lowercase, 1+ uppercase, 1+ digit, 1+ special character
*
* @return A password for a service account.
*/
private String generatePassword() {
String generatedPassword = "superSecurePassword";
return generatedPassword;
public static String generatePassword() {

CharacterRule lowercaseCharacterRule = new CharacterRule(EnglishCharacterData.LowerCase, 1);
CharacterRule uppercaseCharacterRule = new CharacterRule(EnglishCharacterData.UpperCase, 1);
CharacterRule numericCharacterRule = new CharacterRule(EnglishCharacterData.Digit, 1);
CharacterRule specialCharacterRule = new CharacterRule(EnglishCharacterData.Special, 1);

List<CharacterRule> rules = Arrays.asList(
lowercaseCharacterRule,
uppercaseCharacterRule,
numericCharacterRule,
specialCharacterRule
);
PasswordGenerator passwordGenerator = new PasswordGenerator();

Random random = Randomness.get();

return passwordGenerator.generatePassword(random.nextInt(8) + 8, rules);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,17 @@
import org.opensearch.security.support.ConfigConstants;
import org.opensearch.security.test.helper.file.FileHelper;
import org.opensearch.security.test.helper.rest.RestHelper.HttpResponse;
import org.opensearch.security.user.UserService;
import org.passay.CharacterCharacteristicsRule;
import org.passay.CharacterRule;
import org.passay.EnglishCharacterData;
import org.passay.LengthRule;
import org.passay.PasswordData;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertNotEquals;
import static org.opensearch.security.OpenSearchSecurityPlugin.PLUGINS_PREFIX;
import static org.opensearch.security.dlic.rest.api.InternalUsersApiAction.RESTRICTED_FROM_USERNAME;
import static org.opensearch.security.support.ConfigConstants.SECURITY_RESTAPI_ADMIN_ENABLED;
Expand Down Expand Up @@ -1004,4 +1011,30 @@ public void checkNullElementsInArray() throws Exception {
Assert.assertEquals(RequestContentValidator.ValidationError.NULL_ARRAY_ELEMENT.message(), settings.get("reason"));
}

@Test
public void testGeneratedPasswordContents() {
String password = UserService.generatePassword();
PasswordData data = new PasswordData(password);

LengthRule lengthRule = new LengthRule(8, 16);

CharacterCharacteristicsRule characteristicsRule = new CharacterCharacteristicsRule();

// Define M (3 in this case)
characteristicsRule.setNumberOfCharacteristics(3);

// Define elements of N (upper, lower, digit, symbol)
characteristicsRule.getRules().add(new CharacterRule(EnglishCharacterData.UpperCase, 1));
characteristicsRule.getRules().add(new CharacterRule(EnglishCharacterData.LowerCase, 1));
characteristicsRule.getRules().add(new CharacterRule(EnglishCharacterData.Digit, 1));
characteristicsRule.getRules().add(new CharacterRule(EnglishCharacterData.Special, 1));

org.passay.PasswordValidator validator = new org.passay.PasswordValidator(lengthRule, characteristicsRule);
validator.validate(data);

String password2 = UserService.generatePassword();
PasswordData data2 = new PasswordData(password2);
assertNotEquals(password, password2);
assertNotEquals(data, data2);
}
}

0 comments on commit 1822e13

Please sign in to comment.