diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd index ce2695a1eba..480ee74939d 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd @@ -9520,7 +9520,7 @@ - +

@@ -9528,15 +9528,8 @@ or not. If the expression returns true, then the value is accepted. If the expression returns false value, then the value is rejected and it will be generated again. Until the maximum number of attempts is reached. -

-
-
-
- - - -

- Message thet will be displayed to user when the expression check fails. + If there are several expressions that all of them must pass for the value to + be accepted. However each of them may produce a different failure message.

@@ -9586,6 +9579,39 @@ + + + + + Expression used to check the data and report a user-friendly message in case + that the check fails. + + + + + + +

+ Expression that is used to check the resulting value whether it is acceptable + or not. If the expression returns true, then the value is accepted. + If the expression returns false value, then the value is rejected. +

+
+
+
+ + + +

+ Message thet will be displayed to user when the expression check fails. +

+
+
+
+ +
+
+ diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/stringpolicy/ValuePolicyGenerator.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/stringpolicy/ValuePolicyGenerator.java index 39e1bfca03c..d304845c365 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/stringpolicy/ValuePolicyGenerator.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/stringpolicy/ValuePolicyGenerator.java @@ -52,6 +52,7 @@ import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.xml.ns._public.common.common_3.CheckExpressionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.LimitationsType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; @@ -362,14 +363,24 @@ private boolean checkAttempt(String generatedValue, Strin if (limitationsType == null) { return true; } - ExpressionType checkExpression = limitationsType.getCheckExpression(); - if (checkExpression != null && !checkExpression(generatedValue, checkExpression, object, shortDesc, task, result)) { + List checkExpressionTypes = limitationsType.getCheckExpression(); + if (!checkExpressions(generatedValue, checkExpressionTypes, object, shortDesc, task, result)) { LOGGER.trace("Check expression returned false for generated value in {}", shortDesc); return false; } // TODO Check pattern return true; } + + private boolean checkExpressions(String generatedValue, List checkExpressionTypes, PrismObject object, String shortDesc, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException { + for (CheckExpressionType checkExpressionType: checkExpressionTypes) { + ExpressionType expression = checkExpressionType.getExpression(); + if (!checkExpression(generatedValue, expression, object, shortDesc, task, result)) { + return false; + } + } + return true; + } public boolean checkExpression(String generatedValue, ExpressionType checkExpression, PrismObject object, String shortDesc, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException { ExpressionVariables variables = new ExpressionVariables(); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java index f4431d3531d..078e84a2213 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java @@ -68,6 +68,7 @@ import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.CharacterClassType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.CheckExpressionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; @@ -754,19 +755,25 @@ private void testMaximalLength(String password, LimitationsType limitations, private void testCheckExpression(String newPassword, LimitationsType lims, PrismObject object, String shortDesc, Task task, OperationResult result, StringBuilder message) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException { - ExpressionType expressionType = lims.getCheckExpression(); - if (expressionType == null) { + List checkExpressions = lims.getCheckExpression(); + if (checkExpressions.isEmpty()) { return; } - if (!valuePolicyGenerator.checkExpression(newPassword, expressionType, object, shortDesc, task, result)) { - String msg = lims.getCheckExpressionMessage(); - if (msg == null) { - msg = "Check expression failed"; + for (CheckExpressionType checkExpression: checkExpressions) { + ExpressionType expressionType = checkExpression.getExpression(); + if (expressionType == null) { + return; + } + if (!valuePolicyGenerator.checkExpression(newPassword, expressionType, object, shortDesc, task, result)) { + String msg = checkExpression.getFailureMessage(); + if (msg == null) { + msg = "Check expression failed"; + } + result.addSubresult(new OperationResult("Check expression", + OperationResultStatus.FATAL_ERROR, msg)); + message.append(msg); + message.append("\n"); } - result.addSubresult(new OperationResult("Check expression", - OperationResultStatus.FATAL_ERROR, msg)); - message.append(msg); - message.append("\n"); } } diff --git a/model/model-impl/src/test/resources/lens/ppolicy/password-policy-props.xml b/model/model-impl/src/test/resources/lens/ppolicy/password-policy-props.xml index e48b413d5f0..077d49cb194 100644 --- a/model/model-impl/src/test/resources/lens/ppolicy/password-policy-props.xml +++ b/model/model-impl/src/test/resources/lens/ppolicy/password-policy-props.xml @@ -28,11 +28,24 @@ 10 0 - + + + + Boom! username + + + + + + Boom! names 30 diff --git a/model/model-impl/src/test/resources/lens/ppolicy/password-policy-username.xml b/model/model-impl/src/test/resources/lens/ppolicy/password-policy-username.xml index 59dda93f6a6..37987032b39 100644 --- a/model/model-impl/src/test/resources/lens/ppolicy/password-policy-username.xml +++ b/model/model-impl/src/test/resources/lens/ppolicy/password-policy-username.xml @@ -28,11 +28,13 @@ 2 0 - + + + 2 diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestPassword.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestPassword.java index f23c5f918af..0a3d0f80946 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestPassword.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestPassword.java @@ -64,6 +64,7 @@ public class TestPassword extends AbstractInitializedModelIntegrationTest { private static final String USER_PASSWORD_5_CLEAR = "s3tSa1al"; private static final String USER_PASSWORD_A_CLEAR = "A"; // too short private static final String USER_PASSWORD_JACK_CLEAR = "12jAcK34"; // contains username + private static final String USER_PASSWORD_SPARROW_CLEAR = "saRRow123"; // contains familyName private static final String USER_PASSWORD_VALID_1 = "abcd123"; private static final String USER_PASSWORD_VALID_2 = "abcd223"; private static final String USER_PASSWORD_VALID_3 = "abcd323"; @@ -818,6 +819,16 @@ public void test224ModifyUserJackPasswordBadJack() throws Exception { USER_PASSWORD_JACK_CLEAR, USER_PASSWORD_VALID_1, USER_PASSWORD_A_CLEAR); } + /** + * Change to password that violates the password policy (contains family name) + * MID-1657 + */ + @Test + public void test226ModifyUserJackPasswordBadSparrow() throws Exception { + doTestModifyUserJackPasswordFailureWithHistory("test226ModifyUserJackPasswordBadSparrow", + USER_PASSWORD_SPARROW_CLEAR, USER_PASSWORD_VALID_1, USER_PASSWORD_A_CLEAR); + } + /** * Change to password that complies with password policy. Again. See that * the change is applied correctly and that it is included in the history. diff --git a/model/model-intest/src/test/resources/common/password-policy-global.xml b/model/model-intest/src/test/resources/common/password-policy-global.xml index c704a2a2612..b9c2c61cc7a 100644 --- a/model/model-intest/src/test/resources/common/password-policy-global.xml +++ b/model/model-intest/src/test/resources/common/password-policy-global.xml @@ -30,24 +30,43 @@ Testing string policy 5 - 8 + 12 3 true - + + + + must not contain username + + + + + + must not contain family name and given name and additional names - must not contain username, family name and given name and additional names Alphas 1