Consider AuthorizationManager for Method Security
Closes gh-9289
This commit is contained in:
committed by
Josh Cummings
parent
f7f435d3f4
commit
84e2e80915
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.security.access.annotation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.core.MethodClassKey;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.security.access.method.MethodAuthorizationContext;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
|
||||
/**
|
||||
* An abstract registry which provides an {@link AuthorizationManager} for the
|
||||
* {@link MethodInvocation}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.5
|
||||
*/
|
||||
abstract class AbstractAuthorizationManagerRegistry {
|
||||
|
||||
static final AuthorizationManager<MethodAuthorizationContext> NULL_MANAGER = (a, o) -> null;
|
||||
|
||||
private final Map<MethodClassKey, AuthorizationManager<MethodAuthorizationContext>> cachedManagers = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Returns an {@link AuthorizationManager} for the {@link MethodAuthorizationContext}.
|
||||
* @param methodAuthorizationContext the {@link MethodAuthorizationContext} to use
|
||||
* @return an {@link AuthorizationManager} to use
|
||||
*/
|
||||
final AuthorizationManager<MethodAuthorizationContext> getManager(
|
||||
MethodAuthorizationContext methodAuthorizationContext) {
|
||||
MethodInvocation methodInvocation = methodAuthorizationContext.getMethodInvocation();
|
||||
Method method = methodInvocation.getMethod();
|
||||
Class<?> targetClass = methodAuthorizationContext.getTargetClass();
|
||||
MethodClassKey cacheKey = new MethodClassKey(method, targetClass);
|
||||
return this.cachedManagers.computeIfAbsent(cacheKey, (k) -> resolveManager(method, targetClass));
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses should implement this method to provide the non-null
|
||||
* {@link AuthorizationManager} for the method and the target class.
|
||||
* @param method the method
|
||||
* @param targetClass the target class
|
||||
* @return the non-null {@link AuthorizationManager}
|
||||
*/
|
||||
@NonNull
|
||||
abstract AuthorizationManager<MethodAuthorizationContext> resolveManager(Method method, Class<?> targetClass);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.security.access.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.security.DenyAll;
|
||||
import javax.annotation.security.PermitAll;
|
||||
import javax.annotation.security.RolesAllowed;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.security.access.method.MethodAuthorizationContext;
|
||||
import org.springframework.security.authorization.AuthorityAuthorizationManager;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link AuthorizationManager} which can determine if an {@link Authentication} has
|
||||
* access to the {@link MethodInvocation} by evaluating if the {@link Authentication}
|
||||
* contains a specified authority from the JSR-250 security annotations.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.5
|
||||
*/
|
||||
public final class Jsr250AuthorizationManager implements AuthorizationManager<MethodAuthorizationContext> {
|
||||
|
||||
private static final Set<Class<? extends Annotation>> JSR250_ANNOTATIONS = new HashSet<>();
|
||||
|
||||
static {
|
||||
JSR250_ANNOTATIONS.add(DenyAll.class);
|
||||
JSR250_ANNOTATIONS.add(PermitAll.class);
|
||||
JSR250_ANNOTATIONS.add(RolesAllowed.class);
|
||||
}
|
||||
|
||||
private final Jsr250AuthorizationManagerRegistry registry = new Jsr250AuthorizationManagerRegistry();
|
||||
|
||||
private String rolePrefix = "ROLE_";
|
||||
|
||||
/**
|
||||
* Sets the role prefix. Defaults to "ROLE_".
|
||||
* @param rolePrefix the role prefix to use
|
||||
*/
|
||||
public void setRolePrefix(String rolePrefix) {
|
||||
Assert.notNull(rolePrefix, "rolePrefix cannot be null");
|
||||
this.rolePrefix = rolePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an {@link Authentication} has access to the {@link MethodInvocation}
|
||||
* by evaluating if the {@link Authentication} contains a specified authority from the
|
||||
* JSR-250 security annotations.
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to check
|
||||
* @param methodAuthorizationContext the {@link MethodAuthorizationContext} to check
|
||||
* @return an {@link AuthorizationDecision} or null if the JSR-250 security
|
||||
* annotations is not present
|
||||
*/
|
||||
@Override
|
||||
public AuthorizationDecision check(Supplier<Authentication> authentication,
|
||||
MethodAuthorizationContext methodAuthorizationContext) {
|
||||
AuthorizationManager<MethodAuthorizationContext> delegate = this.registry
|
||||
.getManager(methodAuthorizationContext);
|
||||
return delegate.check(authentication, methodAuthorizationContext);
|
||||
}
|
||||
|
||||
private final class Jsr250AuthorizationManagerRegistry extends AbstractAuthorizationManagerRegistry {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
AuthorizationManager<MethodAuthorizationContext> resolveManager(Method method, Class<?> targetClass) {
|
||||
for (Annotation annotation : findJsr250Annotations(method, targetClass)) {
|
||||
if (annotation instanceof DenyAll) {
|
||||
return (a, o) -> new AuthorizationDecision(false);
|
||||
}
|
||||
if (annotation instanceof PermitAll) {
|
||||
return (a, o) -> new AuthorizationDecision(true);
|
||||
}
|
||||
if (annotation instanceof RolesAllowed) {
|
||||
RolesAllowed rolesAllowed = (RolesAllowed) annotation;
|
||||
return AuthorityAuthorizationManager.hasAnyRole(Jsr250AuthorizationManager.this.rolePrefix,
|
||||
rolesAllowed.value());
|
||||
}
|
||||
}
|
||||
return NULL_MANAGER;
|
||||
}
|
||||
|
||||
private Set<Annotation> findJsr250Annotations(Method method, Class<?> targetClass) {
|
||||
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
||||
Set<Annotation> annotations = findAnnotations(specificMethod);
|
||||
return (annotations.isEmpty()) ? findAnnotations(specificMethod.getDeclaringClass()) : annotations;
|
||||
}
|
||||
|
||||
private Set<Annotation> findAnnotations(AnnotatedElement annotatedElement) {
|
||||
return AnnotatedElementUtils.findAllMergedAnnotations(annotatedElement, JSR250_ANNOTATIONS);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.security.access.annotation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.security.access.method.MethodAuthorizationContext;
|
||||
import org.springframework.security.authorization.AuthorityAuthorizationManager;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
/**
|
||||
* An {@link AuthorizationManager} which can determine if an {@link Authentication} has
|
||||
* access to the {@link MethodInvocation} by evaluating if the {@link Authentication}
|
||||
* contains a specified authority from the Spring Security's {@link Secured} annotation.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.5
|
||||
*/
|
||||
public final class SecuredAuthorizationManager implements AuthorizationManager<MethodAuthorizationContext> {
|
||||
|
||||
private final SecuredAuthorizationManagerRegistry registry = new SecuredAuthorizationManagerRegistry();
|
||||
|
||||
/**
|
||||
* Determines if an {@link Authentication} has access to the {@link MethodInvocation}
|
||||
* by evaluating if the {@link Authentication} contains a specified authority from the
|
||||
* Spring Security's {@link Secured} annotation.
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to check
|
||||
* @param methodAuthorizationContext the {@link MethodAuthorizationContext} to check
|
||||
* @return an {@link AuthorizationDecision} or null if the {@link Secured} annotation
|
||||
* is not present
|
||||
*/
|
||||
@Override
|
||||
public AuthorizationDecision check(Supplier<Authentication> authentication,
|
||||
MethodAuthorizationContext methodAuthorizationContext) {
|
||||
AuthorizationManager<MethodAuthorizationContext> delegate = this.registry
|
||||
.getManager(methodAuthorizationContext);
|
||||
return delegate.check(authentication, methodAuthorizationContext);
|
||||
}
|
||||
|
||||
private static final class SecuredAuthorizationManagerRegistry extends AbstractAuthorizationManagerRegistry {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
AuthorizationManager<MethodAuthorizationContext> resolveManager(Method method, Class<?> targetClass) {
|
||||
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
||||
Secured secured = findSecuredAnnotation(specificMethod);
|
||||
return (secured != null) ? AuthorityAuthorizationManager.hasAnyAuthority(secured.value()) : NULL_MANAGER;
|
||||
}
|
||||
|
||||
private Secured findSecuredAnnotation(Method method) {
|
||||
Secured secured = AnnotationUtils.findAnnotation(method, Secured.class);
|
||||
return (secured != null) ? secured
|
||||
: AnnotationUtils.findAnnotation(method.getDeclaringClass(), Secured.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.security.access.intercept.aopalliance;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.security.access.method.AuthorizationMethodAfterAdvice;
|
||||
import org.springframework.security.access.method.AuthorizationMethodBeforeAdvice;
|
||||
import org.springframework.security.access.method.MethodAuthorizationContext;
|
||||
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
/**
|
||||
* Provides security interception of AOP Alliance based method invocations.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.5
|
||||
*/
|
||||
public final class AuthorizationMethodInterceptor implements MethodInterceptor {
|
||||
|
||||
private final AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> beforeAdvice;
|
||||
|
||||
private final AuthorizationMethodAfterAdvice<MethodAuthorizationContext> afterAdvice;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
* @param beforeAdvice the {@link AuthorizationMethodBeforeAdvice} to use
|
||||
* @param afterAdvice the {@link AuthorizationMethodAfterAdvice} to use
|
||||
*/
|
||||
public AuthorizationMethodInterceptor(AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> beforeAdvice,
|
||||
AuthorizationMethodAfterAdvice<MethodAuthorizationContext> afterAdvice) {
|
||||
this.beforeAdvice = beforeAdvice;
|
||||
this.afterAdvice = afterAdvice;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should be used to enforce security on a {@link MethodInvocation}.
|
||||
* @param mi the method being invoked which requires a security decision
|
||||
* @return the returned value from the {@link MethodInvocation}
|
||||
*/
|
||||
@Override
|
||||
public Object invoke(@NonNull MethodInvocation mi) throws Throwable {
|
||||
MethodAuthorizationContext methodAuthorizationContext = getMethodAuthorizationContext(mi);
|
||||
this.beforeAdvice.before(this::getAuthentication, methodAuthorizationContext);
|
||||
Object returnedObject = mi.proceed();
|
||||
return this.afterAdvice.after(this::getAuthentication, methodAuthorizationContext, returnedObject);
|
||||
}
|
||||
|
||||
private MethodAuthorizationContext getMethodAuthorizationContext(MethodInvocation mi) {
|
||||
Object target = mi.getThis();
|
||||
Class<?> targetClass = (target != null) ? AopUtils.getTargetClass(target) : null;
|
||||
return new MethodAuthorizationContext(mi, targetClass);
|
||||
}
|
||||
|
||||
private Authentication getAuthentication() {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication == null) {
|
||||
throw new AuthenticationCredentialsNotFoundException(
|
||||
"An Authentication object was not found in the SecurityContext");
|
||||
}
|
||||
return authentication;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.security.access.method;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link AuthorizationMethodAfterAdvice} which can determine if an
|
||||
* {@link Authentication} has access to the {@link T} object using an
|
||||
* {@link AuthorizationManager} if a {@link MethodMatcher} matches.
|
||||
*
|
||||
* @param <T> the type of object that the authorization check is being done one.
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.5
|
||||
*/
|
||||
public final class AuthorizationManagerMethodAfterAdvice<T> implements AuthorizationMethodAfterAdvice<T> {
|
||||
|
||||
private final MethodMatcher methodMatcher;
|
||||
|
||||
private final AuthorizationManager<T> authorizationManager;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
* @param methodMatcher the {@link MethodMatcher} to use
|
||||
* @param authorizationManager the {@link AuthorizationManager} to use
|
||||
*/
|
||||
public AuthorizationManagerMethodAfterAdvice(MethodMatcher methodMatcher,
|
||||
AuthorizationManager<T> authorizationManager) {
|
||||
Assert.notNull(methodMatcher, "methodMatcher cannot be null");
|
||||
Assert.notNull(authorizationManager, "authorizationManager cannot be null");
|
||||
this.methodMatcher = methodMatcher;
|
||||
this.authorizationManager = authorizationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an {@link Authentication} has access to the {@link T} object using
|
||||
* the {@link AuthorizationManager}.
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to check
|
||||
* @param object the {@link T} object to check
|
||||
* @throws AccessDeniedException if access is not granted
|
||||
*/
|
||||
@Override
|
||||
public Object after(Supplier<Authentication> authentication, T object, Object returnedObject) {
|
||||
this.authorizationManager.verify(authentication, object);
|
||||
return returnedObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return this.methodMatcher;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.security.access.method;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link AuthorizationMethodBeforeAdvice} which can determine if an
|
||||
* {@link Authentication} has access to the {@link T} object using an
|
||||
* {@link AuthorizationManager} if a {@link MethodMatcher} matches.
|
||||
*
|
||||
* @param <T> the type of object that the authorization check is being done one.
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.5
|
||||
*/
|
||||
public final class AuthorizationManagerMethodBeforeAdvice<T> implements AuthorizationMethodBeforeAdvice<T> {
|
||||
|
||||
private final MethodMatcher methodMatcher;
|
||||
|
||||
private final AuthorizationManager<T> authorizationManager;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
* @param methodMatcher the {@link MethodMatcher} to use
|
||||
* @param authorizationManager the {@link AuthorizationManager} to use
|
||||
*/
|
||||
public AuthorizationManagerMethodBeforeAdvice(MethodMatcher methodMatcher,
|
||||
AuthorizationManager<T> authorizationManager) {
|
||||
Assert.notNull(methodMatcher, "methodMatcher cannot be null");
|
||||
Assert.notNull(authorizationManager, "authorizationManager cannot be null");
|
||||
this.methodMatcher = methodMatcher;
|
||||
this.authorizationManager = authorizationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an {@link Authentication} has access to the {@link T} object using
|
||||
* the {@link AuthorizationManager}.
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to check
|
||||
* @param object the {@link T} object to check
|
||||
* @throws AccessDeniedException if access is not granted
|
||||
*/
|
||||
@Override
|
||||
public void before(Supplier<Authentication> authentication, T object) {
|
||||
this.authorizationManager.verify(authentication, object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return this.methodMatcher;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.security.access.method;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
/**
|
||||
* An Authorization advice that can determine if an {@link Authentication} has access to
|
||||
* the returned object from the {@link MethodInvocation}. The {@link #getMethodMatcher()}
|
||||
* describes when the advice applies for the method.
|
||||
*
|
||||
* @param <T> the type of object that the authorization check is being done one.
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.5
|
||||
*/
|
||||
public interface AuthorizationMethodAfterAdvice<T> extends Pointcut {
|
||||
|
||||
/**
|
||||
* Returns the default {@link ClassFilter}.
|
||||
* @return the {@link ClassFilter#TRUE} to use
|
||||
*/
|
||||
@Override
|
||||
default ClassFilter getClassFilter() {
|
||||
return ClassFilter.TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an {@link Authentication} has access to the returned object from the
|
||||
* {@link MethodInvocation}.
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to check
|
||||
* @param object the {@link T} object to check
|
||||
* @param returnedObject the returned object from the {@link MethodInvocation} to
|
||||
* check
|
||||
* @return the <code>Object</code> that will ultimately be returned to the caller (if
|
||||
* an implementation does not wish to modify the object to be returned to the caller,
|
||||
* the implementation should simply return the same object it was passed by the
|
||||
* <code>returnedObject</code> method argument)
|
||||
*/
|
||||
Object after(Supplier<Authentication> authentication, T object, Object returnedObject);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.security.access.method;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
/**
|
||||
* An advice which can determine if an {@link Authentication} has access to the {@link T}
|
||||
* object. The {@link #getMethodMatcher()} describes when the advice applies for the
|
||||
* method.
|
||||
*
|
||||
* @param <T> the type of object that the authorization check is being done one.
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.5
|
||||
*/
|
||||
public interface AuthorizationMethodBeforeAdvice<T> extends Pointcut {
|
||||
|
||||
/**
|
||||
* Returns the default {@link ClassFilter}.
|
||||
* @return the {@link ClassFilter#TRUE} to use
|
||||
*/
|
||||
@Override
|
||||
default ClassFilter getClassFilter() {
|
||||
return ClassFilter.TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an {@link Authentication} has access to the {@link T} object.
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to check
|
||||
* @param object the {@link T} object to check
|
||||
*/
|
||||
void before(Supplier<Authentication> authentication, T object);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.security.access.method;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.aop.support.StaticMethodMatcher;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
/**
|
||||
* An {@link AuthorizationMethodAfterAdvice} which delegates to specific
|
||||
* {@link AuthorizationMethodAfterAdvice}s and returns the result (possibly modified) from
|
||||
* the {@link MethodInvocation}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.5
|
||||
*/
|
||||
public final class DelegatingAuthorizationMethodAfterAdvice
|
||||
implements AuthorizationMethodAfterAdvice<MethodAuthorizationContext> {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final MethodMatcher methodMatcher = new StaticMethodMatcher() {
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
for (AuthorizationMethodAfterAdvice<MethodAuthorizationContext> delegate : DelegatingAuthorizationMethodAfterAdvice.this.delegates) {
|
||||
MethodMatcher methodMatcher = delegate.getMethodMatcher();
|
||||
if (methodMatcher.matches(method, targetClass)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
private final List<AuthorizationMethodAfterAdvice<MethodAuthorizationContext>> delegates;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
* @param delegates the {@link AuthorizationMethodAfterAdvice}s to use
|
||||
*/
|
||||
public DelegatingAuthorizationMethodAfterAdvice(
|
||||
List<AuthorizationMethodAfterAdvice<MethodAuthorizationContext>> delegates) {
|
||||
this.delegates = delegates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return this.methodMatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to specific {@link AuthorizationMethodAfterAdvice}s and returns the
|
||||
* <code>returnedObject</code> (possibly modified) from the method argument.
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to check
|
||||
* @param methodAuthorizationContext the {@link MethodAuthorizationContext} to check
|
||||
* @param returnedObject the returned object from the {@link MethodInvocation} to
|
||||
* check
|
||||
* @return the <code>returnedObject</code> (possibly modified) from the method
|
||||
* argument
|
||||
*/
|
||||
@Override
|
||||
public Object after(Supplier<Authentication> authentication, MethodAuthorizationContext methodAuthorizationContext,
|
||||
Object returnedObject) {
|
||||
if (this.logger.isTraceEnabled()) {
|
||||
this.logger.trace(
|
||||
LogMessage.format("Post Authorizing %s from %s", returnedObject, methodAuthorizationContext));
|
||||
}
|
||||
Object result = returnedObject;
|
||||
for (AuthorizationMethodAfterAdvice<MethodAuthorizationContext> delegate : this.delegates) {
|
||||
if (this.logger.isTraceEnabled()) {
|
||||
this.logger.trace(LogMessage.format("Checking authorization on %s from %s using %s", result,
|
||||
methodAuthorizationContext, delegate));
|
||||
}
|
||||
result = delegate.after(authentication, methodAuthorizationContext, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.security.access.method;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.aop.support.StaticMethodMatcher;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
/**
|
||||
* An {@link AuthorizationMethodBeforeAdvice} which delegates to a specific
|
||||
* {@link AuthorizationMethodBeforeAdvice} and grants access if all
|
||||
* {@link AuthorizationMethodBeforeAdvice}s granted or abstained. Denies access only if
|
||||
* one of the {@link AuthorizationMethodBeforeAdvice}s denied.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.5
|
||||
*/
|
||||
public final class DelegatingAuthorizationMethodBeforeAdvice
|
||||
implements AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final MethodMatcher methodMatcher = new StaticMethodMatcher() {
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
for (AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> delegate : DelegatingAuthorizationMethodBeforeAdvice.this.delegates) {
|
||||
MethodMatcher methodMatcher = delegate.getMethodMatcher();
|
||||
if (methodMatcher.matches(method, targetClass)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
private final List<AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>> delegates;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
* @param delegates the {@link AuthorizationMethodBeforeAdvice}s to use
|
||||
*/
|
||||
public DelegatingAuthorizationMethodBeforeAdvice(
|
||||
List<AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>> delegates) {
|
||||
this.delegates = delegates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return this.methodMatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to a specific {@link AuthorizationMethodBeforeAdvice} and grants access
|
||||
* if all {@link AuthorizationMethodBeforeAdvice}s granted or abstained. Denies only
|
||||
* if one of the {@link AuthorizationMethodBeforeAdvice}s denied.
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to check
|
||||
* @param methodAuthorizationContext the {@link MethodAuthorizationContext} to check
|
||||
*/
|
||||
@Override
|
||||
public void before(Supplier<Authentication> authentication, MethodAuthorizationContext methodAuthorizationContext) {
|
||||
if (this.logger.isTraceEnabled()) {
|
||||
this.logger.trace(LogMessage.format("Pre Authorizing %s", methodAuthorizationContext));
|
||||
}
|
||||
for (AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> delegate : this.delegates) {
|
||||
if (this.logger.isTraceEnabled()) {
|
||||
this.logger.trace(LogMessage.format("Checking authorization on %s using %s", methodAuthorizationContext,
|
||||
delegate));
|
||||
}
|
||||
delegate.before(authentication, methodAuthorizationContext);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.security.access.method;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
/**
|
||||
* An authorization context which is holds the {@link MethodInvocation}, the target class
|
||||
* and the returned object.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.5
|
||||
*/
|
||||
public final class MethodAuthorizationContext {
|
||||
|
||||
private final MethodInvocation methodInvocation;
|
||||
|
||||
private final Class<?> targetClass;
|
||||
|
||||
private Object returnObject;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
* @param methodInvocation the {@link MethodInvocation} to use
|
||||
* @param targetClass the target class to use
|
||||
*/
|
||||
public MethodAuthorizationContext(MethodInvocation methodInvocation, Class<?> targetClass) {
|
||||
this.methodInvocation = methodInvocation;
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link MethodInvocation}.
|
||||
* @return the {@link MethodInvocation} to use
|
||||
*/
|
||||
public MethodInvocation getMethodInvocation() {
|
||||
return this.methodInvocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target class.
|
||||
* @return the target class to use
|
||||
*/
|
||||
public Class<?> getTargetClass() {
|
||||
return this.targetClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the returned object from the {@link MethodInvocation}.
|
||||
* @return the returned object from the {@link MethodInvocation} to use
|
||||
*/
|
||||
public Object getReturnObject() {
|
||||
return this.returnObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the returned object from the {@link MethodInvocation}.
|
||||
* @param returnObject the returned object from the {@link MethodInvocation} to use
|
||||
*/
|
||||
public void setReturnObject(Object returnObject) {
|
||||
this.returnObject = returnObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MethodAuthorizationContext[methodInvocation=" + this.methodInvocation + ", targetClass="
|
||||
+ this.targetClass + ", returnObject=" + this.returnObject + ']';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -75,9 +75,22 @@ public final class AuthorityAuthorizationManager<T> implements AuthorizationMana
|
||||
* @return the new instance
|
||||
*/
|
||||
public static <T> AuthorityAuthorizationManager<T> hasAnyRole(String... roles) {
|
||||
return hasAnyRole(ROLE_PREFIX, roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of {@link AuthorityAuthorizationManager} with the provided
|
||||
* authorities.
|
||||
* @param rolePrefix the role prefix for <code>roles</code>
|
||||
* @param roles the authorities to check for prefixed with <code>rolePrefix</code>
|
||||
* @param <T> the type of object being authorized
|
||||
* @return the new instance
|
||||
*/
|
||||
public static <T> AuthorityAuthorizationManager<T> hasAnyRole(String rolePrefix, String[] roles) {
|
||||
Assert.notNull(rolePrefix, "rolePrefix cannot be null");
|
||||
Assert.notEmpty(roles, "roles cannot be empty");
|
||||
Assert.noNullElements(roles, "roles cannot contain null values");
|
||||
return hasAnyAuthority(toNamedRolesArray(roles));
|
||||
return hasAnyAuthority(toNamedRolesArray(rolePrefix, roles));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,10 +106,10 @@ public final class AuthorityAuthorizationManager<T> implements AuthorizationMana
|
||||
return new AuthorityAuthorizationManager<>(authorities);
|
||||
}
|
||||
|
||||
private static String[] toNamedRolesArray(String... roles) {
|
||||
private static String[] toNamedRolesArray(String rolePrefix, String[] roles) {
|
||||
String[] result = new String[roles.length];
|
||||
for (int i = 0; i < roles.length; i++) {
|
||||
result[i] = ROLE_PREFIX + roles[i];
|
||||
result[i] = rolePrefix + roles[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.security.authorization.method;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.core.MethodClassKey;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.security.access.method.MethodAuthorizationContext;
|
||||
|
||||
/**
|
||||
* An abstract registry which provides an {@link ExpressionAttribute} for the
|
||||
* {@link MethodInvocation}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.5
|
||||
*/
|
||||
abstract class AbstractExpressionAttributeRegistry<T extends ExpressionAttribute> {
|
||||
|
||||
private final Map<MethodClassKey, T> cachedAttributes = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Returns an {@link ExpressionAttribute} for the {@link MethodAuthorizationContext}.
|
||||
* @param methodAuthorizationContext the {@link MethodAuthorizationContext} to use
|
||||
* @return the {@link ExpressionAttribute} to use
|
||||
*/
|
||||
final T getAttribute(MethodAuthorizationContext methodAuthorizationContext) {
|
||||
MethodInvocation methodInvocation = methodAuthorizationContext.getMethodInvocation();
|
||||
Method method = methodInvocation.getMethod();
|
||||
Class<?> targetClass = methodAuthorizationContext.getTargetClass();
|
||||
return getAttribute(method, targetClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link ExpressionAttribute} for the method and the target class.
|
||||
* @param method the method
|
||||
* @param targetClass the target class
|
||||
* @return the {@link ExpressionAttribute} to use
|
||||
*/
|
||||
final T getAttribute(Method method, Class<?> targetClass) {
|
||||
MethodClassKey cacheKey = new MethodClassKey(method, targetClass);
|
||||
return this.cachedAttributes.computeIfAbsent(cacheKey, (k) -> resolveAttribute(method, targetClass));
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses should implement this method to provide the non-null
|
||||
* {@link ExpressionAttribute} for the method and the target class.
|
||||
* @param method the method
|
||||
* @param targetClass the target class
|
||||
* @return the non-null {@link ExpressionAttribute}
|
||||
*/
|
||||
@NonNull
|
||||
abstract T resolveAttribute(Method method, Class<?> targetClass);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.security.authorization.method;
|
||||
|
||||
import org.springframework.expression.Expression;
|
||||
|
||||
/**
|
||||
* An {@link Expression} attribute.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.5
|
||||
*/
|
||||
class ExpressionAttribute {
|
||||
|
||||
/**
|
||||
* Represents an empty attribute with null {@link Expression}.
|
||||
*/
|
||||
static final ExpressionAttribute NULL_ATTRIBUTE = new ExpressionAttribute(null);
|
||||
|
||||
private final Expression expression;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
* @param expression the {@link Expression} to use
|
||||
*/
|
||||
ExpressionAttribute(Expression expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Expression}.
|
||||
* @return the {@link Expression} to use
|
||||
*/
|
||||
Expression getExpression() {
|
||||
return this.expression;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.security.authorization.method;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import reactor.util.annotation.NonNull;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.security.access.expression.ExpressionUtils;
|
||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.method.MethodAuthorizationContext;
|
||||
import org.springframework.security.access.prepost.PostAuthorize;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link AuthorizationManager} which can determine if an {@link Authentication} has
|
||||
* access to the {@link MethodInvocation} by evaluating an expression from the
|
||||
* {@link PostAuthorize} annotation.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.5
|
||||
*/
|
||||
public final class PostAuthorizeAuthorizationManager implements AuthorizationManager<MethodAuthorizationContext> {
|
||||
|
||||
private final PostAuthorizeExpressionAttributeRegistry registry = new PostAuthorizeExpressionAttributeRegistry();
|
||||
|
||||
private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
|
||||
/**
|
||||
* Sets the {@link MethodSecurityExpressionHandler}.
|
||||
* @param expressionHandler the {@link MethodSecurityExpressionHandler} to use
|
||||
*/
|
||||
public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) {
|
||||
Assert.notNull(expressionHandler, "expressionHandler cannot be null");
|
||||
this.expressionHandler = expressionHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an {@link Authentication} has access to the {@link MethodInvocation}
|
||||
* by evaluating an expression from the {@link PostAuthorize} annotation.
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to check
|
||||
* @param methodAuthorizationContext the {@link MethodAuthorizationContext} to check
|
||||
* @return an {@link AuthorizationDecision} or null if the {@link PostAuthorize}
|
||||
* annotation is not present
|
||||
*/
|
||||
@Override
|
||||
public AuthorizationDecision check(Supplier<Authentication> authentication,
|
||||
MethodAuthorizationContext methodAuthorizationContext) {
|
||||
ExpressionAttribute attribute = this.registry.getAttribute(methodAuthorizationContext);
|
||||
if (attribute == ExpressionAttribute.NULL_ATTRIBUTE) {
|
||||
return null;
|
||||
}
|
||||
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication.get(),
|
||||
methodAuthorizationContext.getMethodInvocation());
|
||||
this.expressionHandler.setReturnObject(methodAuthorizationContext.getReturnObject(), ctx);
|
||||
boolean granted = ExpressionUtils.evaluateAsBoolean(attribute.getExpression(), ctx);
|
||||
return new AuthorizationDecision(granted);
|
||||
}
|
||||
|
||||
private final class PostAuthorizeExpressionAttributeRegistry
|
||||
extends AbstractExpressionAttributeRegistry<ExpressionAttribute> {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
ExpressionAttribute resolveAttribute(Method method, Class<?> targetClass) {
|
||||
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
||||
PostAuthorize postAuthorize = findPostAuthorizeAnnotation(specificMethod);
|
||||
if (postAuthorize == null) {
|
||||
return ExpressionAttribute.NULL_ATTRIBUTE;
|
||||
}
|
||||
Expression postAuthorizeExpression = PostAuthorizeAuthorizationManager.this.expressionHandler
|
||||
.getExpressionParser().parseExpression(postAuthorize.value());
|
||||
return new ExpressionAttribute(postAuthorizeExpression);
|
||||
}
|
||||
|
||||
private PostAuthorize findPostAuthorizeAnnotation(Method method) {
|
||||
PostAuthorize postAuthorize = AnnotationUtils.findAnnotation(method, PostAuthorize.class);
|
||||
return (postAuthorize != null) ? postAuthorize
|
||||
: AnnotationUtils.findAnnotation(method.getDeclaringClass(), PostAuthorize.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.security.authorization.method;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.aop.support.StaticMethodMatcher;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.method.AuthorizationMethodAfterAdvice;
|
||||
import org.springframework.security.access.method.MethodAuthorizationContext;
|
||||
import org.springframework.security.access.prepost.PostFilter;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link AuthorizationMethodAfterAdvice} which filters a <code>returnedObject</code>
|
||||
* from the {@link MethodInvocation} by evaluating an expression from the
|
||||
* {@link PostFilter} annotation.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.5
|
||||
*/
|
||||
public final class PostFilterAuthorizationMethodAfterAdvice
|
||||
implements AuthorizationMethodAfterAdvice<MethodAuthorizationContext> {
|
||||
|
||||
private final PostFilterExpressionAttributeRegistry registry = new PostFilterExpressionAttributeRegistry();
|
||||
|
||||
private final MethodMatcher methodMatcher = new StaticMethodMatcher() {
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return PostFilterAuthorizationMethodAfterAdvice.this.registry.getAttribute(method,
|
||||
targetClass) != ExpressionAttribute.NULL_ATTRIBUTE;
|
||||
}
|
||||
};
|
||||
|
||||
private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
|
||||
/**
|
||||
* Sets the {@link MethodSecurityExpressionHandler}.
|
||||
* @param expressionHandler the {@link MethodSecurityExpressionHandler} to use
|
||||
*/
|
||||
public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) {
|
||||
Assert.notNull(expressionHandler, "expressionHandler cannot be null");
|
||||
this.expressionHandler = expressionHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return this.methodMatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters a <code>returnedObject</code> from the {@link MethodInvocation} by
|
||||
* evaluating an expression from the {@link PostFilter} annotation.
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to check
|
||||
* @param methodAuthorizationContext the {@link MethodAuthorizationContext} to check
|
||||
* @param returnedObject the returned object from the {@link MethodInvocation} to
|
||||
* check
|
||||
* @return filtered <code>returnedObject</code> from the {@link MethodInvocation}
|
||||
*/
|
||||
@Override
|
||||
public Object after(Supplier<Authentication> authentication, MethodAuthorizationContext methodAuthorizationContext,
|
||||
Object returnedObject) {
|
||||
if (returnedObject == null) {
|
||||
return null;
|
||||
}
|
||||
ExpressionAttribute attribute = this.registry.getAttribute(methodAuthorizationContext);
|
||||
if (attribute == ExpressionAttribute.NULL_ATTRIBUTE) {
|
||||
return returnedObject;
|
||||
}
|
||||
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication.get(),
|
||||
methodAuthorizationContext.getMethodInvocation());
|
||||
Object result = this.expressionHandler.filter(returnedObject, attribute.getExpression(), ctx);
|
||||
methodAuthorizationContext.setReturnObject(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private final class PostFilterExpressionAttributeRegistry
|
||||
extends AbstractExpressionAttributeRegistry<ExpressionAttribute> {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
ExpressionAttribute resolveAttribute(Method method, Class<?> targetClass) {
|
||||
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
||||
PostFilter postFilter = findPostFilterAnnotation(specificMethod);
|
||||
if (postFilter == null) {
|
||||
return ExpressionAttribute.NULL_ATTRIBUTE;
|
||||
}
|
||||
Expression postFilterExpression = PostFilterAuthorizationMethodAfterAdvice.this.expressionHandler
|
||||
.getExpressionParser().parseExpression(postFilter.value());
|
||||
return new ExpressionAttribute(postFilterExpression);
|
||||
}
|
||||
|
||||
private PostFilter findPostFilterAnnotation(Method method) {
|
||||
PostFilter postFilter = AnnotationUtils.findAnnotation(method, PostFilter.class);
|
||||
return (postFilter != null) ? postFilter
|
||||
: AnnotationUtils.findAnnotation(method.getDeclaringClass(), PostFilter.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.security.authorization.method;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import reactor.util.annotation.NonNull;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.security.access.expression.ExpressionUtils;
|
||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.method.MethodAuthorizationContext;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link AuthorizationManager} which can determine if an {@link Authentication} has
|
||||
* access to the {@link MethodInvocation} by evaluating an expression from the
|
||||
* {@link PreAuthorize} annotation.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.5
|
||||
*/
|
||||
public final class PreAuthorizeAuthorizationManager implements AuthorizationManager<MethodAuthorizationContext> {
|
||||
|
||||
private final PreAuthorizeExpressionAttributeRegistry registry = new PreAuthorizeExpressionAttributeRegistry();
|
||||
|
||||
private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
|
||||
/**
|
||||
* Sets the {@link MethodSecurityExpressionHandler}.
|
||||
* @param expressionHandler the {@link MethodSecurityExpressionHandler} to use
|
||||
*/
|
||||
public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) {
|
||||
Assert.notNull(expressionHandler, "expressionHandler cannot be null");
|
||||
this.expressionHandler = expressionHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an {@link Authentication} has access to the {@link MethodInvocation}
|
||||
* by evaluating an expression from the {@link PreAuthorize} annotation.
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to check
|
||||
* @param methodAuthorizationContext the {@link MethodAuthorizationContext} to check
|
||||
* @return an {@link AuthorizationDecision} or null if the {@link PreAuthorize}
|
||||
* annotation is not present
|
||||
*/
|
||||
@Override
|
||||
public AuthorizationDecision check(Supplier<Authentication> authentication,
|
||||
MethodAuthorizationContext methodAuthorizationContext) {
|
||||
ExpressionAttribute attribute = this.registry.getAttribute(methodAuthorizationContext);
|
||||
if (attribute == ExpressionAttribute.NULL_ATTRIBUTE) {
|
||||
return null;
|
||||
}
|
||||
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication.get(),
|
||||
methodAuthorizationContext.getMethodInvocation());
|
||||
boolean granted = ExpressionUtils.evaluateAsBoolean(attribute.getExpression(), ctx);
|
||||
return new AuthorizationDecision(granted);
|
||||
}
|
||||
|
||||
private final class PreAuthorizeExpressionAttributeRegistry
|
||||
extends AbstractExpressionAttributeRegistry<ExpressionAttribute> {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
ExpressionAttribute resolveAttribute(Method method, Class<?> targetClass) {
|
||||
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
||||
PreAuthorize preAuthorize = findPreAuthorizeAnnotation(specificMethod);
|
||||
if (preAuthorize == null) {
|
||||
return ExpressionAttribute.NULL_ATTRIBUTE;
|
||||
}
|
||||
Expression preAuthorizeExpression = PreAuthorizeAuthorizationManager.this.expressionHandler
|
||||
.getExpressionParser().parseExpression(preAuthorize.value());
|
||||
return new ExpressionAttribute(preAuthorizeExpression);
|
||||
}
|
||||
|
||||
private PreAuthorize findPreAuthorizeAnnotation(Method method) {
|
||||
PreAuthorize preAuthorize = AnnotationUtils.findAnnotation(method, PreAuthorize.class);
|
||||
return (preAuthorize != null) ? preAuthorize
|
||||
: AnnotationUtils.findAnnotation(method.getDeclaringClass(), PreAuthorize.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.security.authorization.method;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.aop.support.StaticMethodMatcher;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.method.AuthorizationMethodBeforeAdvice;
|
||||
import org.springframework.security.access.method.MethodAuthorizationContext;
|
||||
import org.springframework.security.access.prepost.PreFilter;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* An {@link AuthorizationMethodBeforeAdvice} which filters a method argument by
|
||||
* evaluating an expression from the {@link PreFilter} annotation.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.5
|
||||
*/
|
||||
public final class PreFilterAuthorizationMethodBeforeAdvice
|
||||
implements AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> {
|
||||
|
||||
private final PreFilterExpressionAttributeRegistry registry = new PreFilterExpressionAttributeRegistry();
|
||||
|
||||
private final MethodMatcher methodMatcher = new StaticMethodMatcher() {
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return PreFilterAuthorizationMethodBeforeAdvice.this.registry.getAttribute(method,
|
||||
targetClass) != PreFilterExpressionAttribute.NULL_ATTRIBUTE;
|
||||
}
|
||||
};
|
||||
|
||||
private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
|
||||
/**
|
||||
* Sets the {@link MethodSecurityExpressionHandler}.
|
||||
* @param expressionHandler the {@link MethodSecurityExpressionHandler} to use
|
||||
*/
|
||||
public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) {
|
||||
Assert.notNull(expressionHandler, "expressionHandler cannot be null");
|
||||
this.expressionHandler = expressionHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return this.methodMatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters a method argument by evaluating an expression from the {@link PreFilter}
|
||||
* annotation.
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to check
|
||||
* @param methodAuthorizationContext the {@link MethodAuthorizationContext} to check
|
||||
*/
|
||||
@Override
|
||||
public void before(Supplier<Authentication> authentication, MethodAuthorizationContext methodAuthorizationContext) {
|
||||
PreFilterExpressionAttribute attribute = this.registry.getAttribute(methodAuthorizationContext);
|
||||
if (attribute == PreFilterExpressionAttribute.NULL_ATTRIBUTE) {
|
||||
return;
|
||||
}
|
||||
MethodInvocation mi = methodAuthorizationContext.getMethodInvocation();
|
||||
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication.get(), mi);
|
||||
Object filterTarget = findFilterTarget(attribute.filterTarget, ctx, mi);
|
||||
this.expressionHandler.filter(filterTarget, attribute.getExpression(), ctx);
|
||||
}
|
||||
|
||||
private Object findFilterTarget(String filterTargetName, EvaluationContext ctx, MethodInvocation methodInvocation) {
|
||||
Object filterTarget;
|
||||
if (StringUtils.hasText(filterTargetName)) {
|
||||
filterTarget = ctx.lookupVariable(filterTargetName);
|
||||
Assert.notNull(filterTarget, () -> "Filter target was null, or no argument with name '" + filterTargetName
|
||||
+ "' found in method.");
|
||||
}
|
||||
else {
|
||||
Object[] arguments = methodInvocation.getArguments();
|
||||
Assert.state(arguments.length == 1,
|
||||
"Unable to determine the method argument for filtering. Specify the filter target.");
|
||||
filterTarget = arguments[0];
|
||||
Assert.notNull(filterTarget,
|
||||
"Filter target was null. Make sure you passing the correct value in the method argument.");
|
||||
}
|
||||
Assert.state(!filterTarget.getClass().isArray(),
|
||||
"Pre-filtering on array types is not supported. Using a Collection will solve this problem.");
|
||||
return filterTarget;
|
||||
}
|
||||
|
||||
private final class PreFilterExpressionAttributeRegistry
|
||||
extends AbstractExpressionAttributeRegistry<PreFilterExpressionAttribute> {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
PreFilterExpressionAttribute resolveAttribute(Method method, Class<?> targetClass) {
|
||||
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
||||
PreFilter preFilter = findPreFilterAnnotation(specificMethod);
|
||||
if (preFilter == null) {
|
||||
return PreFilterExpressionAttribute.NULL_ATTRIBUTE;
|
||||
}
|
||||
Expression preFilterExpression = PreFilterAuthorizationMethodBeforeAdvice.this.expressionHandler
|
||||
.getExpressionParser().parseExpression(preFilter.value());
|
||||
return new PreFilterExpressionAttribute(preFilterExpression, preFilter.filterTarget());
|
||||
}
|
||||
|
||||
private PreFilter findPreFilterAnnotation(Method method) {
|
||||
PreFilter preFilter = AnnotationUtils.findAnnotation(method, PreFilter.class);
|
||||
return (preFilter != null) ? preFilter
|
||||
: AnnotationUtils.findAnnotation(method.getDeclaringClass(), PreFilter.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class PreFilterExpressionAttribute extends ExpressionAttribute {
|
||||
|
||||
private static final PreFilterExpressionAttribute NULL_ATTRIBUTE = new PreFilterExpressionAttribute(null, null);
|
||||
|
||||
private final String filterTarget;
|
||||
|
||||
private PreFilterExpressionAttribute(Expression expression, String filterTarget) {
|
||||
super(expression);
|
||||
this.filterTarget = filterTarget;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user