diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/AjaxCompositedIconButton.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/AjaxCompositedIconButton.java index ba165703b9d..93610509b5f 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/AjaxCompositedIconButton.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/AjaxCompositedIconButton.java @@ -32,6 +32,7 @@ /** * @author Viliam Repan (lazyman) + * @author skublik */ public abstract class AjaxCompositedIconButton extends AjaxLink { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/orgs/OrgTreePanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/orgs/OrgTreePanel.html index 9bf90dddba6..bad5f8fdaf5 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/orgs/OrgTreePanel.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/orgs/OrgTreePanel.html @@ -24,7 +24,7 @@

-
+
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/ResourceContentPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/ResourceContentPanel.java index e556cf0200e..ad050c4f488 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/ResourceContentPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/ResourceContentPanel.java @@ -282,7 +282,7 @@ protected BaseSortableDataProvider> initProvider() { @Override protected ObjectQuery createContentQuery() { ObjectQuery parentQuery = super.createContentQuery(); - QueryFactory queryFactory = getPrismContext().queryFactory(); + QueryFactory queryFactory = pageBase.getPrismContext().queryFactory(); List filters = new ArrayList<>(); if (parentQuery != null) { diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ClockworkAuthorizationHelper.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ClockworkAuthorizationHelper.java index e498b5252c5..e263d8729c4 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ClockworkAuthorizationHelper.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ClockworkAuthorizationHelper.java @@ -132,7 +132,7 @@ private ObjectSecurityConstraints a // the same account in one operation object = elementContext.getObjectNew(); } - String operationUrl = ModelImplUtils.getOperationUrlFromDelta(primaryDeltaClone); + String deltaOperationUrl = ModelImplUtils.getOperationUrlFromDelta(primaryDeltaClone); ObjectSecurityConstraints securityConstraints = securityEnforcer.compileSecurityConstraints(object, ownerResolver, task, result); if (securityConstraints == null) { if (LOGGER.isTraceEnabled()) { @@ -145,10 +145,10 @@ private ObjectSecurityConstraints a // Process assignments/inducements first. If the assignments/inducements are allowed then we // have to ignore the assignment item in subsequent security checks if (object.canRepresent(FocusType.class)) { - processAssignment(context, elementContext, primaryDeltaClone, operationUrl, FocusType.F_ASSIGNMENT, object, ownerResolver, securityConstraints, task, result); + processAssignment(context, elementContext, primaryDeltaClone, deltaOperationUrl, FocusType.F_ASSIGNMENT, object, ownerResolver, securityConstraints, task, result); } if (object.canRepresent(AbstractRoleType.class)) { - processAssignment(context, elementContext, primaryDeltaClone, operationUrl, AbstractRoleType.F_INDUCEMENT, object, ownerResolver, securityConstraints, task, result); + processAssignment(context, elementContext, primaryDeltaClone, deltaOperationUrl, AbstractRoleType.F_INDUCEMENT, object, ownerResolver, securityConstraints, task, result); } } @@ -205,7 +205,7 @@ private ObjectSecurityConstraints a if (primaryDeltaClone != null && !primaryDeltaClone.isEmpty()) { // TODO: optimize, avoid evaluating the constraints twice - securityEnforcer.authorize(operationUrl, getRequestAuthorizationPhase(context) , AuthorizationParameters.Builder.buildObjectDelta(object, primaryDeltaClone), ownerResolver, task, result); + securityEnforcer.authorize(deltaOperationUrl, getRequestAuthorizationPhase(context) , AuthorizationParameters.Builder.buildObjectDelta(object, primaryDeltaClone), ownerResolver, task, result); } if (LOGGER.isTraceEnabled()) { @@ -225,7 +225,7 @@ private void processAssignment( LensContext context, LensElementContext elementContext, ObjectDelta primaryDeltaClone, - String operationUrl, + String deltaOperationUrl, ItemName assignmentElementQName, PrismObject object, OwnerResolver ownerResolver, @@ -240,7 +240,7 @@ private void processAssignment( } if (primaryDeltaClone.hasItemOrSubitemDelta(assignmentElementQName)) { - AccessDecision assignmentItemDecision = determineDecisionForAssignmentItems(securityConstraints, primaryDeltaClone, currentObject, operationUrl, getRequestAuthorizationPhase(context)); + AccessDecision assignmentItemDecision = determineDecisionForAssignmentItems(securityConstraints, primaryDeltaClone, currentObject, deltaOperationUrl, assignmentElementQName, getRequestAuthorizationPhase(context)); LOGGER.trace("Security decision for {} items: {}", assignmentElementQName.getLocalPart(), assignmentItemDecision); if (assignmentItemDecision == AccessDecision.ALLOW) { // Nothing to do, operation is allowed for all values @@ -252,7 +252,7 @@ private void processAssignment( } throw new AuthorizationException("Access denied"); } else { - AuthorizationDecisionType allItemsDecision = securityConstraints.findAllItemsDecision(operationUrl, getRequestAuthorizationPhase(context)); + AuthorizationDecisionType allItemsDecision = securityConstraints.findAllItemsDecision(deltaOperationUrl, getRequestAuthorizationPhase(context)); if (allItemsDecision == AuthorizationDecisionType.ALLOW) { // Nothing to do, operation is allowed for all values } else if (allItemsDecision == AuthorizationDecisionType.DENY) { @@ -263,14 +263,14 @@ private void processAssignment( } else { // No blank decision for assignment modification yet // process each assignment individually - authorizeAssignmentRequest(context, operationUrl, ModelAuthorizationAction.ASSIGN.getUrl(), + authorizeAssignmentRequest(context, deltaOperationUrl, ModelAuthorizationAction.ASSIGN.getUrl(), assignmentElementQName, object, ownerResolver, securityConstraints, PlusMinusZero.PLUS, true, task, result); if (!primaryDeltaClone.isAdd()) { // We want to allow unassignment even if there are policies. Otherwise we would not be able to get // rid of that assignment - authorizeAssignmentRequest(context, operationUrl, ModelAuthorizationAction.UNASSIGN.getUrl(), + authorizeAssignmentRequest(context, deltaOperationUrl, ModelAuthorizationAction.UNASSIGN.getUrl(), assignmentElementQName, object, ownerResolver, securityConstraints, PlusMinusZero.MINUS, false, task, result); } @@ -393,7 +393,7 @@ private void authorizeAssignmentRequ if (LOGGER.isDebugEnabled()) { LOGGER.debug("{} of target {} to {} denied", operationDesc, target, object); } - securityEnforcer.failAuthorization("with assignment", getRequestAuthorizationPhase(context), autzParams, result); + securityEnforcer.failAuthorization("with "+assignmentElementQName.getLocalPart(), getRequestAuthorizationPhase(context), autzParams, result); } } @@ -419,9 +419,9 @@ private List deterimneOrderConstraints(QName assignmentEle } private AccessDecision determineDecisionForAssignmentItems( - ObjectSecurityConstraints securityConstraints, ObjectDelta primaryDelta, PrismObject currentObject, String operationUrl, - AuthorizationPhaseType requestAuthorizationPhase) { - return securityEnforcer.determineSubitemDecision(securityConstraints, primaryDelta, currentObject, operationUrl, requestAuthorizationPhase, SchemaConstants.PATH_ASSIGNMENT); + ObjectSecurityConstraints securityConstraints, ObjectDelta primaryDelta, PrismObject currentObject, String deltaOperationUrl, + ItemName assignmentElementQName, AuthorizationPhaseType requestAuthorizationPhase) { + return securityEnforcer.determineSubitemDecision(securityConstraints, primaryDelta, currentObject, deltaOperationUrl, requestAuthorizationPhase, assignmentElementQName); } private AuthorizationPhaseType getRequestAuthorizationPhase(LensContext context) { diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityAdvanced.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityAdvanced.java index 24f666e387c..c29b5ce66ae 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityAdvanced.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityAdvanced.java @@ -112,6 +112,9 @@ public class TestSecurityAdvanced extends AbstractSecurityTest { protected static final File ROLE_READ_ROLE_MEMBERS_NONE_FILE = new File(TEST_DIR, "role-read-role-members-none.xml"); protected static final String ROLE_READ_ROLE_MEMBERS_NONE_OID = "9e93dfb2-3eff-11e7-b56b-1b0e35f837fc"; + protected static final File ROLE_ROLE_ADMINISTRATOR_FILE = new File(TEST_DIR, "role-role-administrator.xml"); + protected static final String ROLE_ROLE_ADMINISTRATOR_OID = "b63ee91e-020c-11e9-a7c2-df4b9f00f209"; + protected static final File ROLE_LIMITED_ROLE_ADMINISTRATOR_FILE = new File(TEST_DIR, "role-limited-role-administrator.xml"); protected static final String ROLE_LIMITED_ROLE_ADMINISTRATOR_OID = "ce67b472-e5a6-11e7-98c3-174355334559"; @@ -160,6 +163,7 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti RESOURCE_DUMMY_VAULT_FILE, RESOURCE_DUMMY_VAULT_OID, initTask, initResult); repoAddObjectFromFile(ROLE_VAULT_DWELLER_FILE, initResult); + repoAddObjectFromFile(ROLE_ROLE_ADMINISTRATOR_FILE, initResult); repoAddObjectFromFile(ROLE_LIMITED_ROLE_ADMINISTRATOR_FILE, initResult); repoAddObjectFromFile(ROLE_LIMITED_READ_ROLE_ADMINISTRATOR_FILE, initResult); repoAddObjectFromFile(ROLE_MAXASSIGNEES_10_FILE, initResult); @@ -180,7 +184,7 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti setDefaultObjectTemplate(UserType.COMPLEX_TYPE, USER_TEMPLATE_SECURITY_OID, initResult); } - protected static final int NUMBER_OF_IMPORTED_ROLES = 17; + protected static final int NUMBER_OF_IMPORTED_ROLES = 18; protected int getNumberOfRoles() { return super.getNumberOfRoles() + NUMBER_OF_IMPORTED_ROLES; @@ -305,7 +309,6 @@ public void test102AutzLechuckPersonaManagement() throws Exception { assertGetDeny(UserType.class, USER_JACK_OID); assertGetDeny(UserType.class, USER_GUYBRUSH_OID); assertGetAllow(UserType.class, USER_LECHUCK_OID); - display("HEREHERE"); assertGetAllow(UserType.class, USER_CHARLES_OID); // TODO: MID-3899 @@ -2376,10 +2379,78 @@ public void test264AutzJackLimitedReadRoleAdministrator() throws Exception { assertItemFlags(roleEmptyEditSchema, ItemPath.create(RoleType.F_INDUCEMENT, AssignmentType.F_CONSTRUCTION, ConstructionType.F_STRENGTH), true, true, true); + + assertAllow("induce role uninteresting to empty role", + (task, result) -> induceRole(RoleType.class, ROLE_EMPTY_OID, ROLE_UNINTERESTING_OID, task, result)); + + assertAllow("uninduce role uninteresting to empty role", + (task, result) -> uninduceRole(RoleType.class, ROLE_EMPTY_OID, ROLE_UNINTERESTING_OID, task, result)); + + assertGlobalStateUntouched(); + } + + /** + * MID-5005 + */ + @Test + public void test266AutzJackRoleAdministrator() throws Exception { + final String TEST_NAME = "test266AutzJackRoleAdministrator"; + displayTestTitle(TEST_NAME); + // GIVEN + cleanupAutzTest(USER_JACK_OID); + assignRole(USER_JACK_OID, ROLE_ROLE_ADMINISTRATOR_OID); + login(USER_JACK_USERNAME); + + // WHEN + displayWhen(TEST_NAME); + + assertGetAllow(UserType.class, USER_JACK_OID); + assertGetDeny(UserType.class, USER_JACK_OID, SelectorOptions.createCollection(GetOperationOptions.createRaw())); + assertGetDeny(UserType.class, USER_GUYBRUSH_OID); + assertGetDeny(UserType.class, USER_GUYBRUSH_OID, SelectorOptions.createCollection(GetOperationOptions.createRaw())); + assertReadDenyRaw(); + + assertSearch(UserType.class, null, 1); + assertSearch(UserType.class, createNameQuery(USER_JACK_USERNAME), 1); + assertSearchDeny(UserType.class, createNameQuery(USER_JACK_USERNAME), SelectorOptions.createCollection(GetOperationOptions.createRaw())); + assertSearch(UserType.class, createNameQuery(USER_GUYBRUSH_USERNAME), 0); + assertSearchDeny(UserType.class, createNameQuery(USER_GUYBRUSH_USERNAME), SelectorOptions.createCollection(GetOperationOptions.createRaw())); + + assertAddDeny(); + assertDeleteDeny(); + + assertAddAllow(ROLE_EXCLUSION_PIRATE_FILE); + + PrismObject roleExclusion = assertGetAllow(RoleType.class, ROLE_EXCLUSION_PIRATE_OID); + display("Exclusion role", roleExclusion); + assertExclusion(roleExclusion, ROLE_PIRATE_OID); + + assertAllow("assign role uninteresting to empty role", + (task, result) -> assignRole(RoleType.class, ROLE_EMPTY_OID, ROLE_UNINTERESTING_OID, task, result)); + + assertAllow("unassign role uninteresting to empty role", + (task, result) -> unassignRole(RoleType.class, ROLE_EMPTY_OID, ROLE_UNINTERESTING_OID, task, result)); + + PrismObject roleEmpty = assertGetAllow(RoleType.class, ROLE_EMPTY_OID); + display("Empty empty (1)", roleEmpty); + assertAssignments(roleEmpty, 0); + assertInducements(roleEmpty, 0); + + assertAllow("induce role uninteresting to empty role", + (task, result) -> induceRole(RoleType.class, ROLE_EMPTY_OID, ROLE_UNINTERESTING_OID, task, result)); + + assertAllow("uninduce role uninteresting to empty role", + (task, result) -> uninduceRole(RoleType.class, ROLE_EMPTY_OID, ROLE_UNINTERESTING_OID, task, result)); + + roleEmpty = assertGetAllow(RoleType.class, ROLE_EMPTY_OID); + display("Empty empty (2)", roleEmpty); + assertAssignments(roleEmpty, 0); + assertInducements(roleEmpty, 0); assertGlobalStateUntouched(); } + @Test public void test270AutzJackModifyPolicyException() throws Exception { diff --git a/model/model-intest/src/test/resources/security/role-role-administrator.xml b/model/model-intest/src/test/resources/security/role-role-administrator.xml new file mode 100644 index 00000000000..2a7c6d438a5 --- /dev/null +++ b/model/model-intest/src/test/resources/security/role-role-administrator.xml @@ -0,0 +1,53 @@ + + + Role Administrator + + self-read + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + + self + + + + read roles + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + + RoleType + + + + write roles + 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 + + RoleType + + name + description + subtype + lifecycleState + requestable + delegable + inducement + assignment + + diff --git a/model/model-intest/src/test/resources/sync/password-policy-azure.xml b/model/model-intest/src/test/resources/sync/password-policy-azure.xml index fa7858cec31..292427ec9ae 100644 --- a/model/model-intest/src/test/resources/sync/password-policy-azure.xml +++ b/model/model-intest/src/test/resources/sync/password-policy-azure.xml @@ -67,7 +67,7 @@ - 50 + 100 \ No newline at end of file diff --git a/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java b/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java index 0db8e1ab1bc..498b614edb1 100644 --- a/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java +++ b/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java @@ -799,6 +799,18 @@ protected void unassignRole(String userOid, String roleOid, ActivationType activ PolicyViolationException, SecurityViolationException { modifyUserAssignment(userOid, roleOid, RoleType.COMPLEX_TYPE, null, task, null, activationType, false, result); } + + protected void unassignRole(Class focusClass, String focusOid, String roleOid, Task task, OperationResult result) throws ObjectNotFoundException, + SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, ObjectAlreadyExistsException, + PolicyViolationException, SecurityViolationException { + unassignRole(focusClass, focusOid, roleOid, (ActivationType) null, task, result); + } + + protected void unassignRole(Class focusClass, String focusOid, String roleOid, ActivationType activationType, Task task, OperationResult result) throws ObjectNotFoundException, + SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, ObjectAlreadyExistsException, + PolicyViolationException, SecurityViolationException { + modifyFocusAssignment(focusClass, focusOid, roleOid, RoleType.COMPLEX_TYPE, null, task, null, activationType, false, result); + } protected void assignRole(Class focusClass, String focusOid, String roleOid, ActivationType activationType, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, ObjectAlreadyExistsException,