Skip to content

Commit

Permalink
Execution-only authorization for midPoint function library (MID-4304)
Browse files Browse the repository at this point in the history
  • Loading branch information
semancik committed Mar 19, 2018
1 parent 716703f commit 7633be8
Show file tree
Hide file tree
Showing 27 changed files with 648 additions and 67 deletions.
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
Expand All @@ -21,5 +21,5 @@
<authorization>
<action>http://midpoint.evolveum.com/xml/ns/public/security/authorization-3#all</action>
</authorization>
<roleType>system</roleType>
<subType>system</subType>
</role>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
Expand Down Expand Up @@ -221,5 +221,5 @@
</owner>
</object>
</authorization>
<roleType>system</roleType>
<subType>system</subType>
</role>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2017 Evolveum
~ Copyright (c) 2017-2018 Evolveum
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -130,5 +130,5 @@
<item>riskLevel</item>
<item>serviceType</item>
</authorization>
<roleType>system</roleType>
<subType>system</subType>
</role>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
Expand Down Expand Up @@ -100,5 +100,5 @@
<item>riskLevel</item>
<item>serviceType</item>
</authorization>
<roleType>system</roleType>
<subType>system</subType>
</role>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2016-2017 Evolveum
~ Copyright (c) 2016-2018 Evolveum
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -83,4 +83,5 @@
<item>roleMembershipRef</item>
<item>delegatedRef</item>
</authorization>
<subType>system</subType>
</role>
Expand Up @@ -163,6 +163,17 @@ public class GetOperationOptions extends AbstractOptions implements Serializable
* Whether to override default iteration method (in searchObjectsIterative) configured for particular DBMS.
*/
private IterationMethodType iterationMethod;

/**
* Whether this operation is already part of the execution phase. I.e. the request authorization was already
* processed. This means that the operation is in fact operation invoked within another operation,
* e.g. invoked from script or expression evaluator.
*
* WARNING: THIS OPTION MUST NOT BE AVAILABLE FROM REMOTE INTERFACES.
* This is safe to use from a secure area of JVM, where the components can trick model to circumvent
* authorizations anyway. But it must not be available outside of the secure area.
*/
private Boolean executionPhase;

public RetrieveOption getRetrieve() {
return retrieve;
Expand Down Expand Up @@ -686,7 +697,7 @@ public static boolean isAttachDiagData(GetOperationOptions options) {
}
return options.attachDiagData;
}

/**
* Whether to attach diagnostics data to the returned object(s).
*/
Expand All @@ -695,6 +706,30 @@ public static GetOperationOptions createAttachDiagData() {
opts.setAttachDiagData(true);
return opts;
}

public Boolean getExecutionPhase() {
return executionPhase;
}

public void setExecutionPhase(Boolean executionPhase) {
this.executionPhase = executionPhase;
}

public static boolean isExecutionPhase(GetOperationOptions options) {
if (options == null) {
return false;
}
if (options.executionPhase == null) {
return false;
}
return options.executionPhase;
}

public static GetOperationOptions createExecutionPhase() {
GetOperationOptions opts = new GetOperationOptions();
opts.setExecutionPhase(true);
return opts;
}

public DefinitionProcessingOption getDefinitionProcessing() {
return definitionProcessing;
Expand Down Expand Up @@ -765,14 +800,15 @@ public boolean equals(Object o) {
Objects.equals(readOnly, that.readOnly) &&
Objects.equals(pointInTimeType, that.pointInTimeType) &&
Objects.equals(staleness, that.staleness) &&
Objects.equals(distinct, that.distinct);
Objects.equals(attachDiagData, that.attachDiagData) &&
Objects.equals(executionPhase, that.executionPhase);
}

@Override
public int hashCode() {
return Objects
.hash(retrieve, resolve, resolveNames, noFetch, raw, tolerateRawData, doNotDiscovery, relationalValueSearchQuery,
allowNotFound, readOnly, staleness, distinct, definitionProcessing);
allowNotFound, readOnly, staleness, distinct, definitionProcessing, attachDiagData, executionPhase);
}

