Skip to content

Commit

Permalink
Write auto-assignment expression profile tests
Browse files Browse the repository at this point in the history
Also, added a note to the XSD docs that expressions in auto-assignment
filters are not supported.
  • Loading branch information
mederly committed Jul 21, 2023
1 parent 920df5d commit 50624f1
Show file tree
Hide file tree
Showing 12 changed files with 319 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

import com.evolveum.midpoint.prism.path.ItemName;

import javax.xml.namespace.QName;

/**
* Constants for all names of the variables in the system.
*
Expand All @@ -31,6 +33,7 @@ public class ExpressionConstants {
public static final String VAR_PROJECTION = "projection";
public static final String VAR_SOURCE = "source";
public static final String VAR_ASSIGNMENT = "assignment";
public static final QName VAR_ASSIGNMENT_QNAME = new QName(SchemaConstants.NS_C, VAR_ASSIGNMENT);
public static final String VAR_ASSIGNMENT_EVALUATOR = "assignmentEvaluator";
public static final String VAR_EVALUATED_ASSIGNMENT = "evaluatedAssignment";
public static final String VAR_ASSIGNMENT_PATH = "assignmentPath";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,13 @@ public boolean matches(
@NotNull MatchingContext ctx)
throws SchemaException, ExpressionEvaluationException, CommunicationException, SecurityViolationException,
ConfigurationException, ObjectNotFoundException {
if (!(value instanceof PrismContainerValue<?>)) {
if (!(value instanceof PrismContainerValue<?> pcv)) {
// This is because of filter limitations;
// TODO we should support application of filters to reference values (and probably property values as well)
throw new UnsupportedOperationException(String.format(
"Object selector with filter cannot be used for values other than container ones: %s",
getDiagInfo(value)));
}
PrismContainerValue<?> pcv = (PrismContainerValue<?>) value;
try {
ObjectFilter evaluatedFilter = getEvaluatedFilter(ctx);
if (evaluatedFilter.match(pcv, SchemaService.get().matchingRuleRegistry())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7479,7 +7479,8 @@
<xsd:annotation>
<xsd:documentation>
<p>
Restrics autoassignment to concrete focus type.
Restrics autoassignment to concrete focus type (or other criteria).
Expressions are NOT supported here for now.
</p>
</xsd:documentation>
</xsd:annotation>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,12 @@ private <AH extends AssignmentHolderType> boolean isApplicableFor(
return true;
}
try {
return SelectorMatcher.forSelector(selector.value()) // FIXME expression profiles
// Note we do NOT provide filter expression evaluator here. Hence, there's no need to manage expression profiles yet.
return SelectorMatcher.forSelector(selector.value())
.withLogging(LOGGER)
.matches(focusContext.getObjectAnyRequired());
} catch (CommonException e) {
String message = "Failed to evaluate selector constrains, selector: %s, focusContext: %s, reason: %s".formatted(
String message = "Failed to evaluate selector constraints, selector: %s, focusContext: %s, reason: %s".formatted(
selector, focusContext, e.getMessage());
result.recordException(message, e);
throw new SystemException(message, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluationContext;
import com.evolveum.midpoint.repo.common.expression.Source;
import com.evolveum.midpoint.schema.config.AutoAssignMappingConfigItem;
import com.evolveum.midpoint.schema.constants.ExpressionConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.util.exception.*;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
Expand Down Expand Up @@ -56,10 +57,9 @@ AH extends AssignmentHolderType> Source<V, D> constructDefaultSource(
}
assignment.targetRef(originObject.getOid(), originObject.asPrismObject().getDefinition().getTypeName(), relation);

Source<PrismContainerValue<AssignmentType>, PrismContainerDefinition<AssignmentType>> source =
new Source<>(assignmentContainer, null, assignmentContainer, FocusType.F_ASSIGNMENT, assignmentDef);
//noinspection unchecked
return (Source<V, D>) source;
return (Source<V, D>) new Source<>(
assignmentContainer, null, assignmentContainer, ExpressionConstants.VAR_ASSIGNMENT_QNAME, assignmentDef);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@ public class TestExpressionProfiles extends AbstractEmptyModelIntegrationTest {
private static final TestObject<RoleType> ROLE_RESTRICTED_BAD_CONSTRUCTION_MAPPING = TestObject.file(
TEST_DIR, "role-restricted-bad-construction-mapping.xml", "c8cae775-2c3b-49bb-98e3-482a095316ef");

// initialized only in specific tests
private static final TestObject<RoleType> ROLE_RESTRICTED_AUTO_GOOD = TestObject.file(
TEST_DIR, "role-restricted-auto-good.xml", "a6ace69f-ecfb-457b-97ea-0b5a8b4a6ad3");
private static final TestObject<RoleType> ROLE_RESTRICTED_AUTO_FILTER_EXPRESSION = TestObject.file(
TEST_DIR, "role-restricted-auto-filter-expression.xml", "885bc0b4-2493-4658-a523-8a3f7eeb770b");
private static final TestObject<RoleType> ROLE_RESTRICTED_AUTO_BAD_MAPPING_EXPRESSION = TestObject.file(
TEST_DIR, "role-restricted-auto-bad-mapping-expression.xml", "26f61dc6-efff-4614-aac6-25753b81512f");
private static final TestObject<RoleType> ROLE_RESTRICTED_AUTO_BAD_MAPPING_CONDITION = TestObject.file(
TEST_DIR, "role-restricted-auto-bad-mapping-condition.xml", "eceab160-de05-4b1b-9d09-27cc789252c3");

@Override
public void initSystem(Task initTask, OperationResult initResult) throws Exception {
super.initSystem(initTask, initResult);
Expand Down Expand Up @@ -132,4 +142,115 @@ public void test120RestrictedRoleBadConstructionMapping() throws Exception {
assertFailure(result);
}
}

/** "Correct" restricted auto-assigned role is used. */
@Test
public void test150RestrictedRoleAutoGood() throws Exception {
Task task = getTestTask();
OperationResult result = task.getResult();

given("auto-assigned role is imported");
ROLE_RESTRICTED_AUTO_GOOD.init(this, task, result);

try {
when("user that should get auto role is added");
UserType user = new UserType()
.name("test150")
.costCenter("auto");
var userOid = addObject(user.asPrismObject(), task, result);

then("user is created");
assertSuccess(result);
assertUserAfter(userOid)
.assignments()
.single()
.assertRole(ROLE_RESTRICTED_AUTO_GOOD.oid);
} finally {
deleteObject(RoleType.class, ROLE_RESTRICTED_AUTO_GOOD.oid);
}
}

