Skip to content

Commit

Permalink
Basic implementation of attorney donor lookup (MID-4072, MID-4205)
Browse files Browse the repository at this point in the history
  • Loading branch information
semancik committed Oct 25, 2017
1 parent 568a68f commit b49e39f
Show file tree
Hide file tree
Showing 13 changed files with 329 additions and 19 deletions.
Expand Up @@ -203,8 +203,8 @@ public <O extends ObjectType> ObjectSecurityConstraints compileSecurityConstrain

@Override
public <T extends ObjectType, O extends ObjectType> ObjectFilter preProcessObjectFilter(String operationUrl, AuthorizationPhaseType phase,
Class<T> objectType, PrismObject<O> object, ObjectFilter origFilter, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException {
return securityEnforcer.preProcessObjectFilter(operationUrl, phase, objectType, object, origFilter, task, result);
Class<T> objectType, PrismObject<O> object, ObjectFilter origFilter, String limitAuthorizationAction, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException {
return securityEnforcer.preProcessObjectFilter(operationUrl, phase, objectType, object, origFilter, limitAuthorizationAction, task, result);
}

@Override
Expand Down
Expand Up @@ -46,7 +46,7 @@ public enum ModelAuthorizationAction implements DisplayableValue<String> {
ASSIGN("assign", "Assign", "ASSIGN_HELP"),
UNASSIGN("unassign", "Unassign", "UNASSIGN_HELP"),
DELEGATE("delegate", "Delegate", "DELEGATE_HELP"),
ATTORNEY("attroney", "Attorney", "ATTRONEY_HELP"),
ATTORNEY("attorney", "Attorney", "ATTORNEY_HELP"),
EXECUTE_SCRIPT("executeScript", "Execute script", "EXECUTE_SCRIPT_HELP"),
CHANGE_CREDENTIALS("changeCredentials", "Change credentials", "CHANGE_CREDENTIALS_HELP"),

Expand Down
Expand Up @@ -22,6 +22,7 @@
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismObjectDefinition;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.query.ObjectFilter;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.schema.ResourceShadowDiscriminator;
import com.evolveum.midpoint.schema.result.OperationResult;
Expand Down Expand Up @@ -143,6 +144,25 @@ <F extends ObjectType> ModelContext<F> previewChanges(
*/
<F extends FocusType> RoleSelectionSpecification getAssignableRoleSpecification(PrismObject<F> focus, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, ConfigurationException, ExpressionEvaluationException, CommunicationException, SecurityViolationException;

/**
* Returns filter for lookup of donors or power of attorney. The donors are the users that have granted
* the power of attorney to the currently logged-in user.
*
* TODO: authorization limitations
*
* @param searchResultType type of the expected search results
* @param origFilter original filter (e.g. taken from GUI search bar)
* @param targetAuthorizationAction Authorization action that the attorney is trying to execute
* on behalf of donor. Only donors for which the use of this authorization was
* not limited will be returned (that does not necessarily mean that the donor
* is able to execute this action, it may be limited by donor's authorizations).
* If the parameter is null then all donors are returned.
* @param task task
* @param parentResult operation result
* @return original filter with AND clause limiting the search.
*/
<T extends ObjectType> ObjectFilter getDonorFilter(Class<T> searchResultType, ObjectFilter origFilter, String targetAuthorizationAction, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException;

/**
* TODO
*
Expand Down
Expand Up @@ -1741,13 +1741,13 @@ private <O extends ObjectType> ObjectQuery preProcessQuerySecurity(Class<O> obje
if (origQuery != null) {
origFilter = origQuery.getFilter();
}
ObjectFilter secFilter = securityEnforcer.preProcessObjectFilter(ModelAuthorizationAction.READ.getUrl(), null, objectType, null, origFilter, task, result);
ObjectFilter secFilter = securityEnforcer.preProcessObjectFilter(ModelAuthorizationAction.READ.getUrl(), null, objectType, null, origFilter, null, task, result);
return updateObjectQuery(origQuery, secFilter);
}

// we expect that objectType is a direct parent of containerType
private <C extends Containerable, O extends ObjectType> ObjectQuery preProcessSubobjectQuerySecurity(Class<C> containerType, Class<O> objectType, ObjectQuery origQuery, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException {
ObjectFilter secParentFilter = securityEnforcer.preProcessObjectFilter(ModelAuthorizationAction.READ.getUrl(), null, objectType, null, null, task, result);
ObjectFilter secParentFilter = securityEnforcer.preProcessObjectFilter(ModelAuthorizationAction.READ.getUrl(), null, objectType, null, null, null, task, result);
if (secParentFilter == null || secParentFilter instanceof AllFilter) {
return origQuery; // no need to update the query
}
Expand Down
Expand Up @@ -430,7 +430,7 @@ public <F extends FocusType> RoleSelectionSpecification getAssignableRoleSpecifi

try {
ObjectFilter filter = securityEnforcer.preProcessObjectFilter(ModelAuthorizationAction.ASSIGN.getUrl(),
AuthorizationPhaseType.REQUEST, AbstractRoleType.class, focus, AllFilter.createAll(), task, result);
AuthorizationPhaseType.REQUEST, AbstractRoleType.class, focus, AllFilter.createAll(), null, task, result);
LOGGER.trace("assignableRoleSpec filter: {}", filter);
spec.setFilter(filter);
if (filter instanceof NoneFilter) {
Expand Down Expand Up @@ -617,6 +617,10 @@ private RoleSelectionSpecEntry getRoleSelectionSpecEq(EqualFilter<String> eqFilt
}


@Override
public <T extends ObjectType> ObjectFilter getDonorFilter(Class<T> searchResultType, ObjectFilter origFilter, String targetAuthorizationAction, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException {
return securityEnforcer.preProcessObjectFilter(ModelAuthorizationAction.ATTORNEY.getUrl(), null, searchResultType, null, origFilter, targetAuthorizationAction, task, parentResult);
}

@Override
public <T extends ObjectType, O extends ObjectType> boolean canSearch(Class<T> resultType,
Expand Down
Expand Up @@ -58,6 +58,7 @@
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.query.NoneFilter;
import com.evolveum.midpoint.prism.query.ObjectFilter;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.prism.query.builder.QueryBuilder;
import com.evolveum.midpoint.prism.util.PrismTestUtil;
Expand Down Expand Up @@ -323,6 +324,12 @@ public abstract class AbstractSecurityTest extends AbstractInitializedModelInteg

protected static final File ROLE_EXPRESSION_READ_ROLES_FILE = new File(TEST_DIR, "role-expression-read-roles.xml");
protected static final String ROLE_EXPRESSION_READ_ROLES_OID = "27058fde-b27e-11e7-b557-e7e43b583989";

protected static final File ROLE_ATTORNEY_CARIBBEAN_UNLIMITED_FILE = new File(TEST_DIR, "role-attorney-caribbean-unlimited.xml");
protected static final String ROLE_ATTORNEY_CARIBBEAN_UNLIMITED_OID = "b27b9f3c-b962-11e7-9c89-03e5b32f525d";

protected static final File ROLE_ATTORNEY_MANAGER_WORKITEMS_FILE = new File(TEST_DIR, "role-attorney-manager-workitems.xml");
protected static final String ROLE_ATTORNEY_MANAGER_WORKITEMS_OID = "5cf5b6c8-b968-11e7-b77d-6b029450f900";

protected static final File ORG_REQUESTABLE_FILE = new File(TEST_DIR,"org-requestable.xml");
protected static final String ORG_REQUESTABLE_OID = "8f2bd344-a46c-4c0b-aa34-db08b7d7f7f2";
Expand Down Expand Up @@ -362,7 +369,7 @@ public abstract class AbstractSecurityTest extends AbstractInitializedModelInteg
protected static final XMLGregorianCalendar JACK_VALID_FROM_LONG_AGO = XmlTypeConverter.createXMLGregorianCalendar(10000L);

protected static final int NUMBER_OF_ALL_USERS = 11;
protected static final int NUMBER_OF_IMPORTED_ROLES = 65;
protected static final int NUMBER_OF_IMPORTED_ROLES = 67;
protected static final int NUMBER_OF_ALL_ORGS = 11;

protected String userRumRogersOid;
Expand Down Expand Up @@ -442,6 +449,8 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti
repoAddObjectFromFile(ROLE_READ_SELF_MODIFY_ORGUNIT_FILE, initResult);
repoAddObjectFromFile(ROLE_INDIRECT_PIRATE_FILE, initResult);
repoAddObjectFromFile(ROLE_EXPRESSION_READ_ROLES_FILE, initResult);
repoAddObjectFromFile(ROLE_ATTORNEY_CARIBBEAN_UNLIMITED_FILE, initResult);
repoAddObjectFromFile(ROLE_ATTORNEY_MANAGER_WORKITEMS_FILE, initResult);

repoAddObjectFromFile(ORG_REQUESTABLE_FILE, initResult);
repoAddObjectFromFile(ORG_INDIRECT_PIRATE_FILE, initResult);
Expand Down Expand Up @@ -803,6 +812,10 @@ protected <O extends ObjectType> PrismObject<O> assertGetAllow(Class<O> type, St
return object;
}

protected <O extends ObjectType> void assertSearchFilter(Class<O> type, ObjectFilter filter, int expectedResults) throws Exception {
assertSearch(type, ObjectQuery.createObjectQuery(filter), null, expectedResults);
}

protected <O extends ObjectType> void assertSearch(Class<O> type, ObjectQuery query, int expectedResults) throws Exception {
assertSearch(type, query, null, expectedResults);
}
Expand Down
Expand Up @@ -31,6 +31,7 @@
import com.evolveum.midpoint.prism.PrismReferenceValue;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.query.ObjectFilter;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.prism.query.builder.QueryBuilder;
import com.evolveum.midpoint.prism.util.PrismTestUtil;
Expand Down Expand Up @@ -65,6 +66,8 @@
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
public class TestSecurityAdvanced extends AbstractSecurityTest {

private static final String AUTHORIZATION_ACTION_WORKITEMS = "http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#workItemsMyRequests";

@Override
public void initSystem(Task initTask, OperationResult initResult) throws Exception {
super.initSystem(initTask, initResult);
Expand Down Expand Up @@ -1261,6 +1264,159 @@ public void test222AutzJackRoleExpressionConstCenterBusiness() throws Exception

assertGlobalStateUntouched();
}

/**
* Unlimited power of attorney. But only granted to Caribbean users.
* MID-4072, MID-4205
*/
@Test
public void test230AttorneyCaribbeanUnlimited() throws Exception {
final String TEST_NAME = "test230AttorneyCaribbeanUnlimited";
displayTestTitle(TEST_NAME);
// GIVEN
cleanupAutzTest(USER_JACK_OID);
assignRole(USER_JACK_OID, ROLE_ATTORNEY_CARIBBEAN_UNLIMITED_OID);

assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE);

login(USER_JACK_USERNAME);

// WHEN
displayWhen(TEST_NAME);

assertReadAllow();
assertAddDeny();
assertModifyDeny();
assertDeleteDeny();

Task task = createTask(TEST_NAME);
OperationResult result = task.getResult();

ObjectFilter donorFilterAll = modelInteractionService.getDonorFilter(UserType.class, null, null, task, result);
display("donorFilterAll", donorFilterAll);
assertSearchFilter(UserType.class, donorFilterAll, 2);

assertGlobalStateUntouched();
}

/**
* Attorney for subordinate employees, but Jack has no org.
* MID-4072, MID-4205
*/
@Test
public void test232ManagerAttorneyNoOrg() throws Exception {
final String TEST_NAME = "test232ManagerAttorneyNoOrg";
displayTestTitle(TEST_NAME);
// GIVEN
cleanupAutzTest(USER_JACK_OID);
assignRole(USER_JACK_OID, ROLE_ATTORNEY_MANAGER_WORKITEMS_OID);

assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE);

login(USER_JACK_USERNAME);

// WHEN
displayWhen(TEST_NAME);

assertReadAllow();
assertAddDeny();
assertModifyDeny();
assertDeleteDeny();

Task task = createTask(TEST_NAME);
OperationResult result = task.getResult();

ObjectFilter donorFilterAll = modelInteractionService.getDonorFilter(UserType.class, null, null, task, result);
display("donorFilterAll", donorFilterAll);
assertSearchFilter(UserType.class, donorFilterAll, 0);

ObjectFilter donorFilterWorkitems = modelInteractionService.getDonorFilter(UserType.class, null, AUTHORIZATION_ACTION_WORKITEMS, task, result);
display("donorFilterWorkitems", donorFilterWorkitems);
assertSearchFilter(UserType.class, donorFilterWorkitems, 0);

assertGlobalStateUntouched();
}

/**
* Attorney for subordinate employees, Jack is manager of Ministry of Rum.
* MID-4072, MID-4205
*/
@Test
public void test234ManagerAttorneyRum() throws Exception {
final String TEST_NAME = "test234ManagerAttorneyRum";
displayTestTitle(TEST_NAME);
// GIVEN
cleanupAutzTest(USER_JACK_OID);
assignRole(USER_JACK_OID, ROLE_ATTORNEY_MANAGER_WORKITEMS_OID);
assignOrg(USER_JACK_OID, ORG_MINISTRY_OF_RUM_OID, SchemaConstants.ORG_MANAGER);

assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE);

login(USER_JACK_USERNAME);

// WHEN
displayWhen(TEST_NAME);

assertReadAllow();
assertAddDeny();
assertModifyDeny();
assertDeleteDeny();

Task task = createTask(TEST_NAME);
OperationResult result = task.getResult();

ObjectFilter donorFilterAll = modelInteractionService.getDonorFilter(UserType.class, null, null, task, result);
display("donorFilterAll", donorFilterAll);
assertSearchFilter(UserType.class, donorFilterAll, 4);

ObjectFilter donorFilterWorkitems = modelInteractionService.getDonorFilter(UserType.class, null, AUTHORIZATION_ACTION_WORKITEMS, task, result);
display("donorFilterWorkitems", donorFilterWorkitems);
assertSearchFilter(UserType.class, donorFilterWorkitems, 4);

assertGlobalStateUntouched();
}

/**
* Attorney for subordinate employees, Jack is manager of Ministry of Rum.
* Also unlimited Caribbean attorney.
* MID-4072, MID-4205
*/
@Test
public void test236ManagerAttorneyCaribbeanRum() throws Exception {
final String TEST_NAME = "test236ManagerAttorneyCaribbeanRum";
displayTestTitle(TEST_NAME);
// GIVEN
cleanupAutzTest(USER_JACK_OID);
assignRole(USER_JACK_OID, ROLE_ATTORNEY_CARIBBEAN_UNLIMITED_OID);
assignRole(USER_JACK_OID, ROLE_ATTORNEY_MANAGER_WORKITEMS_OID);
assignOrg(USER_JACK_OID, ORG_MINISTRY_OF_RUM_OID, SchemaConstants.ORG_MANAGER);

assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE);

login(USER_JACK_USERNAME);

// WHEN
displayWhen(TEST_NAME);

assertReadAllow();
assertAddDeny();
assertModifyDeny();
assertDeleteDeny();

Task task = createTask(TEST_NAME);
OperationResult result = task.getResult();

ObjectFilter donorFilterAll = modelInteractionService.getDonorFilter(UserType.class, null, null, task, result);
display("donorFilterAll", donorFilterAll);
assertSearchFilter(UserType.class, donorFilterAll, 5);

display("DONOR");
ObjectFilter donorFilterWorkitems = modelInteractionService.getDonorFilter(UserType.class, null, AUTHORIZATION_ACTION_WORKITEMS, task, result);
display("donorFilterWorkitems", donorFilterWorkitems);
assertSearchFilter(UserType.class, donorFilterWorkitems, 5);

assertGlobalStateUntouched();
}


@Override
Expand Down
2 changes: 1 addition & 1 deletion model/model-intest/src/test/resources/logback-test.xml
Expand Up @@ -92,7 +92,7 @@
<logger name="com.evolveum.midpoint.model.impl.controller.ObjectMerger" level="DEBUG" />
<logger name="com.evolveum.midpoint.notifications" level="DEBUG" />
<logger name="com.evolveum.midpoint.security" level="DEBUG" />
<logger name="com.evolveum.midpoint.security.impl.SecurityEnforcerImpl" level="DEBUG" />
<logger name="com.evolveum.midpoint.security.enforcer.impl.SecurityEnforcerImpl" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.security" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.util.AbstractSearchIterativeTaskHandler" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.sync.SynchronizationServiceImpl" level="DEBUG" />
Expand Down
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2017 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.
-->
<role oid="b27b9f3c-b962-11e7-9c89-03e5b32f525d"
xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3">
<name>Attorney Caribbean Unlimited</name>
<description>Unlimited power of attorney. But limited only to Caribbean users (objects)</description>

<authorization>
<name>attorney-read-all</name>
<action>http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read</action>
</authorization>

<authorization>
<name>attorney-unlimited</name>
<action>http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#attorney</action>
<object>
<type>UserType</type>
<filter>
<q:equal>
<q:path>locality</q:path>
<q:value>Caribbean</q:value>
</q:equal>
</filter>
</object>
</authorization>

</role>

0 comments on commit b49e39f

Please sign in to comment.