public GetOperationOptions clone() {
Expand All @@ -788,6 +824,8 @@ public GetOperationOptions clone() {
clone.pointInTimeType = this.pointInTimeType;
clone.staleness = this.staleness;
clone.distinct = this.distinct;
clone.attachDiagData = this.attachDiagData;
clone.executionPhase = this.executionPhase;
if (this.relationalValueSearchQuery != null) {
clone.relationalValueSearchQuery = this.relationalValueSearchQuery.clone();
}
Expand Down Expand Up @@ -818,6 +856,8 @@ public void shortDump(StringBuilder sb) {
appendVal(sb, "distinct", distinct);
appendVal(sb, "relationalValueSearchQuery", relationalValueSearchQuery);
appendVal(sb, "definitionProcessing", definitionProcessing);
appendFlag(sb, "attachDiagData", attachDiagData);
appendFlag(sb, "executionPhase", executionPhase);
removeLastComma(sb);
}

Expand All @@ -840,6 +880,7 @@ public static Collection<SelectorOptions<GetOperationOptions>> fromRestOptions(L
for (ItemPath excludePath : ItemPath.fromStringList(exclude)) {
rv.add(SelectorOptions.create(excludePath, GetOperationOptions.createDontRetrieve()));
}
// Do NOT set executionPhase here!
return rv;
}

Expand All @@ -865,6 +906,8 @@ public static GetOperationOptions fromRestOptions(List<String> options, Definiti
if (GetOperationOptionsType.F_RESOLVE_NAMES.getLocalPart().equals(option)) {
rv.setResolveNames(true);
}

// Do NOT set executionPhase here!
}

rv.setDefinitionProcessing(definitionProcessing);
Expand Down
Expand Up @@ -699,7 +699,7 @@ private Collection<RoleSelectionSpecEntry> createSingleDisplayableValueCollectio
}

private RoleSelectionSpecEntry getRoleSelectionSpecEq(EqualFilter<String> eqFilter) throws SchemaException {
if (QNameUtil.match(RoleType.F_ROLE_TYPE, eqFilter.getElementName())) {
if (QNameUtil.match(RoleType.F_ROLE_TYPE, eqFilter.getElementName()) || QNameUtil.match(RoleType.F_SUB_TYPE, eqFilter.getElementName())) {
List<PrismPropertyValue<String>> ppvs = eqFilter.getValues();
if (ppvs.size() > 1) {
throw new SchemaException("More than one value in roleType search filter");
Expand Down
Expand Up @@ -205,10 +205,17 @@ public <O extends ObjectType> void applySchemasAndSecurity(PrismObject<O> object
}

if (phase == null) {
applySchemasAndSecurityPhase(object, securityConstraints, objectDefinition, rootOptions, AuthorizationPhaseType.REQUEST, task, result);
if (!GetOperationOptions.isExecutionPhase(rootOptions)) {
applySchemasAndSecurityPhase(object, securityConstraints, objectDefinition, rootOptions, AuthorizationPhaseType.REQUEST, task, result);
}
applySchemasAndSecurityPhase(object, securityConstraints, objectDefinition, rootOptions, AuthorizationPhaseType.EXECUTION, task, result);
} else {
applySchemasAndSecurityPhase(object, securityConstraints, objectDefinition, rootOptions, phase, task, result);
if (phase == AuthorizationPhaseType.REQUEST && GetOperationOptions.isExecutionPhase(rootOptions)) {
// Skip application of security constraints for request phase.
// The caller asked to skip evaluation of request authorization, so everything is allowed here.
} else {
applySchemasAndSecurityPhase(object, securityConstraints, objectDefinition, rootOptions, phase, task, result);
}
}

ObjectTemplateType objectTemplateType;
Expand Down
Expand Up @@ -879,8 +879,9 @@ public <T extends ObjectType> T resolveReference(ObjectReferenceType reference)
throw new SchemaException("No definition for type " + type);
}
return modelService.getObject(
objectDefinition.getCompileTimeClass(), reference.getOid(), null, getCurrentTask(), getCurrentResult())
.asObjectable();
objectDefinition.getCompileTimeClass(), reference.getOid(),
SelectorOptions.createCollection(GetOperationOptions.createExecutionPhase()), getCurrentTask(), getCurrentResult())
.asObjectable();
}

@Override
Expand All @@ -907,7 +908,9 @@ public <T extends ObjectType> T getObject(Class<T> type, String oid,
@Override
public <T extends ObjectType> T getObject(Class<T> type, String oid) throws ObjectNotFoundException, SchemaException,
CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException {
PrismObject<T> prismObject = modelService.getObject(type, oid, null, getCurrentTask(), getCurrentResult());
PrismObject<T> prismObject = modelService.getObject(type, oid,
getDefaultGetOptionCollection(),
getCurrentTask(), getCurrentResult());
return prismObject.asObjectable();
}

Expand Down Expand Up @@ -1059,7 +1062,8 @@ public <T extends ObjectType> List<T> searchObjects(
ObjectNotFoundException, SecurityViolationException,
CommunicationException, ConfigurationException, ExpressionEvaluationException {
return MiscSchemaUtil.toObjectableList(
modelService.searchObjects(type, query, null, getCurrentTask(), getCurrentResult()));
modelService.searchObjects(type, query,
getDefaultGetOptionCollection(), getCurrentTask(), getCurrentResult()));
}

@Override
Expand All @@ -1078,7 +1082,8 @@ public <T extends ObjectType> void searchObjectsIterative(Class<T> type,
throws SchemaException, ObjectNotFoundException,
CommunicationException, ConfigurationException,
SecurityViolationException, ExpressionEvaluationException {
modelService.searchObjectsIterative(type, query, handler, null, getCurrentTask(), getCurrentResult());
modelService.searchObjectsIterative(type, query, handler,
getDefaultGetOptionCollection(), getCurrentTask(), getCurrentResult());
}

@Override
Expand All @@ -1087,7 +1092,8 @@ public <T extends ObjectType> T searchObjectByName(Class<T> type, String name)
SchemaException, ExpressionEvaluationException {
ObjectQuery nameQuery = ObjectQueryUtil.createNameQuery(name, prismContext);
List<PrismObject<T>> foundObjects = modelService
.searchObjects(type, nameQuery, null, getCurrentTask(), getCurrentResult());
.searchObjects(type, nameQuery,
getDefaultGetOptionCollection(), getCurrentTask(), getCurrentResult());
if (foundObjects.isEmpty()) {
return null;
}
Expand All @@ -1103,7 +1109,8 @@ public <T extends ObjectType> T searchObjectByName(Class<T> type, PolyString nam
SchemaException, ExpressionEvaluationException {
ObjectQuery nameQuery = ObjectQueryUtil.createNameQuery(name, prismContext);
List<PrismObject<T>> foundObjects = modelService
.searchObjects(type, nameQuery, null, getCurrentTask(), getCurrentResult());
.searchObjects(type, nameQuery,
getDefaultGetOptionCollection(), getCurrentTask(), getCurrentResult());
if (foundObjects.isEmpty()) {
return null;
}
Expand All @@ -1119,7 +1126,8 @@ public <T extends ObjectType> T searchObjectByName(Class<T> type, PolyStringType
SchemaException, ExpressionEvaluationException {
ObjectQuery nameQuery = ObjectQueryUtil.createNameQuery(name, prismContext);
List<PrismObject<T>> foundObjects = modelService
.searchObjects(type, nameQuery, null, getCurrentTask(), getCurrentResult());
.searchObjects(type, nameQuery,
getDefaultGetOptionCollection(), getCurrentTask(), getCurrentResult());
if (foundObjects.isEmpty()) {
return null;
}
Expand All @@ -1144,7 +1152,8 @@ public <T extends ObjectType> int countObjects(Class<T> type,
ObjectQuery query) throws SchemaException, ObjectNotFoundException,
SecurityViolationException, ConfigurationException,
CommunicationException, ExpressionEvaluationException {
return modelService.countObjects(type, query, null, getCurrentTask(), getCurrentResult());
return modelService.countObjects(type, query,
getDefaultGetOptionCollection(), getCurrentTask(), getCurrentResult());
}

@Override
Expand Down Expand Up @@ -1572,7 +1581,8 @@ public TaskType submitTaskFromTemplate(String templateTaskOid, List<Item<?, ?>>
if (principal == null) {
throw new SecurityViolationException("No current user");
}
TaskType newTask = modelService.getObject(TaskType.class, templateTaskOid, null, opTask, result).asObjectable();
TaskType newTask = modelService.getObject(TaskType.class, templateTaskOid,
getDefaultGetOptionCollection(), opTask, result).asObjectable();
newTask.setName(PolyStringType.fromOrig(newTask.getName().getOrig() + " " + (int) (Math.random()*10000)));
newTask.setOid(null);
newTask.setTaskIdentifier(null);
Expand Down Expand Up @@ -1689,4 +1699,8 @@ public Collection<PrismValue> collectAssignedFocusMappingsResults(@NotNull ItemP
}
return rv;
}

private Collection<SelectorOptions<GetOperationOptions>> getDefaultGetOptionCollection() {
return SelectorOptions.createCollection(GetOperationOptions.createExecutionPhase());
}
}

0 comments on commit 7633be8

Please sign in to comment.