Skip to content

Commit

Permalink
Fix create/modifyTaskRef in MetadataType
Browse files Browse the repository at this point in the history
When storing task references in MetadataType we now always store
a reference to the root task there. All subtasks are (in most cases)
transient, and storing their OIDs for future reference makes almost
no sense.

This resolves MID-7179.

(cherry picked from commit 1ceb912)
  • Loading branch information
mederly committed Sep 29, 2021
1 parent 4893857 commit 7381fe4
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,7 @@
<xsd:annotation>
<xsd:documentation>
Reference to the task that created the object (if it was a persistent one).
If the task was a subtask, then the reference to the task tree is stored here.
</xsd:documentation>
<xsd:appinfo>
<a:displayName>MetadataType.createTaskRef</a:displayName>
Expand Down Expand Up @@ -1111,6 +1112,8 @@
<xsd:documentation>
Reference to the task that last modified the object (if it was a persistent one).
If the last modification was carried out by synchronous task, this reference will be empty.

If the task was a subtask, then the reference to the task tree is stored here.
</xsd:documentation>
<xsd:appinfo>
<a:displayName>MetadataType.modifyTaskRef</a:displayName>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
import com.evolveum.midpoint.prism.util.CloneUtil;
import com.evolveum.midpoint.schema.constants.Channel;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import com.evolveum.midpoint.task.api.RunningTask;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

Expand All @@ -33,8 +35,6 @@
import static com.evolveum.midpoint.prism.PrismContainerValue.asContainerable;
import static com.evolveum.midpoint.prism.path.ItemPath.CompareResult.EQUIVALENT;
import static com.evolveum.midpoint.prism.path.ItemPath.CompareResult.SUPERPATH;
import static java.util.Collections.emptySet;
import static java.util.Collections.singleton;

