Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
Signed-off-by: Tony Tkacik <tonydamage@gmail.com>
  • Loading branch information
tonydamage committed Feb 10, 2023
1 parent 92ab8c8 commit 35cc72a
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4330,7 +4330,7 @@
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
<xsd:element name="effectiveProvisioningPolicy" type="tns:ShadowProvisioningPolicyType" minOccurs="0">
<xsd:element name="effectiveProvisioningPolicy" type="tns:EffectiveShadowProvisioningPolicyType" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
Effective provisioning policy derived from Shadow marks and resource configuration.
Expand Down Expand Up @@ -5635,4 +5635,30 @@
<xsd:element name="readOnly" type="xsd:boolean" minOccurs="0" default="false" />
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="EffectiveShadowProvisioningPolicyType">
<xsd:annotation>
<xsd:documentation>
Shadow specific provisioning policy. This policy is applied to concrete shadows using TagType.
</xsd:documentation>
<xsd:appinfo>
<a:container>true</a:container>
<a:since>4.7</a:since>
<a:experimental>true</a:experimental>
</xsd:appinfo>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="protected" type="xsd:boolean" minOccurs="1" default="false">
<xsd:annotation>
<xsd:documentation>
Protected shadows cannot be changed. They are out of IDM control.
This is only informational property. Changing it will have no effect on
whether object is protected or not. Object protection is a strict policy that
cannot be easily overridden.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="readOnly" type="xsd:boolean" minOccurs="1" default="false" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
Original file line number Diff line number Diff line change
Expand Up @@ -338,10 +338,12 @@ public boolean isDependencyTarget(
return DependencyProcessor.matches(this, dependency);
}

@Override
public ObjectDelta<ShadowType> getSyncDelta() {
return syncDelta;
}

@Override
public void setSyncDelta(ObjectDelta<ShadowType> syncDelta) {
this.syncDelta = syncDelta;
state.invalidate(); // sync delta is a parameter for adjuster
Expand Down Expand Up @@ -617,6 +619,7 @@ public boolean matches(ProjectionContextKey otherKey, boolean compareOrder) {
|| otherKey.getOrder() == key.getOrder();
}

@Override
public boolean isGone() {
return key.isGone();
}
Expand All @@ -637,6 +640,7 @@ public void addAccountSyncDelta(ObjectDelta<ShadowType> delta) throws SchemaExce
}
}