/** This checks that filter expressions are not supported - hence, safe. :) */
@Test
public void test160RestrictedRoleAutoFilterExpression() throws Exception {
Task task = getTestTask();
OperationResult result = task.getResult();

given("auto-assigned role is imported");
ROLE_RESTRICTED_AUTO_FILTER_EXPRESSION.init(this, task, result);

try {
when("user that should get auto role is added");
UserType user = new UserType()
.name("test160");
var userOid = addObject(user.asPrismObject(), task, result);

then("user is created but without assignments");
assertSuccess(result);
assertUserAfter(userOid)
.assertAssignments(0);
} finally {
deleteObject(RoleType.class, ROLE_RESTRICTED_AUTO_FILTER_EXPRESSION.oid);
}
}

/** Non-compliant script in mapping expression. */
@Test
public void test170RestrictedRoleAutoBadMappingExpression() throws Exception {
Task task = getTestTask();
OperationResult result = task.getResult();

given("auto-assigned role is imported");
ROLE_RESTRICTED_AUTO_BAD_MAPPING_EXPRESSION.init(this, task, result);

try {
when("user that should get auto role is added");
UserType user = new UserType()
.name("test170")
.costCenter("auto");
try {
addObject(user.asPrismObject(), task, result);
fail("unexpected success");
} catch (SecurityViolationException e) {
assertExpectedException(e)
.hasMessageContaining("Denied access to functionality of script in expression in mapping in autoassign mapping")
.hasMessageContaining("restricted-auto-bad-mapping-expression") // object name
.hasMessageContaining("@autoassign/focus/mapping/123") // item path of the offending mapping TODO fix after MID-8943 is fixed
.hasMessageContaining("Access to Groovy method java.lang.System#setProperty denied (applied expression profile 'restricted')");
assertFailure(result);
}
} finally {
deleteObject(RoleType.class, ROLE_RESTRICTED_AUTO_BAD_MAPPING_EXPRESSION.oid);
}
}

