/** * Copyright (c) 2014-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. */ package com.evolveum.midpoint.security.impl; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.Visitor; import com.evolveum.midpoint.prism.delta.ContainerDelta; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.match.MatchingRuleRegistry; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.query.*; import com.evolveum.midpoint.prism.query.builder.QueryBuilder; import com.evolveum.midpoint.prism.query.builder.S_AtomicFilterExit; import com.evolveum.midpoint.prism.query.builder.S_FilterEntryOrEmpty; import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.MiscSchemaUtil; import com.evolveum.midpoint.schema.util.ObjectQueryUtil; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.security.api.*; import com.evolveum.midpoint.util.Producer; import com.evolveum.midpoint.util.exception.AuthorizationException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType; import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.mutable.MutableBoolean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; import org.springframework.stereotype.Component; import javax.xml.namespace.QName; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; /** * @author Radovan Semancik * */ @Component("securityEnforcer") public class SecurityEnforcerImpl implements SecurityEnforcer { private static final Trace LOGGER = TraceManager.getTrace(SecurityEnforcerImpl.class); private static final boolean FILTER_TRACE_ENABLED = false; @Autowired @Qualifier("cacheRepositoryService") private RepositoryService repositoryService; @Autowired private MatchingRuleRegistry matchingRuleRegistry; @Autowired private PrismContext prismContext; private UserProfileService userProfileService = null; @Override public UserProfileService getUserProfileService() { return userProfileService; } @Override public void setUserProfileService(UserProfileService userProfileService) { this.userProfileService = userProfileService; } @Override public MidPointPrincipal getPrincipal() throws SecurityViolationException { return SecurityUtil.getPrincipal(); } @Override public boolean isAuthenticated() { return SecurityUtil.isAuthenticated(); } @Override public void setupPreAuthenticatedSecurityContext(Authentication authentication) { SecurityContext securityContext = SecurityContextHolder.getContext(); securityContext.setAuthentication(authentication); } @Override public void setupPreAuthenticatedSecurityContext(PrismObject<UserType> user) throws SchemaException { MidPointPrincipal principal; if (userProfileService == null) { LOGGER.warn("No user profile service set up in SecurityEnforcer. " + "This is OK in low-level tests but it is a serious problem in running system"); principal = new MidPointPrincipal(user.asObjectable()); } else { principal = userProfileService.getPrincipal(user); } Authentication authentication = new PreAuthenticatedAuthenticationToken(principal, null); setupPreAuthenticatedSecurityContext(authentication); } @Override public <O extends ObjectType, T extends ObjectType> boolean isAuthorized(String operationUrl, AuthorizationPhaseType phase, PrismObject<O> object, ObjectDelta<O> delta, PrismObject<T> target, OwnerResolver ownerResolver) throws SchemaException { MidPointPrincipal midPointPrincipal = getMidPointPrincipal(); if (phase == null) { if (!isAuthorizedInternal(midPointPrincipal, operationUrl, AuthorizationPhaseType.REQUEST, object, delta, target, ownerResolver)) { return false; } return isAuthorizedInternal(midPointPrincipal, operationUrl, AuthorizationPhaseType.EXECUTION, object, delta, target, ownerResolver); } else { return isAuthorizedInternal(midPointPrincipal, operationUrl, phase, object, delta, target, ownerResolver); } } private <O extends ObjectType, T extends ObjectType> boolean isAuthorizedInternal(MidPointPrincipal midPointPrincipal, String operationUrl, AuthorizationPhaseType phase, PrismObject<O> object, ObjectDelta<O> delta, PrismObject<T> target, OwnerResolver ownerResolver) throws SchemaException { if (AuthorizationConstants.AUTZ_NO_ACCESS_URL.equals(operationUrl)){ return false; } if (phase == null) { throw new IllegalArgumentException("No phase"); } boolean allow = false; LOGGER.trace("AUTZ: evaluating authorization principal={}, op={}, phase={}, object={}, delta={}, target={}", midPointPrincipal, operationUrl, phase, object, delta, target); final Collection<ItemPath> allowedItems = new ArrayList<>(); Collection<Authorization> authorities = getAuthorities(midPointPrincipal); if (authorities != null) { for (GrantedAuthority authority: authorities) { if (authority instanceof Authorization) { Authorization autz = (Authorization)authority; String autzHumanReadableDesc = autz.getHumanReadableDesc(); LOGGER.trace("Evaluating {}", autzHumanReadableDesc); // First check if the authorization is applicable. // action if (!autz.getAction().contains(operationUrl) && !autz.getAction().contains(AuthorizationConstants.AUTZ_ALL_URL)) { LOGGER.trace(" {} not applicable for operation {}", autzHumanReadableDesc, operationUrl); continue; } // phase if (autz.getPhase() == null) { LOGGER.trace(" {} is applicable for all phases (continuing evaluation)", autzHumanReadableDesc); } else { if (autz.getPhase() != phase) { LOGGER.trace(" {} is not applicable for phases {} (breaking evaluation)", autzHumanReadableDesc, phase); continue; } else { LOGGER.trace(" {} is applicable for phases {} (continuing evaluation)", autzHumanReadableDesc, phase); } } // object if (isApplicable(autz.getObject(), object, midPointPrincipal, ownerResolver, "object", autzHumanReadableDesc)) { LOGGER.trace(" {} applicable for object {} (continuing evaluation)", autzHumanReadableDesc, object); } else { LOGGER.trace(" {} not applicable for object {}, none of the object specifications match (breaking evaluation)", autzHumanReadableDesc, object); continue; } // target if (isApplicable(autz.getTarget(), target, midPointPrincipal, ownerResolver, "target", autzHumanReadableDesc)) { LOGGER.trace(" {} applicable for target {} (continuing evaluation)", autzHumanReadableDesc, object); } else { LOGGER.trace(" {} not applicable for target {}, none of the target specifications match (breaking evaluation)", autzHumanReadableDesc, object); continue; } // authority is applicable to this situation. now we can process the decision. AuthorizationDecisionType decision = autz.getDecision(); if (decision == null || decision == AuthorizationDecisionType.ALLOW) { // if there is more than one role which specify // different authz (e.g one role specify allow for whole // objet, the other role specify allow only for some // attributes. this ended with allow for whole object (MID-2018) Collection<ItemPath> allowed = getItems(autz); if (allow && allowedItems.isEmpty()){ LOGGER.trace(" {}: ALLOW operation {} (but continue evaluation)", autzHumanReadableDesc, operationUrl); } else if (allow && allowed.isEmpty()){ allowedItems.clear(); } else { allowedItems.addAll(allowed); } LOGGER.trace(" {}: ALLOW operation {} (but continue evaluation)", autzHumanReadableDesc, operationUrl); allow = true; // Do NOT break here. Other authorization statements may still deny the operation } else { // item if (isApplicableItem(autz, object, delta)) { LOGGER.trace(" {}: Deny authorization applicable for items (continuing evaluation)", autzHumanReadableDesc); } else { LOGGER.trace(" {} not applicable for items (breaking evaluation)", autzHumanReadableDesc); continue; } LOGGER.trace(" {}: DENY operation {}", autzHumanReadableDesc, operationUrl); allow = false; // Break right here. Deny cannot be overridden by allow. This decision cannot be changed. break; } } else { LOGGER.warn("Unknown authority type {} in user {}", authority.getClass(), getUsername(midPointPrincipal)); } } } if (allow) { // Still check allowedItems. We may still deny the operation. if (allowedItems.isEmpty()) { // This means all items are allowed. No need to check anything LOGGER.trace(" Empty list of allowed items, operation allowed"); } else { // all items in the object and delta must be allowed if (delta != null) { allow = processAuthorizationDelta(delta, allowedItems); } else if (object != null) { allow = processAuthorizationObject(object, allowedItems); } } } if (LOGGER.isTraceEnabled()) { LOGGER.trace("AUTZ result: principal={}, operation={}: {}", midPointPrincipal, operationUrl, allow); } return allow; } private <O extends ObjectType> boolean processAuthorizationObject(PrismContainer<O> object, final Collection<ItemPath> allowedItems) { return isContainerAllowed(object.getValue(), allowedItems); } private <C extends Containerable> boolean processAuthorizationContainerDelta(ContainerDelta<C> cdelta, final Collection<ItemPath> allowedItems) { final MutableBoolean itemDecision = new MutableBoolean(true); cdelta.foreach(cval -> { if (!isContainerAllowed(cval, allowedItems)) { itemDecision.setValue(false); } }); return itemDecision.booleanValue(); } private Visitor createItemVisitor(final Collection<ItemPath> allowedItems, final MutableBoolean itemDecision) { return visitable -> { if (visitable instanceof Item) { // TODO: problem with empty containers such as // orderConstraint in assignment. Skip all // empty items ... for now. if (((Item)visitable).isEmpty()) { return; } ItemPath itemPath = ((Item)visitable).getPath(); if (itemPath != null && !itemPath.isEmpty()) { if (!isInList(itemPath, allowedItems)) { LOGGER.trace(" DENY operation because item {} in the object is not allowed", itemPath); itemDecision.setValue(false); } } } }; } private boolean isContainerAllowed(PrismContainerValue<?> cval, Collection<ItemPath> allowedItems) { if (cval.isEmpty()) { // TODO: problem with empty containers such as // orderConstraint in assignment. Skip all // empty items ... for now. return true; } boolean decision = true; for (Item<?, ?> item: cval.getItems()) { ItemPath itemPath = item.getPath(); if (item instanceof PrismContainer<?>) { if (isInList(itemPath, allowedItems)) { // entire container is allowed. We do not need to go deeper } else { List<PrismContainerValue<?>> subValues = (List)((PrismContainer<?>)item).getValues(); for (PrismContainerValue<?> subValue: subValues) { if (!isContainerAllowed(subValue, allowedItems)) { decision = false; } } } } else { if (!isInList(itemPath, allowedItems)) { LOGGER.trace(" DENY operation because item {} in the object is not allowed", itemPath); decision = false; } } } return decision; } private <O extends ObjectType> boolean processAuthorizationDelta(ObjectDelta<O> delta, final Collection<ItemPath> allowedItems) { if (delta.isAdd()) { return processAuthorizationObject(delta.getObjectToAdd(), allowedItems); } else { for (ItemDelta<?,?> itemDelta: delta.getModifications()) { ItemPath itemPath = itemDelta.getPath(); if (itemDelta instanceof ContainerDelta<?>) { if (!isInList(itemPath, allowedItems)) { if (!processAuthorizationContainerDelta((ContainerDelta<?>)itemDelta, allowedItems)) { return false; } } } else { if (!isInList(itemPath, allowedItems)) { LOGGER.trace(" DENY operation because item {} in the delta is not allowed", itemPath); return false; } } } return true; } } private boolean isInList(ItemPath itemPath, Collection<ItemPath> allowedItems) { boolean itemAllowed = false; for (ItemPath allowedPath: allowedItems) { if (allowedPath.isSubPathOrEquivalent(itemPath)) { itemAllowed = true; break; } } return itemAllowed; } @Override public <O extends ObjectType, T extends ObjectType> void authorize(String operationUrl, AuthorizationPhaseType phase, PrismObject<O> object, ObjectDelta<O> delta, PrismObject<T> target, OwnerResolver ownerResolver, OperationResult result) throws SecurityViolationException, SchemaException { boolean allow = isAuthorized(operationUrl, phase, object, delta, target, ownerResolver); if (!allow) { failAuthorization(operationUrl, phase, object, delta, target, result); } } @Override public <O extends ObjectType, T extends ObjectType> void failAuthorization(String operationUrl, AuthorizationPhaseType phase, PrismObject<O> object, ObjectDelta<O> delta, PrismObject<T> target, OperationResult result) throws SecurityViolationException { MidPointPrincipal principal = getPrincipal(); String username = getQuotedUsername(principal); String message; if (target == null && object == null) { message = "User '"+username+"' not authorized for operation "+ operationUrl; } else if (target == null) { message = "User '"+username+"' not authorized for operation "+ operationUrl + " on " + object; } else { message = "User '"+username+"' not authorized for operation "+ operationUrl + " on " + object + " with target " + target; } LOGGER.error("{}", message); AuthorizationException e = new AuthorizationException(message); result.recordFatalError(e.getMessage(), e); throw e; } private <O extends ObjectType> boolean isApplicable(List<OwnedObjectSelectorType> objectSpecTypes, PrismObject<O> object, MidPointPrincipal midPointPrincipal, OwnerResolver ownerResolver, String desc, String autzHumanReadableDesc) throws SchemaException { if (objectSpecTypes != null && !objectSpecTypes.isEmpty()) { if (object == null) { LOGGER.trace(" {} not applicable for null {}", autzHumanReadableDesc, desc); return false; } for (OwnedObjectSelectorType autzObject: objectSpecTypes) { if (isApplicable(autzObject, object, midPointPrincipal, ownerResolver, desc, autzHumanReadableDesc)) { return true; } } return false; } else { LOGGER.trace(" {}: No {} specification in authorization (authorization is applicable)", autzHumanReadableDesc, desc); return true; } } private <O extends ObjectType> boolean isApplicable(SubjectedObjectSelectorType objectSelector, PrismObject<O> object, MidPointPrincipal principal, OwnerResolver ownerResolver, String desc, String autzHumanReadableDesc) throws SchemaException { if (!repositoryService.selectorMatches(objectSelector, object, LOGGER, " " + autzHumanReadableDesc + " not applicable for " + desc + " because of ")) { return false; } OrgRelationObjectSpecificationType specOrgRelation = objectSelector.getOrgRelation(); // Special List<SpecialObjectSpecificationType> specSpecial = objectSelector.getSpecial(); if (specSpecial != null && !specSpecial.isEmpty()) { if (objectSelector.getFilter() != null || objectSelector.getOrgRef() != null || specOrgRelation != null) { throw new SchemaException("Both filter/org 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 {}", autzHumanReadableDesc, desc); return true; } else { LOGGER.trace(" {}: 'self' authorization not applicable for {}, principal OID: {}, {} OID {}", autzHumanReadableDesc, desc, principalOid, desc, object.getOid()); } } } else { throw new SchemaException("Unsupported special "+desc+" specification specified in "+autzHumanReadableDesc+": "+special); } } return false; } else { LOGGER.trace(" {}: specials empty: {}", autzHumanReadableDesc, specSpecial); } // orgRelation if (specOrgRelation != null) { boolean match = false; for (ObjectReferenceType subjectParentOrgRef: principal.getUser().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; } } if (objectSelector instanceof OwnedObjectSelectorType) { // Owner SubjectedObjectSelectorType ownerSpec = ((OwnedObjectSelectorType)objectSelector).getOwner(); if (ownerSpec != null) { if (ownerResolver == null) { ownerResolver = userProfileService; 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, ownerResolver, "owner of "+desc, autzHumanReadableDesc); 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; } } } LOGGER.trace(" {} applicable for {} (filter)", autzHumanReadableDesc, desc); return true; } private <O extends ObjectType> boolean matchesOrgRelation(PrismObject<O> object, ObjectReferenceType subjectParentOrgRef, OrgRelationObjectSpecificationType specOrgRelation, String autzHumanReadableDesc, String desc) throws SchemaException { if (!MiscSchemaUtil.compareRelation(specOrgRelation.getSubjectRelation(), subjectParentOrgRef.getRelation())) { return false; } if (BooleanUtils.isTrue(specOrgRelation.isIncludeReferenceOrg()) && subjectParentOrgRef.getOid().equals(object.getOid())) { return true; } if (specOrgRelation.getScope() == null) { return repositoryService.isDescendant(object, subjectParentOrgRef.getOid()); } switch (specOrgRelation.getScope()) { case ALL_DESCENDANTS: return repositoryService.isDescendant(object, subjectParentOrgRef.getOid()); case DIRECT_DESCENDANTS: return hasParentOrgRef(object, subjectParentOrgRef.getOid()); case ALL_ANCESTORS: return repositoryService.isAncestor(object, subjectParentOrgRef.getOid()); default: throw new UnsupportedOperationException("Unknown orgRelation scope "+specOrgRelation.getScope()); } } private <O extends ObjectType> boolean hasParentOrgRef(PrismObject<O> object, String oid) { List<ObjectReferenceType> objParentOrgRefs = object.asObjectable().getParentOrgRef(); for (ObjectReferenceType objParentOrgRef: objParentOrgRefs) { if (oid.equals(objParentOrgRef.getOid())) { return true; } } return false; } private <O extends ObjectType, T extends ObjectType> boolean isApplicableItem(Authorization autz, PrismObject<O> object, ObjectDelta<O> delta) throws SchemaException { List<ItemPathType> itemPaths = autz.getItem(); if (itemPaths == null || itemPaths.isEmpty()) { // No item constraints. Applicable for all items. LOGGER.trace(" items empty"); return true; } for (ItemPathType itemPathType: itemPaths) { ItemPath itemPath = itemPathType.getItemPath(); if (delta == null) { if (object != null) { if (object.containsItem(itemPath, false)) { LOGGER.trace(" applicable object item "+itemPath); return true; } } } else { ItemDelta<?,?> itemDelta = delta.findItemDelta(itemPath); if (itemDelta != null && !itemDelta.isEmpty()) { LOGGER.trace(" applicable delta item "+itemPath); return true; } } } LOGGER.trace(" no applicable item"); return false; } private Collection<ItemPath> getItems(Authorization autz) { List<ItemPathType> itemPaths = autz.getItem(); Collection<ItemPath> items = new ArrayList<>(itemPaths.size()); if (itemPaths != null) { for (ItemPathType itemPathType: itemPaths) { ItemPath itemPath = itemPathType.getItemPath(); items.add(itemPath); } } return items; } /** * Spring security method. It is practically applicable only for simple cases. */ @Override public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { if (object instanceof MethodInvocation) { MethodInvocation methodInvocation = (MethodInvocation)object; // TODO } else if (object instanceof FilterInvocation) { FilterInvocation filterInvocation = (FilterInvocation)object; // TODO } else { SecurityUtil.logSecurityDeny(object, ": Unknown type of secure object"); throw new IllegalArgumentException("Unknown type of secure object"); } Object principalObject = authentication.getPrincipal(); if (!(principalObject instanceof MidPointPrincipal)) { if (authentication.getPrincipal() instanceof String && "anonymousUser".equals(principalObject)){ SecurityUtil.logSecurityDeny(object, ": Not logged in"); throw new InsufficientAuthenticationException("Not logged in."); } throw new IllegalArgumentException("Expected that spring security principal will be of type "+ MidPointPrincipal.class.getName()+" but it was "+principalObject.getClass()); } Collection<String> configActions = SecurityUtil.getActions(configAttributes); for(String configAction: configActions) { boolean isAuthorized; try { isAuthorized = isAuthorized(configAction, null, null, null, null, null); } catch (SchemaException e) { throw new SystemException(e.getMessage(), e); } if (isAuthorized) { return; } } SecurityUtil.logSecurityDeny(object, ": Not authorized", null, configActions); // Sparse exception method by purpose. We do not want to expose details to attacker. // Better message is logged. throw new AccessDeniedException("Not authorized"); } @Override public boolean supports(ConfigAttribute attribute) { if (attribute instanceof SecurityConfig) { return true; } else { return false; } } @Override public boolean supports(Class<?> clazz) { if (MethodInvocation.class.isAssignableFrom(clazz)) { return true; } else if (FilterInvocation.class.isAssignableFrom(clazz)) { return true; } else { return false; } } private String getQuotedUsername(Authentication authentication) { String username = "(none)"; Object principal = authentication.getPrincipal(); if (principal != null) { if (principal instanceof MidPointPrincipal) { username = "'"+((MidPointPrincipal)principal).getUsername()+"'"; } else { username = "(unknown:"+principal+")"; } } return username; } private String getQuotedUsername(MidPointPrincipal principal) { if (principal == null) { return "(none)"; } return "'"+((MidPointPrincipal)principal).getUsername()+"'"; } private MidPointPrincipal getMidPointPrincipal() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null) { LOGGER.warn("No authentication"); return null; } Object principal = authentication.getPrincipal(); if (principal == null) { LOGGER.warn("Null principal"); return null; } if (!(principal instanceof MidPointPrincipal)) { if (authentication.getPrincipal() instanceof String && "anonymousUser".equals(principal)){ return null; } LOGGER.warn("Unknown principal type {}", principal.getClass()); return null; } return (MidPointPrincipal)principal; } private Collection<Authorization> getAuthorities(MidPointPrincipal principal) { if (principal == null) { // Anonymous access, possibly with elevated privileges Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); Collection<Authorization> authorizations = new ArrayList<>(); if (authentication != null) { for (GrantedAuthority authority: authentication.getAuthorities()) { if (authority instanceof Authorization) { authorizations.add((Authorization)authority); } } } return authorizations; } else { return principal.getAuthorities(); } } @Override public <O extends ObjectType> ObjectSecurityConstraints compileSecurityConstraints(PrismObject<O> object, OwnerResolver ownerResolver) throws SchemaException { MidPointPrincipal principal = getMidPointPrincipal(); if (object == null) { throw new IllegalArgumentException("Cannot compile security constraints of null object"); } LOGGER.trace("AUTZ: evaluating security constraints principal={}, object={}", principal, object); ObjectSecurityConstraintsImpl objectSecurityConstraints = new ObjectSecurityConstraintsImpl(); Collection<Authorization> authorities = getAuthorities(principal); if (authorities != null) { for (Authorization autz: authorities) { String autzHumanReadableDesc = autz.getHumanReadableDesc(); LOGGER.trace("Evaluating {}", autzHumanReadableDesc); // skip action applicability evaluation. We are interested in all actions // object if (isApplicable(autz.getObject(), object, principal, ownerResolver, "object", autzHumanReadableDesc)) { LOGGER.trace(" {} applicable for object {} (continuing evaluation)", autzHumanReadableDesc, object); } else { LOGGER.trace(" {} not applicable for object {}, none of the object specifications match (breaking evaluation)", autzHumanReadableDesc, object); continue; } // skip target applicability evaluation. We do not have a target here List<String> actions = autz.getAction(); AuthorizationPhaseType phase = autz.getPhase(); AuthorizationDecisionType decision = autz.getDecision(); if (decision == null || decision == AuthorizationDecisionType.ALLOW) { Collection<ItemPath> items = getItems(autz); if (items == null || items.isEmpty()) { applyDecision(objectSecurityConstraints.getActionDecisionMap(), actions, phase, AuthorizationDecisionType.ALLOW); } else { for (ItemPath item: items) { applyItemDecision(objectSecurityConstraints.getItemConstraintMap(), item, actions, phase, AuthorizationDecisionType.ALLOW); } } } else { Collection<ItemPath> items = getItems(autz); if (items == null || items.isEmpty()) { applyDecision(objectSecurityConstraints.getActionDecisionMap(), actions, phase, AuthorizationDecisionType.DENY); } else { for (ItemPath item: items) { applyItemDecision(objectSecurityConstraints.getItemConstraintMap(), item, actions, phase, AuthorizationDecisionType.DENY); } } } } } if (LOGGER.isTraceEnabled()) { LOGGER.trace("AUTZ: evaluated security constraints principal={}, object={}:\n{}", principal, object, objectSecurityConstraints.debugDump()); } return objectSecurityConstraints; } private void applyItemDecision(Map<ItemPath, ItemSecurityConstraintsImpl> itemConstraintMap, ItemPath item, List<String> actions, AuthorizationPhaseType phase, AuthorizationDecisionType decision) { ItemSecurityConstraintsImpl entry = itemConstraintMap.get(item); if (entry == null) { entry = new ItemSecurityConstraintsImpl(); itemConstraintMap.put(item,entry); } applyDecision(entry.getActionDecisionMap(), actions, phase, decision); } private void applyDecision(Map<String, PhaseDecisionImpl> actionDecisionMap, List<String> actions, AuthorizationPhaseType phase, AuthorizationDecisionType decision) { for (String action: actions) { if (phase == null) { applyDecisionRequest(actionDecisionMap, action, decision); applyDecisionExecution(actionDecisionMap, action, decision); } else if (phase == AuthorizationPhaseType.REQUEST){ applyDecisionRequest(actionDecisionMap, action, decision); } else if (phase == AuthorizationPhaseType.EXECUTION) { applyDecisionExecution(actionDecisionMap, action, decision); } else { throw new IllegalArgumentException("Unknown phase "+phase); } } } private void applyDecisionRequest(Map<String, PhaseDecisionImpl> actionDecisionMap, String action, AuthorizationDecisionType decision) { PhaseDecisionImpl phaseDecision = actionDecisionMap.get(action); if (phaseDecision == null) { phaseDecision = new PhaseDecisionImpl(); phaseDecision.setRequestDecision(decision); actionDecisionMap.put(action, phaseDecision); } else if (phaseDecision.getRequestDecision() == null || // deny overrides (phaseDecision.getRequestDecision() == AuthorizationDecisionType.ALLOW && decision == AuthorizationDecisionType.DENY)) { phaseDecision.setRequestDecision(decision); } } private void applyDecisionExecution(Map<String, PhaseDecisionImpl> actionDecisionMap, String action, AuthorizationDecisionType decision) { PhaseDecisionImpl phaseDecision = actionDecisionMap.get(action); if (phaseDecision == null) { phaseDecision = new PhaseDecisionImpl(); phaseDecision.setExecDecision(decision); actionDecisionMap.put(action, phaseDecision); } else if (phaseDecision.getExecDecision() == null || // deny overrides (phaseDecision.getExecDecision() == AuthorizationDecisionType.ALLOW && decision == AuthorizationDecisionType.DENY)) { phaseDecision.setExecDecision(decision); } } @Override public <T extends ObjectType, O extends ObjectType> ObjectFilter preProcessObjectFilter(String operationUrl, AuthorizationPhaseType phase, Class<T> objectType, PrismObject<O> object, ObjectFilter origFilter) throws SchemaException { MidPointPrincipal principal = getMidPointPrincipal(); LOGGER.trace("AUTZ: evaluating search pre-process principal={}, objectType={}: orig filter {}", principal, objectType, origFilter); if (origFilter == null) { origFilter = AllFilter.createAll(); } ObjectFilter finalFilter; if (phase != null) { finalFilter = preProcessObjectFilterInternal(principal, operationUrl, phase, true, objectType, object, origFilter); } else { ObjectFilter filterBoth = preProcessObjectFilterInternal(principal, operationUrl, null, false, objectType, object, origFilter); ObjectFilter filterRequest = preProcessObjectFilterInternal(principal, operationUrl, AuthorizationPhaseType.REQUEST, false, objectType, object, origFilter); ObjectFilter filterExecution = preProcessObjectFilterInternal(principal, operationUrl, AuthorizationPhaseType.EXECUTION, false, objectType, object, origFilter); finalFilter = ObjectQueryUtil.filterOr(filterBoth, ObjectQueryUtil.filterAnd(filterRequest, filterExecution)); } LOGGER.trace("AUTZ: evaluated search pre-process principal={}, objectType={}: {}", principal, objectType, finalFilter); if (finalFilter instanceof AllFilter) { // compatibility return null; } return finalFilter; } private <T extends ObjectType, O extends ObjectType> ObjectFilter preProcessObjectFilterInternal(MidPointPrincipal principal, String operationUrl, AuthorizationPhaseType phase, boolean includeNullPhase, Class<T> objectType, PrismObject<O> object, ObjectFilter origFilter) throws SchemaException { Collection<Authorization> authorities = getAuthorities(principal); ObjectFilter securityFilterAllow = null; ObjectFilter securityFilterDeny = null; boolean hasAllowAll = false; if (authorities != null) { for (GrantedAuthority authority: authorities) { if (authority instanceof Authorization) { Authorization autz = (Authorization)authority; LOGGER.trace("Evaluating authorization {}", autz); // action if (!autz.getAction().contains(operationUrl) && !autz.getAction().contains(AuthorizationConstants.AUTZ_ALL_URL)) { LOGGER.trace(" Authorization not applicable for operation {}", operationUrl); continue; } // phase if (autz.getPhase() == phase || (includeNullPhase && autz.getPhase() == null)) { LOGGER.trace(" Authorization is applicable for phases {} (continuing evaluation)", phase); } else { LOGGER.trace(" Authorization is not applicable for phase {}", phase); continue; } // object or target ObjectFilter autzObjSecurityFilter = null; List<OwnedObjectSelectorType> objectSpecTypes; if (object == null) { // object not present. Therefore we are looking for object here objectSpecTypes = autz.getObject(); } else { // object present. Therefore we are looking for target objectSpecTypes = autz.getTarget(); // .. but we need to decide whether this authorization is applicable to the object if (!isApplicableItem(autz, object, null)) { LOGGER.trace(" Authorization is not applicable for object {}", object); } } boolean applicable = true; if (objectSpecTypes != null && !objectSpecTypes.isEmpty()) { applicable = false; for (OwnedObjectSelectorType objectSpecType: objectSpecTypes) { ObjectFilter objSpecSecurityFilter = null; TypeFilter objSpecTypeFilter = null; SearchFilterType specFilterType = objectSpecType.getFilter(); ObjectReferenceType specOrgRef = objectSpecType.getOrgRef(); OrgRelationObjectSpecificationType specOrgRelation = objectSpecType.getOrgRelation(); QName specTypeQName = objectSpecType.getType(); PrismObjectDefinition<T> objectDefinition = null; // Type if (specTypeQName != null) { specTypeQName = prismContext.getSchemaRegistry().qualifyTypeName(specTypeQName); PrismObjectDefinition<?> specObjectDef = prismContext.getSchemaRegistry().findObjectDefinitionByType(specTypeQName); if (specObjectDef == null) { throw new SchemaException("Unknown object type "+specTypeQName+" in "+autz.getHumanReadableDesc()); } Class<?> specObjectClass = specObjectDef.getCompileTimeClass(); if (!objectType.isAssignableFrom(specObjectClass)) { LOGGER.trace(" Authorization not applicable for object because of type mismatch, authorization {}, query {}", new Object[]{specObjectClass, objectType}); continue; } else { LOGGER.trace(" Authorization is applicable for object because of type match, authorization {}, query {}", new Object[]{specObjectClass, objectType}); // The spec type is a subclass of requested type. So it might be returned from the search. // We need to use type filter. objSpecTypeFilter = TypeFilter.createType(specTypeQName, null); // and now we have a more specific object definition to use later in filter processing objectDefinition = (PrismObjectDefinition<T>) specObjectDef; } } // Owner if (objectSpecType.getOwner() != null) { if (objectDefinition == null) { objectDefinition = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(objectType); } // TODO: MID-3899 if (AbstractRoleType.class.isAssignableFrom(objectType)) { objSpecSecurityFilter = applyOwnerFilterOwnerRef(new ItemPath(AbstractRoleType.F_OWNER_REF), objSpecSecurityFilter, principal, objectDefinition); } else if (TaskType.class.isAssignableFrom(objectType)) { objSpecSecurityFilter = applyOwnerFilterOwnerRef(new ItemPath(TaskType.F_OWNER_REF), objSpecSecurityFilter, principal, objectDefinition); } else { LOGGER.trace(" Authorization not applicable for object because it has owner specification (this is not applicable for search)"); continue; } } applicable = true; // Special List<SpecialObjectSpecificationType> specSpecial = objectSpecType.getSpecial(); if (specSpecial != null && !specSpecial.isEmpty()) { if (specFilterType != null || specOrgRef != null || specOrgRelation != null) { throw new SchemaException("Both filter/org and special object specification specified in authorization"); } ObjectFilter specialFilter = null; for (SpecialObjectSpecificationType special: specSpecial) { if (special == SpecialObjectSpecificationType.SELF) { String principalOid = principal.getOid(); specialFilter = ObjectQueryUtil.filterOr(specialFilter, InOidFilter.createInOid(principalOid)); } else { throw new SchemaException("Unsupported special object specification specified in authorization: "+special); } } objSpecSecurityFilter = specTypeQName != null ? TypeFilter.createType(specTypeQName, specialFilter) : specialFilter; } else { LOGGER.trace(" specials empty: {}", specSpecial); } // Filter if (specFilterType != null) { if (objectDefinition == null) { objectDefinition = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(objectType); } ObjectFilter specFilter = QueryJaxbConvertor.createObjectFilter(objectDefinition, specFilterType, prismContext); if (specFilter != null) { ObjectQueryUtil.assertNotRaw(specFilter, "Filter in authorization object has undefined items. Maybe a 'type' specification is missing in the authorization?"); ObjectQueryUtil.assertPropertyOnly(specFilter, "Filter in authorization object is not property-only filter"); } LOGGER.trace(" applying property filter {}", specFilter); objSpecSecurityFilter = ObjectQueryUtil.filterAnd(objSpecSecurityFilter, specFilter); } else { LOGGER.trace(" filter empty"); } // Org if (specOrgRef != null) { ObjectFilter orgFilter = QueryBuilder.queryFor(ObjectType.class, prismContext) .isChildOf(specOrgRef.getOid()).buildFilter(); objSpecSecurityFilter = ObjectQueryUtil.filterAnd(objSpecSecurityFilter, orgFilter); LOGGER.trace(" applying org filter {}", orgFilter); } else { LOGGER.trace(" org empty"); } // orgRelation if (specOrgRelation != null) { ObjectFilter objSpecOrgRelationFilter = null; QName subjectRelation = specOrgRelation.getSubjectRelation(); for (ObjectReferenceType subjectParentOrgRef: principal.getUser().getParentOrgRef()) { if (MiscSchemaUtil.compareRelation(subjectRelation, subjectParentOrgRef.getRelation())) { S_FilterEntryOrEmpty q = QueryBuilder.queryFor(ObjectType.class, prismContext); S_AtomicFilterExit q2; if (specOrgRelation.getScope() == null || specOrgRelation.getScope() == OrgScopeType.ALL_DESCENDANTS) { q2 = q.isChildOf(subjectParentOrgRef.getOid()); } else if (specOrgRelation.getScope() == OrgScopeType.DIRECT_DESCENDANTS) { q2 = q.isDirectChildOf(subjectParentOrgRef.getOid()); } else if (specOrgRelation.getScope() == OrgScopeType.ALL_ANCESTORS) { q2 = q.isParentOf(subjectParentOrgRef.getOid()); } else { throw new UnsupportedOperationException("Unknown orgRelation scope "+specOrgRelation.getScope()); } if (BooleanUtils.isTrue(specOrgRelation.isIncludeReferenceOrg())) { q2 = q2.or().id(subjectParentOrgRef.getOid()); } objSpecOrgRelationFilter = ObjectQueryUtil.filterOr(objSpecOrgRelationFilter, q2.buildFilter()); } } if (objSpecOrgRelationFilter == null) { objSpecOrgRelationFilter = NoneFilter.createNone(); } objSpecSecurityFilter = ObjectQueryUtil.filterAnd(objSpecSecurityFilter, objSpecOrgRelationFilter); LOGGER.trace(" applying orgRelation filter {}", objSpecOrgRelationFilter); } else { LOGGER.trace(" orgRelation empty"); } if (objSpecTypeFilter != null) { objSpecTypeFilter.setFilter(objSpecSecurityFilter); objSpecSecurityFilter = objSpecTypeFilter; } traceFilter("objSpecSecurityFilter", objectSpecType, objSpecSecurityFilter); autzObjSecurityFilter = ObjectQueryUtil.filterOr(autzObjSecurityFilter, objSpecSecurityFilter); } } else { LOGGER.trace(" No object specification in authorization (authorization is universaly applicable)"); autzObjSecurityFilter = AllFilter.createAll(); } traceFilter("autzObjSecurityFilter", autz, autzObjSecurityFilter); if (applicable) { // authority is applicable to this situation. now we can process the decision. AuthorizationDecisionType decision = autz.getDecision(); if (decision == null || decision == AuthorizationDecisionType.ALLOW) { // allow if (ObjectQueryUtil.isAll(autzObjSecurityFilter)) { // this is "allow all" authorization. hasAllowAll = true; } else { securityFilterAllow = ObjectQueryUtil.filterOr(securityFilterAllow, autzObjSecurityFilter); } } else { // deny if (autz.getItem() != null && !autz.getItem().isEmpty()) { // This is a tricky situation. We have deny authorization, but it only denies access to // some items. Therefore we need to find the objects and then filter out the items. // Therefore do not add this authorization into the filter. } else { if (ObjectQueryUtil.isAll(autzObjSecurityFilter)) { // This is "deny all". We cannot have anything stronger than that. // There is no point in continuing the evaluation. LOGGER.trace("AUTZ search pre-process: principal={}, operation={}: deny all", new Object[]{getUsername(principal), operationUrl}); NoneFilter secFilter = NoneFilter.createNone(); traceFilter("secFilter", null, secFilter); return secFilter; } securityFilterDeny = ObjectQueryUtil.filterOr(securityFilterDeny, autzObjSecurityFilter); } } } traceFilter("securityFilterAllow", autz, securityFilterAllow); traceFilter("securityFilterDeny", autz, securityFilterDeny); } else { LOGGER.warn("Unknown authority type {} in user {}", authority.getClass(), getUsername(principal)); } } } traceFilter("securityFilterAllow", null, securityFilterAllow); traceFilter("securityFilterDeny", null, securityFilterDeny); ObjectFilter origWithAllowFilter; if (hasAllowAll) { origWithAllowFilter = origFilter; } else if (securityFilterAllow == null) { // Nothing has been allowed. This means default deny. LOGGER.trace("AUTZ search pre-process: principal={}, operation={}: default deny", new Object[]{getUsername(principal), operationUrl}); NoneFilter secFilter = NoneFilter.createNone(); traceFilter("secFilter", null, secFilter); return secFilter; } else { origWithAllowFilter = ObjectQueryUtil.filterAnd(origFilter, securityFilterAllow); } if (securityFilterDeny == null) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("AUTZ search pre-process: principal={}, operation={}: allow:\n{}", getUsername(principal), operationUrl, origWithAllowFilter==null?"null":origWithAllowFilter.debugDump()); } traceFilter("origWithAllowFilter", null, origWithAllowFilter); return origWithAllowFilter; } else { ObjectFilter secFilter = ObjectQueryUtil.filterAnd(origWithAllowFilter, NotFilter.createNot(securityFilterDeny)); if (LOGGER.isTraceEnabled()) { LOGGER.trace("AUTZ search pre-process: principal={}, operation={}: allow (with deny clauses):\n{}", getUsername(principal), operationUrl, secFilter==null?"null":secFilter.debugDump()); } traceFilter("secFilter", null, secFilter); return secFilter; } } private <T extends ObjectType> ObjectFilter applyOwnerFilterOwnerRef(ItemPath ownerRefPath, ObjectFilter objSpecSecurityFilter, MidPointPrincipal principal, PrismObjectDefinition<T> objectDefinition) { PrismReferenceDefinition ownerRefDef = objectDefinition.findReferenceDefinition(ownerRefPath); S_AtomicFilterExit builder = QueryBuilder.queryFor(AbstractRoleType.class, prismContext) .item(ownerRefPath, ownerRefDef).ref(principal.getUser().getOid()); // TODO don't understand this code for (ObjectReferenceType subjectParentOrgRef: principal.getUser().getParentOrgRef()) { if (ObjectTypeUtil.isDefaultRelation(subjectParentOrgRef.getRelation())) { builder = builder.or().item(ownerRefPath, ownerRefDef).ref(subjectParentOrgRef.getOid()); } } ObjectFilter objSpecOwnerFilter = builder.buildFilter(); objSpecSecurityFilter = ObjectQueryUtil.filterAnd(objSpecSecurityFilter, objSpecOwnerFilter); LOGGER.trace(" applying owner filter {}", objSpecOwnerFilter); return objSpecSecurityFilter; } private void traceFilter(String message, Object forObj, ObjectFilter filter) { if (FILTER_TRACE_ENABLED) { LOGGER.trace("FILTER {} for {}:\n{}", message, forObj, filter==null?null:filter.debugDump(1)); } } private Object getUsername(MidPointPrincipal principal) { return principal==null?null:principal.getUsername(); } @Override public <O extends ObjectType, R extends AbstractRoleType> ItemSecurityDecisions getAllowedRequestAssignmentItems( MidPointPrincipal midPointPrincipal, PrismObject<O> object, PrismObject<R> target, OwnerResolver ownerResolver) throws SchemaException { ItemSecurityDecisions decisions = new ItemSecurityDecisions(); for(Authorization autz: getAuthorities(midPointPrincipal)) { String autzHumanReadableDesc = autz.getHumanReadableDesc(); LOGGER.trace("Evaluating {}", autzHumanReadableDesc); // First check if the authorization is applicable. // action if (!autz.getAction().contains(AuthorizationConstants.AUTZ_UI_ASSIGN_ACTION_URL) && !autz.getAction().contains(AuthorizationConstants.AUTZ_ALL_URL)) { LOGGER.trace(" {} not applicable for operation {}", autzHumanReadableDesc, AuthorizationConstants.AUTZ_UI_ASSIGN_ACTION_URL); continue; } // phase if (autz.getPhase() != null && autz.getPhase() != AuthorizationPhaseType.REQUEST) { LOGGER.trace(" {} is not applicable for phase {} (breaking evaluation)", autzHumanReadableDesc, AuthorizationPhaseType.REQUEST); continue; } // object if (isApplicable(autz.getObject(), object, midPointPrincipal, ownerResolver, "object", autzHumanReadableDesc)) { LOGGER.trace(" {} applicable for object {} (continuing evaluation)", autzHumanReadableDesc, object); } else { LOGGER.trace(" {} not applicable for object {}, none of the object specifications match (breaking evaluation)", autzHumanReadableDesc, object); continue; } // target if (isApplicable(autz.getTarget(), target, midPointPrincipal, ownerResolver, "target", autzHumanReadableDesc)) { LOGGER.trace(" {} applicable for target {} (continuing evaluation)", autzHumanReadableDesc, object); } else { LOGGER.trace(" {} not applicable for target {}, none of the target specifications match (breaking evaluation)", autzHumanReadableDesc, object); continue; } // authority is applicable to this situation. now we can process the decision. AuthorizationDecisionType decision = autz.getDecision(); if (decision == null || decision == AuthorizationDecisionType.ALLOW) { Collection<ItemPath> items = getItems(autz); if (items.isEmpty()) { LOGGER.trace(" {}: ALLOW all items (but continue evaluation)", autzHumanReadableDesc); if (decisions.getDefaultDecision() != AuthorizationDecisionType.DENY) { decisions.setDefaultDecision(AuthorizationDecisionType.ALLOW); } } else { for(ItemPath item: items) { LOGGER.trace(" {}: ALLOW item {} (but continue evaluation)", autzHumanReadableDesc, item); if (decisions.getItemDecisionMap().get(item) != AuthorizationDecisionType.DENY) { decisions.getItemDecisionMap().put(item, AuthorizationDecisionType.ALLOW); } } } } else { Collection<ItemPath> items = getItems(autz); if (items.isEmpty()) { LOGGER.trace(" {}: DENY all items (breaking evaluation)", autzHumanReadableDesc); // Total deny. Reset everything. Return just deny decisions = new ItemSecurityDecisions(); decisions.setDefaultDecision(AuthorizationDecisionType.DENY); break; } else { for(ItemPath item: items) { LOGGER.trace(" {}: DENY item {} (but continue evaluation)", autzHumanReadableDesc, item); decisions.getItemDecisionMap().put(item, AuthorizationDecisionType.DENY); } } } } return decisions; } @Override public <T> T runAs(Producer<T> producer, PrismObject<UserType> user) throws SchemaException { LOGGER.debug("Running {} as {}", producer, user); Authentication origAuthentication = SecurityContextHolder.getContext().getAuthentication(); setupPreAuthenticatedSecurityContext(user); try { return producer.run(); } finally { SecurityContextHolder.getContext().setAuthentication(origAuthentication); LOGGER.debug("Finished running {} as {}", producer, user); } } @Override public <T> T runPrivileged(Producer<T> producer) { LOGGER.debug("Running {} as privileged", producer); Authentication origAuthentication = SecurityContextHolder.getContext().getAuthentication(); LOGGER.trace("ORIG auth {}", origAuthentication); // Try to reuse the original identity as much as possible. All we need to is add AUTZ_ALL // to the list of authorities Authorization privilegedAuthorization = createPrivilegedAuthorization(); Object newPrincipal = null; if (origAuthentication != null) { Object origPrincipal = origAuthentication.getPrincipal(); if (origAuthentication instanceof AnonymousAuthenticationToken) { newPrincipal = origPrincipal; } else { LOGGER.trace("ORIG principal {} ({})", origPrincipal, origPrincipal.getClass()); if (origPrincipal != null) { if (origPrincipal instanceof MidPointPrincipal) { MidPointPrincipal newMidPointPrincipal = ((MidPointPrincipal)origPrincipal).clone(); newMidPointPrincipal.getAuthorities().add(privilegedAuthorization); newPrincipal = newMidPointPrincipal; } } } Collection<GrantedAuthority> newAuthorities = new ArrayList<>(); newAuthorities.addAll(origAuthentication.getAuthorities()); newAuthorities.add(privilegedAuthorization); PreAuthenticatedAuthenticationToken newAuthorization = new PreAuthenticatedAuthenticationToken(newPrincipal, null, newAuthorities); LOGGER.trace("NEW auth {}", newAuthorization); SecurityContextHolder.getContext().setAuthentication(newAuthorization); } else { LOGGER.debug("No original authentication, do NOT setting any privileged security context"); } try { return producer.run(); } finally { SecurityContextHolder.getContext().setAuthentication(origAuthentication); LOGGER.debug("Finished running {} as privileged", producer); LOGGER.trace("Security context after privileged operation: {}", SecurityContextHolder.getContext()); } } private Authorization createPrivilegedAuthorization() { AuthorizationType authorizationType = new AuthorizationType(); authorizationType.getAction().add(AuthorizationConstants.AUTZ_ALL_URL); return new Authorization(authorizationType); } }