This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/master by this push:
new 0c5820e427 Upgrading Passay
0c5820e427 is described below
commit 0c5820e42764eaedfa54407e9f291c16bd008e93
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Tue Apr 7 09:49:05 2026 +0200
Upgrading Passay
---
.../core/spring/policy/DefaultPasswordRule.java | 204 +++++++--------------
.../spring/security/DefaultPasswordGenerator.java | 16 +-
.../core/spring/security/PasswordGenerator.java | 78 ++++++++
.../core/spring/security/SecureRandomUtils.java | 10 +-
.../spring/security/PasswordGeneratorTest.java | 39 ++++
.../apache/syncope/fit/core/PullTaskITCase.java | 2 +-
pom.xml | 2 +-
7 files changed, 200 insertions(+), 151 deletions(-)
diff --git
a/core/spring/src/main/java/org/apache/syncope/core/spring/policy/DefaultPasswordRule.java
b/core/spring/src/main/java/org/apache/syncope/core/spring/policy/DefaultPasswordRule.java
index ad1b81b051..e39b6abafc 100644
---
a/core/spring/src/main/java/org/apache/syncope/core/spring/policy/DefaultPasswordRule.java
+++
b/core/spring/src/main/java/org/apache/syncope/core/spring/policy/DefaultPasswordRule.java
@@ -19,16 +19,12 @@
package org.apache.syncope.core.spring.policy;
import java.io.InputStream;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashSet;
+import java.util.Comparator;
import java.util.List;
-import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.commons.lang3.Strings;
import org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf;
import org.apache.syncope.common.lib.policy.PasswordRuleConf;
import org.apache.syncope.core.persistence.api.EncryptorManager;
@@ -37,18 +33,16 @@ import
org.apache.syncope.core.persistence.api.entity.user.LinkedAccount;
import org.apache.syncope.core.persistence.api.entity.user.User;
import org.apache.syncope.core.provisioning.api.rules.PasswordRule;
import org.apache.syncope.core.provisioning.api.rules.PasswordRuleConfClass;
-import org.passay.CharacterData;
-import org.passay.CharacterRule;
-import org.passay.EnglishCharacterData;
-import org.passay.IllegalCharacterRule;
-import org.passay.LengthRule;
+import org.apache.syncope.core.spring.security.PasswordGenerator;
+import org.passay.DefaultPasswordValidator;
import org.passay.PasswordData;
import org.passay.PasswordValidator;
-import org.passay.PropertiesMessageResolver;
-import org.passay.RepeatCharactersRule;
-import org.passay.Rule;
-import org.passay.RuleResult;
-import org.passay.UsernameRule;
+import org.passay.ValidationResult;
+import org.passay.dictionary.ArrayWordList;
+import org.passay.dictionary.WordListDictionary;
+import org.passay.resolver.PropertiesMessageResolver;
+import org.passay.rule.DictionaryRule;
+import org.passay.rule.Rule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -60,71 +54,22 @@ public class DefaultPasswordRule implements PasswordRule {
protected static final Logger LOG =
LoggerFactory.getLogger(DefaultPasswordRule.class);
- public static List<Rule> conf2Rules(final DefaultPasswordRuleConf conf) {
- List<Rule> rules = new ArrayList<>();
-
- LengthRule lengthRule = new LengthRule();
- if (conf.getMinLength() > 0) {
- lengthRule.setMinimumLength(conf.getMinLength());
- }
- if (conf.getMaxLength() > 0) {
- lengthRule.setMaximumLength(conf.getMaxLength());
- }
- rules.add(lengthRule);
-
- if (conf.getAlphabetical() > 0) {
- rules.add(new CharacterRule(EnglishCharacterData.Alphabetical,
conf.getAlphabetical()));
- }
-
- if (conf.getUppercase() > 0) {
- rules.add(new CharacterRule(EnglishCharacterData.UpperCase,
conf.getUppercase()));
- }
-
- if (conf.getLowercase() > 0) {
- rules.add(new CharacterRule(EnglishCharacterData.LowerCase,
conf.getLowercase()));
- }
-
- if (conf.getDigit() > 0) {
- rules.add(new CharacterRule(EnglishCharacterData.Digit,
conf.getDigit()));
- }
-
- if (conf.getSpecial() > 0) {
- rules.add(new CharacterRule(new CharacterData() {
-
- @Override
- public String getErrorCode() {
- return "INSUFFICIENT_SPECIAL";
- }
-
- @Override
- public String getCharacters() {
- return new
String(ArrayUtils.toPrimitive(conf.getSpecialChars().toArray(Character[]::new)));
- }
- }, conf.getSpecial()));
- }
-
- if (!conf.getIllegalChars().isEmpty()) {
- rules.add(new IllegalCharacterRule(
-
ArrayUtils.toPrimitive(conf.getIllegalChars().toArray(Character[]::new))));
- }
-
- if (conf.getRepeatSame() > 0) {
- rules.add(new RepeatCharactersRule(conf.getRepeatSame()));
- }
-
- if (!conf.isUsernameAllowed()) {
- rules.add(new UsernameRule(true, true));
- }
-
- return rules;
- }
+ protected final PropertiesMessageResolver messageResolver;
@Autowired
protected EncryptorManager encryptorManager;
protected DefaultPasswordRuleConf conf;
- protected PasswordValidator passwordValidator;
+ public DefaultPasswordRule() {
+ Properties passay = new Properties();
+ try (InputStream in =
getClass().getResourceAsStream("/passay.properties")) {
+ passay.load(in);
+ messageResolver = new PropertiesMessageResolver(passay);
+ } catch (Exception e) {
+ throw new IllegalStateException("Could not initialize Passay", e);
+ }
+ }
@Override
public PasswordRuleConf getConf() {
@@ -135,96 +80,77 @@ public class DefaultPasswordRule implements PasswordRule {
public void setConf(final PasswordRuleConf conf) {
if (conf instanceof DefaultPasswordRuleConf defaultPasswordRuleConf) {
this.conf = defaultPasswordRuleConf;
-
- Properties passay = new Properties();
- try (InputStream in =
getClass().getResourceAsStream("/passay.properties")) {
- passay.load(in);
- passwordValidator = new PasswordValidator(new
PropertiesMessageResolver(passay), conf2Rules(this.conf));
- } catch (Exception e) {
- throw new IllegalStateException("Could not initialize Passay",
e);
- }
} else {
throw new IllegalArgumentException(
DefaultPasswordRuleConf.class.getName() + " expected, got
" + conf.getClass().getName());
}
}
- protected void enforce(final String clear, final String username, final
Set<String> wordsNotPermitted) {
- RuleResult result = passwordValidator.validate(
- username == null ? new PasswordData(clear) : new
PasswordData(username, clear));
- if (!result.isValid()) {
- throw new PasswordPolicyException(String.join(",",
passwordValidator.getMessages(result)));
+ protected void enforce(final String username, final String clearPassword,
final Collection<String> notPermitted) {
+ List<Rule> rules = PasswordGenerator.conf2Rules(conf);
+ if (!notPermitted.isEmpty()) {
+ rules.add(new DictionaryRule(new WordListDictionary(new
ArrayWordList(
+
notPermitted.stream().distinct().sorted(Comparator.naturalOrder()).toArray(String[]::new),
true)),
+ true));
}
- // check words not permitted
- wordsNotPermitted.stream().
- filter(word -> Strings.CI.contains(clear, word)).findFirst().
- ifPresent(word -> {
- throw new PasswordPolicyException("Used word(s) not
permitted");
- });
+ PasswordValidator passwordValidator = new
DefaultPasswordValidator(messageResolver, rules);
+ ValidationResult result = passwordValidator.validate(
+ username == null ? new PasswordData(clearPassword) : new
PasswordData(username, clearPassword));
+ if (!result.isValid()) {
+ throw new
PasswordPolicyException(result.getMessages().stream().collect(Collectors.joining(",")));
+ }
}
@Override
public void enforce(final String username, final String clearPassword) {
- if (clearPassword != null) {
- Set<String> wordsNotPermitted = new
HashSet<>(conf.getWordsNotPermitted());
- enforce(clearPassword, username, wordsNotPermitted);
+ if (clearPassword == null) {
+ return;
}
+
+ enforce(username, clearPassword, Set.of());
}
@Transactional(readOnly = true)
@Override
public void enforce(final User user, final String clearPassword) {
- if (clearPassword != null) {
- Set<String> wordsNotPermitted = new
HashSet<>(conf.getWordsNotPermitted());
- wordsNotPermitted.addAll(
- conf.getSchemasNotPermitted().stream().
- map(schema -> user.getPlainAttr(schema).
- map(PlainAttr::getValuesAsStrings).orElse(null)).
- filter(Objects::nonNull).
- filter(values -> !CollectionUtils.isEmpty(values)).
- flatMap(Collection::stream).
- collect(Collectors.toSet()));
-
- enforce(clearPassword, user.getUsername(), wordsNotPermitted);
+ if (clearPassword == null) {
+ return;
}
+
+ List<String> notPermitted = conf.getSchemasNotPermitted().stream().
+ map(schema -> user.getPlainAttr(schema).
+ map(PlainAttr::getValuesAsStrings).orElse(null)).
+ filter(values -> !CollectionUtils.isEmpty(values)).
+ flatMap(Collection::stream).
+ toList();
+
+ enforce(user.getUsername(), clearPassword, notPermitted);
}
@Transactional(readOnly = true)
@Override
public void enforce(final LinkedAccount account) {
- conf.getWordsNotPermitted().addAll(
- conf.getSchemasNotPermitted().stream().
- map(schema -> account.getPlainAttr(schema).
- map(PlainAttr::getValuesAsStrings).orElse(null)).
- filter(Objects::nonNull).
- filter(values -> !CollectionUtils.isEmpty(values)).
- flatMap(Collection::stream).
- toList());
-
- if (account.getPassword() != null) {
- String clear = null;
- if (account.canDecodeSecrets()) {
- try {
- clear =
encryptorManager.getInstance().decode(account.getPassword(),
account.getCipherAlgorithm());
- } catch (Exception e) {
- LOG.error("Could not decode password for {}", account, e);
- }
- }
-
- if (clear != null) {
- Set<String> wordsNotPermitted = new
HashSet<>(conf.getWordsNotPermitted());
- wordsNotPermitted.addAll(
- conf.getSchemasNotPermitted().stream().
- map(schema -> account.getPlainAttr(schema).
-
map(PlainAttr::getValuesAsStrings).orElse(null)).
- filter(Objects::nonNull).
- filter(values ->
!CollectionUtils.isEmpty(values)).
- flatMap(Collection::stream).
- collect(Collectors.toSet()));
-
- enforce(clear, account.getUsername(), wordsNotPermitted);
+ String clearPassword = null;
+ if (account.getPassword() != null && account.canDecodeSecrets()) {
+ try {
+ clearPassword = encryptorManager.getInstance().decode(
+ account.getPassword(), account.getCipherAlgorithm());
+ } catch (Exception e) {
+ LOG.error("Could not decode password for {}", account, e);
}
}
+ if (clearPassword == null) {
+ return;
+ }
+
+ List<String> notPermitted = conf.getSchemasNotPermitted().stream().
+ map(schema -> account.getPlainAttr(schema).
+ map(PlainAttr::getValuesAsStrings).orElse(null)).
+ filter(values -> !CollectionUtils.isEmpty(values)).
+ flatMap(Collection::stream).
+ toList();
+
+ enforce(account.getUsername(), clearPassword, notPermitted);
}
}
diff --git
a/core/spring/src/main/java/org/apache/syncope/core/spring/security/DefaultPasswordGenerator.java
b/core/spring/src/main/java/org/apache/syncope/core/spring/security/DefaultPasswordGenerator.java
index 73a03d93d7..8ee5ad2f38 100644
---
a/core/spring/src/main/java/org/apache/syncope/core/spring/security/DefaultPasswordGenerator.java
+++
b/core/spring/src/main/java/org/apache/syncope/core/spring/security/DefaultPasswordGenerator.java
@@ -30,9 +30,9 @@ import org.apache.syncope.core.persistence.api.entity.Realm;
import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
import org.apache.syncope.core.provisioning.api.rules.PasswordRule;
import org.apache.syncope.core.spring.implementation.ImplementationManager;
-import org.apache.syncope.core.spring.policy.DefaultPasswordRule;
-import org.passay.CharacterRule;
-import org.passay.EnglishCharacterData;
+import org.passay.data.EnglishCharacterData;
+import org.passay.rule.CharacterRule;
+import org.passay.rule.Rule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
@@ -104,6 +104,7 @@ public class DefaultPasswordGenerator implements
PasswordGenerator {
DefaultPasswordRuleConf result = new DefaultPasswordRuleConf();
result.setMinLength(VERY_MIN_LENGTH);
result.setMaxLength(VERY_MAX_LENGTH);
+ result.setUsernameAllowed(true);
defaultRuleConfs.forEach(ruleConf -> {
if (ruleConf.getMinLength() > result.getMinLength()) {
@@ -170,7 +171,9 @@ public class DefaultPasswordGenerator implements
PasswordGenerator {
}
protected String generate(final DefaultPasswordRuleConf ruleConf) {
- List<CharacterRule> characterRules =
DefaultPasswordRule.conf2Rules(ruleConf).stream().
+ List<Rule> rules = PasswordGenerator.conf2Rules(ruleConf);
+
+ List<CharacterRule> characterRules = rules.stream().
filter(CharacterRule.class::isInstance).map(CharacterRule.class::cast).
toList();
if (characterRules.isEmpty()) {
@@ -178,9 +181,12 @@ public class DefaultPasswordGenerator implements
PasswordGenerator {
characterRules = List.of(
new CharacterRule(EnglishCharacterData.Alphabetical,
halfMinLength),
new CharacterRule(EnglishCharacterData.Digit,
halfMinLength));
+
+ rules.addAll(characterRules);
}
int min = Math.max(ruleConf.getMinLength(),
characterRules.stream().mapToInt(CharacterRule::getNumberOfCharacters).sum());
- return SecureRandomUtils.passwordGenerator().generatePassword(min,
characterRules);
+
+ return SecureRandomUtils.passwordGenerator(min,
rules).generate().toString();
}
}
diff --git
a/core/spring/src/main/java/org/apache/syncope/core/spring/security/PasswordGenerator.java
b/core/spring/src/main/java/org/apache/syncope/core/spring/security/PasswordGenerator.java
index 758ea159f4..c57515b1a5 100644
---
a/core/spring/src/main/java/org/apache/syncope/core/spring/security/PasswordGenerator.java
+++
b/core/spring/src/main/java/org/apache/syncope/core/spring/security/PasswordGenerator.java
@@ -18,13 +18,91 @@
*/
package org.apache.syncope.core.spring.security;
+import java.util.ArrayList;
+import java.util.Comparator;
import java.util.List;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf;
import org.apache.syncope.core.persistence.api.entity.ExternalResource;
import org.apache.syncope.core.persistence.api.entity.Realm;
import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
+import org.passay.UnicodeString;
+import org.passay.data.CharacterData;
+import org.passay.data.EnglishCharacterData;
+import org.passay.dictionary.ArrayWordList;
+import org.passay.dictionary.WordListDictionary;
+import org.passay.rule.CharacterRule;
+import org.passay.rule.DictionaryRule;
+import org.passay.rule.IllegalCharacterRule;
+import org.passay.rule.LengthRule;
+import org.passay.rule.RepeatCharactersRule;
+import org.passay.rule.Rule;
+import org.passay.rule.UsernameRule;
public interface PasswordGenerator {
+ static List<Rule> conf2Rules(final DefaultPasswordRuleConf conf) {
+ List<Rule> rules = new ArrayList<>();
+
+ if (conf.getMinLength() > 0 || conf.getMaxLength() > 0) {
+ rules.add(new LengthRule(
+ conf.getMinLength() > 0 ? conf.getMinLength() : 0,
+ conf.getMaxLength() > 0 ? conf.getMaxLength() :
Integer.MAX_VALUE));
+ }
+
+ if (conf.getAlphabetical() > 0) {
+ rules.add(new CharacterRule(EnglishCharacterData.Alphabetical,
conf.getAlphabetical()));
+ }
+
+ if (conf.getUppercase() > 0) {
+ rules.add(new CharacterRule(EnglishCharacterData.UpperCase,
conf.getUppercase()));
+ }
+
+ if (conf.getLowercase() > 0) {
+ rules.add(new CharacterRule(EnglishCharacterData.LowerCase,
conf.getLowercase()));
+ }
+
+ if (conf.getDigit() > 0) {
+ rules.add(new CharacterRule(EnglishCharacterData.Digit,
conf.getDigit()));
+ }
+
+ if (conf.getSpecial() > 0) {
+ rules.add(new CharacterRule(new CharacterData() {
+
+ @Override
+ public String getErrorCode() {
+ return "INSUFFICIENT_SPECIAL";
+ }
+
+ @Override
+ public String getCharacters() {
+ return new
String(ArrayUtils.toPrimitive(conf.getSpecialChars().toArray(Character[]::new)));
+ }
+ }, conf.getSpecial()));
+ }
+
+ if (!conf.getIllegalChars().isEmpty()) {
+ rules.add(new IllegalCharacterRule(
+ new
UnicodeString(ArrayUtils.toPrimitive(conf.getIllegalChars().toArray(Character[]::new)))));
+ }
+
+ if (conf.getRepeatSame() > 0) {
+ rules.add(new RepeatCharactersRule(conf.getRepeatSame()));
+ }
+
+ if (!conf.isUsernameAllowed()) {
+ rules.add(new UsernameRule(true, true));
+ }
+
+ if (!conf.getWordsNotPermitted().isEmpty()) {
+ conf.getWordsNotPermitted().sort(Comparator.naturalOrder());
+ rules.add(new DictionaryRule(new WordListDictionary(
+ new
ArrayWordList(conf.getWordsNotPermitted().toArray(String[]::new), true)),
true));
+ }
+
+ return rules;
+ }
+
String generate(ExternalResource resource, List<Realm> realms);
String generate(List<PasswordPolicy> policies);
diff --git
a/core/spring/src/main/java/org/apache/syncope/core/spring/security/SecureRandomUtils.java
b/core/spring/src/main/java/org/apache/syncope/core/spring/security/SecureRandomUtils.java
index 4b78d52bd1..bc641be1a0 100644
---
a/core/spring/src/main/java/org/apache/syncope/core/spring/security/SecureRandomUtils.java
+++
b/core/spring/src/main/java/org/apache/syncope/core/spring/security/SecureRandomUtils.java
@@ -21,16 +21,16 @@ package org.apache.syncope.core.spring.security;
import com.fasterxml.uuid.Generators;
import com.fasterxml.uuid.NoArgGenerator;
import java.security.SecureRandom;
+import java.util.List;
import java.util.UUID;
import org.apache.commons.text.RandomStringGenerator;
-import org.passay.PasswordGenerator;
+import org.passay.generate.PasswordGenerator;
+import org.passay.rule.Rule;
public final class SecureRandomUtils {
private static final SecureRandom RANDOM = new SecureRandom();
- private static final PasswordGenerator PASSWORD_GENERATOR = new
PasswordGenerator(RANDOM);
-
private static final RandomStringGenerator FOR_PASSWORD = new
RandomStringGenerator.Builder().
usingRandom(RANDOM::nextInt).
withinRange('0', 'z').
@@ -90,8 +90,8 @@ public final class SecureRandomUtils {
return UUID_GENERATOR.generate();
}
- public static PasswordGenerator passwordGenerator() {
- return PASSWORD_GENERATOR;
+ public static PasswordGenerator passwordGenerator(final int length, final
List<? extends Rule> rules) {
+ return new PasswordGenerator(RANDOM, length, 2, rules);
}
private SecureRandomUtils() {
diff --git
a/core/spring/src/test/java/org/apache/syncope/core/spring/security/PasswordGeneratorTest.java
b/core/spring/src/test/java/org/apache/syncope/core/spring/security/PasswordGeneratorTest.java
index 50ea8be828..8927d4e0cb 100644
---
a/core/spring/src/test/java/org/apache/syncope/core/spring/security/PasswordGeneratorTest.java
+++
b/core/spring/src/test/java/org/apache/syncope/core/spring/security/PasswordGeneratorTest.java
@@ -18,6 +18,7 @@
*/
package org.apache.syncope.core.spring.security;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -26,8 +27,10 @@ import
org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf;
import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
import org.apache.syncope.core.spring.SpringTestConfiguration;
import org.apache.syncope.core.spring.implementation.PasswordRuleTest;
+import org.apache.syncope.core.spring.policy.DefaultPasswordRule;
import org.junit.jupiter.api.Test;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+import tools.jackson.databind.json.JsonMapper;
@SpringJUnitConfig(classes = { SpringTestConfiguration.class })
public class PasswordGeneratorTest {
@@ -97,6 +100,42 @@ public class PasswordGeneratorTest {
assertTrue(generatedPassword.chars().anyMatch(c -> '@' == c || '!' ==
c || '%' == c));
}
+ @Test
+ public void validateGenerated() {
+ String input =
+ """
+{
+ "_class": "org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf",
+ "alphabetical": 0,
+ "digit": 1,
+ "illegalChars": [],
+ "lowercase": 0,
+ "maxLength": 64,
+ "minLength": 10,
+ "name": "org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf",
+ "repeatSame": 0,
+ "schemasNotPermitted": [],
+ "special": 0,
+ "specialChars": [],
+ "uppercase": 0,
+ "usernameAllowed": false,
+ "wordsNotPermitted": [
+ "notpermitted1",
+ "notpermitted2"
+ ]
+}
+""";
+ DefaultPasswordRuleConf ruleConf =
JsonMapper.builder().build().readValue(input, DefaultPasswordRuleConf.class);
+ TestImplementation passwordRule = new TestImplementation();
+ passwordRule.setBody(POJOHelper.serialize(ruleConf));
+
+ String password = passwordGenerator.generate(List.of(new
TestPasswordPolicy(passwordRule)));
+
+ DefaultPasswordRule rule = new DefaultPasswordRule();
+ rule.setConf(ruleConf);
+ assertDoesNotThrow(() -> rule.enforce((String) null, password));
+ }
+
@Test
public void issueSYNCOPE678() {
String password = passwordGenerator.generate(List.of());
diff --git
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java
index 25fef98085..d0634ac717 100644
---
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java
+++
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java
@@ -840,7 +840,7 @@ public class PullTaskITCase extends AbstractTaskITCase {
userCR.getResources().clear();
String email =
userCR.getPlainAttr("email").orElseThrow().getValues().getFirst();
- userCR.getPlainAttrs().add(new
Attr.Builder("userId").value(email).build());
+ userCR.getPlainAttrs().add(attr("userId", email));
REMEDIATION_SERVICE.remedy(remediation.getKey(), userCR);
diff --git a/pom.xml b/pom.xml
index 926e1162b6..b792a75dbc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1317,7 +1317,7 @@ under the License.
<dependency>
<groupId>org.passay</groupId>
<artifactId>passay</artifactId>
- <version>1.6.6</version>
+ <version>2.0.0</version>
</dependency>
<dependency>