diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/ExpressionConstants.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/ExpressionConstants.java index db85c3146dc..991feb5e5d4 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/ExpressionConstants.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/ExpressionConstants.java @@ -112,4 +112,8 @@ public class ExpressionConstants { public static final QName VAR_OBJECT_DISPLAY_INFORMATION = new QName(SchemaConstants.NS_C, "objectDisplayInformation"); public static final QName VAR_TARGET_DISPLAY_INFORMATION = new QName(SchemaConstants.NS_C, "targetDisplayInformation"); + + public static final QName VAR_PERFORMER = new QName(SchemaConstants.NS_C, "performer"); + public static final QName VAR_OUTPUT = new QName(SchemaConstants.NS_C, "output"); + public static final QName VAR_EVENT = new QName(SchemaConstants.NS_C, "event"); } diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java index 85b02734c56..ac26ac3adf0 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java @@ -205,6 +205,8 @@ public abstract class SchemaConstants { public static final ItemPath PATH_PASSWORD = new ItemPath(C_CREDENTIALS, CredentialsType.F_PASSWORD); public static final ItemPath PATH_PASSWORD_VALUE = new ItemPath(C_CREDENTIALS, CredentialsType.F_PASSWORD, PasswordType.F_VALUE); + public static final ItemPath PATH_PASSWORD_FORCE_CHANGE = new ItemPath(C_CREDENTIALS, CredentialsType.F_PASSWORD, + PasswordType.F_FORCE_CHANGE); public static final ItemPath PATH_PASSWORD_METADATA = new ItemPath(C_CREDENTIALS, CredentialsType.F_PASSWORD, PasswordType.F_METADATA); public static final ItemPath PATH_NONCE = new ItemPath(C_CREDENTIALS, CredentialsType.F_NONCE); diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ObjectTypeUtil.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ObjectTypeUtil.java index 2f65631e5dd..9231a3b8eaa 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ObjectTypeUtil.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ObjectTypeUtil.java @@ -615,6 +615,7 @@ public static T getExtensionItemRealValue(@Nullable ExtensionType extension, return item != null ? (T) item.getRealValue() : null; } + @NotNull public static QName normalizeRelation(QName name) { if (name == null) { return SchemaConstants.ORG_DEFAULT; diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-certification-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-certification-3.xsd index a944c508494..38e94e3c25b 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-certification-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-certification-3.xsd @@ -1355,6 +1355,18 @@ + + + + Instructions how to format reviewers comments before storing them into metadata. + EXPERIMENTAL + + + true + 3.7.1 + + + 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 c860a1b4f8b..d3fd3eb45af 100755 --- 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 @@ -3846,7 +3846,7 @@ - + Exact order to match. This is a short-hand for setting both @@ -3854,7 +3854,7 @@ - + Minimum matching order. Applicable only if "order" element is not set. @@ -3862,7 +3862,7 @@ - + Maximum matching order. Applicable only if "order" element is not set. @@ -3870,7 +3870,7 @@ - + The new value for order for this relation (or summary order), to be used when @@ -3878,7 +3878,7 @@ - + Relation to which the order constraints apply. If none present, summary (i.e. non-delegation) order is considered. @@ -14575,7 +14575,15 @@ - + + + + + + + + + @@ -14587,6 +14595,79 @@ + + + + + + + + + + + + + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-policy-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-policy-3.xsd index 8120dd5a675..de0e19c55ba 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-policy-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-policy-3.xsd @@ -638,7 +638,39 @@ - + + + + Specification of relation(s) when this exclusion constraint should be applied at the source side. + (I.e. this is evaluated against the object defining this exclusion constraint.) + The default is "order = 1". + + EXPERIMENTAL. Currently it does not work with non-member relations because of assignment + evaluation optimizations (see TestSegregationOfDuties.test950JackSelfExclusion). So it can + be used only for default and manager relations. + + + 3.7.1 + + + + + + + Specification of relation(s) when this exclusion constraint should be applied at the target side. + (I.e. this is evaluated against the target object.) + The default is "order = 1". + + EXPERIMENTAL. Currently it does not work with non-member relations because of assignment + evaluation optimizations (see TestSegregationOfDuties.test950JackSelfExclusion). So it can + be used only for default and manager relations. + + + 3.7.1 + + + + true diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-workflows-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-workflows-3.xsd index 58265c9d566..6a3f275c0e1 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-workflows-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-workflows-3.xsd @@ -647,11 +647,61 @@ + + + + Instructions how to format approvers comments before storing them into metadata. + EXPERIMENTAL + + + true + 3.7.1 + + + + + + + Instructions how to format approvers/reviewers comments before storing them into metadata. + Normally midPoint stores comments as they were entered by performers. However, each deployment can + tailor these e.g. by including performer name along with the comment. + EXPERIMENTAL + + + true + 3.7.1 + + + + + + + How to construct the comment. For example: performer.fullName + ': ' + output.comment. + + Available variables: + - performer (i.e. reviewer or approver), + - output (of AbstractWorkItemOutputType), + - workItem (of AbstractWorkItemType - only for certification), + - event (of WorkItemCompletionEventType - only for approvals). + + + + + + + Whether to include the particular output in comments. For example: output.comment != null. + Null or empty values are skipped regardless of the condition. + + + + + + diff --git a/model/certification-impl/pom.xml b/model/certification-impl/pom.xml index b481b23e030..27916b7a254 100644 --- a/model/certification-impl/pom.xml +++ b/model/certification-impl/pom.xml @@ -1,6 +1,6 @@ - - - - - - - - - - - - - - - - - - diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java index 72289ebab0f..1889a4b1e57 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java @@ -326,4 +326,9 @@ LocalizableMessageType createLocalizableMessageType(LocalizableMessageTemplateTy Map variables, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException; + + public CredentialResetResponseType requestCredentialsReset(PrismObject focus, String credentialsId, + CredentialsResetPolicyType resetMethod, Task task, OperationResult result) + throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, + SecurityViolationException, ExpressionEvaluationException, ObjectAlreadyExistsException, PolicyViolationException; } diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/AssignmentPath.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/AssignmentPath.java index 7b6f038bf3e..b6e2cd7b590 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/AssignmentPath.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/AssignmentPath.java @@ -26,6 +26,7 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentPathType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ExtensionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.OrderConstraintsType; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -89,6 +90,13 @@ public interface AssignmentPath extends DebugDumpable, ShortDumpable { */ ObjectType getProtoRole(); + /** + * Shallow clone. + */ + AssignmentPath clone(); + + AssignmentPath cloneFirst(int n); + AssignmentPathType toAssignmentPathType(boolean includeAssignmentsContent); ExtensionType collectExtensions(int startAt) throws SchemaException; @@ -104,4 +112,17 @@ default AssignmentPathSegment getAt(int index) { return getSegment(index); } + /** + * Returns true if the path matches specified order constraints. All of them must match. + * Although there are some defaults, it is recommended to specify constraints explicitly. + * Currently not supported on empty paths. + * + * Not all parts of OrderConstraintsType are supported. Namely, resetOrder item has no meaning here. + */ + boolean matches(@NotNull List orderConstraints); + + /** + * Preliminary (limited) implementation. To be used to compare paths pointing to the same target object. Use with care. + */ + boolean equivalent(AssignmentPath other); } diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/AssignmentPathSegment.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/AssignmentPathSegment.java index c92be33f1c5..e04d316d150 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/AssignmentPathSegment.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/AssignmentPathSegment.java @@ -23,8 +23,11 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentPathSegmentType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.OrderConstraintsType; import org.jetbrains.annotations.NotNull; +import java.util.List; + /** * Single assignment in an assignment path. In addition to the AssignmentType, it contains resolved target: * full object, resolved from targetRef. If targetRef resolves to multiple objects, in the path segment @@ -77,4 +80,13 @@ public interface AssignmentPathSegment extends DebugDumpable, ShortDumpable { @NotNull AssignmentPathSegmentType toAssignmentPathSegmentType(boolean includeAssignmentsContent); + + /** + * Returns true if the path segment matches specified order constraints. All of them must match. + * Although there are some defaults, it is recommended to specify constraints explicitly. + */ + boolean matches(@NotNull List orderConstraints); + + // Preliminary limited implementation. Use with care. + boolean equivalent(AssignmentPathSegment otherSegment); } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java index bbefdde8d25..0dd21f4b9f0 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java @@ -52,7 +52,9 @@ import com.evolveum.midpoint.repo.common.expression.ObjectDeltaObject; import com.evolveum.midpoint.schema.*; import com.evolveum.midpoint.schema.constants.SchemaConstants; +import com.evolveum.midpoint.schema.util.LocalizationUtil; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; +import com.evolveum.midpoint.schema.util.SecurityPolicyUtil; import com.evolveum.midpoint.security.api.MidPointPrincipal; import com.evolveum.midpoint.security.api.SecurityContextManager; import com.evolveum.midpoint.security.api.UserProfileService; @@ -106,7 +108,11 @@ import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.DisplayableValue; +import com.evolveum.midpoint.util.LocalizableMessage; +import com.evolveum.midpoint.util.LocalizableMessageBuilder; +import com.evolveum.midpoint.util.MiscUtil; import com.evolveum.midpoint.util.QNameUtil; +import com.evolveum.midpoint.util.SingleLocalizableMessage; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; @@ -1464,4 +1470,72 @@ public LocalizableMessageType createLocalizableMessageType(LocalizableMessageTem vars.addVariableDefinitions(variables); return LensUtil.interpretLocalizableMessageTemplate(template, vars, expressionFactory, prismContext, task, result); } + + @Override + public CredentialResetResponseType requestCredentialsReset(PrismObject user, String credentialsId, + CredentialsResetPolicyType resetMethod, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, + SecurityViolationException, ExpressionEvaluationException, ObjectAlreadyExistsException, PolicyViolationException { + +// CredentialSourceType credentialSource = resetMethod.getNewCredentialSource(); +// +// CredentialSourceTypeType credentialSourceType = null; +// if (credentialSource != null) { +// credentialSourceType = credentialSource.getCredentialSource(); +// } + +// SecurityPolicyType securityPolicyType = getSecurityPolicy(user, task, parentResult); +// +// String authenticationName = resetMethod.getAuthenticationName(); +// if (authenticationName != null) { +// AbstractAuthenticationPolicyType authPolicy = SecurityPolicyUtil +// .getAuthenticationPolicy(authenticationName, securityPolicyType); +// } + + + ValuePolicyType valuePolicyType = getValuePolicy(user, task, parentResult); + String newPassword = generateValue(valuePolicyType, 8, false, user, "generate password for user", task, parentResult); +// if (credentialSourceType == null) { +// ValuePolicyType valuePolicyType = getValuePolicy(user, task, parentResult); +// newPassword = generateValue(valuePolicyType, 8, false, user, "generate password for user", task, parentResult); +// } else { +// switch(credentialSourceType) { +// case GENERATE: +// ValuePolicyType valuePolicyType = getValuePolicy(user, task, parentResult); +// newPassword = generateValue(valuePolicyType, 8, false, user, "generate password for user", task, parentResult); +// break; +// default: +// valuePolicyType = getValuePolicy(user, task, parentResult); +// newPassword = generateValue(valuePolicyType, 8, false, user, "generate password for user", task, parentResult); +// break; +// } +// } + + ProtectedStringType newProtectedPassword = new ProtectedStringType(); + newProtectedPassword.setClearValue(newPassword); + ObjectDelta passwordObjectDelta = ObjectDelta.createModificationReplaceProperty(UserType.class, user.getOid(), + SchemaConstants.PATH_PASSWORD_VALUE, prismContext, newPassword); + + if (BooleanUtils.isTrue(resetMethod.isForceChange())) { + passwordObjectDelta.addModificationReplaceProperty(SchemaConstants.PATH_PASSWORD_FORCE_CHANGE, Boolean.TRUE); + } + + Collection> result = modelService.executeChanges( + MiscUtil.createCollection(passwordObjectDelta), ModelExecuteOptions.createRaw(), task, parentResult); + + parentResult.recomputeStatus(); + + CredentialResetResponseType response = new CredentialResetResponseType(); + response.setNewCredential(newPassword); + // TODO work with the result + LocalizableMessage message = LocalizableMessageBuilder.buildFallbackMessage("Reset password successfull."); + + response.setMessage(LocalizationUtil.createLocalizableMessageType(message)); + + + + +// cacheRepositoryService.modifyObject(type, oid, modifications, parentResult); + return response; + } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathImpl.java index 0b59d0a6aa7..f995429fc01 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathImpl.java @@ -30,6 +30,7 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentPathType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ExtensionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.OrderConstraintsType; import org.jetbrains.annotations.NotNull; /** @@ -149,12 +150,15 @@ public ObjectType getProtoRole() { return protoRole; } - /** - * Shallow clone. - */ + @Override public AssignmentPathImpl clone() { + return cloneFirst(size()); + } + + @Override + public AssignmentPathImpl cloneFirst(int n) { AssignmentPathImpl clone = new AssignmentPathImpl(prismContext); - clone.segments.addAll(this.segments); + clone.segments.addAll(this.segments.subList(0, n)); return clone; } @@ -246,4 +250,28 @@ public PrismContext getPrismContext() { public ExtensionType collectExtensions(int startAt) throws SchemaException { return AssignmentPathUtil.collectExtensions(this, startAt, prismContext); } + + @Override + public boolean matches(@NotNull List orderConstraints) { + if (isEmpty()) { + throw new UnsupportedOperationException("Checking order constraints on empty assignment path is not currently supported."); + } else { + return last().matches(orderConstraints); + } + } + + @Override + public boolean equivalent(AssignmentPath other) { + if (size() != other.size()) { + return false; + } + for (int i = 0; i < segments.size(); i++) { + AssignmentPathSegment segment = segments.get(i); + AssignmentPathSegment otherSegment = other.getSegments().get(i); + if (!segment.equivalent(otherSegment)) { + return false; + } + } + return true; + } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathSegmentImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathSegmentImpl.java index a652ced5869..a3c462005f9 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathSegmentImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathSegmentImpl.java @@ -631,4 +631,25 @@ public Integer getLastEqualOrderSegmentIndex() { public void setLastEqualOrderSegmentIndex(Integer lastEqualOrderSegmentIndex) { this.lastEqualOrderSegmentIndex = lastEqualOrderSegmentIndex; } + + @Override + public boolean matches(@NotNull List orderConstraints) { + return computeMatchingOrder(evaluationOrder, null, orderConstraints); + } + + // preliminary implementation; use only to compare segments in paths (pointing to the same target OID) + // that are to be checked for equivalency + @Override + public boolean equivalent(AssignmentPathSegment otherSegment) { + if (!ObjectTypeUtil.relationsEquivalent(relation, otherSegment.getRelation())) { + return false; + } + if (target == null && otherSegment.getTarget() == null) { + return true; // TODO reconsider this in general case + } + if (target == null || otherSegment.getTarget() == null) { + return false; + } + return java.util.Objects.equals(target.getOid(), otherSegment.getTarget().getOid()); + } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedPolicyRuleImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedPolicyRuleImpl.java index 6dd956f9d0e..b7d07e70003 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedPolicyRuleImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedPolicyRuleImpl.java @@ -77,6 +77,8 @@ public class EvaluatedPolicyRuleImpl implements EvaluatedPolicyRule { * This is what assignmentPath (Engineer->Employee->(maybe some metarole)->rule) and directOwner (Employee) are for. * * For global policy rules, assignmentPath is the path to the target object that matched global policy rule. + * + * TODO When it can be null? */ @Nullable private final AssignmentPath assignmentPath; @Nullable private final ObjectType directOwner; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluationOrderImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluationOrderImpl.java index 9a0e63ff0f4..98bea9869ca 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluationOrderImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluationOrderImpl.java @@ -107,13 +107,16 @@ public EvaluationOrder decrease(MultiSet relations) { // must always be private: public interface will not allow to modify object state! private void advanceThis(QName relation, int amount) { - relation = ObjectTypeUtil.normalizeRelation(relation); - orderMap.put(relation, getMatchingRelationOrder(relation) + amount); + @NotNull QName normalizedRelation = ObjectTypeUtil.normalizeRelation(relation); + orderMap.put(normalizedRelation, getMatchingRelationOrder(normalizedRelation) + amount); } @Override public int getMatchingRelationOrder(QName relation) { checkConsistence(); + if (relation == null) { + return getSummaryOrder(); + } return orderMap.getOrDefault(ObjectTypeUtil.normalizeRelation(relation), 0); } @@ -133,6 +136,7 @@ public Map diff(EvaluationOrder newState) { @SuppressWarnings({"unchecked", "raw"}) Collection relations = CollectionUtils.union(getRelations(), newState.getRelations()); Map rv = new HashMap<>(); + // relation is not null below relations.forEach(relation -> rv.put(relation, newState.getMatchingRelationOrder(relation) - getMatchingRelationOrder(relation))); return rv; } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ConsolidationProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ConsolidationProcessor.java index 771bba6f33b..a9e6399e165 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ConsolidationProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ConsolidationProcessor.java @@ -196,9 +196,11 @@ private ObjectDelta consolidateValuesToModifyD LOGGER.trace("Object class definition for {} consolidation:\n{}", projCtx.getResourceShadowDiscriminator(), rOcDef.debugDump()); } - consolidateAttributes(context, projCtx, addUnchangedValues, rOcDef, objectDelta, existingDelta, StrengthSelector.ALL_EXCEPT_WEAK); + + StrengthSelector strengthSelector = projCtx.isAdd() ? StrengthSelector.ALL : StrengthSelector.ALL_EXCEPT_WEAK; + consolidateAttributes(context, projCtx, addUnchangedValues, rOcDef, objectDelta, existingDelta, strengthSelector); - consolidateAssociations(context, projCtx, addUnchangedValues, rOcDef, objectDelta, existingDelta, StrengthSelector.ALL_EXCEPT_WEAK); + consolidateAssociations(context, projCtx, addUnchangedValues, rOcDef, objectDelta, existingDelta, strengthSelector); return objectDelta; } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/evaluators/ExclusionConstraintEvaluator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/evaluators/ExclusionConstraintEvaluator.java index 5e0b511aa88..f1a48c588b8 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/evaluators/ExclusionConstraintEvaluator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/evaluators/ExclusionConstraintEvaluator.java @@ -17,10 +17,7 @@ package com.evolveum.midpoint.model.impl.lens.projector.policy.evaluators; import com.evolveum.midpoint.common.LocalizationService; -import com.evolveum.midpoint.model.api.context.AssignmentPath; -import com.evolveum.midpoint.model.api.context.EvaluatedExclusionTrigger; -import com.evolveum.midpoint.model.api.context.EvaluatedPolicyRule; -import com.evolveum.midpoint.model.api.context.EvaluatedPolicyRuleTrigger; +import com.evolveum.midpoint.model.api.context.*; import com.evolveum.midpoint.model.impl.lens.EvaluatedAssignmentImpl; import com.evolveum.midpoint.model.impl.lens.EvaluatedAssignmentTargetImpl; import com.evolveum.midpoint.model.impl.lens.LensContext; @@ -45,10 +42,7 @@ import com.evolveum.midpoint.util.exception.PolicyViolationException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SecurityViolationException; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ExclusionPolicyConstraintType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType; import com.evolveum.prism.xml.ns._public.types_3.EvaluationTimeType; import org.jetbrains.annotations.NotNull; @@ -58,8 +52,8 @@ import javax.xml.bind.JAXBElement; import javax.xml.namespace.QName; import java.util.Collection; +import java.util.Collections; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; import static com.evolveum.midpoint.util.LocalizableMessageBuilder.buildFallbackMessage; @@ -91,32 +85,87 @@ public EvaluatedPolicyRuleTrigger evaluate(JAXBElement sourceOrderConstraints = defaultIfEmpty(constraint.getValue().getOrderConstraint()); + List targetOrderConstraints = defaultIfEmpty(constraint.getValue().getTargetOrderConstraint()); + if (ctx.policyRule.isGlobal()) { + if (!pathMatches(ctx.policyRule.getAssignmentPath(), sourceOrderConstraints)) { + System.out.println("[global] Source assignment path does not match: " + ctx.policyRule.getAssignmentPath()); + return null; + } + } else { + // It is not clear how to match orderConstraint with assignment path of the constraint. + // Let us try the following test: we consider it matching if there's at least one segment + // on the path that matches the constraint. + boolean found = ctx.policyRule.getAssignmentPath().getSegments().stream() + .anyMatch(segment -> segment.matches(sourceOrderConstraints)); + if (!found) { +// System.out.println("Source assignment path does not match: constraints=" + sourceOrderConstraints + ", whole path=" + ctx.policyRule.getAssignmentPath()); + return null; + } + } + // We consider all policy rules, i.e. also from induced targets. (It is not possible to collect local // rules for individual targets in the chain - rules are computed only for directly evaluated assignments.) - // In order to avoid false positives, we consider all targets from the current assignment as "allowed" - Set allowedTargetOids = ctx.evaluatedAssignment.getNonNegativeTargets().stream() - .filter(t -> t.appliesToFocus()) - .map(t -> t.getOid()) - .collect(Collectors.toSet()); +// // In order to avoid false positives, we consider all targets from the current assignment as "allowed" +// Set allowedTargetOids = ctx.evaluatedAssignment.getNonNegativeTargets().stream() +// .filter(t -> t.appliesToFocus()) +// .map(t -> t.getOid()) +// .collect(Collectors.toSet()); + + List nonNegativeTargetsA = ctx.evaluatedAssignment.getNonNegativeTargets(); for (EvaluatedAssignmentImpl assignmentB : ctx.evaluatedAssignmentTriple.getNonNegativeValues()) { - for (EvaluatedAssignmentTargetImpl targetB : assignmentB.getNonNegativeTargets()) { - if (!targetB.appliesToFocus() || allowedTargetOids.contains(targetB.getOid())) { + if (assignmentB.equals(ctx.evaluatedAssignment)) { // TODO (value instead of reference equality?) + continue; + } +targetB: for (EvaluatedAssignmentTargetImpl targetB : assignmentB.getNonNegativeTargets()) { + if (!pathMatches(targetB.getAssignmentPath(), targetOrderConstraints)) { +// System.out.println("Target assignment path does not match: constraints=" + targetOrderConstraints + ", whole path=" + targetB.getAssignmentPath()); continue; } - if (matches(constraint.getValue().getTargetRef(), targetB, prismContext, matchingRuleRegistry, "exclusion constraint")) { - return createTrigger(ctx.evaluatedAssignment, assignmentB, targetB, constraint.getValue(), ctx.policyRule, ctx, result); + if (!oidMatches(constraint.getValue().getTargetRef(), targetB, prismContext, matchingRuleRegistry, "exclusion constraint")) { + continue; + } + // To avoid false positives let us check if this target is not already covered by assignment being evaluated + // (is this really needed?) + for (EvaluatedAssignmentTargetImpl targetA : nonNegativeTargetsA) { + if (targetA.appliesToFocusWithAnyRelation() + && targetA.getOid() != null && targetA.getOid().equals(targetB.getOid()) + && targetA.getAssignmentPath().equivalent(targetB.getAssignmentPath())) { + continue targetB; + } } + return createTrigger(ctx.evaluatedAssignment, assignmentB, targetB, constraint.getValue(), ctx.policyRule, ctx, result); } } return null; } - static boolean matches(ObjectReferenceType targetRef, EvaluatedAssignmentTargetImpl assignmentTarget, + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + private boolean pathMatches(AssignmentPath assignmentPath, List definedOrderConstraints) { + if (assignmentPath == null) { + throw new IllegalStateException("Check this. Assignment path is null."); + } + if (assignmentPath.isEmpty()) { + throw new IllegalStateException("Check this. Assignment path is empty."); + } + return assignmentPath.matches(definedOrderConstraints); + } + + @NotNull + private List defaultIfEmpty(List definedOrderConstraints) { + return !definedOrderConstraints.isEmpty() ? definedOrderConstraints : defaultOrderConstraints(); + } + + private List defaultOrderConstraints() { + return Collections.singletonList(new OrderConstraintsType(prismContext).order(1)); + } + + static boolean oidMatches(ObjectReferenceType targetRef, EvaluatedAssignmentTargetImpl assignmentTarget, PrismContext prismContext, MatchingRuleRegistry matchingRuleRegistry, String context) throws SchemaException { if (targetRef == null) { - throw new SchemaException("No targetRef in " + context); + return true; // this means we rely on comparing relations } if (assignmentTarget.getOid() == null) { return false; // shouldn't occur diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/evaluators/HasAssignmentConstraintEvaluator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/evaluators/HasAssignmentConstraintEvaluator.java index 76ddde3cd07..591330ff5af 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/evaluators/HasAssignmentConstraintEvaluator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/evaluators/HasAssignmentConstraintEvaluator.java @@ -111,7 +111,7 @@ public EvaluatedPolicyRuleTrigger evaluate(JAXBElement names = new ArrayList<>(); - for (QName relation : order.getRelations()) { + for (@NotNull QName relation : order.getRelations()) { int count = order.getMatchingRelationOrder(relation); if (count == 0) { continue; diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestSegregationOfDuties.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestSegregationOfDuties.java index 47323316036..9a1880131e2 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestSegregationOfDuties.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestSegregationOfDuties.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Evolveum + * Copyright (c) 2010-2018 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import java.util.List; import java.util.function.Consumer; +import com.evolveum.midpoint.model.api.ModelExecuteOptions; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext.ClassMode; import org.springframework.test.context.ContextConfiguration; @@ -40,6 +41,7 @@ import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.util.PrismAsserts; +import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.MiscSchemaUtil; import com.evolveum.midpoint.task.api.Task; @@ -139,6 +141,12 @@ public class TestSegregationOfDuties extends AbstractInitializedModelIntegration protected static final File ROLE_CRIMINAL_FILE = new File(TEST_DIR, "role-criminal.xml"); protected static final String ROLE_CRIMINAL_OID = "f6deb182-55a3-11e7-b519-27bdcd6d9490"; + protected static final File ROLE_SELF_EXCLUSION_FILE = new File(TEST_DIR, "role-self-exclusion.xml"); + protected static final String ROLE_SELF_EXCLUSION_OID = "9577bd6c-dd5d-48e5-bbb1-554bba5db9be"; + + protected static final File ROLE_SELF_EXCLUSION_MANAGER_MEMBER_FILE = new File(TEST_DIR, "role-self-exclusion-manager-member.xml"); + protected static final String ROLE_SELF_EXCLUSION_MANAGER_MEMBER_OID = "aeed4751-fad6-4c4e-9ece-c793128e0c13"; + private static final File CONFIG_WITH_GLOBAL_RULES_EXCLUSION_FILE = new File(TEST_DIR, "global-policy-rules-exclusion.xml"); private static final File CONFIG_WITH_GLOBAL_RULES_SOD_APPROVAL_FILE = new File(TEST_DIR, "global-policy-rules-sod-approval.xml"); @@ -168,6 +176,8 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti repoAddObjectFromFile(ROLE_CITIZEN_US_FILE, initResult); repoAddObjectFromFile(ROLE_MINISTER_FILE, initResult); repoAddObjectFromFile(ROLE_CRIMINAL_FILE, initResult); + repoAddObjectFromFile(ROLE_SELF_EXCLUSION_FILE, initResult); + repoAddObjectFromFile(ROLE_SELF_EXCLUSION_MANAGER_MEMBER_FILE, initResult); } @Test @@ -293,7 +303,6 @@ public void test130SimpleExclusionBoth1() throws Exception { modifications.add((createAssignmentModification(ROLE_PIRATE_OID, RoleType.COMPLEX_TYPE, null, null, null, true))); ObjectDelta userDelta = ObjectDelta.createModifyDelta(USER_JACK_OID, modifications, UserType.class, prismContext); - try { modelService.executeChanges(MiscSchemaUtil.createCollection(userDelta), null, task, result); @@ -318,7 +327,6 @@ public void test132SimpleExclusionBoth1Deprecated() throws Exception { modifications.add((createAssignmentModification(ROLE_PIRATE_OID, RoleType.COMPLEX_TYPE, null, null, null, true))); ObjectDelta userDelta = ObjectDelta.createModifyDelta(USER_JACK_OID, modifications, UserType.class, prismContext); - try { modelService.executeChanges(MiscSchemaUtil.createCollection(userDelta), null, task, result); @@ -343,7 +351,6 @@ public void test140SimpleExclusionBoth2() throws Exception { modifications.add((createAssignmentModification(ROLE_JUDGE_OID, RoleType.COMPLEX_TYPE, null, null, null, true))); ObjectDelta userDelta = ObjectDelta.createModifyDelta(USER_JACK_OID, modifications, UserType.class, prismContext); - try { modelService.executeChanges(MiscSchemaUtil.createCollection(userDelta), null, task, result); @@ -368,7 +375,6 @@ public void test142SimpleExclusionBoth2Deprecated() throws Exception { modifications.add((createAssignmentModification(ROLE_JUDGE_DEPRECATED_OID, RoleType.COMPLEX_TYPE, null, null, null, true))); ObjectDelta userDelta = ObjectDelta.createModifyDelta(USER_JACK_OID, modifications, UserType.class, prismContext); - try { modelService.executeChanges(MiscSchemaUtil.createCollection(userDelta), null, task, result); @@ -561,6 +567,125 @@ Consumer getJudgeExceptionBlock(String excludedRoleName) { }; } + @Test + public void test190DifferentRelations() throws Exception { + final String TEST_NAME = "test190DifferentRelations"; + displayTestTitle(TEST_NAME); + + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + + Collection> modifications = new ArrayList<>(); + modifications.add((createAssignmentModification(ROLE_JUDGE_OID, RoleType.COMPLEX_TYPE, SchemaConstants.ORG_APPROVER, null, null, true))); + modifications.add((createAssignmentModification(ROLE_PIRATE_OID, RoleType.COMPLEX_TYPE, null, null, null, true))); + ObjectDelta userDelta = ObjectDelta.createModifyDelta(USER_JACK_OID, modifications, UserType.class, prismContext); + + try { + modelService.executeChanges(MiscSchemaUtil.createCollection(userDelta), null, task, result); + } finally { + unassignRole(USER_JACK_OID, ROLE_JUDGE_OID, SchemaConstants.ORG_APPROVER, task, result); + unassignRole(USER_JACK_OID, ROLE_PIRATE_OID, task, result); + } + + assertAssignedNoRole(USER_JACK_OID, task, result); + } + + @Test + public void test191DifferentRelationsDeprecatedCase1() throws Exception { + final String TEST_NAME = "test191DifferentRelationsCase1"; + displayTestTitle(TEST_NAME); + + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + + Collection> modifications = new ArrayList<>(); + modifications.add((createAssignmentModification(ROLE_JUDGE_DEPRECATED_OID, RoleType.COMPLEX_TYPE, SchemaConstants.ORG_APPROVER, null, true))); + modifications.add((createAssignmentModification(ROLE_PIRATE_OID, RoleType.COMPLEX_TYPE, null, null, null, true))); + ObjectDelta userDelta = ObjectDelta.createModifyDelta(USER_JACK_OID, modifications, UserType.class, prismContext); + + try { + modelService.executeChanges(MiscSchemaUtil.createCollection(userDelta), null, task, result); + } finally { + unassignRole(USER_JACK_OID, ROLE_JUDGE_DEPRECATED_OID, SchemaConstants.ORG_APPROVER, task, result); + unassignRole(USER_JACK_OID, ROLE_PIRATE_OID, task, result); + } + + assertAssignedNoRole(USER_JACK_OID, task, result); + } + + @Test + public void test192DifferentRelationsDeprecatedCase2() throws Exception { + final String TEST_NAME = "test191DifferentRelationsCase1"; + displayTestTitle(TEST_NAME); + + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + + Collection> modifications = new ArrayList<>(); + modifications.add((createAssignmentModification(ROLE_JUDGE_DEPRECATED_OID, RoleType.COMPLEX_TYPE, null, null, true))); + modifications.add((createAssignmentModification(ROLE_PIRATE_OID, RoleType.COMPLEX_TYPE, SchemaConstants.ORG_APPROVER, null, null, true))); + ObjectDelta userDelta = ObjectDelta.createModifyDelta(USER_JACK_OID, modifications, UserType.class, prismContext); + + try { + modelService.executeChanges(MiscSchemaUtil.createCollection(userDelta), null, task, result); + } finally { + unassignRole(USER_JACK_OID, ROLE_JUDGE_DEPRECATED_OID, task, result); + unassignRole(USER_JACK_OID, ROLE_PIRATE_OID, SchemaConstants.ORG_APPROVER, task, result); + } + + assertAssignedNoRole(USER_JACK_OID, task, result); + } + + @Test + public void test193BothRelationsApprover() throws Exception { + final String TEST_NAME = "test193BothRelationsApprover"; + displayTestTitle(TEST_NAME); + + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + + Collection> modifications = new ArrayList<>(); + modifications.add((createAssignmentModification(ROLE_JUDGE_OID, RoleType.COMPLEX_TYPE, SchemaConstants.ORG_APPROVER, null, null, true))); + modifications.add((createAssignmentModification(ROLE_PIRATE_OID, RoleType.COMPLEX_TYPE, SchemaConstants.ORG_APPROVER, null, null, true))); + ObjectDelta userDelta = ObjectDelta.createModifyDelta(USER_JACK_OID, modifications, UserType.class, prismContext); + + try { + modelService.executeChanges(MiscSchemaUtil.createCollection(userDelta), null, task, result); + } finally { + unassignRole(USER_JACK_OID, ROLE_JUDGE_OID, SchemaConstants.ORG_APPROVER, task, result); + unassignRole(USER_JACK_OID, ROLE_PIRATE_OID, SchemaConstants.ORG_APPROVER, task, result); + } + + assertAssignedNoRole(USER_JACK_OID, task, result); + } + + @Test + public void test194MemberAndManager() throws Exception { + final String TEST_NAME = "test194MemberAndManager"; + displayTestTitle(TEST_NAME); + + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + + Collection> modifications = new ArrayList<>(); + modifications.add((createAssignmentModification(ROLE_JUDGE_OID, RoleType.COMPLEX_TYPE, SchemaConstants.ORG_MANAGER, null, null, true))); + modifications.add((createAssignmentModification(ROLE_PIRATE_OID, RoleType.COMPLEX_TYPE, SchemaConstants.ORG_DEFAULT, null, null, true))); + ObjectDelta userDelta = ObjectDelta.createModifyDelta(USER_JACK_OID, modifications, UserType.class, prismContext); + + try { + modelService.executeChanges(MiscSchemaUtil.createCollection(userDelta), null, task, result); + + AssertJUnit.fail("Expected policy violation, but it went well"); + } catch (PolicyViolationException e) { + System.out.println("Got expected exception: " + e.getMessage()); + } finally { + unassignRole(USER_JACK_OID, ROLE_JUDGE_OID, SchemaConstants.ORG_MANAGER, task, result); + unassignRole(USER_JACK_OID, ROLE_PIRATE_OID, SchemaConstants.ORG_DEFAULT, task, result); + } + + assertAssignedNoRole(USER_JACK_OID, task, result); + } + /** * MID-3685 */ @@ -1548,6 +1673,75 @@ public void test929GuybrushUnassignRoleCriminal() throws Exception { assertNotAssignedRole(userAfter, ROLE_MINISTER_OID); } + /** + * This does not work because of current optimizations regarding non-default relations: + * "2018-02-19 17:02:15,977 [main] DEBUG (c.e.m.model.impl.lens.AssignmentEvaluator): Skipping processing of assignment target 9577bd6c-dd5d-48e5-bbb1-554bba5db9be because + * relation {http://midpoint.evolveum.com/xml/ns/public/common/org-3}approver is configured for recompute skip (mode=ZERO)" + * + * i.e. it works only when evaluateAllAssignmentRelationsOnRecompute option is set + */ + @Test(enabled = false) + public void test950JackSelfExclusion() throws Exception { + final String TEST_NAME = "test950JackSelfExclusion"; + displayTestTitle(TEST_NAME); + + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + + // This should go well + assignRole(USER_JACK_OID, ROLE_SELF_EXCLUSION_OID, SchemaConstants.ORG_APPROVER, task, result); + + assertSuccess(result); + + try { + // This should die + ModelExecuteOptions options = new ModelExecuteOptions(); +// options.setEvaluateAllAssignmentRelationsOnRecompute(true); + assignRole(USER_JACK_OID, ROLE_SELF_EXCLUSION_OID, SchemaConstants.ORG_OWNER, options, task, result); + + fail("Expected policy violation after adding second self-exclusion role, but it went well"); + } catch (PolicyViolationException e) { + System.out.println("Got expected exception: " + e.getMessage()); + //assertMessage(e, "Violation of SoD policy: Role \"Judge\" excludes role \"Pirate\", they cannot be assigned at the same time"); + result.computeStatus(); + assertFailure(result); + } + + unassignRole(USER_JACK_OID, ROLE_SELF_EXCLUSION_OID, SchemaConstants.ORG_APPROVER, task, result); + + assertAssignedNoRole(USER_JACK_OID, task, result); + } + + @Test + public void test952JackSelfExclusionManagerMember() throws Exception { + final String TEST_NAME = "test952JackSelfExclusionManagerMember"; + displayTestTitle(TEST_NAME); + + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + + // This should go well + assignRole(USER_JACK_OID, ROLE_SELF_EXCLUSION_MANAGER_MEMBER_OID, SchemaConstants.ORG_DEFAULT, task, result); + + assertSuccess(result); + + try { + // This should die + assignRole(USER_JACK_OID, ROLE_SELF_EXCLUSION_MANAGER_MEMBER_OID, SchemaConstants.ORG_MANAGER, task, result); + + fail("Expected policy violation after adding second self-exclusion role, but it went well"); + } catch (PolicyViolationException e) { + System.out.println("Got expected exception: " + e.getMessage()); + //assertMessage(e, "Violation of SoD policy: Role \"Judge\" excludes role \"Pirate\", they cannot be assigned at the same time"); + result.computeStatus(); + assertFailure(result); + } + + unassignRole(USER_JACK_OID, ROLE_SELF_EXCLUSION_MANAGER_MEMBER_OID, SchemaConstants.ORG_DEFAULT, task, result); + + assertAssignedNoRole(USER_JACK_OID, task, result); + } + private PrismObject assignRolePolicyFailure(String TEST_NAME, String userOid, String roleOid, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, ObjectAlreadyExistsException, SecurityViolationException { try { // WHEN diff --git a/model/model-intest/src/test/resources/orgstruct/role-meta-piracy-org.xml b/model/model-intest/src/test/resources/orgstruct/role-meta-piracy-org.xml index c9c682890f5..eaa12a1de24 100644 --- a/model/model-intest/src/test/resources/orgstruct/role-meta-piracy-org.xml +++ b/model/model-intest/src/test/resources/orgstruct/role-meta-piracy-org.xml @@ -39,7 +39,7 @@ 1 - + default 0 diff --git a/model/model-intest/src/test/resources/rbac/sod/role-self-exclusion-manager-member.xml b/model/model-intest/src/test/resources/rbac/sod/role-self-exclusion-manager-member.xml new file mode 100644 index 00000000000..d0eeb04919a --- /dev/null +++ b/model/model-intest/src/test/resources/rbac/sod/role-self-exclusion-manager-member.xml @@ -0,0 +1,69 @@ + + + + + self-exclusion-manager-member + + + self exclusion: no manager and member at once + + + + + + 1 + manager + + + 1 + default + + + + + + 1 + default + + + 1 + manager + + + + + + + + + + diff --git a/model/model-intest/src/test/resources/rbac/sod/role-self-exclusion.xml b/model/model-intest/src/test/resources/rbac/sod/role-self-exclusion.xml new file mode 100644 index 00000000000..99a4778f06e --- /dev/null +++ b/model/model-intest/src/test/resources/rbac/sod/role-self-exclusion.xml @@ -0,0 +1,69 @@ + + + + + self-exclusion + + + self exclusion: no owner and approver at once + + + + + + 1 + approver + + + 1 + owner + + + + + + 1 + owner + + + 1 + approver + + + + + + + + + + diff --git a/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/WorkflowManager.java b/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/WorkflowManager.java index bec39248493..fdbbf9e7ad9 100644 --- a/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/WorkflowManager.java +++ b/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/WorkflowManager.java @@ -29,6 +29,7 @@ import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.*; +import com.evolveum.midpoint.wf.util.PerformerCommentsFormatter; import com.evolveum.midpoint.wf.util.ChangesByState; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; @@ -151,4 +152,6 @@ ApprovalSchemaExecutionInformationType getApprovalSchemaExecutionInformation(Str List getApprovalSchemaPreview(ModelContext modelContext, Task opTask, OperationResult parentResult) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, SecurityViolationException, ExpressionEvaluationException; + + PerformerCommentsFormatter createPerformerCommentsFormatter(PerformerCommentsFormattingType formatting); } \ No newline at end of file diff --git a/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/util/PerformerCommentsFormatter.java b/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/util/PerformerCommentsFormatter.java new file mode 100644 index 00000000000..d8b496800c6 --- /dev/null +++ b/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/util/PerformerCommentsFormatter.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2010-2018 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.wf.util; + +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractWorkItemType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemCompletionEventType; +import org.jetbrains.annotations.NotNull; + +/** + * Ensures formatting of performers (approvers, reviewers) comments before storing them into metadata. + * May optimize repository accesses by caching performers information retrieved. + * + * @author mederly + */ +public interface PerformerCommentsFormatter { + + String formatComment(@NotNull AbstractWorkItemType workItem, Task task, OperationResult result); + + String formatComment(@NotNull WorkItemCompletionEventType event, Task task, OperationResult result); + +} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/WorkflowManagerImpl.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/WorkflowManagerImpl.java index 9840a3c1e3d..1675481a6f2 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/WorkflowManagerImpl.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/WorkflowManagerImpl.java @@ -18,12 +18,12 @@ import com.evolveum.midpoint.model.api.ModelInteractionService; import com.evolveum.midpoint.model.api.context.ModelContext; -import com.evolveum.midpoint.model.common.SystemObjectCache; import com.evolveum.midpoint.prism.Containerable; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.schema.GetOperationOptions; import com.evolveum.midpoint.schema.SearchResultList; import com.evolveum.midpoint.schema.SelectorOptions; @@ -41,9 +41,12 @@ import com.evolveum.midpoint.wf.impl.activiti.dao.ProcessInstanceProvider; import com.evolveum.midpoint.wf.impl.activiti.dao.WorkItemManager; import com.evolveum.midpoint.wf.impl.activiti.dao.WorkItemProvider; +import com.evolveum.midpoint.wf.impl.processes.common.WfExpressionEvaluationHelper; import com.evolveum.midpoint.wf.impl.tasks.WfTaskController; import com.evolveum.midpoint.wf.impl.tasks.WfTaskUtil; +import com.evolveum.midpoint.wf.impl.util.PerformerCommentsFormatterImpl; import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; +import com.evolveum.midpoint.wf.util.PerformerCommentsFormatter; import com.evolveum.midpoint.wf.util.ApprovalUtils; import com.evolveum.midpoint.wf.util.ChangesByState; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; @@ -74,8 +77,9 @@ public class WorkflowManagerImpl implements WorkflowManager, TaskDeletionListene @Autowired private WfTaskUtil wfTaskUtil; @Autowired private MiscDataUtil miscDataUtil; @Autowired private ApprovalSchemaExecutionInformationHelper approvalSchemaExecutionInformationHelper; - @Autowired private SystemObjectCache systemObjectCache; @Autowired private TaskManager taskManager; + @Autowired private RepositoryService repositoryService; + @Autowired private WfExpressionEvaluationHelper expressionEvaluationHelper; private static final String DOT_INTERFACE = WorkflowManager.class.getName() + "."; @@ -310,4 +314,9 @@ public List getApprovalSchemaPreview(Mod result.recordSuccessIfUnknown(); } } + + @Override + public PerformerCommentsFormatter createPerformerCommentsFormatter(PerformerCommentsFormattingType formatting) { + return new PerformerCommentsFormatterImpl(formatting, repositoryService, expressionEvaluationHelper); + } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/WfExpressionEvaluationHelper.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/WfExpressionEvaluationHelper.java index c63c17b4d2e..0bcddd823e0 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/WfExpressionEvaluationHelper.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/WfExpressionEvaluationHelper.java @@ -115,4 +115,12 @@ public boolean evaluateBooleanExpression(ExpressionType expressionType, Expressi Boolean.class, DOMUtil.XSD_BOOLEAN, null, task, result); return MiscUtil.getSingleValue(values, false, contextDescription); } + + public String evaluateStringExpression(ExpressionType expressionType, ExpressionVariables expressionVariables, + String contextDescription, Task task, OperationResult result) + throws ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException { + Collection values = evaluateExpression(expressionType, expressionVariables, contextDescription, + String.class, DOMUtil.XSD_STRING, null, task, result); + return MiscUtil.getSingleValue(values, null, contextDescription); + } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfTaskUtil.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfTaskUtil.java index 1246dedc8d1..3e23d698afe 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfTaskUtil.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfTaskUtil.java @@ -16,6 +16,7 @@ package com.evolveum.midpoint.wf.impl.tasks; import com.evolveum.midpoint.model.api.context.ModelContext; +import com.evolveum.midpoint.model.common.SystemObjectCache; import com.evolveum.midpoint.model.impl.lens.LensContext; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.delta.ItemDelta; @@ -27,14 +28,17 @@ import com.evolveum.midpoint.schema.util.WfContextUtil; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.task.api.TaskBinding; +import com.evolveum.midpoint.task.api.TaskManager; import com.evolveum.midpoint.util.MiscUtil; import com.evolveum.midpoint.util.exception.*; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.wf.api.WorkflowManager; import com.evolveum.midpoint.wf.impl.WfConfiguration; import com.evolveum.midpoint.wf.impl.processors.ChangeProcessor; import com.evolveum.midpoint.schema.ObjectTreeDeltas; import com.evolveum.midpoint.wf.impl.processors.primary.aspect.PrimaryChangeAspect; +import com.evolveum.midpoint.wf.util.PerformerCommentsFormatter; import com.evolveum.midpoint.wf.util.ApprovalUtils; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.apache.commons.lang3.StringUtils; @@ -43,6 +47,7 @@ import org.springframework.stereotype.Component; import java.util.*; +import java.util.Objects; import java.util.stream.Collectors; import static com.evolveum.midpoint.schema.constants.ObjectTypes.TASK; @@ -65,6 +70,9 @@ public class WfTaskUtil { @Autowired private WfConfiguration wfConfiguration; @Autowired private PrismContext prismContext; @Autowired private ProvisioningService provisioningService; + @Autowired private SystemObjectCache systemObjectCache; + @Autowired private TaskManager taskManager; + @Autowired private WorkflowManager workflowManager; private static final Trace LOGGER = TraceManager.getTrace(WfTaskUtil.class); @@ -192,7 +200,7 @@ public String getRootTaskOid(Task task) { return ref != null ? ref.getOid() : null; } - public void deleteModelOperationContext(Task task) throws SchemaException, ObjectNotFoundException { + public void deleteModelOperationContext(Task task) throws SchemaException { task.setModelOperationContext(null); } @@ -210,11 +218,17 @@ public Collection getApprovedByFromTaskTree(Task task, Oper } public Collection getApproverCommentsFromTaskTree(Task task, OperationResult result) throws SchemaException { + Task opTask = taskManager.createTaskInstance(); Collection rv = new HashSet<>(); + PrismObject systemConfiguration = systemObjectCache.getSystemConfiguration(result); + PerformerCommentsFormattingType formatting = systemConfiguration != null && + systemConfiguration.asObjectable().getWorkflowConfiguration() != null ? + systemConfiguration.asObjectable().getWorkflowConfiguration().getApproverCommentsFormatting() : null; + PerformerCommentsFormatter formatter = workflowManager.createPerformerCommentsFormatter(formatting); List tasks = task.listSubtasksDeeply(result); tasks.add(task); for (Task aTask : tasks) { - rv.addAll(getApproverComments(WfContextUtil.getWorkflowContext(aTask.getTaskPrismObject()))); + rv.addAll(getApproverComments(WfContextUtil.getWorkflowContext(aTask.getTaskPrismObject()), formatter, opTask, result)); } return rv; } @@ -229,15 +243,20 @@ private static List getApprovedBy(WfContextType wfc) { } @NotNull - private static Collection getApproverComments(WfContextType wfc) { - return wfc == null ? emptySet() : wfc.getEvent().stream() + private static Collection getApproverComments(WfContextType wfc, PerformerCommentsFormatter formatter, + Task opTask, OperationResult result) { + if (wfc == null) { + return emptySet(); + } + return wfc.getEvent().stream() .flatMap(MiscUtil.instancesOf(WorkItemCompletionEventType.class)) - .filter(e -> ApprovalUtils.isApproved(e.getOutput()) && e.getInitiatorRef() != null && StringUtils.isNotEmpty(e.getOutput().getComment())) - .map(e -> e.getOutput().getComment()) + .filter(e -> ApprovalUtils.isApproved(e.getOutput()) && e.getInitiatorRef() != null) + .map(e -> formatter.formatComment(e, opTask, result)) + .filter(Objects::nonNull) .collect(Collectors.toSet()); } - // handlers are stored in the list in the order they should be executed; so the last one has to be pushed first + // handlers are stored in the list in the order they should be executed; so the last one has to be pushed first void pushHandlers(Task task, List handlers) { for (int i = handlers.size()-1; i >= 0; i--) { UriStackEntry entry = handlers.get(i); diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/util/PerformerCommentsFormatterImpl.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/util/PerformerCommentsFormatterImpl.java new file mode 100644 index 00000000000..a431d77a21c --- /dev/null +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/util/PerformerCommentsFormatterImpl.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2010-2018 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.wf.impl.util; + +import com.evolveum.midpoint.repo.api.RepositoryService; +import com.evolveum.midpoint.repo.common.expression.ExpressionVariables; +import com.evolveum.midpoint.schema.constants.ExpressionConstants; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.exception.*; +import com.evolveum.midpoint.util.logging.LoggingUtils; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.wf.impl.processes.common.WfExpressionEvaluationHelper; +import com.evolveum.midpoint.wf.util.PerformerCommentsFormatter; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author mederly + */ +public class PerformerCommentsFormatterImpl implements PerformerCommentsFormatter { + + private static final Trace LOGGER = TraceManager.getTrace(PerformerCommentsFormatterImpl.class); + + @Nullable private final PerformerCommentsFormattingType formatting; + @NotNull private final RepositoryService repositoryService; + @NotNull private final WfExpressionEvaluationHelper expressionEvaluationHelper; + + private final Map performersCache = new HashMap<>(); + + public PerformerCommentsFormatterImpl(@Nullable PerformerCommentsFormattingType formatting, + @NotNull RepositoryService repositoryService, @NotNull WfExpressionEvaluationHelper expressionEvaluationHelper) { + this.formatting = formatting; + this.repositoryService = repositoryService; + this.expressionEvaluationHelper = expressionEvaluationHelper; + } + + @Override + public String formatComment(@NotNull AbstractWorkItemType workItem, Task task, OperationResult result) { + return formatComment(workItem.getPerformerRef(), workItem.getOutput(), workItem, null, task, result); + } + + @Override + public String formatComment(@NotNull WorkItemCompletionEventType event, Task task, OperationResult result) { + return formatComment(event.getInitiatorRef(), event.getOutput(), null, event, task, result); + } + + private String formatComment(ObjectReferenceType performerRef, AbstractWorkItemOutputType output, AbstractWorkItemType workItem, + WorkItemCompletionEventType event, Task task, OperationResult result) { + if (formatting == null || formatting.getCondition() == null && formatting.getValue() == null) { + return output.getComment(); + } + ObjectType performer = getPerformer(performerRef, result); + ExpressionVariables variables = new ExpressionVariables(); + variables.addVariableDefinition(ExpressionConstants.VAR_PERFORMER, performer); + variables.addVariableDefinition(ExpressionConstants.VAR_OUTPUT, output); + variables.addVariableDefinition(ExpressionConstants.VAR_WORK_ITEM, workItem); + variables.addVariableDefinition(ExpressionConstants.VAR_EVENT, event); + if (formatting.getCondition() != null) { + try { + boolean condition = expressionEvaluationHelper.evaluateBooleanExpression(formatting.getCondition(), variables, + "condition in performer comments formatter", task, result); + if (!condition) { + return null; + } + } catch (CommonException e) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't evaluate condition expression in comments formatter - continuing as if it were true; " + + "performer = {}, output = {}, workItem = {}, event = {}", e, performer, output, workItem, event); + } + } + if (formatting.getValue() != null) { + try { + return expressionEvaluationHelper.evaluateStringExpression(formatting.getValue(), variables, + "value in performer comments formatter", task, result); + } catch (CommonException e) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't evaluate value expression in comments formatter - using plain comment value; " + + "performer = {}, output = {}, workItem = {}, event = {}", e, performer, output, workItem, event); + return output.getComment(); + } + } else { + return output.getComment(); + } + } + + @Nullable + private ObjectType getPerformer(ObjectReferenceType performerRef, OperationResult result) { + if (performerRef == null || performerRef.getOid() == null) { + return null; + } + String performerOid = performerRef.getOid(); + if (performersCache.containsKey(performerOid)) { + return performersCache.get(performerOid); // potentially null (if performer was previously searched for but not found) + } + UserType performer; + try { + performer = repositoryService.getObject(UserType.class, performerOid, null, result).asObjectable(); // TODO other types when needed + } catch (ObjectNotFoundException | SchemaException e) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't resolve performer {}", e, ObjectTypeUtil.toShortString(performerRef)); + performer = null; + } + performersCache.put(performerOid, performer); + return performer; + } +} diff --git a/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/policy/assignments/metarole/TestAssignmentsWithDifferentMetaroles.java b/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/policy/assignments/metarole/TestAssignmentsWithDifferentMetaroles.java index b84293cf98c..5c4eb308ad2 100644 --- a/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/policy/assignments/metarole/TestAssignmentsWithDifferentMetaroles.java +++ b/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/policy/assignments/metarole/TestAssignmentsWithDifferentMetaroles.java @@ -489,7 +489,7 @@ protected void afterFirstClockworkRun(Task rootTask, List subtasks, List jackAfter = getUser(userJackOid); display("jack after", jackAfter); assertAssignedRoles(jackAfter, roleRole29Oid); - assertAssignmentMetadata(jackAfter, roleRole29Oid, emptySet(), emptySet(), singleton(USER_ADMINISTRATOR_OID), singleton("comment1")); + assertAssignmentMetadata(jackAfter, roleRole29Oid, emptySet(), emptySet(), singleton(USER_ADMINISTRATOR_OID), singleton("administrator :: comment1")); } private void assertAssignmentMetadata(PrismObject object, String targetOid, Set createApproverOids, @@ -610,7 +610,7 @@ protected void afterFirstClockworkRun(Task rootTask, List subtasks, List jackAfter = getUser(userJackOid); display("jack after", jackAfter); assertAssignedRoles(jackAfter, roleRole29Oid); - assertAssignmentMetadata(jackAfter, roleRole29Oid, emptySet(), emptySet(), singleton(USER_ADMINISTRATOR_OID), singleton("comment2")); + assertAssignmentMetadata(jackAfter, roleRole29Oid, emptySet(), emptySet(), singleton(USER_ADMINISTRATOR_OID), singleton("administrator :: comment2")); } @Test @@ -742,7 +742,7 @@ protected void afterFirstClockworkRun(Task rootTask, List subtasks, List jack = getUser(userJackOid); display("jack", jack); assertAssignedRoles(jack, roleRole28Oid); - assertAssignmentMetadata(jack, roleRole28Oid, singleton(USER_ADMINISTRATOR_OID), singleton("comment3"), emptySet(), emptySet()); + assertAssignmentMetadata(jack, roleRole28Oid, singleton(USER_ADMINISTRATOR_OID), singleton("administrator :: comment3"), emptySet(), emptySet()); } @Test @@ -854,7 +854,7 @@ protected void afterFirstClockworkRun(Task rootTask, List subtasks, List jackAfter = getUser(userJackOid); display("jack after", jackAfter); assertAssignedRoles(jackAfter, roleRole28Oid); - assertAssignmentMetadata(jackAfter, roleRole28Oid, singleton(USER_ADMINISTRATOR_OID), singleton("comment3"), singleton(USER_ADMINISTRATOR_OID), singleton("comment4")); + assertAssignmentMetadata(jackAfter, roleRole28Oid, singleton(USER_ADMINISTRATOR_OID), singleton("administrator :: comment3"), singleton(USER_ADMINISTRATOR_OID), singleton("administrator :: comment4")); } @Test diff --git a/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/policy/lifecycle/AbstractTestLifecycle.java b/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/policy/lifecycle/AbstractTestLifecycle.java index 5c87ed17d68..8fd1c7c2f10 100644 --- a/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/policy/lifecycle/AbstractTestLifecycle.java +++ b/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/policy/lifecycle/AbstractTestLifecycle.java @@ -117,7 +117,7 @@ public void test010CreateRolePirate() throws Exception { singleton(ObjectTypeUtil.createObjectRef(userLead1Oid, ObjectTypes.USER).relation(SchemaConstants.ORG_DEFAULT)), new HashSet<>(metadata.getCreateApproverRef())); assertEquals("Wrong create approval comments", - singleton("creation comment"), + singleton("lead1 :: creation comment"), new HashSet<>(metadata.getCreateApprovalComment())); } } @@ -149,7 +149,7 @@ public void test100ModifyRolePirateDescription() throws Exception { singleton(ObjectTypeUtil.createObjectRef(userPirateOwnerOid, ObjectTypes.USER).relation(SchemaConstants.ORG_DEFAULT)), new HashSet<>(metadata.getModifyApproverRef())); assertEquals("Wrong modify approval comments", - singleton("modification comment"), + singleton("pirate-owner :: modification comment"), new HashSet<>(metadata.getModifyApprovalComment())); } diff --git a/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/policy/sod/AbstractTestSoD.java b/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/policy/sod/AbstractTestSoD.java index ce75f7eb444..d1bcb70b502 100644 --- a/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/policy/sod/AbstractTestSoD.java +++ b/model/workflow-impl/src/test/java/com/evolveum/midpoint/wf/impl/policy/sod/AbstractTestSoD.java @@ -172,7 +172,7 @@ protected String getObjectOid() { @Override protected List getExpectedTasks() { return Collections.singletonList( - new ExpectedTask(rolePirateOid, "Assigning role \"Pirate\" to user \"jack\"")); + new ExpectedTask(rolePirateOid, "Role \"Pirate\" excludes role \"Judge\"")); } @Override @@ -286,7 +286,7 @@ protected String getObjectOid() { @Override protected List getExpectedTasks() { return Collections.singletonList( - new ExpectedTask(roleRespectableOid, "Assigning role \"Respectable\" to user \"jack\"")); + new ExpectedTask(roleRespectableOid, "Role \"Thief\" (Respectable -> Thief) excludes role \"Judge\"")); } @Override diff --git a/model/workflow-impl/src/test/resources/common/system-configuration.xml b/model/workflow-impl/src/test/resources/common/system-configuration.xml index 7aab5aa1eab..0878f1dd663 100644 --- a/model/workflow-impl/src/test/resources/common/system-configuration.xml +++ b/model/workflow-impl/src/test/resources/common/system-configuration.xml @@ -66,6 +66,18 @@ true + + + + + + + + true diff --git a/model/workflow-impl/src/test/resources/policy/object/system-configuration.xml b/model/workflow-impl/src/test/resources/policy/object/system-configuration.xml index 80a96de0acd..1f1365a235b 100644 --- a/model/workflow-impl/src/test/resources/policy/object/system-configuration.xml +++ b/model/workflow-impl/src/test/resources/policy/object/system-configuration.xml @@ -57,7 +57,19 @@ true never never - + + + + + + + + + approve-employee-role-add diff --git a/model/workflow-impl/src/test/resources/policy/system-configuration-global.xml b/model/workflow-impl/src/test/resources/policy/system-configuration-global.xml index 74b1b42425f..52a47f4aea2 100644 --- a/model/workflow-impl/src/test/resources/policy/system-configuration-global.xml +++ b/model/workflow-impl/src/test/resources/policy/system-configuration-global.xml @@ -57,7 +57,19 @@ true never never - + + + + + + + + + diff --git a/model/workflow-impl/src/test/resources/policy/system-configuration.xml b/model/workflow-impl/src/test/resources/policy/system-configuration.xml index 17915a482e4..e08f5d38c11 100644 --- a/model/workflow-impl/src/test/resources/policy/system-configuration.xml +++ b/model/workflow-impl/src/test/resources/policy/system-configuration.xml @@ -71,7 +71,19 @@ true - + + + + + + + + + diff --git a/samples/hogwarts/accounts.csv b/samples/hogwarts/accounts.csv new file mode 100644 index 00000000000..247c4618676 --- /dev/null +++ b/samples/hogwarts/accounts.csv @@ -0,0 +1,70 @@ +login,firstname,lastname,memberOf,managerOf,disabled,password +h.potter,Harry,Potter,Hogwarts/Students/Gryffindor,quiddich-griffindor,false,asd123 +h.granger,Hermione,Granger,Hogwarts/Students/Gryffindor,,false,huGHa +r.weasley,Ron,Weasley,Hogwarts/Students/Gryffindor,,false,asd123 +f.weasley,Fred,Weasley,Hogwarts/Students/Gryffindor;quiddich-griffindor,,false,sLh5D +ge.weasley,George,Weasley,Hogwarts/Students/Gryffindor;quiddich-griffindor,,false,Hhktd +gi.weasley,Ginny,Weasley,Hogwarts/Students/Gryffindor,,false,HidpQ +p.weasley,Percy,Weasley,Hogwarts/Students/Gryffindor,,false,BVzp7 +n.longbottom,Neville,Longbottom,Hogwarts/Students/Gryffindor,,false,4j91q +s.finnigan,Seamus,Finnigan,Hogwarts/Students/Gryffindor,,false,X3rVs +o.wood,Oliver,Wood,Hogwarts/Students/Gryffindor,quiddich-griffindor,false,He7jK +k.bell,Katie,Bell,Hogwarts/Students/Gryffindor;quiddich-griffindor,,false,CStTz +l.brown,Lavender,Brown,Hogwarts/Students/Gryffindor,,false,3PnNC +c.creevey,Colin,Creevey,Hogwarts/Students/Gryffindor,,false,FxRQO +d.creevey,Dennis,Creevey,Hogwarts/Students/Gryffindor,,false,O0Unq +a.johnson,Angelina,Johnson,Hogwarts/Students/Gryffindor;quiddich-griffindor,,false,xwlPf +l.jordan,Lee,Jordan,Hogwarts/Students/Gryffindor,,false,FeJKf +c.mcLaggen,Cormac,McLaggen,Hogwarts/Students/Gryffindor,,false,WGV9Z +p.patil,Parvati,Patil,Hogwarts/Students/Gryffindor,,false,L06xC +a.spinnet,Alicia,Spinnet,Hogwarts/Students/Gryffindor;quiddich-griffindor,,false,3QyWK +d.thomas,Dean,Thomas,Hogwarts/Students/Gryffindor;quiddich-griffindor,,false,7bUIs +s.bones,Susan,Bones,Hogwarts/Students/Hufflepuff,,false,zzkzQ +c.diggory,Cedric,Diggory,Hogwarts/Students/Hufflepuff,quiddich-hufflepuff,false,dDtXQ +j.finchFletchley,Justin,Finch-Fletchley,Hogwarts/Students/Hufflepuff,,false,4hicr +e.macmillan,Ernie,Macmillan,Hogwarts/Students/Hufflepuff,,false,o1vdP +z.smith,Zacharias,Smith,Hogwarts/Students/Hufflepuff;quiddich-hufflepuff,,false,wWytb +m.oflaherty,Maxine,O'Flaherty,Hogwarts/Students/Hufflepuff;quiddich-hufflepuff,,false,8zSQC +a.rickett,Anthony,Rickett,Hogwarts/Students/Hufflepuff;quiddich-hufflepuff,,false,aR5Qz +m.mcManus,Michael,McManus,Hogwarts/Students/Hufflepuff;quiddich-hufflepuff,,false,68oPS +m.preece,Malcolm,Preece,Hogwarts/Students/Hufflepuff;quiddich-hufflepuff,,false,SjkHQ +h.macavoy,Heidi,Macavoy,Hogwarts/Students/Hufflepuff;quiddich-hufflepuff,,false,jkxdA +t.applebee,Tamsin,Applebee,Hogwarts/Students/Hufflepuff;quiddich-hufflepuff,,false,b5eaL +l.lovegood,Luna,Lovegood,Hogwarts/Students/Ravenclaw,,false,gVpvc +t.boot,Terry,Boot,Hogwarts/Students/Ravenclaw,,false,jMeJC +ch.Chang,Cho,Chang,Hogwarts/Students/Ravenclaw;quiddich-ravenclaw,,false,MyNFI +p.clearwater,Penelope,Clearwater,Hogwarts/Students/Ravenclaw,,false,beT2o +m.corner,Michael,Corner,Hogwarts/Students/Ravenclaw,,false,SzZjR +r.davies,Roger,Davies,Hogwarts/Students/Ravenclaw,quiddich-ravenclaw,false,1WPNp +m.edgecombe,Marietta,Edgecombe,Hogwarts/Students/Ravenclaw,,false,9NXxc +a.goldstein,Anthony,Goldstein,Hogwarts/Students/Ravenclaw,,false,QGLi0 +pa.patil,Padma,Patil,Hogwarts/Students/Ravenclaw,,false,L06xC +j.stretton,Jeremy,Stretton,Hogwarts/Students/Ravenclaw;quiddich-ravenclaw,,false,Qo2kc +r.burrow,Randolph,Burrow,Hogwarts/Students/Ravenclaw;quiddich-ravenclaw,,false,BtwrF +d.inglebee,Duncan,Inglebee,Hogwarts/Students/Ravenclaw;quiddich-ravenclaw,,false,0hFEp +d.malfoy,Draco,Malfoy,Hogwarts/Students/Slytherin;quiddich-slytherin,,false,lOBrZ +m.bulstrode,Millicent,Bulstrode,Hogwarts/Students/Slytherin,,false,fzFmz +v.crabbe,Vincent,Crabbe,Hogwarts/Students/Slytherin;quiddich-slytherin,,false,gFv53 +m.flint,Marcus,Flint,Hogwarts/Students/Slytherin,quiddich-slytherin,false,Iy6lp +g.goyle,Gregory,Goyle,Hogwarts/Students/Slytherin;quiddich-slytherin,,false,wboNH +g.montague,Graham,Montague,Hogwarts/Students/Slytherin;quiddich-slytherin,,false,H08hH +t.nott,Theodore,Nott,Hogwarts/Students/Slytherin,,false,sOc81 +p.parkinson,Pansy,Parkinson,Hogwarts/Students/Slytherin,,false,wd7TU +b.zabini,Blaise,Zabini,Hogwarts/Students/Slytherin,,false,bwdzH +a.dumbledore,Albus,Dumbledore,Hogwarts/Staff/Professors,Hogwarts/Staff/Professors;Hogwarts/Staff/Auxiliary,false,asd123 +l.voldemort,Lord,Voldemort,Hogwarts/Staff/Professors,,false,w3Hn3 +m.mcGonagall,Minerva,McGonagall,Hogwarts/Staff/Professors,Hogwarts/Students/Gryffindor,false,LnwYb +s.snape,Severus,Snape,Hogwarts/Staff/Professors,Hogwarts/Students/Slytherin,false,3p0AE +p.sprout,Pomona,Sprout,Hogwarts/Staff/Professors,Hogwarts/Students/Hufflepuff,false,TPL2T +f.flitwick,Filius,Flitwick,Hogwarts/Staff/Professors,Hogwarts/Students/Ravenclaw,false,3seVL +s.trelawney,Sybill,Trelawney,Hogwarts/Staff/Professors,,false,irY4l +ch.burbage,Charity,Burbage,Hogwarts/Staff/Professors,,false,JIZxz +r.hooch,Rolanda,Hooch,Hogwarts/Staff/Professors,,false,VmbKi +s.kettleburn,Silvanus,Kettleburn,Hogwarts/Staff/Professors,,false,tVxYS +g.lockhart,Gilderoy,Lockhart,Hogwarts/Staff/Professors,,false,asd123 +a.sinistra,Aurora,Sinistra,Hogwarts/Staff/Professors,,false,top0f +s.vector,Septima,Vector,Hogwarts/Staff/Professors,,false,NJFjE +a.filch,Argus,Filch,Hogwarts/Staff/Auxiliary,,false,LUdDa +r.hagrid,Rubeus,Hagrid,Hogwarts/Staff/Auxiliary;Hogwarts/Staff/Professors,,false,asd123 +i.pince,Irma,Pince,Hogwarts/Staff/Auxiliary,,false,ZnHa4 +p.pomfrey,Poppy,Pomfrey,Hogwarts/Staff/Auxiliary,,false,bvYIK diff --git a/samples/hogwarts/groups.ldif b/samples/hogwarts/groups.ldif new file mode 100644 index 00000000000..2dd974753ca --- /dev/null +++ b/samples/hogwarts/groups.ldif @@ -0,0 +1,73 @@ +version: 1 + +dn: ou=groups,dc=example,dc=com +objectClass: organizationalUnit +ou: groups + +dn: cn=hogwarts,ou=groups,dc=example,dc=com +objectClass: groupOfNames +cn: hogwarts +member: uid=nobody,ou=People,dc=example,dc=com +description: Hogwarts organization structure. Include all students, staff, t + eachers etc. + +dn: cn=Minister of magic,ou=groups,dc=example,dc=com +objectClass: groupOfNames +cn: Minister of magic +member: uid=nobody,ou=People,dc=example,dc=com +member: uid=c.fudge,ou=People,dc=example,dc=com + +dn: cn=quiddich-griffindor,ou=groups,dc=example,dc=com +objectClass: groupOfNames +cn: quiddich-griffindor +member: uid=nobody,ou=People,dc=example,dc=com + +dn: cn=quiddich-ravenclaw,ou=groups,dc=example,dc=com +objectClass: groupOfNames +cn: quiddich-ravenclaw +member: uid=nobody,ou=People,dc=example,dc=com + +dn: cn=quiddich-slytherin,ou=groups,dc=example,dc=com +objectClass: groupOfNames +cn: quiddich-slytherin +member: uid=nobody,ou=People,dc=example,dc=com + +dn: cn=quiddich,ou=groups,dc=example,dc=com +objectClass: groupOfNames +cn: quiddich +member: uid=nobody,ou=People,dc=example,dc=com + +dn: cn=quiddich-hufflepuff,ou=groups,dc=example,dc=com +objectClass: groupOfNames +cn: quiddich-hufflepuff +member: uid=nobody,ou=People,dc=example,dc=com + +dn: cn=herbologyTeacher,ou=groups,dc=example,dc=com +objectClass: top +objectClass: groupOfNames +cn: herbologyTeacher +member: uid=nobody,dc=example,dc=com + +dn: cn=potionsTeacher,ou=groups,dc=example,dc=com +objectClass: top +objectClass: groupOfNames +cn: potionsTeacher +member: uid=nobody,dc=example,dc=com + +dn: cn=defenceAgainstDarkArts,ou=groups,dc=example,dc=com +objectClass: top +objectClass: groupOfNames +cn: defenceAgainstDarkArts +member: uid=nobody,dc=example,dc=com + +dn: cn=transfigurationTeacher,ou=groups,dc=example,dc=com +objectClass: top +objectClass: groupOfNames +cn: transfigurationTeacher +member: uid=nobody,dc=example,dc=com + +dn: cn=duellingClassroomAccess,ou=groups,dc=example,dc=com +objectClass: top +objectClass: groupOfNames +cn: duellingClassroomAccess +member: uid=nobody,dc=example,dc=com diff --git a/samples/hogwarts/objects/accessCertificationDefinitions/access-certification-definition.xml b/samples/hogwarts/objects/accessCertificationDefinitions/access-certification-definition.xml new file mode 100644 index 00000000000..0210c1ae646 --- /dev/null +++ b/samples/hogwarts/objects/accessCertificationDefinitions/access-certification-definition.xml @@ -0,0 +1,88 @@ + + + + User's assignemnts according to the manager + Certifies all users' assignments. Everything is certified by the administrator. + http://midpoint.evolveum.com/xml/ns/public/certification/handlers-3#direct-assignment + + 1 + Manager's review + In this stage, the manager has to review all the assignments of users belonging to his org unit. + P14D + PT48H + PT12H + true + + + false + + + + + + + + addAssignees + Level1 + + + + + + UserType + + + parentOrgRef + + SUBTREE + + + + + + + true + true + false + + + + + \ No newline at end of file diff --git a/samples/hogwarts/objects/objectTemplates/object-template-create-org-struct.xml b/samples/hogwarts/objects/objectTemplates/object-template-create-org-struct.xml new file mode 100644 index 00000000000..dae2d6acb30 --- /dev/null +++ b/samples/hogwarts/objects/objectTemplates/object-template-create-org-struct.xml @@ -0,0 +1,128 @@ + + + + Org Template + + + Org-org mapping + true + strong + + identifier + orgpath + + + orgType + + + + c:OrgType + + + c:name + polyStringNorm + + + + + + true + + + + + + + name + + + + + access + + + orgType + + + + + + + + identifier + + + + + + RoleType + 12345678-d34d-b33f-f00d-111111111222 + + + + assignment + + + + + + + assignment + + + + + + + + + Assign meta role + true + strong + + + RoleType + 12345678-d34d-b33f-f00d-111111111222 + + + + assignment + + + + diff --git a/samples/hogwarts/objects/objectTemplates/object-template-user.xml b/samples/hogwarts/objects/objectTemplates/object-template-user.xml new file mode 100644 index 00000000000..6c58a083ffe --- /dev/null +++ b/samples/hogwarts/objects/objectTemplates/object-template-user.xml @@ -0,0 +1,114 @@ + + + + User Template + + + + strong + + $user/givenName + + + $user/familyName + + + + + + $user/fullName + + + + + + + + end user role + strong + + name + + + + c:RoleType + 00000000-0000-0000-0000-000000000008 + + + + assignment + + + + + + + + + strong + + + + + employeeType + + + + + + + diff --git a/samples/hogwarts/objects/orgs/org-hogwarts.xml b/samples/hogwarts/objects/orgs/org-hogwarts.xml new file mode 100644 index 00000000000..21402a43178 --- /dev/null +++ b/samples/hogwarts/objects/orgs/org-hogwarts.xml @@ -0,0 +1,29 @@ + + + + hogwarts + + Hogwarts + + Hogwarts organization structure. Include all students, staff, teachers etc. + + true + + diff --git a/samples/hogwarts/objects/orgs/org-minister-of-magic.xml b/samples/hogwarts/objects/orgs/org-minister-of-magic.xml new file mode 100644 index 00000000000..68956d56697 --- /dev/null +++ b/samples/hogwarts/objects/orgs/org-minister-of-magic.xml @@ -0,0 +1,24 @@ + + + + Minister of magic + Minister of magic + true + diff --git a/samples/hogwarts/objects/orgs/org-quiddich-griffindor.xml b/samples/hogwarts/objects/orgs/org-quiddich-griffindor.xml new file mode 100644 index 00000000000..a4a844c7fb2 --- /dev/null +++ b/samples/hogwarts/objects/orgs/org-quiddich-griffindor.xml @@ -0,0 +1,35 @@ + + + + quiddich-griffindor + Griffindor + + Griffindoch quiddich team members + + true + team + + + + + + + + diff --git a/samples/hogwarts/objects/orgs/org-quiddich-hufflepuff.xml b/samples/hogwarts/objects/orgs/org-quiddich-hufflepuff.xml new file mode 100644 index 00000000000..defc7061500 --- /dev/null +++ b/samples/hogwarts/objects/orgs/org-quiddich-hufflepuff.xml @@ -0,0 +1,35 @@ + + + + quiddich-hufflepuff + Hufflepuff + + Hufflepuff quiddich team members + + true + team + + + + + + + + diff --git a/samples/hogwarts/objects/orgs/org-quiddich-ravenclaw.xml b/samples/hogwarts/objects/orgs/org-quiddich-ravenclaw.xml new file mode 100644 index 00000000000..cff283e5b0d --- /dev/null +++ b/samples/hogwarts/objects/orgs/org-quiddich-ravenclaw.xml @@ -0,0 +1,57 @@ + + + + quiddich-ravenclaw + Ravenclaw + + Ravenclaw quiddich team members + + true + team + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/hogwarts/objects/orgs/org-quiddich-slytherin.xml b/samples/hogwarts/objects/orgs/org-quiddich-slytherin.xml new file mode 100644 index 00000000000..6fb1c347438 --- /dev/null +++ b/samples/hogwarts/objects/orgs/org-quiddich-slytherin.xml @@ -0,0 +1,57 @@ + + + + quiddich-slytherin + Slytherin + + Slytherin quiddich team members + + true + team + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/hogwarts/objects/orgs/org-quiddich-teams.xml b/samples/hogwarts/objects/orgs/org-quiddich-teams.xml new file mode 100644 index 00000000000..1b0e5555cba --- /dev/null +++ b/samples/hogwarts/objects/orgs/org-quiddich-teams.xml @@ -0,0 +1,28 @@ + + + + quiddich + Quiddich Teams + + Teams structure. + + true + team + diff --git a/samples/hogwarts/objects/resources/resource-csv.xml b/samples/hogwarts/objects/resources/resource-csv.xml new file mode 100644 index 00000000000..60fcbfd45f8 --- /dev/null +++ b/samples/hogwarts/objects/resources/resource-csv.xml @@ -0,0 +1,442 @@ + + + + + + + HR + Source resource + + + + + c:connectorType + com.evolveum.polygon.connector.csv.CsvConnector + + + + + + + /opt.midpoint/csv/accounts.csv + utf-8 + " + ALL + , + ; + login + password + + + + + + + + + + + + + Default Account + true + + ri:AccountObjectClass + + ri:login + + Login + + + 0 + + + + name + + + + + + ri:firstname + First name + Definition of Firstname attribute handling. + + + givenName + + + + + ri:lastname + Last name + Definition of Lastname attribute handling. + + + $user/familyName + + + + + ri:memberOf + Member of specified organization unit/project + + + 0 + -1 + + + + + c:OrgType + + + c:name + polyStringNorm + + + + + + true + + + + + + + name + + + + + access + + + orgType + + + + + + + + identifier + + + + + + + assignment + + + + + + + + + + + + ri:managerOf + Manager of specified organization unit/project + + + 0 + -1 + + + + + c:OrgType + manager + + + c:name + polyStringNorm + + + + + + true + + + + + + + name + + + + + access + + + orgType + + + + + + + + identifier + + + + + + + assignment + + + + + + + + + + + c:RoleType + e2c88fea-db21-11e5-80ba-d7b2f1155264 + + + + assignment + + + + + + + + + + + + + + + + + + + weak + + + + + + + + + + + + + + + + + ri:disabled + false + true + + + + false + + + + + + + true + + + + Correlation expression is a search query. + Following search query will look for users that have "name" + equal to the "login" attribute of the account. Simply speaking, + it will look for match in usernames in the IDM and the resource. + The correlation rule always looks for users, so it will not match + any other object type. + + + c:name + + $account/attributes/ri:login + + + + + + + + + linked + true + + + deleted + true + + http://midpoint.evolveum.com/xml/ns/public/model/action-3#unlink + + + + unlinked + true + + http://midpoint.evolveum.com/xml/ns/public/model/action-3#link + + + + unmatched + true + + http://midpoint.evolveum.com/xml/ns/public/model/action-3#addFocus + + + + + + diff --git a/samples/hogwarts/objects/resources/resource-openldap.xml b/samples/hogwarts/objects/resources/resource-openldap.xml new file mode 100644 index 00000000000..d99b91172c6 --- /dev/null +++ b/samples/hogwarts/objects/resources/resource-openldap.xml @@ -0,0 +1,359 @@ + + + + Localhost OpenLDAP + + + + + c:connectorType + com.evolveum.polygon.connector.ldap.LdapConnector + + + + + + + 389 + localhost + dc=example,dc=com + cn=idm,ou=Administrators,dc=example,dc=com + secret + always + auto + SSHA + uid,cn + 2.5.13.3 + memberOf + createTimestamp + + + false + false + false + + + + + + + ri:inetOrgPerson + ri:groupOfUniqueNames + ri:groupOfNames + ri:organizationalUnit + + + + + + default + Default Account + true + ri:inetOrgPerson + + ri:dn + Distinguished Name + mr:distinguishedName + + + $user/name + + + + + + + + ri:entryUUID + Entry UUID + mr:stringIgnoreCase + + + ri:cn + Common Name + + 1 + + + + fullName + + + + + fullName + + + + + ri:sn + Surname + + + familyName + + + + + familyName + + + + + ri:givenName + Given Name + + + givenName + + + + + givenName + + + + + ri:uid + Login Name + mr:stringIgnoreCase + + weak + + name + + + + + + + + name + + + + + ri:memberOf + mr:stringIgnoreCase + explicit + + + + ri:group + LDAP Group Membership + entitlement + ldapGroup + objectToSubject + ri:member + ri:dn + true + + + + 5 + + + + + + http://prism.evolveum.com/xml/ns/public/matching-rule-3#stringIgnoreCase + attributes/ri:dn + cn=idm,ou=Administrators,dc=example,dc=com + + + + + + + + + + + + + + entitlement + ldapGroup + LDAP Group + ri:groupOfNames + + ri:dn + mr:distinguishedName + + + + $focus/name + + + + + + + + ri:member + mr:distinguishedName + + weak + + uid=nobody,ou=People,dc=example,dc=com + + + + + ri:cn + mr:stringIgnoreCase + + weak + + $focus/name + + + + + name + + + + + ri:description + + + description + + + + + description + + + + + + + + + + Account sync + ri:inetOrgPerson + account + default + UserType + true + + + + c:employeeNumber + + declare namespace ri="http://midpoint.evolveum.com/xml/ns/public/resource/instance/10000000-0000-0000-0000-000000000003"; + $account/attributes/ri:employeeNumber + + + + + c:employeeNumber + + + + + + + + linked + true + + + deleted + + + + unlinked + + + + unmatched + + + + + + Group sync + ri:groupOfNames + entitlement + ldapGroup + RoleType + true + + + c:name + + $shadow/attributes/cn + + + + + + linked + true + + + deleted + + + + unlinked + + + + unmatched + + + + + + diff --git a/samples/hogwarts/objects/roles/role-approver.xml b/samples/hogwarts/objects/roles/role-approver.xml new file mode 100644 index 00000000000..5758ab6d748 --- /dev/null +++ b/samples/hogwarts/objects/roles/role-approver.xml @@ -0,0 +1,129 @@ + + + + Approver + Role authorizing users to make approval decisions on work items. + + gui-approver-access + + Allow access to list of work items in GUI. Allow access to pages that show object details, + so the approver may examine who is requesting and what is requesting. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#workItem + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#myWorkItems + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#claimableWorkItems + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#userDetails + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#roleDetails + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#orgUnit + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#service + + + workitems-delegate + + Allow delegation of own work items. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#delegateOwnWorkItems + + + tasks-read + + Allow to see the requester of the operation that is being approved and the current delta. + In order for the approver to see other properties (e.g. history of the approvals) please allow read access + to other items as well, e.g. to the whole workflowContext. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + + TaskType + + workflowContext/requesterRef + workflowContext/processorSpecificState + + + users-read + + Allow to read basic user properties to be able to display requestor details in the + approval forms. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + + UserType + + name + givenName + familyName + fullName + employeeType + employeeNumber + + + roles-read + + Allow to read basic role properties to be able to display details of the requested role. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + + RoleType + + name + displayName + identifier + description + riskLevel + roleType + + + orgs-read + + Allow to read basic org properties to be able to display details of the requested org. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + + OrgType + + name + displayName + identifier + description + riskLevel + orgType + + + services-read + + Allow to read basic service properties to be able to display details of the requested service. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + + ServiceType + + name + displayName + identifier + description + riskLevel + serviceType + + system + \ No newline at end of file diff --git a/samples/hogwarts/objects/roles/role-duelling-classromm-access.xml b/samples/hogwarts/objects/roles/role-duelling-classromm-access.xml new file mode 100644 index 00000000000..21d9ca2451d --- /dev/null +++ b/samples/hogwarts/objects/roles/role-duelling-classromm-access.xml @@ -0,0 +1,53 @@ + + + + Duelling classroom access + + + + + + + ri:group + + strong + + + + + attributes/ri:cn + duellingClassroomAccess + + + onResourceIfNeeded + + + + + + + + + + + true + \ No newline at end of file diff --git a/samples/hogwarts/objects/roles/role-end-user.xml b/samples/hogwarts/objects/roles/role-end-user.xml new file mode 100644 index 00000000000..22a34e591d9 --- /dev/null +++ b/samples/hogwarts/objects/roles/role-end-user.xml @@ -0,0 +1,232 @@ + + + + End user + Role authorizing end users to log in, change their passwords and review assigned accounts. + + gui-self-service-access + + Allow access to all self-service operations in GUI. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#selfAll + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#task + + + self-read + + Allow to read all the properties of "self" object. I.e. every logged-in user can read + object that represent his own identity. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + + self + + + + self-shadow-read + + Allow to read all the properties of all the shadows that belong to "self" object. + I.e. every logged-in user can read all his accounts. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + + ShadowType + + self + + + + + self-persona-read + + Allow to read all the personas of currently logged-in user. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + + UserType + + self + + + + + self-credentials-request + + Allow to modify user's own credentials. + Note that this is a request phase authorization. It also requires corresponding execution-phase authorization. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#changeCredentials + request + + self + + credentials + + + self-shadow-credentials-request + + Allow to modify credentials of all users accounts. + Note that this is a request phase authorization. It also requires corresponding execution-phase authorization. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#changeCredentials + request + + ShadowType + + self + + + credentials + + + assign-requestable-roles + + Allow to assign requestable roles. This allows to request roles in a request-and-approve process. + The requestable roles will be displayed in the role request dialog by default. + Please note that the roles also need an approved definition to go through the approval process. + Otherwise they will be assigned automatically wihout any approval. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#assign + + self + + + RoleType + + + requestable + true + + + + + + self-execution-modify + + Authorization that allows to self-modification of some properties, but only in execution phase. + The limitation real limitation of these operations is done in the request phase. + E.g. the modification of assignments is controlled in the request phase by using the #assign + authorization. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#modify + execution + + self + + + + self-shadow-execution-add-modify-delete + + Authorization that allows to self-modification of user's accounts, but only in execution phase. + The real limitation of these operations is done in the request phase. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#add + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#modify + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#delete + execution + + ShadowType + + self + + + + + assignment-target-read + + Authorization that allows to read all the object that are possible assignment targets. We want that + to display the targets in the selection windows. + Note that this authorization may be too broad for production use. Normally it should be limited to just + selected properties such as name and description. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + + OrgType + + + ResourceType + + + RoleType + + + ServiceType + + + UserType + + + TaskType + + + + assignment-target-read-task + + Authorization that allows to read workflow status of tasks. This is used to display requests + to the end users, especially in the "My Requests" box in user dashboard. + This authorization is a temporary solution. It will be replaced by a finer-grained + permissions in the future. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + + TaskType + + workflowContext + + + self-owned-task-read + + Authorization that allows to see all tasks owned by a currently logged-in user. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + + TaskType + + self + + + + + self-owned-task-add-execute-changes + + Authorization to create a new 'execute changes' task owned by a currently logged-in user. + This is needed to execute asynchronous operations from the GUI. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#add + + TaskType + + + handlerUri + http://midpoint.evolveum.com/xml/ns/public/model/synchronization/task/execute/handler-3 + + + + self + + + + system + \ No newline at end of file diff --git a/samples/hogwarts/objects/roles/role-herbology-teacher.xml b/samples/hogwarts/objects/roles/role-herbology-teacher.xml new file mode 100644 index 00000000000..147396572af --- /dev/null +++ b/samples/hogwarts/objects/roles/role-herbology-teacher.xml @@ -0,0 +1,52 @@ + + + + Herbology Teacher + + + + + + + ri:group + + strong + + + + + attributes/ri:cn + herbologyTeacher + + + onResourceIfNeeded + + + + + + + + + + + true + \ No newline at end of file diff --git a/samples/hogwarts/objects/roles/role-ldap.xml b/samples/hogwarts/objects/roles/role-ldap.xml new file mode 100644 index 00000000000..e1da72155ae --- /dev/null +++ b/samples/hogwarts/objects/roles/role-ldap.xml @@ -0,0 +1,32 @@ + + + + User OpenDJ + + A basic role, that specifies account on OpenDJ resource + + + + + + + + true + diff --git a/samples/hogwarts/objects/roles/role-manager-full-control.xml b/samples/hogwarts/objects/roles/role-manager-full-control.xml new file mode 100644 index 00000000000..1037c82debd --- /dev/null +++ b/samples/hogwarts/objects/roles/role-manager-full-control.xml @@ -0,0 +1,151 @@ + + + Manager Full Control + + Role that gives access to the organizational units and objects stored + there for organizational unit managers. A manager can read everything in + the units that he is managing. And it can change all the contained objects. + + + gui + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#selfAll + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#orgAll + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#user + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#myWorkItems + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#workItem + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#certificationDecisions + + + + approve-reject + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#completeAllWorkItems + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#delegateAllWorkItems + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#delegateOwnWorkItems + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#readAllWorkItems + + + campaing management + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#openCertificationCampaignReviewStage + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#closeCertificationCampaignReviewStage + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#startCertificationRemediation + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#readOwnCertificationDecisions + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#recordCertificationDecision + + + autz-read + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + + + org:manager + allDescendants + true + + + + + autz-read + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + + + org:manager + allAncestors + true + + + + + autz-write + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#modify + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#add + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#delete + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#assign + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#unassign + + + org:manager + + + + + autz-shadow + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#modify + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#add + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#delete + + ShadowType + + + org:manager + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +true + + + excluded-role + + + + + + + + + + + diff --git a/samples/hogwarts/objects/roles/role-meta-ldap-group.xml b/samples/hogwarts/objects/roles/role-meta-ldap-group.xml new file mode 100644 index 00000000000..f26c60c8202 --- /dev/null +++ b/samples/hogwarts/objects/roles/role-meta-ldap-group.xml @@ -0,0 +1,60 @@ + + + + Meta OpenDJ + + A basic role, that specifies account on OpenDJ resource + + + + + + entitlement + ldapGroup + + OrgType + 1 + + + + + + account + default + + ri:group + + strong + + + + entitlement + ldapGroup + + + + + + + UserType + 2 + + false + diff --git a/samples/hogwarts/objects/roles/role-owner.xml b/samples/hogwarts/objects/roles/role-owner.xml new file mode 100644 index 00000000000..91e617c3617 --- /dev/null +++ b/samples/hogwarts/objects/roles/role-owner.xml @@ -0,0 +1,56 @@ + + + Owner Control + + Role that gives access to the organizational units and objects stored + there for organizational unit managers. A manager can read everything in + the units that he is managing. And it can change all the contained objects. + + + gui + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#selfAll + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#myWorkItems + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#workItem + + + + approve-reject + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#completeAllWorkItems + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#delegateAllWorkItems + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#delegateOwnWorkItems + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#readAllWorkItems + + + true + + + excluded-role + + + + + + + + + + + diff --git a/samples/hogwarts/objects/roles/role-policy-rule-sod.xml b/samples/hogwarts/objects/roles/role-policy-rule-sod.xml new file mode 100644 index 00000000000..8225ec98d99 --- /dev/null +++ b/samples/hogwarts/objects/roles/role-policy-rule-sod.xml @@ -0,0 +1,43 @@ + + + + Metarole exclude all + + + excluded-role + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/hogwarts/objects/roles/role-policy-rule.xml b/samples/hogwarts/objects/roles/role-policy-rule.xml new file mode 100644 index 00000000000..2b6b9b932de --- /dev/null +++ b/samples/hogwarts/objects/roles/role-policy-rule.xml @@ -0,0 +1,58 @@ + + metarole-approval-role-approvers-all + Requests to assign role holding this metarole will be approved by the role approver(s) using "all must approve" method + Metarole: approval by the role approver(s) - all must approve + + + + + add + + + + + + 10 + + + + User's manager + + + + allMustApprove + reject + + + + + + + + + + + add + + + + + + 20 + + + + Role approvers (all) + owner + allMustApprove + reject + + + + + + + \ No newline at end of file diff --git a/samples/hogwarts/objects/roles/role-potions-teacher.xml b/samples/hogwarts/objects/roles/role-potions-teacher.xml new file mode 100644 index 00000000000..5548968af2a --- /dev/null +++ b/samples/hogwarts/objects/roles/role-potions-teacher.xml @@ -0,0 +1,51 @@ + + + + Potions Teacher + + + + + + + ri:group + + strong + + + + + attributes/ri:cn + potionsTeacher + + + onResourceIfNeeded + + + + + + + + + + true + \ No newline at end of file diff --git a/samples/hogwarts/objects/roles/role-transfiguration-defense-against-dark.xml b/samples/hogwarts/objects/roles/role-transfiguration-defense-against-dark.xml new file mode 100644 index 00000000000..63be2a25d15 --- /dev/null +++ b/samples/hogwarts/objects/roles/role-transfiguration-defense-against-dark.xml @@ -0,0 +1,53 @@ + + + + Defence Against the Dark Arts Teacher + + + + + + + ri:group + + strong + + + + + attributes/ri:cn + defenceAgainstDarkArts + + + onResourceIfNeeded + + + + + + + + + + + true + \ No newline at end of file diff --git a/samples/hogwarts/objects/roles/role-transfiguration-teacher.xml b/samples/hogwarts/objects/roles/role-transfiguration-teacher.xml new file mode 100644 index 00000000000..03cf5b646ba --- /dev/null +++ b/samples/hogwarts/objects/roles/role-transfiguration-teacher.xml @@ -0,0 +1,53 @@ + + + + Transfiguration Teacher + + + + + + + ri:group + + strong + + + + + attributes/ri:cn + transfigurationTeacher + + + onResourceIfNeeded + + + + + + + + + + + true + \ No newline at end of file diff --git a/samples/hogwarts/objects/systemConfiguration/system-configuration.xml b/samples/hogwarts/objects/systemConfiguration/system-configuration.xml new file mode 100644 index 00000000000..d3693b5aaa6 --- /dev/null +++ b/samples/hogwarts/objects/systemConfiguration/system-configuration.xml @@ -0,0 +1,213 @@ + + + + SystemConfiguration + + + + INFO + com.evolveum.midpoint.model.impl.lens.Clockwork + + + INFO + com.evolveum.midpoint.model.impl.lens.projector.Projector + + + OFF + com.evolveum.midpoint.repo.sql.helpers.ObjectRetriever + + + INFO + com.evolveum.midpoint.security.enforcer.impl + + + OFF + net.sf.jasperreports.engine.fill.JRFillDataset + + + WARN + org.apache.wicket.resource.PropertiesFactory + + + WARN + org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl + + + OFF + org.hibernate.engine.jdbc.batch.internal.BatchingBatch + + + OFF + org.hibernate.engine.jdbc.spi.SqlExceptionHelper + + + ERROR + org.springframework.context.support.ResourceBundleMessageSource + + + ERROR + ro.isdc.wro.extensions.processor.css.Less4jProcessor + + + %date [%X{subsystem}] [%thread] %level \(%logger\): %msg%n + ${midpoint.home}/log/midpoint.log + ${midpoint.home}/log/midpoint-%d{yyyy-MM-dd}.%i.log + 10 + 100MB + true + + + %date %level: %msg%n + ${midpoint.home}/log/midpoint-profile.log + ${midpoint.home}/log/midpoint-profile-%d{yyyy-MM-dd}.%i.log + 10 + 100MB + true + + MIDPOINT_LOG + INFO + + false +
false
+
+
+ + c:OrgType + + + + c:UserType + + + + UserType + employee + + + active + + archival + archived + + + + + + + archived + + archival-data-reduction + + telephoneNumber + + + + + + + + false + + + + false + false + false + false + false + false + false + false + false + false + + + + P3M + + + P1M + + + + false + + + + /self/profile + + View/edit your profile + + fa fa-user + + green + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#selfProfile + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#selfAll + + + /self/credentials + + View/edit your credentials + + fa fa-shield + + blue + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#selfCredentials + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#selfAll + + + /admin/users + + + fa fa-users + + red + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#users + + + /admin/resources + + + fa fa-database + + purple + http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#resources + + +
\ No newline at end of file diff --git a/samples/hogwarts/objects/users/user-fudge.xml b/samples/hogwarts/objects/users/user-fudge.xml new file mode 100644 index 00000000000..bea38742654 --- /dev/null +++ b/samples/hogwarts/objects/users/user-fudge.xml @@ -0,0 +1,75 @@ + + + + c.fudge + + + + + + + + + + + + + + + + + + + + + + + + + Cornelius Fudge + Cornelius + Fudge + + + + asd123 + + + + \ No newline at end of file diff --git a/testing/story/testng-integration.xml b/testing/story/testng-integration.xml index e2351462896..49aec810d57 100644 --- a/testing/story/testng-integration.xml +++ b/testing/story/testng-integration.xml @@ -46,6 +46,7 @@ +