/** * Licensed to the Austrian Association for Software Tool Integration (AASTI) * under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright * ownership. The AASTI licenses this file to you 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 org.openengsb.connector.serviceacl.internal; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; import java.util.Collection; import java.util.List; import java.util.Set; import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.lang.ClassUtils; import org.openengsb.connector.serviceacl.ServicePermission; import org.openengsb.core.api.AliveState; import org.openengsb.core.api.context.ContextHolder; import org.openengsb.core.api.security.SecurityAttributeProvider; import org.openengsb.core.api.security.annotation.Anonymous; import org.openengsb.core.api.security.annotation.SecurityAttribute; import org.openengsb.core.api.security.annotation.SecurityAttributes; import org.openengsb.core.api.security.model.SecurityAttributeEntry; import org.openengsb.core.api.security.service.UserDataManager; import org.openengsb.core.api.security.service.UserNotFoundException; import org.openengsb.core.common.AbstractOpenEngSBConnectorService; import org.openengsb.domain.authorization.AuthorizationDomain; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.AnnotationUtils; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import com.google.common.collect.Sets; public class ServiceAclServiceImpl extends AbstractOpenEngSBConnectorService implements AuthorizationDomain { private static final Logger LOGGER = LoggerFactory.getLogger(ServiceAclServiceImpl.class); private UserDataManager userManager; private List<SecurityAttributeProvider> attributeProviders; public ServiceAclServiceImpl() { } public ServiceAclServiceImpl(UserDataManager userManager, List<SecurityAttributeProvider> attributeProviders) { this.userManager = userManager; this.attributeProviders = attributeProviders; } @Override public AliveState getAliveState() { return AliveState.ONLINE; } @Override public Access checkAccess(String user, Object object) { if (!(object instanceof MethodInvocation)) { return Access.ABSTAINED; } MethodInvocation methodInvocation = (MethodInvocation) object; Anonymous public1 = AnnotationUtils.findAnnotation(methodInvocation.getMethod(), Anonymous.class); if (public1 != null) { return Access.GRANTED; } Collection<ServicePermission> permissions; try { permissions = userManager.getAllPermissionsForUser(user, ServicePermission.class); } catch (UserNotFoundException e) { LOGGER.warn("user not found in acl-connector", e); return Access.ABSTAINED; } if (hasServiceTypeAccess(permissions, methodInvocation)) { return Access.GRANTED; } return Access.ABSTAINED; } private boolean hasServiceTypeAccess(Collection<ServicePermission> permissions, final MethodInvocation object) { Class<? extends Object> serviceClass = object.getThis().getClass(); final Collection<String> typeNames = getTypeNamesForClass(serviceClass); final Collection<String> operationNames = getOperationNamesForMethod(object.getMethod()); final Collection<String> instanceNames = getServiceInstanceNames(object.getThis()); return Iterators.any(permissions.iterator(), new Predicate<ServicePermission>() { @Override public boolean apply(ServicePermission input) { if (!validatePermission(input)) { LOGGER.error("invalid permission detected: {} - {}", input, input.describe()); return false; } String context = input.getContext(); if (context != null && !context.equals(ContextHolder.get().getCurrentContextId())) { return false; } String type = input.getType(); if (type != null && !typeNames.contains(type)) { return false; } String instanceId = input.getInstance(); if (instanceId != null && !instanceNames.contains(instanceId)) { return false; } if (input.getOperation() == null) { return true; } return operationNames.contains(input.getOperation()); } private boolean validatePermission(ServicePermission input) { if (input.getType() == null && input.getInstance() == null) { return false; } return true; } }); } private Collection<String> getServiceInstanceNames(Object this1) { Collection<SecurityAttributeEntry> attributes = Lists.newArrayList(); for (SecurityAttributeProvider p : attributeProviders) { attributes.addAll(p.getAttribute(this1)); } Collection<SecurityAttributeEntry> filtered = Collections2.filter(attributes, new Predicate<SecurityAttributeEntry>() { @Override public boolean apply(SecurityAttributeEntry input) { return input.getKey().equals("name"); } }); return Collections2.transform(filtered, new Function<SecurityAttributeEntry, String>() { @Override public String apply(SecurityAttributeEntry input) { return input.getValue(); } }); } private Collection<String> getOperationNamesForMethod(Method method) { Collection<String> result = Sets.newHashSet(); result.add(method.getName()); @SuppressWarnings("unchecked") List<Class<?>> allInterfaces = ClassUtils.getAllInterfaces(method.getDeclaringClass()); allInterfaces.add(method.getDeclaringClass()); for (Class<?> interfaze : allInterfaces) { Method method2; try { method2 = interfaze.getMethod(method.getName(), method.getParameterTypes()); } catch (NoSuchMethodException e) { continue; } for (SecurityAttribute a : findAllSecurityAttributeAnnotations(method2)) { if (a.key().equals("name")) { result.add(a.value()); } } } return result; } private Collection<String> getTypeNamesForClass(Class<? extends Object> serviceClass) { Set<String> result = Sets.newHashSet(); @SuppressWarnings("unchecked") List<Class<?>> allInterfaces = ClassUtils.getAllInterfaces(serviceClass); allInterfaces.add(serviceClass); for (Class<?> clazz : allInterfaces) { result.add(clazz.getName()); result.addAll(findAllSecurityNames(clazz)); } return result; } private Collection<String> findAllSecurityNames(Class<?> clazz) { Set<String> result = Sets.newHashSet(); SecurityAttribute[] annotations = findAllSecurityAttributeAnnotations(clazz); for (SecurityAttribute a : annotations) { if (a.key().equals("name")) { result.add(a.value()); } } return result; } private SecurityAttribute[] findAllSecurityAttributeAnnotations(AnnotatedElement serviceClass) { SecurityAttribute annotation = serviceClass.getAnnotation(SecurityAttribute.class); if (annotation != null) { return new SecurityAttribute[]{ annotation }; } SecurityAttributes annotations = serviceClass.getAnnotation(SecurityAttributes.class); if (annotations == null) { return new SecurityAttribute[0]; } return annotations.value(); } public void setAttributeProviders(List<SecurityAttributeProvider> attributeProviders) { this.attributeProviders = attributeProviders; } }