Search in sources :

Example 1 with ObjectFilterExpressionEvaluator

use of com.evolveum.midpoint.repo.api.query.ObjectFilterExpressionEvaluator in project midpoint by Evolveum.

the class SecurityEnforcerImpl method parseAndEvaluateFilter.

private <O extends ObjectType> ObjectFilter parseAndEvaluateFilter(MidPointPrincipal principal, PrismObjectDefinition<O> objectDefinition, SearchFilterType specFilterType, String objectTargetDesc, String autzHumanReadableDesc, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException {
    ObjectFilter specFilter = prismContext.getQueryConverter().createObjectFilter(objectDefinition, specFilterType);
    if (specFilter == null) {
        return null;
    }
    ObjectFilterExpressionEvaluator filterEvaluator = createFilterEvaluator(principal, objectTargetDesc, autzHumanReadableDesc, task, result);
    return filterEvaluator.evaluate(specFilter);
}
Also used : ObjectFilterExpressionEvaluator(com.evolveum.midpoint.repo.api.query.ObjectFilterExpressionEvaluator)

Example 2 with ObjectFilterExpressionEvaluator

use of com.evolveum.midpoint.repo.api.query.ObjectFilterExpressionEvaluator in project midpoint by Evolveum.

the class SecurityEnforcerImpl method isApplicable.

/**
 * @param otherSelfOids Which OIDs should match "self" in addition to the current principal OID. Usually these could be
 *                      some or all of delegators' OIDs, i.e. people that delegated privileges to the current principal.
 *                      The reason is that if we want to match assignee or requestor (probably targetObject and owner as well)
 *                      we want to give appropriate privileges also to assignee/requestor delegates.
 */
private <O extends ObjectType> boolean isApplicable(SubjectedObjectSelectorType objectSelector, PrismObject<O> object, MidPointPrincipal principal, Collection<String> otherSelfOids, OwnerResolver ownerResolver, String desc, String autzHumanReadableDesc, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException {
    ObjectFilterExpressionEvaluator filterExpressionEvaluator = createFilterEvaluator(principal, desc, autzHumanReadableDesc, task, result);
    if (!repositoryService.selectorMatches(objectSelector, object, filterExpressionEvaluator, LOGGER, "    " + autzHumanReadableDesc + " not applicable for " + desc + " because of")) {
        // No need to log inapplicability here. It should be logged inside repositoryService.selectorMatches()
        return false;
    }
    OrgRelationObjectSpecificationType specOrgRelation = objectSelector.getOrgRelation();
    RoleRelationObjectSpecificationType specRoleRelation = objectSelector.getRoleRelation();
    // Special
    List<SpecialObjectSpecificationType> specSpecial = objectSelector.getSpecial();
    if (specSpecial != null && !specSpecial.isEmpty()) {
        if (objectSelector.getFilter() != null || objectSelector.getOrgRef() != null || specOrgRelation != null || specRoleRelation != null) {
            throw new SchemaException("Both filter/org/role/archetype and special " + desc + " specification specified in " + autzHumanReadableDesc);
        }
        for (SpecialObjectSpecificationType special : specSpecial) {
            if (special == SpecialObjectSpecificationType.SELF) {
                String principalOid = principal != null ? principal.getOid() : null;
                if (principalOid == null) {
                // This is a rare case. It should not normally happen. But it may happen in tests
                // or during initial import. Therefore we are not going to die here. Just ignore it.
                } else {
                    if (principalOid.equals(object.getOid())) {
                        LOGGER.trace("    {}: 'self' authorization applicable for {} - match on principal OID ({})", autzHumanReadableDesc, desc, principalOid);
                        return true;
                    } else if (otherSelfOids != null && otherSelfOids.contains(object.getOid())) {
                        LOGGER.trace("    {}: 'self' authorization applicable for {} - match on other 'self OID' ({})", autzHumanReadableDesc, desc, object.getOid());
                        return true;
                    } else {
                        LOGGER.trace("    {}: 'self' authorization not applicable for {}, principal OID: {} (other accepted self OIDs: {}), {} OID {}", autzHumanReadableDesc, desc, principalOid, otherSelfOids, desc, object.getOid());
                    }
                }
            } else {
                throw new SchemaException("Unsupported special " + desc + " specification specified in " + autzHumanReadableDesc + ": " + special);
            }
        }
        LOGGER.trace("    {}: special authorization not applicable for {}", autzHumanReadableDesc, desc);
        return false;
    } else {
        LOGGER.trace("    {}: specials empty: {}", autzHumanReadableDesc, specSpecial);
    }
    // orgRelation
    if (specOrgRelation != null) {
        boolean match = false;
        for (ObjectReferenceType subjectParentOrgRef : principal.getFocus().getParentOrgRef()) {
            if (matchesOrgRelation(object, subjectParentOrgRef, specOrgRelation, autzHumanReadableDesc, desc)) {
                LOGGER.trace("    org {} applicable for {}, object OID {} because subject org {} matches", autzHumanReadableDesc, desc, object.getOid(), subjectParentOrgRef.getOid());
                match = true;
                break;
            }
        }
        if (!match) {
            LOGGER.trace("    org {} not applicable for {}, object OID {} because none of the subject orgs matches", autzHumanReadableDesc, desc, object.getOid());
            return false;
        }
    }
    // roleRelation
    if (specRoleRelation != null) {
        boolean match = false;
        for (ObjectReferenceType subjectRoleMembershipRef : principal.getFocus().getRoleMembershipRef()) {
            if (matchesRoleRelation(object, subjectRoleMembershipRef, specRoleRelation)) {
                LOGGER.trace("    {} applicable for {}, object OID {} because subject role relation {} matches", autzHumanReadableDesc, desc, object.getOid(), subjectRoleMembershipRef.getOid());
                match = true;
                break;
            }
        }
        if (!match) {
            LOGGER.trace("    {} not applicable for {}, object OID {} because none of the subject roles matches", autzHumanReadableDesc, desc, object.getOid());
            return false;
        }
    }
    if (objectSelector instanceof OwnedObjectSelectorType) {
        OwnedObjectSelectorType ownedObjectSelector = (OwnedObjectSelectorType) objectSelector;
        // Owner
        SubjectedObjectSelectorType ownerSpec = ownedObjectSelector.getOwner();
        if (ownerSpec != null) {
            if (ownerResolver == null) {
                ownerResolver = securityContextManager.getUserProfileService();
                if (ownerResolver == null) {
                    LOGGER.trace("    {}: owner object spec not applicable for {}, object OID {} because there is no owner resolver", autzHumanReadableDesc, desc, object.getOid());
                    return false;
                }
            }
            PrismObject<? extends FocusType> owner = ownerResolver.resolveOwner(object);
            if (owner == null) {
                LOGGER.trace("    {}: owner object spec not applicable for {}, object OID {} because it has no owner", autzHumanReadableDesc, desc, object.getOid());
                return false;
            }
            boolean ownerApplicable = isApplicable(ownerSpec, owner, principal, emptySet(), ownerResolver, "owner of " + desc, autzHumanReadableDesc, task, result);
            if (!ownerApplicable) {
                LOGGER.trace("    {}: owner object spec not applicable for {}, object OID {} because owner does not match (owner={})", autzHumanReadableDesc, desc, object.getOid(), owner);
                return false;
            }
        }
        // Delegator
        SubjectedObjectSelectorType delegatorSpec = ownedObjectSelector.getDelegator();
        if (delegatorSpec != null) {
            if (!isSelf(delegatorSpec)) {
                throw new SchemaException("Unsupported non-self delegator clause");
            }
            if (!object.canRepresent(UserType.class)) {
                LOGGER.trace("    {}: delegator object spec not applicable for {}, because the object is not user", autzHumanReadableDesc, desc);
                return false;
            }
            boolean found = false;
            for (ObjectReferenceType objectDelegatedRef : ((UserType) object.asObjectable()).getDelegatedRef()) {
                if (principal.getOid().equals(objectDelegatedRef.getOid())) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                if (BooleanUtils.isTrue(delegatorSpec.isAllowInactive())) {
                    for (AssignmentType objectAssignment : ((UserType) object.asObjectable()).getAssignment()) {
                        ObjectReferenceType objectAssignmentTargetRef = objectAssignment.getTargetRef();
                        if (objectAssignmentTargetRef == null) {
                            continue;
                        }
                        if (principal.getOid().equals(objectAssignmentTargetRef.getOid())) {
                            if (relationRegistry.isDelegation(objectAssignmentTargetRef.getRelation())) {
                                found = true;
                                break;
                            }
                        }
                    }
                }
                if (!found) {
                    LOGGER.trace("    {}: delegator object spec not applicable for {}, object OID {} because delegator does not match", autzHumanReadableDesc, desc, object.getOid());
                    return false;
                }
            }
        }
        // Requestor
        SubjectedObjectSelectorType requestorSpec = ownedObjectSelector.getRequester();
        if (requestorSpec != null) {
            PrismObject<? extends ObjectType> requestor = getRequestor(object, result);
            if (requestor == null) {
                LOGGER.trace("    {}: requester object spec not applicable for {}, object OID {} because it has no requestor", autzHumanReadableDesc, desc, object.getOid());
                return false;
            }
            boolean requestorApplicable = isApplicable(requestorSpec, requestor, principal, getDelegatorsForRequestor(principal), ownerResolver, "requestor of " + desc, autzHumanReadableDesc, task, result);
            if (!requestorApplicable) {
                LOGGER.trace("    {}: requester object spec not applicable for {}, object OID {} because requestor does not match (requestor={})", autzHumanReadableDesc, desc, object.getOid(), requestor);
                return false;
            }
        }
        // Requestor
        SubjectedObjectSelectorType relatedObjectSpec = ownedObjectSelector.getRelatedObject();
        if (relatedObjectSpec != null) {
            PrismObject<? extends ObjectType> relatedObject = getRelatedObject(object, result);
            if (relatedObject == null) {
                LOGGER.trace("    {}: related object spec not applicable for {}, object OID {} because it has no related object", autzHumanReadableDesc, desc, object.getOid());
                return false;
            }
            boolean relatedObjectApplicable = isApplicable(relatedObjectSpec, relatedObject, principal, getDelegatorsForRelatedObjects(principal), ownerResolver, "related object of " + desc, autzHumanReadableDesc, task, result);
            if (!relatedObjectApplicable) {
                LOGGER.trace("    {}: related object spec not applicable for {}, object OID {} because related object does not match (related object={})", autzHumanReadableDesc, desc, object.getOid(), relatedObject);
                return false;
            }
        }
        // Assignee
        SubjectedObjectSelectorType assigneeSpec = ownedObjectSelector.getAssignee();
        if (assigneeSpec != null) {
            List<PrismObject<? extends ObjectType>> assignees = getAssignees(object, result);
            if (assignees.isEmpty()) {
                LOGGER.trace("    {}: assignee spec not applicable for {}, object OID {} because it has no assignees", autzHumanReadableDesc, desc, object.getOid());
                return false;
            }
            Collection<String> relevantDelegators = getDelegatorsForAssignee(principal);
            boolean assigneeApplicable = false;
            for (PrismObject<? extends ObjectType> assignee : assignees) {
                if (isApplicable(assigneeSpec, assignee, principal, relevantDelegators, ownerResolver, "assignee of " + desc, autzHumanReadableDesc, task, result)) {
                    assigneeApplicable = true;
                    break;
                }
            }
            if (!assigneeApplicable) {
                LOGGER.trace("    {}: assignee spec not applicable for {}, object OID {} because none of the assignees match (assignees={})", autzHumanReadableDesc, desc, object.getOid(), assignees);
                return false;
            }
        }
        // Tenant
        TenantSelectorType tenantSpec = ownedObjectSelector.getTenant();
        if (tenantSpec != null) {
            if (BooleanUtils.isTrue(tenantSpec.isSameAsSubject())) {
                ObjectReferenceType subjectTenantRef = principal.getFocus().getTenantRef();
                if (subjectTenantRef == null || subjectTenantRef.getOid() == null) {
                    LOGGER.trace("    {}: tenant object spec not applicable for {}, object OID {} because subject does not have tenantRef", autzHumanReadableDesc, desc, object.getOid());
                    return false;
                }
                ObjectReferenceType objectTenantRef = object.asObjectable().getTenantRef();
                if (objectTenantRef == null || objectTenantRef.getOid() == null) {
                    LOGGER.trace("    {}: tenant object spec not applicable for {}, object OID {} because object does not have tenantRef", autzHumanReadableDesc, desc, object.getOid());
                    return false;
                }
                if (!subjectTenantRef.getOid().equals(objectTenantRef.getOid())) {
                    LOGGER.trace("    {}: tenant object spec not applicable for {}, object OID {} because of tenant mismatch", autzHumanReadableDesc, desc, object.getOid());
                    return false;
                }
                if (!BooleanUtils.isTrue(tenantSpec.isIncludeTenantOrg())) {
                    O objectType = object.asObjectable();
                    if (objectType instanceof OrgType) {
                        if (BooleanUtils.isTrue(((OrgType) objectType).isTenant())) {
                            LOGGER.trace("    {}: tenant object spec not applicable for {}, object OID {} because it is a tenant org and it is not included", autzHumanReadableDesc, desc, object.getOid());
                            return false;
                        }
                    }
                }
            } else {
                LOGGER.trace("    {}: tenant object spec not applicable for {}, object OID {} because there is a strange tenant specificaiton in authorization", autzHumanReadableDesc, desc, object.getOid());
                return false;
            }
        }
    }
    LOGGER.trace("    {} applicable for {} (filter)", autzHumanReadableDesc, desc);
    return true;
}
Also used : SchemaException(com.evolveum.midpoint.util.exception.SchemaException) ObjectFilterExpressionEvaluator(com.evolveum.midpoint.repo.api.query.ObjectFilterExpressionEvaluator)

Aggregations

ObjectFilterExpressionEvaluator (com.evolveum.midpoint.repo.api.query.ObjectFilterExpressionEvaluator)2 SchemaException (com.evolveum.midpoint.util.exception.SchemaException)1