Skip to content

Commit

Permalink
Authorizations: read = get + search (MID-4860)
Browse files Browse the repository at this point in the history
  • Loading branch information
semancik committed Sep 3, 2018
1 parent b69a4cd commit 78cdd40
Show file tree
Hide file tree
Showing 15 changed files with 419 additions and 93 deletions.
Expand Up @@ -294,16 +294,16 @@ public <O extends ObjectType> ObjectSecurityConstraints compileSecurityConstrain
}

@Override
public <T extends ObjectType, O extends ObjectType> ObjectFilter preProcessObjectFilter(String operationUrl, AuthorizationPhaseType phase,
public <T extends ObjectType, O extends ObjectType> ObjectFilter preProcessObjectFilter(String[] operationUrls, AuthorizationPhaseType phase,
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);
return securityEnforcer.preProcessObjectFilter(operationUrls, phase, objectType, object, origFilter, limitAuthorizationAction, task, result);
}

@Override
public <T extends ObjectType, O extends ObjectType> boolean canSearch(String operationUrl,
public <T extends ObjectType, O extends ObjectType> boolean canSearch(String[] operationUrls,
AuthorizationPhaseType phase, Class<T> objectType, PrismObject<O> object, boolean includeSpecial, ObjectFilter filter, Task task, OperationResult result)
throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException {
return securityEnforcer.canSearch(operationUrl, phase, objectType, object, includeSpecial, filter, task, result);
return securityEnforcer.canSearch(operationUrls, phase, objectType, object, includeSpecial, filter, task, result);
}

@Override
Expand Down
@@ -1,5 +1,5 @@
/*
* 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 @@ -23,6 +23,8 @@
public enum ModelAuthorizationAction implements DisplayableValue<String> {

READ("read", "Read", "READ_HELP"),
GET("get", "Get", "GET_HELP"),
SEARCH("search", "Search", "SEARCH_HELP"),
ADD("add", "Add", "ADD_HELP"),
MODIFY("modify", "Modify", "MODIFY_HELP"),
DELETE("delete", "Delete", "DELETE_HELP"),
Expand Down Expand Up @@ -85,6 +87,13 @@ public enum ModelAuthorizationAction implements DisplayableValue<String> {

RAW_OPERATION("rawOperation", "Raw operation", "RAW_OPERATION_HELP"),
PARTIAL_EXECUTION("partialExecution", "Partial execution", "PARTIAL_EXECUTION_HELP");

public static final String[] AUTZ_ACTIONS_URLS_SEARCH = new String[] { READ.getUrl(), SEARCH.getUrl() };
public static final String[] AUTZ_ACTIONS_URLS_GET = new String[] { READ.getUrl(), GET.getUrl() };
public static final String[] AUTZ_ACTIONS_URLS_ADD = new String[] { ADD.getUrl() };
public static final String[] AUTZ_ACTIONS_URLS_MODIFY = new String[] { MODIFY.getUrl() };
public static final String[] AUTZ_ACTIONS_URLS_ASSIGN = new String[] { ASSIGN.getUrl() };
public static final String[] AUTZ_ACTIONS_URLS_ATTORNEY = new String[] { ATTORNEY.getUrl() };

private String url;
private String label;
Expand Down
Expand Up @@ -790,16 +790,23 @@ public <T extends ObjectType> SearchResultList<PrismObject<T>> searchObjects(Cla
QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(true);
}
switch (searchProvider) {
case EMULATED: list = emulatedSearchProvider.searchObjects(type, query, options, result); break;
case REPOSITORY: list = cacheRepositoryService.searchObjects(type, query, options, result); break;
case PROVISIONING: list = provisioning.searchObjects(type, query, options, task, result); break;
case EMULATED:
list = emulatedSearchProvider.searchObjects(type, query, options, result);
break;
case REPOSITORY:
list = cacheRepositoryService.searchObjects(type, query, options, result);
break;
case PROVISIONING:
list = provisioning.searchObjects(type, query, options, task, result);
break;
case TASK_MANAGER:
list = taskManager.searchObjects(type, query, options, result);
if (workflowManager != null && TaskType.class.isAssignableFrom(type) && !GetOperationOptions.isRaw(rootOptions) && !GetOperationOptions.isNoFetch(rootOptions)) {
workflowManager.augmentTaskObjectList(list, options, task, result);
}
break;
default: throw new AssertionError("Unexpected search provider: " + searchProvider);
default:
throw new AssertionError("Unexpected search provider: " + searchProvider);
}
result.computeStatus();
result.cleanupResult();
Expand All @@ -816,6 +823,10 @@ public <T extends ObjectType> SearchResultList<PrismObject<T>> searchObjects(Cla
if (list == null) {
list = new SearchResultList<>(new ArrayList<PrismObject<T>>());
}

if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Basic search returned {} results (before hooks, security, etc.)", list.size());
}

for (PrismObject<T> object : list) {
if (hookRegistry != null) {
Expand All @@ -842,6 +853,10 @@ public <T extends ObjectType> SearchResultList<PrismObject<T>> searchObjects(Cla
} finally {
exitModelMethod();
}

if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Final search returned {} results (after hooks, security and all other processing)", list.size());
}

return list;
}
Expand Down Expand Up @@ -1051,13 +1066,17 @@ protected boolean isFilterNone(ObjectQuery query, OperationResult result) {
}

protected void logQuery(ObjectQuery query) {
if (!LOGGER.isTraceEnabled()) {
return;
}
if (query != null){
if (query.getPaging() == null) {
LOGGER.trace("Searching objects with null paging (query in TRACE).");
LOGGER.trace("Searching objects with null paging. Query:\n{}", query.debugDump(1));
} else {
LOGGER.trace("Searching objects from {} to {} ordered {} by {} (query in TRACE).",
LOGGER.trace("Searching objects from {} to {} ordered {} by {}. Query:\n{}",
query.getPaging().getOffset(), query.getPaging().getMaxSize(),
query.getPaging().getDirection(), query.getPaging().getOrderBy());
query.getPaging().getDirection(), query.getPaging().getOrderBy(),
query.debugDump(1));
}
}
}
Expand Down Expand Up @@ -1086,6 +1105,7 @@ public <T extends ObjectType> SearchResultMetadata searchObjectsIterative(Class<

query = preProcessQuerySecurity(type, query, task, result);
if (isFilterNone(query, result)) {
LOGGER.trace("Skipping search because filter is NONE");
return null;
}

Expand Down Expand Up @@ -1165,6 +1185,7 @@ public <T extends ObjectType> Integer countObjects(Class<T> type, ObjectQuery qu

query = preProcessQuerySecurity(type, query, task, result);
if (isFilterNone(query, result)) {
LOGGER.trace("Skipping count because filter is NONE");
return 0;
}

Expand All @@ -1180,9 +1201,15 @@ public <T extends ObjectType> Integer countObjects(Class<T> type, ObjectQuery qu
objectManager = ObjectTypes.ObjectManager.REPOSITORY;
}
switch (objectManager) {
case PROVISIONING: count = provisioning.countObjects(type, query, options, task, parentResult); break;
case REPOSITORY: count = cacheRepositoryService.countObjects(type, query, options, parentResult); break;
case TASK_MANAGER: count = taskManager.countObjects(type, query, parentResult); break;
case PROVISIONING:
count = provisioning.countObjects(type, query, options, task, parentResult);
break;
case REPOSITORY:
count = cacheRepositoryService.countObjects(type, query, options, parentResult);
break;
case TASK_MANAGER:
count = taskManager.countObjects(type, query, parentResult);
break;
default: throw new AssertionError("Unexpected objectManager: " + objectManager);
}
} catch (ConfigurationException | SecurityViolationException | SchemaException | ObjectNotFoundException | CommunicationException | ExpressionEvaluationException | RuntimeException | Error e) {
Expand Down Expand Up @@ -1761,13 +1788,14 @@ 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, null, task, result);
ObjectFilter secFilter = securityEnforcer.preProcessObjectFilter(ModelAuthorizationAction.AUTZ_ACTIONS_URLS_SEARCH, 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, null, task, result);
// Search containers is an operation on one object. Therefore even if it works with a search filter, it requires GET authorizations
ObjectFilter secParentFilter = securityEnforcer.preProcessObjectFilter(ModelAuthorizationAction.AUTZ_ACTIONS_URLS_GET, 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 @@ -399,12 +399,12 @@ public RefinedObjectClassDefinition getEditObjectClassDefinition(PrismObject<Sha
}

ItemPath attributesPath = SchemaConstants.PATH_ATTRIBUTES;
AuthorizationDecisionType attributesReadDecision = schemaTransformer.computeItemDecision(securityConstraints, attributesPath, ModelAuthorizationAction.READ.getUrl(),
securityConstraints.getActionDecision(ModelAuthorizationAction.READ.getUrl(), phase), phase);
AuthorizationDecisionType attributesAddDecision = schemaTransformer.computeItemDecision(securityConstraints, attributesPath, ModelAuthorizationAction.ADD.getUrl(),
securityConstraints.getActionDecision(ModelAuthorizationAction.ADD.getUrl(), phase), phase);
AuthorizationDecisionType attributesModifyDecision = schemaTransformer.computeItemDecision(securityConstraints, attributesPath, ModelAuthorizationAction.MODIFY.getUrl(),
securityConstraints.getActionDecision(ModelAuthorizationAction.MODIFY.getUrl(), phase), phase);
AuthorizationDecisionType attributesReadDecision = schemaTransformer.computeItemDecision(securityConstraints, attributesPath, ModelAuthorizationAction.AUTZ_ACTIONS_URLS_GET,
securityConstraints.findAllItemsDecision(ModelAuthorizationAction.AUTZ_ACTIONS_URLS_GET, phase), phase);
AuthorizationDecisionType attributesAddDecision = schemaTransformer.computeItemDecision(securityConstraints, attributesPath, ModelAuthorizationAction.AUTZ_ACTIONS_URLS_ADD,
securityConstraints.findAllItemsDecision(ModelAuthorizationAction.ADD.getUrl(), phase), phase);
AuthorizationDecisionType attributesModifyDecision = schemaTransformer.computeItemDecision(securityConstraints, attributesPath, ModelAuthorizationAction.AUTZ_ACTIONS_URLS_MODIFY,
securityConstraints.findAllItemsDecision(ModelAuthorizationAction.MODIFY.getUrl(), phase), phase);
LOGGER.trace("Attributes container access read:{}, add:{}, modify:{}", attributesReadDecision, attributesAddDecision,
attributesModifyDecision);

Expand All @@ -415,9 +415,9 @@ public RefinedObjectClassDefinition getEditObjectClassDefinition(PrismObject<Sha
layeredROCD = layeredROCD.clone();
for (LayerRefinedAttributeDefinition rAttrDef: layeredROCD.getAttributeDefinitions()) {
ItemPath attributePath = new ItemPath(ShadowType.F_ATTRIBUTES, rAttrDef.getName());
AuthorizationDecisionType attributeReadDecision = schemaTransformer.computeItemDecision(securityConstraints, attributePath, ModelAuthorizationAction.READ.getUrl(), attributesReadDecision, phase);
AuthorizationDecisionType attributeAddDecision = schemaTransformer.computeItemDecision(securityConstraints, attributePath, ModelAuthorizationAction.ADD.getUrl(), attributesAddDecision, phase);
AuthorizationDecisionType attributeModifyDecision = schemaTransformer.computeItemDecision(securityConstraints, attributePath, ModelAuthorizationAction.MODIFY.getUrl(), attributesModifyDecision, phase);
AuthorizationDecisionType attributeReadDecision = schemaTransformer.computeItemDecision(securityConstraints, attributePath, ModelAuthorizationAction.AUTZ_ACTIONS_URLS_GET, attributesReadDecision, phase);
AuthorizationDecisionType attributeAddDecision = schemaTransformer.computeItemDecision(securityConstraints, attributePath, ModelAuthorizationAction.AUTZ_ACTIONS_URLS_ADD, attributesAddDecision, phase);
AuthorizationDecisionType attributeModifyDecision = schemaTransformer.computeItemDecision(securityConstraints, attributePath, ModelAuthorizationAction.AUTZ_ACTIONS_URLS_MODIFY, attributesModifyDecision, phase);
LOGGER.trace("Attribute {} access read:{}, add:{}, modify:{}", rAttrDef.getName(), attributeReadDecision,
attributeAddDecision, attributeModifyDecision);
if (attributeReadDecision != AuthorizationDecisionType.ALLOW) {
Expand Down Expand Up @@ -475,7 +475,7 @@ public <F extends FocusType> RoleSelectionSpecification getAssignableRoleSpecifi
spec.setFilter(NoneFilter.createNone());
return spec;
}
decision = securityConstraints.getActionDecision(ModelAuthorizationAction.MODIFY.getUrl(), AuthorizationPhaseType.REQUEST);
decision = securityConstraints.findAllItemsDecision(ModelAuthorizationAction.MODIFY.getUrl(), AuthorizationPhaseType.REQUEST);
if (decision == AuthorizationDecisionType.ALLOW) {
getAllRoleTypesSpec(spec, result);
result.recordSuccess();
Expand All @@ -489,7 +489,7 @@ public <F extends FocusType> RoleSelectionSpecification getAssignableRoleSpecifi
}

try {
ObjectFilter filter = securityEnforcer.preProcessObjectFilter(ModelAuthorizationAction.ASSIGN.getUrl(),
ObjectFilter filter = securityEnforcer.preProcessObjectFilter(ModelAuthorizationAction.AUTZ_ACTIONS_URLS_ASSIGN,
AuthorizationPhaseType.REQUEST, AbstractRoleType.class, focus, AllFilter.createAll(), null, task, result);
LOGGER.trace("assignableRoleSpec filter: {}", filter);
spec.setFilter(filter);
Expand Down Expand Up @@ -679,7 +679,7 @@ 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);
return securityEnforcer.preProcessObjectFilter(ModelAuthorizationAction.AUTZ_ACTIONS_URLS_ATTORNEY, null, searchResultType, null, origFilter, targetAuthorizationAction, task, parentResult);
}

@Override
Expand All @@ -689,7 +689,7 @@ public <T extends ObjectType, O extends ObjectType> boolean canSearch(Class<T> r
if (objectOid != null) {
object = (PrismObject<O>) objectResolver.getObject(objectType, objectOid, null, task, result).asPrismObject();
}
return securityEnforcer.canSearch(ModelAuthorizationAction.READ.getUrl(), null, resultType, object, includeSpecial, query.getFilter(), task, result);
return securityEnforcer.canSearch(ModelAuthorizationAction.AUTZ_ACTIONS_URLS_SEARCH, null, resultType, object, includeSpecial, query.getFilter(), task, result);
}

@Override
Expand Down

0 comments on commit 78cdd40

Please sign in to comment.