Created
March 18, 2012 21:12
-
-
Save novoj/2081353 to your computer and use it in GitHub Desktop.
Combining custom annotations for securing methods with Spring Security (http://blog.novoj.net)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package cz.novoj.spring.security.aop; | |
import cz.novoj.spring.security.annotation.RulesRelation; | |
import cz.novoj.spring.security.annotation.RulesRelation.BooleanOperation; | |
import org.springframework.core.annotation.AnnotationUtils; | |
import org.springframework.security.access.ConfigAttribute; | |
import org.springframework.security.access.method.AbstractMethodSecurityMetadataSource; | |
import org.springframework.security.access.prepost.*; | |
import org.springframework.util.Assert; | |
import org.springframework.util.ClassUtils; | |
import java.lang.Class; | |
import java.lang.annotation.Annotation; | |
import java.lang.reflect.Method; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.Collections; | |
import java.util.List; | |
/** | |
* Replacement for standard {@link PrePostAnnotationSecurityMetadataSource} that supports multiple different | |
* custom security annotations that are combined into a single SPEL expression in a following way: | |
* | |
* - all security rules placed upon method are by default combined with OR relation | |
* - security rules placed upon method and the owning class are always combined with OR relation - meaning you | |
* can place global rule for all methods of the class (such as Admin always can call anything with any parameters) that | |
* override specific security rules placed on respective methods | |
* - relation among rules at the same place (ie. annotations for single method, annotations for single class) can be | |
* changed by {@link @RulesRelation} annotation | |
* | |
* @author Jan Novotný ([email protected]) | |
*/ | |
public class ExperimentalPrePostAnnotationSecurityMetadataSource extends AbstractMethodSecurityMetadataSource { | |
private final PrePostInvocationAttributeFactory attributeFactory; | |
public ExperimentalPrePostAnnotationSecurityMetadataSource(PrePostInvocationAttributeFactory attributeFactory) { | |
this.attributeFactory = attributeFactory; | |
} | |
public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) { | |
if (method.getDeclaringClass() == Object.class) { | |
return Collections.emptyList(); | |
} | |
logger.trace("Looking for Pre/Post annotations for method '" + | |
method.getName() + "' on target class '" + targetClass + "'"); | |
AnnotationGroupHolderTuple<PreFilter> preFilter = findAnnotation(method, targetClass, PreFilter.class); | |
AnnotationGroupHolderTuple<PreAuthorize> preAuthorize = findAnnotation(method, targetClass, PreAuthorize.class); | |
AnnotationGroupHolderTuple<PostFilter> postFilter = findAnnotation(method, targetClass, PostFilter.class); | |
AnnotationGroupHolderTuple<PostAuthorize> postAuthorize = findAnnotation(method, targetClass, PostAuthorize.class); | |
if (!preFilter.hasValue() && !preAuthorize.hasValue() && !postFilter.hasValue() && !postAuthorize.hasValue() ) { | |
// There is no meta-data so return | |
logger.trace("No expression annotations found"); | |
return Collections.emptyList(); | |
} | |
PreInvocationAttribute pre = getPreInvocationAttribute(preFilter, preAuthorize); | |
PostInvocationAttribute post = getPostInvocationAttribute(postFilter, postAuthorize); | |
ArrayList<ConfigAttribute> attrs = new ArrayList<ConfigAttribute>(2); | |
if (pre != null) { | |
attrs.add(pre); | |
logger.debug("Method " + targetClass + "#" + method.getName() + " will be checked before invocation: " + pre.getAttribute()); | |
} | |
if (post != null) { | |
attrs.add(post); | |
logger.debug("Method " + targetClass + "#" + method.getName() + " will be checked after invocation: " + pre.getAttribute()); | |
} | |
attrs.trimToSize(); | |
return attrs; | |
} | |
/** | |
* Composes PreInvocationAttribute from @PreFilter and @PreAuthorize annotations found on method and class level. | |
* @param preFilter | |
* @param preAuthorize | |
* @return | |
*/ | |
private PreInvocationAttribute getPreInvocationAttribute(AnnotationGroupHolderTuple<PreFilter> preFilter, AnnotationGroupHolderTuple<PreAuthorize> preAuthorize) { | |
String filterObject = null; | |
StringBuilder preFilterAttribute = null; | |
if (preFilter.hasValue()) { | |
preFilterAttribute = new StringBuilder(); | |
if (preFilter.getClassAnnotations().hasValue()) { | |
preFilterAttribute.append("("); | |
filterObject = composePreFilterAttribute(filterObject, preFilterAttribute, preFilter.getClassAnnotations()); | |
preFilterAttribute.append(")"); | |
} | |
if (preFilterAttribute.length() > 0 && preFilter.getMethodAnnotations().hasValue()) { | |
preFilterAttribute.append(" or "); | |
} | |
if (preFilter.getMethodAnnotations().hasValue()) { | |
preFilterAttribute.append("("); | |
filterObject = composePreFilterAttribute(filterObject, preFilterAttribute, preFilter.getMethodAnnotations()); | |
preFilterAttribute.append(")"); | |
} | |
} | |
StringBuilder preAuthorizeAttribute = null; | |
if (preAuthorize.hasValue()) { | |
preAuthorizeAttribute = new StringBuilder(); | |
if (preAuthorize.getClassAnnotations().hasValue()) { | |
preAuthorizeAttribute.append("("); | |
composePreAuthorizeAttribute(preAuthorizeAttribute, preAuthorize.getClassAnnotations()); | |
preAuthorizeAttribute.append(")"); | |
} | |
if (preAuthorizeAttribute.length() > 0 && preAuthorize.getMethodAnnotations().hasValue()) { | |
preAuthorizeAttribute.append(" or "); | |
} | |
if (preAuthorize.getMethodAnnotations().hasValue()) { | |
preAuthorizeAttribute.append("("); | |
composePreAuthorizeAttribute(preAuthorizeAttribute, preAuthorize.getMethodAnnotations()); | |
preAuthorizeAttribute.append(")"); | |
} | |
} | |
return attributeFactory.createPreInvocationAttribute( | |
preFilterAttribute != null ? preFilterAttribute.toString() : null, | |
filterObject, | |
preAuthorizeAttribute != null ? preAuthorizeAttribute.toString() : null | |
); | |
} | |
/** | |
* Composes SPEL expression for @PreFilter annotation. Takes into account @RulesRelation annotation if defined for | |
* relation composition. | |
* | |
* @param filterObject | |
* @param preFilterAttribute | |
* @param preFilterAnnotations | |
* @return | |
*/ | |
private String composePreFilterAttribute(String filterObject, StringBuilder preFilterAttribute, AnnotationGroupHolder<PreFilter> preFilterAnnotations) { | |
final List<PreFilter> annotations = preFilterAnnotations.getAnnotations(); | |
for (int i = 0; i < annotations.size(); i++) { | |
PreFilter filter = annotations.get(i); | |
if (filter.filterTarget() != null) { | |
Assert.isTrue(filterObject == null || filterObject.equals(filter.filterTarget()), "Different filter target objects are not supported!"); | |
filterObject = filter.filterTarget(); | |
} | |
preFilterAttribute.append("(").append(filter.value()).append(")"); | |
if (i < annotations.size() - 1) { | |
if (preFilterAnnotations.getRelation() == BooleanOperation.OR) { | |
preFilterAttribute.append(" or "); | |
} else { | |
preFilterAttribute.append(" and "); | |
} | |
} | |
} | |
return filterObject; | |
} | |
/** | |
* Composes SPEL expression for @PreAuthorize annotation. Takes into account @RulesRelation annotation if defined for | |
* relation composition. | |
* | |
* @param preAuthorizeAttribute | |
* @param preAuthorizeAnnotations | |
*/ | |
private void composePreAuthorizeAttribute(StringBuilder preAuthorizeAttribute, AnnotationGroupHolder<PreAuthorize> preAuthorizeAnnotations) { | |
final List<PreAuthorize> annotations = preAuthorizeAnnotations.getAnnotations(); | |
for (int i = 0; i < annotations.size(); i++) { | |
PreAuthorize filter = annotations.get(i); | |
preAuthorizeAttribute.append("(").append(filter.value()).append(")"); | |
if (i < annotations.size() - 1) { | |
if (preAuthorizeAnnotations.getRelation() == BooleanOperation.OR) { | |
preAuthorizeAttribute.append(" or "); | |
} else { | |
preAuthorizeAttribute.append(" and "); | |
} | |
} | |
} | |
} | |
/** | |
* Composes PostInvocationAttribute from @PostFilter and @PostAuthorize annotations found on method and class level. | |
* @param postFilter | |
* @param postAuthorize | |
* @return | |
*/ | |
private PostInvocationAttribute getPostInvocationAttribute(AnnotationGroupHolderTuple<PostFilter> postFilter, AnnotationGroupHolderTuple<PostAuthorize> postAuthorize) { | |
StringBuilder postFilterAttribute = null; | |
if (postFilter.hasValue()) { | |
postFilterAttribute = new StringBuilder(); | |
if (postFilter.getClassAnnotations().hasValue()) { | |
postFilterAttribute.append("("); | |
composePostFilterAttribute(postFilterAttribute, postFilter.getClassAnnotations()); | |
postFilterAttribute.append(")"); | |
} | |
if (postFilterAttribute.length() > 0 && postFilter.getMethodAnnotations().hasValue()) { | |
postFilterAttribute.append(" or "); | |
} | |
if (postFilter.getMethodAnnotations().hasValue()) { | |
postFilterAttribute.append("("); | |
composePostFilterAttribute(postFilterAttribute, postFilter.getMethodAnnotations()); | |
postFilterAttribute.append(")"); | |
} | |
} | |
StringBuilder postAuthorizeAttribute = null; | |
if (postAuthorize.hasValue()) { | |
postAuthorizeAttribute = new StringBuilder(); | |
if (postAuthorize.getClassAnnotations().hasValue()) { | |
postAuthorizeAttribute.append("("); | |
composePostAuthorizeAttribute(postAuthorizeAttribute, postAuthorize.getClassAnnotations()); | |
postAuthorizeAttribute.append(")"); | |
} | |
if (postAuthorizeAttribute.length() > 0 && postAuthorize.getMethodAnnotations().hasValue()) { | |
postAuthorizeAttribute.append(" or "); | |
} | |
if (postAuthorize.getMethodAnnotations().hasValue()) { | |
postAuthorizeAttribute.append("("); | |
composePostAuthorizeAttribute(postAuthorizeAttribute, postAuthorize.getMethodAnnotations()); | |
postAuthorizeAttribute.append(")"); | |
} | |
} | |
return attributeFactory.createPostInvocationAttribute( | |
postFilterAttribute != null ? postFilterAttribute.toString() : null, | |
postAuthorizeAttribute != null ? postAuthorizeAttribute.toString() : null | |
); | |
} | |
/** | |
* Composes SPEL expression for @PostFilter annotation. Takes into account @RulesRelation annotation if defined for | |
* relation composition. | |
* | |
* @param postFilterAttribute | |
* @param postFilterAnnotations | |
*/ | |
private void composePostFilterAttribute(StringBuilder postFilterAttribute, AnnotationGroupHolder<PostFilter> postFilterAnnotations) { | |
final List<PostFilter> annotations = postFilterAnnotations.getAnnotations(); | |
for (int i = 0; i < annotations.size(); i++) { | |
PostFilter filter = annotations.get(i); | |
postFilterAttribute.append("(").append(filter.value()).append(")"); | |
if (i < annotations.size() - 1) { | |
if (postFilterAnnotations.getRelation() == BooleanOperation.OR) { | |
postFilterAttribute.append(" or "); | |
} else { | |
postFilterAttribute.append(" and "); | |
} | |
} | |
} | |
} | |
/** | |
* Composes SPEL expression for @PostAuthorize annotation. Takes into account @RulesRelation annotation if defined for | |
* relation composition. | |
* | |
* @param postAuthorizeAttribute | |
* @param postAuthorizeAnnotations | |
*/ | |
private void composePostAuthorizeAttribute(StringBuilder postAuthorizeAttribute, AnnotationGroupHolder<PostAuthorize> postAuthorizeAnnotations) { | |
final List<PostAuthorize> annotations = postAuthorizeAnnotations.getAnnotations(); | |
for (int i = 0; i < annotations.size(); i++) { | |
PostAuthorize filter = annotations.get(i); | |
postAuthorizeAttribute.append("(").append(filter.value()).append(")"); | |
if (i < annotations.size() - 1) { | |
if (postAuthorizeAnnotations.getRelation() == BooleanOperation.OR) { | |
postAuthorizeAttribute.append(" or "); | |
} else { | |
postAuthorizeAttribute.append(" and "); | |
} | |
} | |
} | |
} | |
public Collection<ConfigAttribute> getAllConfigAttributes() { | |
return null; | |
} | |
/** | |
* This method finds a particular annotation on method or class level. It uses following schema: | |
* 1) tries to find annotations on specific method {@link ClassUtils#getMostSpecificMethod(Method, Class<?>)} | |
* 2) tries to find annotations on passed method (if differs from specific one) | |
* 3) tries to find annotations on class level | |
* | |
* This method differs from the former Spring Security behaviour so that if finds ALL annotations of the passed | |
* kind. Ie. when you have multiple custom annotations placed on the method / class and all these annotations are | |
* annotated with fe. @PreAuthorize annotation, all these annotations are found and combined together into | |
* the AnnotationGroupHolderTuple. | |
* | |
* Lookup doesn't finish when annotations are found on the method level, but class is examined always too. Return | |
* object always hold both results - method and class annotations together. | |
*/ | |
private <A extends Annotation> AnnotationGroupHolderTuple<A> findAnnotation(Method method, Class<?> targetClass, Class<A> annotationClass) { | |
// The method may be on an interface, but we need attributes from the target class. | |
// If the target class is null, the method will be unchanged. | |
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass); | |
List<A> methodAnnotation = ExtendedAnnotationUtils.findAnnotation(specificMethod, annotationClass); | |
RulesRelation methodAnnotationRelation = AnnotationUtils.findAnnotation(specificMethod, RulesRelation.class); | |
if (methodAnnotation != null) { | |
logger.debug(methodAnnotation + " found on specific method: " + specificMethod); | |
} else { | |
// Check the original (e.g. interface) method | |
if (specificMethod != method) { | |
methodAnnotation = ExtendedAnnotationUtils.findAnnotation(method, annotationClass); | |
methodAnnotationRelation = AnnotationUtils.findAnnotation(method, RulesRelation.class); | |
if (methodAnnotation != null) { | |
logger.debug(methodAnnotation + " found on: " + method); | |
} | |
} | |
} | |
// Check the class-level (note declaringClass, not targetClass, which may not actually implement the method) | |
List<A> classAnnotation = ExtendedAnnotationUtils.findAnnotation(specificMethod.getDeclaringClass(), annotationClass); | |
RulesRelation classAnnotationRelation = AnnotationUtils.findAnnotation(specificMethod.getDeclaringClass(), RulesRelation.class); | |
if (classAnnotation != null) { | |
logger.debug(classAnnotation + " found on: " + specificMethod.getDeclaringClass().getName()); | |
} | |
return new AnnotationGroupHolderTuple<A>( | |
new AnnotationGroupHolder<A>(classAnnotation, classAnnotationRelation != null ? classAnnotationRelation.value() : BooleanOperation.OR), | |
new AnnotationGroupHolder<A>(methodAnnotation, methodAnnotationRelation != null ? methodAnnotationRelation.value() : BooleanOperation.OR) | |
); | |
} | |
/** | |
* Simple DTO for transferring found annotations on class and method level along with related @RulesRelation annotation value. | |
* @param <A> | |
*/ | |
private static class AnnotationGroupHolderTuple<A> { | |
private final AnnotationGroupHolder<A> classAnnotations; | |
private final AnnotationGroupHolder<A> methodAnnotations; | |
private AnnotationGroupHolderTuple(AnnotationGroupHolder<A> classAnnotations, AnnotationGroupHolder<A> methodAnnotations) { | |
this.classAnnotations = classAnnotations; | |
this.methodAnnotations = methodAnnotations; | |
} | |
public boolean hasValue() { | |
return classAnnotations.hasValue() || methodAnnotations.hasValue(); | |
} | |
public AnnotationGroupHolder<A> getClassAnnotations() { | |
return classAnnotations; | |
} | |
public AnnotationGroupHolder<A> getMethodAnnotations() { | |
return methodAnnotations; | |
} | |
} | |
/** | |
* Simple DTO for transferring found annotations and @RulesRelation annotation value. | |
* @param <A> | |
*/ | |
private static class AnnotationGroupHolder<A> { | |
private final List<A> annotations; | |
private final BooleanOperation relation; | |
private AnnotationGroupHolder(List<A> annotations, BooleanOperation relation) { | |
this.annotations = annotations; | |
this.relation = relation; | |
} | |
public boolean hasValue() { | |
return annotations != null && !annotations.isEmpty(); | |
} | |
public List<A> getAnnotations() { | |
return annotations; | |
} | |
public BooleanOperation getRelation() { | |
return relation; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package cz.novoj.spring.security.aop; | |
import org.springframework.core.BridgeMethodResolver; | |
import org.springframework.core.annotation.AnnotationUtils; | |
import org.springframework.util.Assert; | |
import java.lang.annotation.Annotation; | |
import java.lang.reflect.Method; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.WeakHashMap; | |
/** | |
* Alteration of the base Spring methods in {@link AnnotationUtils} with small change allowing to find multiple annotations | |
* instead of first one. | |
* | |
* @author Jan Novotný ([email protected]) | |
*/ | |
public abstract class ExtendedAnnotationUtils { | |
private static final Map<Class, Boolean> annotatedInterfaceCache = new WeakHashMap<Class, Boolean>(); | |
/** | |
* Returns all annotations that are exactly instance of passed type or multiple custom annotations that are | |
* itself annotated with passed annotationType. | |
* | |
* Slightly modified copy of: | |
* | |
* @see AnnotationUtils#getAnnotation(java.lang.reflect.Method, Class) | |
*/ | |
public static <A extends Annotation> List<A> getAnnotation(Method method, Class<A> annotationType) { | |
Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method); | |
List<A> result = new ArrayList<A>(); | |
A ann = resolvedMethod.getAnnotation(annotationType); | |
if (ann != null) { | |
result.add(ann); | |
} | |
for (Annotation metaAnn : resolvedMethod.getAnnotations()) { | |
ann = metaAnn.annotationType().getAnnotation(annotationType); | |
if (ann != null) { | |
result.add(ann); | |
} | |
} | |
return result.isEmpty() ? null : result; | |
} | |
/** | |
* Returns all annotations that are exactly instance of passed type or multiple custom annotations that are | |
* itself annotated with passed annotationType. | |
* | |
* Slightly modified copy of: | |
* | |
* @see AnnotationUtils#findAnnotation(java.lang.reflect.Method, Class) | |
*/ | |
public static <A extends Annotation> List<A> findAnnotation(Method method, Class<A> annotationType) { | |
List<A> annotation = getAnnotation(method, annotationType); | |
Class<?> cl = method.getDeclaringClass(); | |
if (annotation == null) { | |
annotation = searchOnInterfaces(method, annotationType, cl.getInterfaces()); | |
} | |
while (annotation == null) { | |
cl = cl.getSuperclass(); | |
if (cl == null || cl == Object.class) { | |
break; | |
} | |
try { | |
Method equivalentMethod = cl.getDeclaredMethod(method.getName(), method.getParameterTypes()); | |
annotation = getAnnotation(equivalentMethod, annotationType); | |
if (annotation == null) { | |
annotation = searchOnInterfaces(method, annotationType, cl.getInterfaces()); | |
} | |
} | |
catch (NoSuchMethodException ex) { | |
// We're done... | |
} | |
} | |
return annotation; | |
} | |
/** | |
* Returns all annotations that are exactly instance of passed type or multiple custom annotations that are | |
* itself annotated with passed annotationType. | |
* | |
* Slightly modified copy of: | |
* | |
* @see AnnotationUtils#getAnnotation(java.lang.reflect.Method, Class) | |
*/ | |
public static <A extends Annotation> List<A> getAnnotation(Class<?> clazz, Class<A> annotationType) { | |
List<A> result = new ArrayList<A>(); | |
A ann = clazz.getAnnotation(annotationType); | |
if (ann != null) { | |
result.add(ann); | |
} | |
for (Annotation metaAnn : clazz.getAnnotations()) { | |
ann = metaAnn.annotationType().getAnnotation(annotationType); | |
if (ann != null) { | |
result.add(ann); | |
} | |
} | |
return result.isEmpty() ? null : result; | |
} | |
/** | |
* Returns all annotations that are exactly instance of passed type or multiple custom annotations that are | |
* itself annotated with passed annotationType. | |
* | |
* Slightly modified copy of: | |
* | |
* @see AnnotationUtils#findAnnotation(Class, Class) | |
*/ | |
public static <A extends Annotation> List<A> findAnnotation(Class<?> clazz, Class<A> annotationType) { | |
Assert.notNull(clazz, "Class must not be null"); | |
List<A> annotation = getAnnotation(clazz, annotationType); | |
if (annotation != null) { | |
return annotation; | |
} | |
for (Class<?> ifc : clazz.getInterfaces()) { | |
annotation = findAnnotation(ifc, annotationType); | |
if (annotation != null) { | |
return annotation; | |
} | |
} | |
Class<?> superClass = clazz.getSuperclass(); | |
if (superClass == null || superClass == Object.class) { | |
return null; | |
} | |
return findAnnotation(superClass, annotationType); | |
} | |
private static <A extends Annotation> List<A> searchOnInterfaces(Method method, Class<A> annotationType, Class[] ifcs) { | |
List<A> annotation = null; | |
for (Class<?> iface : ifcs) { | |
if (isInterfaceWithAnnotatedMethods(iface)) { | |
try { | |
Method equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes()); | |
annotation = getAnnotation(equivalentMethod, annotationType); | |
} | |
catch (NoSuchMethodException ex) { | |
// Skip this interface - it doesn't have the method... | |
} | |
if (annotation != null) { | |
break; | |
} | |
} | |
} | |
return annotation; | |
} | |
private static boolean isInterfaceWithAnnotatedMethods(Class<?> iface) { | |
synchronized (annotatedInterfaceCache) { | |
Boolean flag = annotatedInterfaceCache.get(iface); | |
if (flag != null) { | |
return flag; | |
} | |
boolean found = false; | |
for (Method ifcMethod : iface.getMethods()) { | |
if (ifcMethod.getAnnotations().length > 0) { | |
found = true; | |
break; | |
} | |
} | |
annotatedInterfaceCache.put(iface, found); | |
return found; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package cz.novoj.spring.security.annotation; | |
import java.lang.annotation.*; | |
/** | |
* Directly specifies form of relation among different custom security annotations at the same place (ie. single method, | |
* single class). | |
* | |
* @author Jan Novotný ([email protected]) | |
*/ | |
@Target({ElementType.METHOD, ElementType.TYPE}) | |
@Retention(RetentionPolicy.RUNTIME) | |
@Inherited | |
@Documented | |
public @interface RulesRelation { | |
enum BooleanOperation { OR, AND } | |
BooleanOperation value() default BooleanOperation.OR; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<beans xmlns="http://www.springframework.org/schema/beans" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" | |
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd | |
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> | |
<aop:config proxy-target-class="true"> | |
<aop:advisor advice-ref="experimentalMethodSecurityInterceptor" | |
pointcut="execution(@(@org.springframework.security.access.prepost.PreAuthorize *) * *.* (..))"/> | |
<aop:advisor advice-ref="experimentalMethodSecurityInterceptor" | |
pointcut="execution(@(@org.springframework.security.access.prepost.PreFilter *) * *.* (..))"/> | |
<aop:advisor advice-ref="experimentalMethodSecurityInterceptor" | |
pointcut="execution(@(@org.springframework.security.access.prepost.PostAuthorize *) * *.* (..))"/> | |
<aop:advisor advice-ref="experimentalMethodSecurityInterceptor" | |
pointcut="execution(@(@org.springframework.security.access.prepost.PostFilter *) * *.* (..))"/> | |
</aop:config> | |
<!-- Configure custom security interceptor --> | |
<bean id="experimentalMethodSecurityInterceptor" | |
class="org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor"> | |
<property name="securityMetadataSource"> | |
<bean class="cz.novoj.spring.security.aop.ExperimentalPrePostAnnotationSecurityMetadataSource"> | |
<constructor-arg> | |
<bean class="org.springframework.security.access.expression.method.ExpressionBasedAnnotationAttributeFactory"> | |
<constructor-arg ref="expressionHandler"/> | |
</bean> | |
</constructor-arg> | |
</bean> | |
</property> | |
<property name="authenticationManager" ref="authenticationManager"/> | |
<property name="validateConfigAttributes" value="false"/> | |
<property name="accessDecisionManager"> | |
<bean class="org.springframework.security.access.vote.AffirmativeBased"> | |
<constructor-arg> | |
<list> | |
<bean class="org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter"> | |
<constructor-arg> | |
<bean class="org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice"> | |
<property name="expressionHandler" ref="expressionHandler"/> | |
</bean> | |
</constructor-arg> | |
</bean> | |
</list> | |
</constructor-arg> | |
</bean> | |
</property> | |
</bean> | |
<bean id="expressionHandler" | |
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler"/> | |
</beans> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
for those searching the blog post to this gist: http://blog.novoj.net/2012/03/27/combining-custom-annotations-for-securing-methods-with-spring-security/ :)