/** Non-compliant script in mapping condition. */
@Test
public void test180RestrictedRoleAutoBadMappingCondition() throws Exception {
Task task = getTestTask();
OperationResult result = task.getResult();

given("auto-assigned role is imported");
ROLE_RESTRICTED_AUTO_BAD_MAPPING_CONDITION.init(this, task, result);

try {
when("user that should get auto role is added");
UserType user = new UserType()
.name("test180")
.costCenter("auto");
try {
addObject(user.asPrismObject(), task, result);
fail("unexpected success");
} catch (SecurityViolationException e) {
assertExpectedException(e)
.hasMessageContaining("Denied access to functionality of script in condition in mapping in autoassign mapping")
.hasMessageContaining("restricted-auto-bad-mapping-condition") // object name
.hasMessageContaining("@autoassign/focus/mapping/456") // item path of the offending mapping TODO fix after MID-8943 is fixed
.hasMessageContaining("Access to Groovy method java.lang.System#setProperty denied (applied expression profile 'restricted')");
assertFailure(result);
}
} finally {
deleteObject(RoleType.class, ROLE_RESTRICTED_AUTO_BAD_MAPPING_CONDITION.oid);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<!--
~ Copyright (C) 2010-2023 Evolveum and contributors
~
~ This work is dual-licensed under the Apache License 2.0
~ and European Union Public License. See LICENSE file for details.
-->

<role xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3"
oid="eceab160-de05-4b1b-9d09-27cc789252c3">
<name>restricted-auto-bad-mapping-condition</name>
<documentation>
Auto-assigned role that contains a non-compliant mapping condition.
</documentation>
<assignment>
<targetRef oid="a2242707-43cd-4f18-b986-573cb468693d" type="ArchetypeType"/>
</assignment>
<autoassign>
<enabled>true</enabled>
<focus>
<mapping id="456">
<expression>
<script>
<code>
assignment // compliant
</code>
</script>
</expression>
<condition>
<script>
<code>
System.setProperty('hack', 'true') // non-compliant
true
</code>
</script>
</condition>
</mapping>
<selector>
<type>UserType</type>
<filter>
<q:equal>
<q:path>costCenter</q:path>
<q:value>auto</q:value>
</q:equal>
</filter>
</selector>
</focus>
</autoassign>
</role>
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!--
~ Copyright (C) 2010-2023 Evolveum and contributors
~
~ This work is dual-licensed under the Apache License 2.0
~ and European Union Public License. See LICENSE file for details.
-->

<role xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3"
oid="26f61dc6-efff-4614-aac6-25753b81512f">
<name>restricted-auto-bad-mapping-expression</name>
<documentation>
Auto-assigned role that contains a non-compliant mapping expression.
</documentation>
<assignment>
<targetRef oid="a2242707-43cd-4f18-b986-573cb468693d" type="ArchetypeType"/>
</assignment>
<autoassign>
<enabled>true</enabled>
<focus>
<mapping id="123">
<expression>
<script>
<code>
System.setProperty('hack', 'true') // non-compliant
assignment
</code>
</script>
</expression>
<condition>
<script>
<code>true</code> <!-- compliant -->
</script>
</condition>
</mapping>
<selector>
<type>UserType</type>
<filter>
<q:equal>
<q:path>costCenter</q:path>
<q:value>auto</q:value>
</q:equal>
</filter>
</selector>
</focus>
</autoassign>
</role>
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!--
~ Copyright (C) 2010-2023 Evolveum and contributors
~
~ This work is dual-licensed under the Apache License 2.0
~ and European Union Public License. See LICENSE file for details.
-->

<role xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3"
oid="885bc0b4-2493-4658-a523-8a3f7eeb770b">
<name>restricted-auto-filter-expression</name>
<documentation>
Auto-assigned role that contains an expression in a filter.
</documentation>
<assignment>
<targetRef oid="a2242707-43cd-4f18-b986-573cb468693d" type="ArchetypeType"/>
</assignment>
<autoassign>
<enabled>true</enabled>
<focus>
<selector>
<type>UserType</type>
<filter>
<q:equal>
<q:path>name</q:path>
<expression>
<script>
<code>
// the script will not be evaluated (for now), so this will not explode - but will not
// assign anything, as there are no unnamed users
throw new IllegalStateException()
</code>
</script>
</expression>
</q:equal>
</filter>
</selector>
</focus>
</autoassign>
</role>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!--
~ Copyright (C) 2010-2023 Evolveum and contributors
~
~ This work is dual-licensed under the Apache License 2.0
~ and European Union Public License. See LICENSE file for details.
-->

<role xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3"
oid="a6ace69f-ecfb-457b-97ea-0b5a8b4a6ad3">
<name>restricted-auto-good</name>
<documentation>
Auto-assigned role that contains only "correct" mappings w.r.t. `restricted` expression profile.
</documentation>
<assignment>
<targetRef oid="a2242707-43cd-4f18-b986-573cb468693d" type="ArchetypeType"/>
</assignment>
<autoassign>
<enabled>true</enabled>
<focus>
<mapping>
<expression>
<script>
<code>
assignment // compliant
</code>
</script>
</expression>
<condition>
<script>
<code>true</code> <!-- compliant -->
</script>
</condition>
</mapping>
<selector>
<type>UserType</type>
<filter>
<q:equal>
<q:path>costCenter</q:path>
<q:value>auto</q:value> <!-- no scripting expressions here are supported for now -->
</q:equal>
</filter>
</selector>
</focus>
</autoassign>
</role>

0 comments on commit 50624f1

Please sign in to comment.