/**
* @author semancik
Expand Down Expand Up @@ -271,7 +271,7 @@ private <F extends ObjectType> void applyCreateMetadata(LensContext<F> context,
if (task.getOwnerRef() != null) {
metaData.setCreatorRef(ObjectTypeUtil.createObjectRefCopy(task.getOwnerRef()));
}
metaData.setCreateTaskRef(task.getOid() != null ? task.getSelfReference() : null);
metaData.setCreateTaskRef(createRootTaskRef(task));
}

private <F extends ObjectType> void applyCreateApprovalMetadata(LensContext<F> context, MetadataType metadata) {
Expand Down Expand Up @@ -306,8 +306,8 @@ public <F extends ObjectType, T extends ObjectType> Collection<ItemDelta<?,?>> c
.item(metadataPath.append(MetadataType.F_MODIFY_TIMESTAMP)).replace(now)
.item(metadataPath.append(MetadataType.F_MODIFIER_REF))
.replace(ObjectTypeUtil.createObjectRefCopy(task.getOwnerRef()))
.item(metadataPath.append(MetadataType.F_MODIFY_TASK_REF)).replaceRealValues(
task.getOid() != null ? singleton(task.getSelfReference()) : emptySet())
.item(metadataPath.append(MetadataType.F_MODIFY_TASK_REF))
.replace(createRootTaskRef(task))
.asItemDeltas());
if (existingMetadata != null) {
createMigrationDelta(existingMetadata, metadataPath, objectType, deltas);
Expand All @@ -325,4 +325,20 @@ private <T extends ObjectType> void createMigrationDelta(MetadataType existingMe
.asItemDelta());
}
}

/**
* Returns a reference suitable for use as create/modifyTaskRef: a reference to the root of the task tree.
*
* (We assume that if the task is a part of a task tree, it is always a {@link RunningTask}.)
*/
private static @Nullable ObjectReferenceType createRootTaskRef(@NotNull Task task) {
if (task instanceof RunningTask) {
return ((RunningTask) task).getRootTask().getSelfReference();
} else if (task.isPersistent()) {
// Actually this should not occur in real life. If a task is persistent, it should be a RunningTask.
return task.getSelfReference();
} else {
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.evolveum.midpoint.prism.PrismContainer;
import com.evolveum.midpoint.schema.constants.Channel;

import com.evolveum.midpoint.test.TestResource;
import com.evolveum.midpoint.util.SingleLocalizableMessage;

import org.springframework.test.annotation.DirtiesContext;
Expand Down Expand Up @@ -62,6 +63,7 @@ public abstract class AbstractPasswordTest extends AbstractInitializedModelInteg
protected static final String USER_PASSWORD_1_CLEAR = "d3adM3nT3llN0Tal3s";
protected static final String USER_PASSWORD_2_CLEAR = "bl4ckP3arl";
protected static final String USER_PASSWORD_3_CLEAR = "wh3r3sTheRum?";
private static final String USER_PASSWORD_3A_CLEAR = "wh3r3sTheRum!!";
protected static final String USER_PASSWORD_4_CLEAR = "sh1v3rM3T1mb3rs";
protected static final String USER_PASSWORD_5_CLEAR = "s3tSa1al";
protected static final String USER_PASSWORD_AA_CLEAR = "AA"; // too short
Expand Down Expand Up @@ -118,6 +120,8 @@ public abstract class AbstractPasswordTest extends AbstractInitializedModelInteg
protected static final String USER_JACK_EMPLOYEE_NUMBER_NEW_GOOD = "pir321";
protected static final String USER_RAPP_EMAIL = "rapp.scallion@evolveum.com";

private static final TestResource<TaskType> TASK_CHANGE_JACK_ACCOUNT_PASSWORD = new TestResource<>(TEST_DIR, "task-change-jack-account-password.xml", "442f8d91-4f1c-4651-b6c6-65b5aa3ab1d4");

public static final String PASSWORD_HELLO_WORLD = "H3ll0w0rld";

public static final int ORG_MINISTRY_OF_OFFENSE_PASSWORD_HISTORY_LENGTH = 3;
Expand Down Expand Up @@ -478,12 +482,59 @@ public void test111ModifyAccountJackPassword() throws Exception {
assertNoUserPasswordNotifications();
}

/**
* Changing shadow password from the task. Checking taskRef being correctly set.
*
* MID-7179
*/
@Test
public void test112ModifyAccountJackPasswordInBackground() throws Exception {
given();
Task task = getTestTask();
OperationResult result = task.getResult();
prepareTest();

when();
addObject(TASK_CHANGE_JACK_ACCOUNT_PASSWORD, task, result);
waitForTaskCloseOrSuspend(TASK_CHANGE_JACK_ACCOUNT_PASSWORD.oid);

then();
assertTask(TASK_CHANGE_JACK_ACCOUNT_PASSWORD.oid, "after")
.assertClosed()
.assertSuccess()
.rootActivityState()
.progress()
.assertSuccessCount(0, 1);

PrismObject<UserType> userJack = getUser(USER_JACK_OID);
display("User after change execution", userJack);
assertUserJack(userJack, "Jack Sparrow");

// User should still have old password
assertUserPassword(userJack, USER_PASSWORD_2_CLEAR);
// Account has new password
assertDummyPassword(ACCOUNT_JACK_DUMMY_USERNAME, USER_PASSWORD_3A_CLEAR);

assertPasswordMetadata(userJack, false, lastPasswordChangeStart, lastPasswordChangeEnd);

assertUser(userJack.getOid(), "after")
.links()
.singleLive()
.resolveTarget()
.display("shadow after")
.passwordMetadata()
.assertModifyTaskOid(TASK_CHANGE_JACK_ACCOUNT_PASSWORD.oid);

assertSingleAccountPasswordNotification(null, USER_JACK_USERNAME, USER_PASSWORD_3A_CLEAR);
assertNoUserPasswordNotifications();
}

/**
* Modify both user and account password. As password outbound mapping is weak the user should have its own password
* and account should have its own password.
*/
@Test
public void test112ModifyJackPasswordUserAndAccount() throws Exception {
public void test115ModifyJackPasswordUserAndAccount() throws Exception {
// GIVEN
Task task = getTestTask();
OperationResult result = task.getResult();
Expand Down Expand Up @@ -1391,7 +1442,7 @@ public void test252ExistingPasswordReuseSucceed() throws Exception {

// THEN
then();
assertSuccess(result);;
assertSuccess(result);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<!--
~ Copyright (C) 2010-2021 Evolveum and contributors
~
~ This work is dual-licensed under the Apache License 2.0
~ and European Union Public License. See LICENSE file for details.
-->

<task xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3"
xmlns:s="http://midpoint.evolveum.com/xml/ns/public/model/scripting-3"
oid="442f8d91-4f1c-4651-b6c6-65b5aa3ab1d4">
<name>change-account-password</name>
<ownerRef oid="00000000-0000-0000-0000-000000000002" type="UserType"/>
<executionStatus>runnable</executionStatus>
<activity>
<work>
<iterativeScripting>
<objects>
<type>ShadowType</type>
<query>
<q:filter>
<q:equal>
<q:path>name</q:path>
<q:value>jack</q:value>
</q:equal>
</q:filter>
</query>
<useRepositoryDirectly>true</useRepositoryDirectly>
</objects>
<scriptExecutionRequest>
<s:execute>
<s:script>
<code>
import com.evolveum.midpoint.xml.ns._public.common.common_3.*
import com.evolveum.prism.xml.ns._public.types_3.*

delta = midpoint.deltaFor(ShadowType.class)
.item(ShadowType.F_CREDENTIALS, CredentialsType.F_PASSWORD, PasswordType.F_VALUE)
.replace(ProtectedStringType.fromClearValue('wh3r3sTheRum!!'))
.asObjectDelta(input.oid)

midpoint.executeChanges(delta)
</code>
</s:script>
</s:execute>
</scriptExecutionRequest>
</iterativeScripting>
</work>
<distribution>
<workerThreads>2</workerThreads>
</distribution>
</activity>
</task>
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
*/
package com.evolveum.midpoint.test.asserter;

import static com.evolveum.midpoint.prism.Referencable.getOid;

import static org.assertj.core.api.Assertions.assertThat;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertNull;

Expand All @@ -17,19 +20,19 @@
*/
public class MetadataAsserter<RA> extends AbstractAsserter<RA> {

private MetadataType metadataType;
private MetadataType metadata;

public MetadataAsserter(MetadataType metadataType, RA returnAsserter, String details) {
public MetadataAsserter(MetadataType metadata, RA returnAsserter, String details) {
super(returnAsserter, details);
this.metadataType = metadataType;
this.metadata = metadata;
}

MetadataType getMetadata() {
return metadataType;
return metadata;
}

public MetadataAsserter<RA> assertNone() {
assertNull("Unexpected "+desc(), metadataType);
assertNull("Unexpected "+desc(), metadata);
return this;
}

Expand All @@ -43,4 +46,9 @@ protected String desc() {
return descWithDetails("metadata of "+getDetails());
}

public MetadataAsserter<RA> assertModifyTaskOid(String expectedOid) {
String realOid = getOid(metadata.getModifyTaskRef());
assertThat(realOid).as("modify task ref OID").isEqualTo(expectedOid);
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -558,4 +558,23 @@ private boolean matches(OperationExecutionType record, OperationExecutionRecordT
&& java.util.Objects.equals(realTaskOid, taskOid)
&& record.getStatus() == status;
}

public MetadataAsserter<PrismObjectAsserter<O, RA>> passwordMetadata() {
MetadataType metadata = getPasswordMetadata();
MetadataAsserter<PrismObjectAsserter<O, RA>> asserter =
new MetadataAsserter<>(metadata, this, "password metadata in " + desc());
copySetupTo(asserter);
return asserter;
}

private MetadataType getPasswordMetadata() {
Item<?, ?> item = object.findItem(
ItemPath.create(
FocusType.F_CREDENTIALS, // the same for ShadowType
CredentialsType.F_PASSWORD,
PasswordType.F_METADATA));
assertThat(item).as("password metadata").isNotNull();
//noinspection unchecked
return ((PrismContainer<MetadataType>) item).getRealValue();
}
}

0 comments on commit 7381fe4

Please sign in to comment.