/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF 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.apache.deltaspike.security.impl.extension; import org.apache.deltaspike.security.api.authorization.SecurityDefinitionException; import org.apache.deltaspike.security.impl.util.SecurityUtils; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.enterprise.inject.spi.AnnotatedMethod; import javax.enterprise.inject.spi.AnnotatedType; class SecurityMetaDataStorage { /** * Contains all known authorizers */ private Set<Authorizer> authorizers = new HashSet<Authorizer>(); /** * Contains all known secured methods. */ private Set<AnnotatedMethod<?>> securedMethods = new HashSet<AnnotatedMethod<?>>(); /** * A mapping between a secured method of a class and its authorizers */ private Map<Class<?>, Map<Method, Set<Authorizer>>> methodAuthorizers = new HashMap<Class<?>, Map<Method, Set<Authorizer>>>(); void addAuthorizer(Authorizer authorizer) { authorizers.add(authorizer); } void addSecuredType(AnnotatedType<?> annotatedType) { for (AnnotatedMethod<?> securedMethod : annotatedType.getMethods()) { addSecuredMethod(securedMethod); } } void addSecuredMethod(AnnotatedMethod<?> annotatedMethod) { securedMethods.add(annotatedMethod); } Set<AnnotatedMethod<?>> getSecuredMethods() { return securedMethods; } void resetSecuredMethods() { securedMethods = null; } /** * This method is invoked by the security interceptor to obtain the * authorizer stack for a secured method */ Set<Authorizer> getAuthorizers(Class<?> targetClass, Method targetMethod) { if (!isMethodMetaDataAvailable(targetClass, targetMethod)) { registerSecuredMethod(targetClass, targetMethod); } return getMethodAuthorizers(targetClass, targetMethod); } void registerSecuredMethods() { for (AnnotatedMethod<?> method : securedMethods) { registerSecuredMethod(method.getDeclaringType().getJavaClass(), method.getJavaMember()); } } synchronized <T> void registerSecuredMethod(Class<T> targetClass, Method targetMethod) { ensureInitializedAuthorizersForClass(targetClass); if (!containsMethodAuthorizers(targetClass, targetMethod)) { Set<AuthorizationParameter> parameterBindings = new HashSet<AuthorizationParameter>(); Class<?>[] parameterTypes = targetMethod.getParameterTypes(); Annotation[][] parameterAnnotations = targetMethod.getParameterAnnotations(); for (int i = 0; i < parameterTypes.length; i++) { Set<Annotation> securityBindings = null; for (final Annotation parameterAnnotation : parameterAnnotations[i]) { if (SecurityUtils.isMetaAnnotatedWithSecurityParameterBinding(parameterAnnotation)) { if (securityBindings == null) { securityBindings = new HashSet<Annotation>(); } securityBindings.add(parameterAnnotation); } } if (securityBindings != null) { parameterBindings.add(new AuthorizationParameter(parameterTypes[i], securityBindings)); } } Set<Authorizer> authorizerStack = new HashSet<Authorizer>(); for (Annotation binding : SecurityUtils.getSecurityBindingTypes(targetClass, targetMethod)) { boolean found = false; // For each security binding, find a valid authorizer for (Authorizer authorizer : authorizers) { if (authorizer.matchesBindings(binding, parameterBindings, targetMethod.getReturnType())) { if (found) { StringBuilder sb = new StringBuilder(); sb.append("Matching authorizer methods found: ["); sb.append(authorizer.getBoundAuthorizerMethod().getDeclaringClass().getName()); sb.append("."); sb.append(authorizer.getBoundAuthorizerMethod().getName()); sb.append("]"); for (Authorizer a : authorizerStack) { if (a.matchesBindings(binding, parameterBindings, targetMethod.getReturnType())) { sb.append(", ["); sb.append(a.getBoundAuthorizerMethod().getDeclaringClass().getName()); sb.append("."); sb.append(a.getBoundAuthorizerMethod().getName()); sb.append("]"); } } throw new SecurityDefinitionException( "Ambiguous authorizers found for security binding type [@" + binding.annotationType().getName() + "] on method [" + targetMethod.getDeclaringClass().getName() + "." + targetMethod.getName() + "]. " + sb.toString()); } authorizerStack.add(authorizer); found = true; } } if (!found) { throw new SecurityDefinitionException( "No matching authorizer found for security binding type [@" + binding.annotationType().getName() + "] on method [" + targetMethod.getDeclaringClass().getName() + "." + targetMethod.getName() + "]."); } } addMethodAuthorizer(targetClass, targetMethod, authorizerStack); } } Set<Authorizer> getAuthorizers() { return authorizers; } private boolean containsMethodAuthorizers(Class<?> targetClass, Method targetMethod) { Map<Method, Set<Authorizer>> resultForClass = methodAuthorizers.get(targetClass); return resultForClass.containsKey(targetMethod); } private void ensureInitializedAuthorizersForClass(Class<?> targetClass) { Map<Method, Set<Authorizer>> resultForClass = methodAuthorizers.get(targetClass); if (resultForClass == null) { methodAuthorizers.put(targetClass, new HashMap<Method, Set<Authorizer>>()); } } private boolean isMethodMetaDataAvailable(Class<?> targetClass, Method targetMethod) { Map<Method, Set<Authorizer>> result = methodAuthorizers.get(targetClass); return result != null && result.containsKey(targetMethod); } private void addMethodAuthorizer(Class<?> targetClass, Method targetMethod, Set<Authorizer> authorizersToAdd) { Map<Method, Set<Authorizer>> authorizerMapping = methodAuthorizers.get(targetClass); if (authorizerMapping == null) { authorizerMapping = new HashMap<Method, Set<Authorizer>>(); methodAuthorizers.put(targetClass, authorizerMapping); } Set<Authorizer> authorizersForMethod = authorizerMapping.get(targetMethod); if (authorizersForMethod == null) { authorizersForMethod = new HashSet<Authorizer>(); authorizerMapping.put(targetMethod, authorizersForMethod); } authorizersForMethod.addAll(authorizersToAdd); } private Set<Authorizer> getMethodAuthorizers(Class<?> targetClass, Method targetMethod) { Map<Method, Set<Authorizer>> resultForClass = methodAuthorizers.get(targetClass); if (resultForClass == null) { throw new IllegalStateException( "no meta-data available for: " + targetClass.getName() + targetMethod.getName()); } return resultForClass.get(targetMethod); } }