/* * Copyright (c) 2010-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.web.security; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.security.api.AuthorizationConstants; import com.evolveum.midpoint.security.api.ItemSecurityDecisions; import com.evolveum.midpoint.security.api.MidPointPrincipal; import com.evolveum.midpoint.security.api.ObjectSecurityConstraints; import com.evolveum.midpoint.security.api.OwnerResolver; import com.evolveum.midpoint.security.api.SecurityEnforcer; import com.evolveum.midpoint.security.api.UserProfileService; import com.evolveum.midpoint.util.DisplayableValue; import com.evolveum.midpoint.util.Producer; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.application.DescriptorLoader; import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractRoleType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationPhaseType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; import org.apache.commons.lang.StringUtils; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.core.Authentication; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import java.util.ArrayList; import java.util.Collection; import java.util.Map; public class MidPointGuiAuthorizationEvaluator implements SecurityEnforcer { private static final Trace LOGGER = TraceManager.getTrace(MidPointGuiAuthorizationEvaluator.class); private SecurityEnforcer securityEnforcer; public MidPointGuiAuthorizationEvaluator(SecurityEnforcer securityEnforcer) { super(); this.securityEnforcer = securityEnforcer; } @Override public UserProfileService getUserProfileService() { return securityEnforcer.getUserProfileService(); } @Override public void setUserProfileService(UserProfileService userProfileService) { securityEnforcer.setUserProfileService(userProfileService); } @Override public void setupPreAuthenticatedSecurityContext(Authentication authentication) { securityEnforcer.setupPreAuthenticatedSecurityContext(authentication); } @Override public void setupPreAuthenticatedSecurityContext(PrismObject<UserType> user) throws SchemaException { securityEnforcer.setupPreAuthenticatedSecurityContext(user); } @Override public boolean isAuthenticated() { return securityEnforcer.isAuthenticated(); } @Override public MidPointPrincipal getPrincipal() throws SecurityViolationException { return securityEnforcer.getPrincipal(); } @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 { securityEnforcer.failAuthorization(operationUrl, phase, object, delta, target, result); } @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 { return securityEnforcer.isAuthorized(operationUrl, phase, object, delta, target, ownerResolver); } @Override public boolean supports(ConfigAttribute attribute) { return securityEnforcer.supports(attribute); } @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 { securityEnforcer.authorize(operationUrl, phase, object, delta, target, ownerResolver, result); } @Override public boolean supports(Class<?> clazz) { return securityEnforcer.supports(clazz); } @Override public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { if (!(object instanceof FilterInvocation)) { return; } FilterInvocation filterInvocation = (FilterInvocation) object; Collection<ConfigAttribute> guiConfigAttr = new ArrayList<>(); for (PageUrlMapping urlMapping : PageUrlMapping.values()) { addSecurityConfig(filterInvocation, guiConfigAttr, urlMapping.getUrl(), urlMapping.getAction()); } Map<String, DisplayableValue<String>[]> actions = DescriptorLoader.getActions(); for (Map.Entry<String, DisplayableValue<String>[]> entry : actions.entrySet()) { addSecurityConfig(filterInvocation, guiConfigAttr, entry.getKey(), entry.getValue()); } if (configAttributes == null || guiConfigAttr.isEmpty()) { return; } Collection<ConfigAttribute> configAttributesToUse = guiConfigAttr; if (guiConfigAttr.isEmpty()) { configAttributesToUse = configAttributes; } try { securityEnforcer.decide(authentication, object, configAttributesToUse); if (LOGGER.isTraceEnabled()) { LOGGER.trace("DECIDE: authentication={}, object={}, configAttributesToUse={}: OK", authentication, object, configAttributesToUse); } } catch (AccessDeniedException | InsufficientAuthenticationException e) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("DECIDE: authentication={}, object={}, configAttributesToUse={}: {}", authentication, object, configAttributesToUse, e); } throw e; } } private void addSecurityConfig(FilterInvocation filterInvocation, Collection<ConfigAttribute> guiConfigAttr, String url, DisplayableValue<String>[] actions) { AntPathRequestMatcher matcher = new AntPathRequestMatcher(url); if (!matcher.matches(filterInvocation.getRequest()) || actions == null) { return; } for (DisplayableValue<String> action : actions) { String actionUri = action.getValue(); if (StringUtils.isBlank(actionUri)) { continue; } //all users has permission to access these resources if (action.equals(AuthorizationConstants.AUTZ_UI_PERMIT_ALL_URL)) { return; } SecurityConfig config = new SecurityConfig(actionUri); if (!guiConfigAttr.contains(config)) { guiConfigAttr.add(config); } } } @Override public <O extends ObjectType> ObjectSecurityConstraints compileSecurityConstraints(PrismObject<O> object, OwnerResolver ownerResolver) throws SchemaException { return securityEnforcer.compileSecurityConstraints(object, ownerResolver); } @Override public <T extends ObjectType, O extends ObjectType> ObjectFilter preProcessObjectFilter(String operationUrl, AuthorizationPhaseType phase, Class<T> objectType, PrismObject<O> object, ObjectFilter origFilter) throws SchemaException { return securityEnforcer.preProcessObjectFilter(operationUrl, phase, objectType, object, origFilter); } @Override public <T> T runAs(Producer<T> producer, PrismObject<UserType> user) throws SchemaException { return securityEnforcer.runAs(producer, user); } @Override public <T> T runPrivileged(Producer<T> producer) { return securityEnforcer.runPrivileged(producer); } @Override public <O extends ObjectType, R extends AbstractRoleType> ItemSecurityDecisions getAllowedRequestAssignmentItems( MidPointPrincipal midPointPrincipal, PrismObject<O> object, PrismObject<R> target, OwnerResolver ownerResolver) throws SchemaException { return securityEnforcer.getAllowedRequestAssignmentItems(midPointPrincipal, object, target, ownerResolver); } }