@Override
public boolean isAdd() {
if (synchronizationPolicyDecision == SynchronizationPolicyDecision.ADD) {
return true;
Expand All @@ -647,6 +651,7 @@ public boolean isAdd() {
}
}

@Override
public boolean isModify() {
if (synchronizationPolicyDecision == SynchronizationPolicyDecision.KEEP) {
return true;
Expand All @@ -657,6 +662,7 @@ public boolean isModify() {
}
}

@Override
public boolean isDelete() {
// Note that there are situations where decision is UNLINK with primary delta being DELETE. (Why?)
return synchronizationPolicyDecision == SynchronizationPolicyDecision.DELETE
Expand Down Expand Up @@ -734,6 +740,7 @@ public void setActive(boolean isActive) {
this.active = isActive;
}

@Override
public Boolean isLegal() {
return legal;
}
Expand Down Expand Up @@ -762,6 +769,7 @@ public void setLegalOldIfUnknown(Boolean value) {
}
}

@Override
public boolean isExists() {
return exists;
}
Expand All @@ -778,6 +786,7 @@ public void setShadowExistsInRepo(boolean shadowExistsInRepo) {
this.shadowExistsInRepo = shadowExistsInRepo;
}

@Override
public SynchronizationIntent getSynchronizationIntent() {
return synchronizationIntent;
}
Expand All @@ -786,6 +795,7 @@ public void setSynchronizationIntent(SynchronizationIntent synchronizationIntent
this.synchronizationIntent = synchronizationIntent;
}

@Override
public SynchronizationPolicyDecision getSynchronizationPolicyDecision() {
return synchronizationPolicyDecision;
}
Expand Down Expand Up @@ -816,6 +826,7 @@ public void setSynchronizationSituationResolved(SynchronizationSituationType syn
this.synchronizationSituationResolved = synchronizationSituationResolved;
}

@Override
public boolean isFullShadow() {
return fullShadow;
}
Expand Down Expand Up @@ -1010,6 +1021,7 @@ public ResourceAttributeDefinition<?> findAttributeDefinition(QName attrName) th
return null;
}

@Override
public Collection<ResourceObjectTypeDependencyType> getDependencies() throws SchemaException, ConfigurationException {
if (dependencies == null) {
ResourceObjectDefinition objectDefinition = getStructuralDefinitionIfNotBroken();
Expand Down Expand Up @@ -1889,4 +1901,8 @@ public boolean isAdministrativeStatusSupported() throws SchemaException, Configu
throws SchemaException, ConfigurationException {
return ItemChangeApplicationModeConfiguration.of(getCompositeObjectDefinition());
}

public boolean isMarkedReadOnly() {
return Boolean.TRUE.equals(getObjectCurrentOrOld().asObjectable().getEffectiveProvisioningPolicy().isReadOnly());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,11 @@ private <F extends ObjectType> void projectProjection(LensContext<F> context, Le
return;
}

if (projectionContext.isMarkedReadOnly()) {
recordSkipReason(result, "Skipping projection because it is marked read-only.");
return;
}

if (projectionContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.BROKEN ||
projectionContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.IGNORE) {
recordSkipReason(result,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ void applyAttributesDefinition(ProvisioningContext ctx, Collection<? extends Ite
throws SchemaException {
for (ItemDelta<?, ?> itemDelta : modifications) {
if (SchemaConstants.PATH_ATTRIBUTES.equivalent(itemDelta.getParentPath())) {
applyAttributeDefinition(ctx, itemDelta);
applyAttributeDefinition(ctx, (ItemDelta) itemDelta);
} else if (SchemaConstants.PATH_ATTRIBUTES.equivalent(itemDelta.getPath())) {
if (itemDelta.isAdd()) {
for (PrismValue value : itemDelta.getValuesToAdd()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SystemException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.EffectiveShadowProvisioningPolicyType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.MarkType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.PolicyStatementTypeType;
Expand All @@ -48,7 +49,8 @@ private abstract class Impl {

protected abstract boolean policyNotExcluded(ShadowType shadow, String markProtectedShadowOid);

protected abstract ShadowProvisioningPolicyType computeEffectivePolicy(Collection<ObjectReferenceType> effectiveMarkRefs,
protected abstract EffectiveShadowProvisioningPolicyType computeEffectivePolicy(
Collection<ObjectReferenceType> effectiveMarkRefs,
ShadowType shadow, OperationResult result);

protected abstract void setEffectiveMarks(ShadowType shadow, Collection<ObjectReferenceType> effectiveMarkRefs);
Expand Down Expand Up @@ -96,54 +98,10 @@ public Collection<MarkType> getShadowMarks(Collection<ObjectReferenceType> tagRe
}
}

public ShadowProvisioningPolicyType getShadowMarkPolicy(Collection<ObjectReferenceType> tagRefs, @NotNull OperationResult result) {
var ret = new ShadowProvisioningPolicyType();
Collection<MarkType> marks = getShadowMarks(tagRefs, result);

// Account is protected if any of shadow marks set it to protected.
boolean isProtected = marks.stream().anyMatch(
t -> t.getProvisioningPolicy() != null &&
BooleanUtils.isTrue(t.getProvisioningPolicy().isProtected()));
ret.setProtected(isProtected);

return ret;
}

public static ShadowMarkManager get() {
return instance;
}

public boolean isProtectedShadow(ShadowType shadow, @NotNull OperationResult result) {
return getShadowMarkPolicy(shadow, result).isProtected();
}

private ShadowProvisioningPolicyType getShadowMarkPolicy(ShadowType shadow, @NotNull OperationResult result) {
if (shadow.getPolicyStatement() == null && shadow.getPolicyStatement().isEmpty()) {
return getShadowMarkPolicy(shadow.getEffectiveMarkRef(), result);
}
Set<ObjectReferenceType> tagRefs = new HashSet<>();
tagRefs.addAll(shadow.getEffectiveMarkRef());
for (var policy: shadow.getPolicyStatement()) {
if (PolicyStatementTypeType.APPLY.equals(policy.getType())) {
tagRefs.add(policy.getMarkRef());
}
}
return getShadowMarkPolicy(tagRefs, result);
}

public boolean isProtectedShadowPolicyNotExcluded(ShadowType shadow) {
if(shadow.getPolicyStatement() != null && !shadow.getPolicyStatement().isEmpty()) {
for (var policy : shadow.getPolicyStatement()) {
if ( PolicyStatementTypeType.EXCLUDE.equals(policy.getType())
&& policy.getMarkRef() != null
&& SystemObjectsType.MARK_PROTECTED_SHADOW.value().equals(policy.getMarkRef().getOid())) {
return false;
}
}
}
return true;
}

public void updateEffectiveMarksAndPolicies(Collection<ResourceObjectPattern> protectedAccountPatterns,
ShadowType shadow, OperationResult result) throws SchemaException {

Expand All @@ -160,22 +118,20 @@ public void updateEffectiveMarksAndPolicies(Collection<ResourceObjectPattern> pr
// so we need to check if shadow is protected
if (ResourceObjectPattern.matches(shadow, protectedAccountPatterns)) {
// Shadow is protected by resource protected object configuration
// FIXME: Add metadata to policy mark
effectiveMarkRefs.add(resourceProtectedShadowMark());
}
}

ShadowProvisioningPolicyType effectivePolicy = behaviour.computeEffectivePolicy(effectiveMarkRefs, shadow, result);
var effectivePolicy = behaviour.computeEffectivePolicy(effectiveMarkRefs, shadow, result);
updateShadowObject(shadow, effectiveMarkRefs, effectivePolicy);
}


private ObjectReferenceType resourceProtectedShadowMark() {
// TODO Maybe add metadata with provenance pointing that this was added by resource configuration
ObjectReferenceType ret = new ObjectReferenceType();
ret.setOid(MARK_PROTECTED_SHADOW_OID);
ret.setType(MarkType.COMPLEX_TYPE);

// TODO Maybe add metadata with provenance pointing that this was added by resource configuration
return ret;
}

Expand Down Expand Up @@ -207,7 +163,7 @@ private static boolean containsOid(Collection<ObjectReferenceType> refs, @NotNul
}

private void updateShadowObject(ShadowType shadow, Collection<ObjectReferenceType> effectiveMarkRefs,
ShadowProvisioningPolicyType effectivePolicy) {
EffectiveShadowProvisioningPolicyType effectivePolicy) {
behaviour.setEffectiveMarks(shadow, effectiveMarkRefs);

shadow.setEffectiveProvisioningPolicy(effectivePolicy);
Expand Down Expand Up @@ -272,9 +228,9 @@ protected boolean containsPolicyStatement(@NotNull ShadowType shadow, @NotNull S


@Override
protected ShadowProvisioningPolicyType computeEffectivePolicy(Collection<ObjectReferenceType> effectiveMarkRefs,
protected EffectiveShadowProvisioningPolicyType computeEffectivePolicy(Collection<ObjectReferenceType> effectiveMarkRefs,
ShadowType shadow, OperationResult result) {
var ret = new ShadowProvisioningPolicyType();
var ret = new EffectiveShadowProvisioningPolicyType();
Collection<MarkType> marks = getShadowMarks(effectiveMarkRefs, result);

// Account is protected if any of shadow marks set it to protected.
Expand Down Expand Up @@ -310,14 +266,14 @@ protected boolean policyNotExcluded(ShadowType shadow, String markProtectedShado
}

@Override
protected ShadowProvisioningPolicyType computeEffectivePolicy(Collection<ObjectReferenceType> effectiveMarkRefs,
protected EffectiveShadowProvisioningPolicyType computeEffectivePolicy(Collection<ObjectReferenceType> effectiveMarkRefs,
ShadowType shadow, OperationResult result) {
if (containsOid(effectiveMarkRefs, MARK_PROTECTED_SHADOW_OID)) {
return new ShadowProvisioningPolicyType()
return new EffectiveShadowProvisioningPolicyType()
._protected(true)
.readOnly(true);
}
return new ShadowProvisioningPolicyType()
return new EffectiveShadowProvisioningPolicyType()
._protected(false)
.readOnly(false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;

import static com.evolveum.midpoint.prism.PrismPropertyValue.getRealValue;
import static com.evolveum.midpoint.provisioning.util.ProvisioningUtil.isProtectedShadow;
import static com.evolveum.midpoint.provisioning.util.ProvisioningUtil.isAddShadowEnabled;
import static com.evolveum.midpoint.provisioning.util.ProvisioningUtil.isModifyShadowEnabled;
import static com.evolveum.midpoint.schema.util.ObjectTypeUtil.asPrismObject;

import java.util.*;
Expand Down Expand Up @@ -295,7 +296,7 @@ public AsynchronousOperationReturnValue<ShadowType> addResourceObject(

Collection<ResourceAttribute<?>> resourceAttributesAfterAdd;

if (isProtectedShadow(ctx.getProtectedAccountPatterns(expressionFactory, result), shadowClone, result)) {
if (!isAddShadowEnabled(ctx.getProtectedAccountPatterns(expressionFactory, result), shadowClone, result)) {
throw new SecurityViolationException("Cannot add protected shadow " + shadowClone);
}

Expand Down Expand Up @@ -503,7 +504,7 @@ private void checkIfProtected(
throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException,
ExpressionEvaluationException, SecurityViolationException {
Collection<ResourceObjectPattern> protectedPatterns = ctx.getProtectedAccountPatterns(expressionFactory, result);
if (isProtectedShadow(protectedPatterns, shadow, result)) {
if (!ProvisioningUtil.isDeleteShadowEnabled(protectedPatterns, shadow, result)) {
// TODO remove this unnecessary logging statement (the error will be logged anyway)
LOGGER.error("Attempt to delete protected resource object " + ctx.getObjectClassDefinition() + ": "
+ identifiers + "; ignoring the request");
Expand Down Expand Up @@ -561,7 +562,7 @@ public AsynchronousOperationReturnValue<Collection<PropertyDelta<PrismPropertyVa

Collection<? extends ResourceAttribute<?>> identifiers = ShadowUtil.getAllIdentifiers(repoShadow);

if (isProtectedShadow(ctx.getProtectedAccountPatterns(expressionFactory, result), repoShadow, result)) {
if (!isModifyShadowEnabled(ctx.getProtectedAccountPatterns(expressionFactory, result), repoShadow, result)) {
if (hasChangesOnResource(itemDeltas)) {
// TODO remove this unnecessary logging statement (the error will be logged anyway)
LOGGER.error("Attempt to modify protected resource object {}: {}", objectClassDefinition, identifiers);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,12 +316,24 @@ public static <T> PropertyDelta<T> narrowPropertyDelta(
return refinedSchema;
}

public static boolean isAddShadowEnabled(Collection<ResourceObjectPattern> protectedAccountPatterns, ShadowType shadow, @NotNull OperationResult result) throws SchemaException {
return !isProtectedShadow(protectedAccountPatterns, shadow, result);
}

public static boolean isModifyShadowEnabled(Collection<ResourceObjectPattern> protectedAccountPatterns, ShadowType shadow, @NotNull OperationResult result) throws SchemaException {
return !isProtectedShadow(protectedAccountPatterns, shadow, result);
}

public static boolean isDeleteShadowEnabled(Collection<ResourceObjectPattern> protectedAccountPatterns, ShadowType shadow, @NotNull OperationResult result) throws SchemaException {
return !isProtectedShadow(protectedAccountPatterns, shadow, result);
}

public static boolean isProtectedShadow(Collection<ResourceObjectPattern> protectedAccountPatterns, ShadowType shadow, @NotNull OperationResult result)
throws SchemaException {
return getEffectiveProvisioningPolicy(protectedAccountPatterns, shadow, result).isProtected();
}

private static ShadowProvisioningPolicyType getEffectiveProvisioningPolicy(Collection<ResourceObjectPattern> protectedAccountPatterns,
private static EffectiveShadowProvisioningPolicyType getEffectiveProvisioningPolicy(Collection<ResourceObjectPattern> protectedAccountPatterns,
ShadowType shadow, @NotNull OperationResult result) throws SchemaException {
if (shadow.getEffectiveProvisioningPolicy() != null) {
return shadow.getEffectiveProvisioningPolicy();
Expand Down

0 comments on commit 35cc72a

Please sign in to comment.