1
0
mirror of synced 2026-05-22 21:33:16 +00:00

Revert AuthorizationManager Method Security

This commit is contained in:
Josh Cummings
2021-04-12 15:46:38 -06:00
parent b352c8f1da
commit 163b5943ca
38 changed files with 5 additions and 3790 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2020 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,22 +75,9 @@ 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(rolePrefix, roles));
return hasAnyAuthority(toNamedRolesArray(roles));
}
/**
@@ -106,10 +93,10 @@ public final class AuthorityAuthorizationManager<T> implements AuthorizationMana
return new AuthorityAuthorizationManager<>(authorities);
}
private static String[] toNamedRolesArray(String rolePrefix, String[] roles) {
private static String[] toNamedRolesArray(String... roles) {
String[] result = new String[roles.length];
for (int i = 0; i < roles.length; i++) {
result[i] = rolePrefix + roles[i];
result[i] = ROLE_PREFIX + roles[i];
}
return result;
}
@@ -1,63 +0,0 @@
/*
* 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.authorization.AuthorizationManager;
/**
* For internal use only, as this contract is likely to change
*
* @author Evgeniy Cheban
*/
abstract class AbstractAuthorizationManagerRegistry {
static final AuthorizationManager<MethodInvocation> NULL_MANAGER = (a, o) -> null;
private final Map<MethodClassKey, AuthorizationManager<MethodInvocation>> cachedManagers = new ConcurrentHashMap<>();
/**
* Returns an {@link AuthorizationManager} for the
* {@link AuthorizationMethodInvocation}.
* @param methodInvocation the {@link AuthorizationMethodInvocation} to use
* @return an {@link AuthorizationManager} to use
*/
final AuthorizationManager<MethodInvocation> getManager(AuthorizationMethodInvocation methodInvocation) {
Method method = methodInvocation.getMethod();
Class<?> targetClass = methodInvocation.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<MethodInvocation> resolveManager(Method method, Class<?> targetClass);
}
@@ -1,68 +0,0 @@
/*
* 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.springframework.core.MethodClassKey;
import org.springframework.lang.NonNull;
/**
* For internal use only, as this contract is likely to change
*
* @author Evgeniy Cheban
*/
abstract class AbstractExpressionAttributeRegistry<T extends ExpressionAttribute> {
private final Map<MethodClassKey, T> cachedAttributes = new ConcurrentHashMap<>();
/**
* Returns an {@link ExpressionAttribute} for the
* {@link AuthorizationMethodInvocation}.
* @param mi the {@link AuthorizationMethodInvocation} to use
* @return the {@link ExpressionAttribute} to use
*/
final T getAttribute(AuthorizationMethodInvocation mi) {
Method method = mi.getMethod();
Class<?> targetClass = mi.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);
}
@@ -1,66 +0,0 @@
/*
* 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.util.function.Supplier;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.lang.Nullable;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.core.Authentication;
/**
* An Authorization manager which can determine if an {@link Authentication} has access to
* a specific object and associated return object. Intended for use specifically to
* evaluate the returning state of a method invocation.
*
* @param <T> the type of object that the authorization check is being done one.
* @author Josh Cummings
* @author Evgeniy Cheban
* @since 5.5
*/
public interface AfterMethodAuthorizationManager<T> {
/**
* Determine if access should be granted for a specific authentication, object and
* returnedObject.
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param object the {@code T} object to check, typically a {@link MethodInvocation}
* @param returnedObject the returnedObject from the method invocation to check
* @throws AccessDeniedException if access is not granted
*/
default void verify(Supplier<Authentication> authentication, T object, Object returnedObject) {
AuthorizationDecision decision = check(authentication, object, returnedObject);
if (decision != null && !decision.isGranted()) {
throw new AccessDeniedException("Access Denied");
}
}
/**
* Determine if access is granted for a specific authentication, object, and
* returnedObject.
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param object the {@code T} object to check, typically a {@link MethodInvocation}
* @param returnedObject the returned object from the method invocation to check
* @return an {@link AuthorizationDecision} or null if no decision could be made
*/
@Nullable
AuthorizationDecision check(Supplier<Authentication> authentication, T object, Object returnedObject);
}
@@ -1,62 +0,0 @@
/*
* 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.util.function.Supplier;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
/**
* Adapts an {@link AuthorizationManager} into an {@link AfterMethodAuthorizationManager}
*
* @param <T> the {@code T} object to authorize, typically a {@link MethodInvocation}
* @author Josh Cummings
* @since 5.5
*/
public final class AfterMethodAuthorizationManagerAdapter<T> implements AfterMethodAuthorizationManager<T> {
private final AuthorizationManager<T> authorizationManager;
/**
* Construct a {@link AfterMethodAuthorizationManagerAdapter} with the provided
* parameters
* @param authorizationManager the {@link AuthorizationManager} to adapt
*/
public AfterMethodAuthorizationManagerAdapter(AuthorizationManager<T> authorizationManager) {
this.authorizationManager = authorizationManager;
}
/**
* Determine if access is granted for a specific authentication and {@code T} object.
*
* Note that the {@code returnedObject} parameter is ignored
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param object the {@code T} object to check, typically a {@link MethodInvocation}
* @param returnedObject the returned object from the method invocation, ignored in
* this implementation
* @return an {@link AuthorizationDecision} or null if no decision could be made
*/
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, T object, Object returnedObject) {
return this.authorizationManager.check(authentication, object);
}
}
@@ -1,79 +0,0 @@
/*
* 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.util.function.Supplier;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.Pointcut;
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 AuthorizationMethodInterceptor} which can determine if an
* {@link Authentication} has access to the result of an {@link MethodInvocation} using an
* {@link AuthorizationManager}
*
* @author Evgeniy Cheban
* @author Josh Cummings
* @since 5.5
*/
public final class AuthorizationManagerAfterMethodInterceptor implements AuthorizationMethodInterceptor {
private final Pointcut pointcut;
private final AfterMethodAuthorizationManager<MethodInvocation> authorizationManager;
/**
* Creates an instance.
* @param pointcut the {@link Pointcut} to use
* @param authorizationManager the {@link AuthorizationManager} to use
*/
public AuthorizationManagerAfterMethodInterceptor(Pointcut pointcut,
AfterMethodAuthorizationManager<MethodInvocation> authorizationManager) {
Assert.notNull(pointcut, "pointcut cannot be null");
Assert.notNull(authorizationManager, "authorizationManager cannot be null");
this.pointcut = pointcut;
this.authorizationManager = authorizationManager;
}
/**
* Determine if an {@link Authentication} has access to the {@link MethodInvocation}
* using the {@link AuthorizationManager}.
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param mi the {@link MethodInvocation} to check
* @throws AccessDeniedException if access is not granted
*/
@Override
public Object invoke(Supplier<Authentication> authentication, MethodInvocation mi) throws Throwable {
Object result = mi.proceed();
this.authorizationManager.verify(authentication, mi, result);
return result;
}
/**
* {@inheritDoc}
*/
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
@@ -1,77 +0,0 @@
/*
* 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.util.function.Supplier;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.Pointcut;
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 AuthorizationMethodInterceptor} which uses a {@link AuthorizationManager} to
* determine if an {@link Authentication} may invoke the given {@link MethodInvocation}
*
* @author Evgeniy Cheban
* @author Josh Cummings
* @since 5.5
*/
public final class AuthorizationManagerBeforeMethodInterceptor implements AuthorizationMethodInterceptor {
private final Pointcut pointcut;
private final AuthorizationManager<MethodInvocation> authorizationManager;
/**
* Creates an instance.
* @param pointcut the {@link Pointcut} to use
* @param authorizationManager the {@link AuthorizationManager} to use
*/
public AuthorizationManagerBeforeMethodInterceptor(Pointcut pointcut,
AuthorizationManager<MethodInvocation> authorizationManager) {
Assert.notNull(pointcut, "pointcut cannot be null");
Assert.notNull(authorizationManager, "authorizationManager cannot be null");
this.pointcut = pointcut;
this.authorizationManager = authorizationManager;
}
/**
* Determine if an {@link Authentication} has access to the {@link MethodInvocation}
* using the configured {@link AuthorizationManager}.
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param mi the {@link MethodInvocation} to check
* @throws AccessDeniedException if access is not granted
*/
@Override
public Object invoke(Supplier<Authentication> authentication, MethodInvocation mi) throws Throwable {
this.authorizationManager.verify(authentication, mi);
return mi.proceed();
}
/**
* {@inheritDoc}
*/
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
@@ -1,85 +0,0 @@
/*
* 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.util.function.Supplier;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.aop.framework.AopInfrastructureBean;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
/**
* A {@link MethodInterceptor} which can determine if an {@link Authentication} has access
* to the {@link MethodInvocation}. {@link #getPointcut()} describes when the interceptor
* applies.
*
* @author Evgeniy Cheban
* @author Josh Cummings
* @since 5.5
*/
public interface AuthorizationMethodInterceptor extends MethodInterceptor, PointcutAdvisor, AopInfrastructureBean {
/**
* {@inheritDoc}
*/
@Override
default Advice getAdvice() {
return this;
}
/**
* {@inheritDoc}
*/
@Override
default boolean isPerInstance() {
return true;
}
/**
* Determine if an {@link Authentication} has access to the {@link MethodInvocation}
* @param mi the {@link MethodInvocation} to intercept and potentially invoke
* @return the result of the method invocation
* @throws Throwable if the interceptor or the target object throws an exception
*/
default Object invoke(MethodInvocation mi) throws Throwable {
Supplier<Authentication> supplier = () -> {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
throw new AuthenticationCredentialsNotFoundException(
"An Authentication object was not found in the SecurityContext");
}
return authentication;
};
return invoke(supplier, new AuthorizationMethodInvocation(supplier, mi));
}
/**
* Determine if an {@link Authentication} has access to the {@link MethodInvocation}
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param mi the {@link MethodInvocation} to intercept and potentially invoke
* @return the result of the method invocation
* @throws Throwable if the interceptor or the target object throws an exception
*/
Object invoke(Supplier<Authentication> authentication, MethodInvocation mi) throws Throwable;
}
@@ -1,80 +0,0 @@
/*
* 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 javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
/**
* A static factory for constructing common {@link AuthorizationMethodInterceptor}s
*
* @author Josh Cummings
* @since 5.5
* @see PreAuthorizeAuthorizationManager
* @see PostAuthorizeAuthorizationManager
* @see SecuredAuthorizationManager
* @see Jsr250AuthorizationManager
*/
public final class AuthorizationMethodInterceptors {
public static AuthorizationMethodInterceptor preAuthorize() {
return preAuthorize(new PreAuthorizeAuthorizationManager());
}
public static AuthorizationMethodInterceptor preAuthorize(PreAuthorizeAuthorizationManager manager) {
return new AuthorizationManagerBeforeMethodInterceptor(
AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class), manager);
}
public static AuthorizationMethodInterceptor postAuthorize() {
return postAuthorize(new PostAuthorizeAuthorizationManager());
}
public static AuthorizationMethodInterceptor postAuthorize(PostAuthorizeAuthorizationManager manager) {
return new AuthorizationManagerAfterMethodInterceptor(
AuthorizationMethodPointcuts.forAnnotations(PostAuthorize.class), manager);
}
public static AuthorizationMethodInterceptor secured() {
return secured(new SecuredAuthorizationManager());
}
public static AuthorizationMethodInterceptor secured(SecuredAuthorizationManager manager) {
return new AuthorizationManagerBeforeMethodInterceptor(
AuthorizationMethodPointcuts.forAnnotations(Secured.class), manager);
}
public static AuthorizationMethodInterceptor jsr250() {
return jsr250(new Jsr250AuthorizationManager());
}
public static AuthorizationMethodInterceptor jsr250(Jsr250AuthorizationManager manager) {
return new AuthorizationManagerBeforeMethodInterceptor(
AuthorizationMethodPointcuts.forAnnotations(DenyAll.class, PermitAll.class, RolesAllowed.class),
manager);
}
private AuthorizationMethodInterceptors() {
}
}
@@ -1,123 +0,0 @@
/*
* 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.AccessibleObject;
import java.lang.reflect.Method;
import java.util.Collections;
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.Pointcut;
import org.springframework.aop.support.AopUtils;
import org.springframework.core.log.LogMessage;
import org.springframework.security.core.Authentication;
/**
* @author Josh Cummings
*/
class AuthorizationMethodInvocation implements MethodInvocation {
private final Log logger = LogFactory.getLog(getClass());
private final Supplier<Authentication> authentication;
private final MethodInvocation methodInvocation;
private final Class<?> targetClass;
private final List<AuthorizationMethodInterceptor> interceptors;
private final int size;
private int currentPosition = 0;
AuthorizationMethodInvocation(Supplier<Authentication> authentication, MethodInvocation methodInvocation) {
this(authentication, methodInvocation, Collections.emptyList());
}
AuthorizationMethodInvocation(Supplier<Authentication> authentication, MethodInvocation methodInvocation,
List<AuthorizationMethodInterceptor> interceptors) {
this.authentication = authentication;
this.methodInvocation = methodInvocation;
this.interceptors = interceptors;
Object target = methodInvocation.getThis();
this.targetClass = (target != null) ? AopUtils.getTargetClass(target) : null;
this.size = interceptors.size();
}
@Override
public Method getMethod() {
return this.methodInvocation.getMethod();
}
@Override
public Object[] getArguments() {
return this.methodInvocation.getArguments();
}
/**
* Return the target class.
* @return the target class
*/
Class<?> getTargetClass() {
return this.targetClass;
}
@Override
public Object proceed() throws Throwable {
if (this.currentPosition == this.size) {
if (this.logger.isDebugEnabled()) {
this.logger.debug(LogMessage.of(() -> "Pre-Authorized " + this.methodInvocation.getMethod()));
}
return this.methodInvocation.proceed();
}
AuthorizationMethodInterceptor interceptor = this.interceptors.get(this.currentPosition);
this.currentPosition++;
Pointcut pointcut = interceptor.getPointcut();
if (!pointcut.getClassFilter().matches(getTargetClass())) {
return proceed();
}
if (!pointcut.getMethodMatcher().matches(getMethod(), getTargetClass())) {
return proceed();
}
if (this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.format("Applying %s (%d/%d)", interceptor.getClass().getSimpleName(),
this.currentPosition, this.size));
}
Object result = interceptor.invoke(this.authentication, this);
if (this.logger.isDebugEnabled()) {
this.logger.debug(LogMessage.of(() -> "Post-Authorized " + this.methodInvocation.getMethod()));
}
return result;
}
@Override
public Object getThis() {
return this.methodInvocation.getThis();
}
@Override
public AccessibleObject getStaticPart() {
return this.methodInvocation.getStaticPart();
}
}
@@ -1,54 +0,0 @@
/*
* 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.annotation.Annotation;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.ComposablePointcut;
import org.springframework.aop.support.Pointcuts;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
/**
* @author Josh Cummings
*/
final class AuthorizationMethodPointcuts {
@SafeVarargs
static Pointcut forAnnotations(Class<? extends Annotation>... annotations) {
ComposablePointcut pointcut = null;
for (Class<? extends Annotation> annotation : annotations) {
if (pointcut == null) {
pointcut = new ComposablePointcut(classOrMethod(annotation));
}
else {
pointcut.union(classOrMethod(annotation));
}
}
return pointcut;
}
private static Pointcut classOrMethod(Class<? extends Annotation> annotation) {
return Pointcuts.union(new AnnotationMatchingPointcut(null, annotation, true),
new AnnotationMatchingPointcut(annotation, true));
}
private AuthorizationMethodPointcuts() {
}
}
@@ -1,89 +0,0 @@
/*
* 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.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.ComposablePointcut;
import org.springframework.security.core.Authentication;
/**
* Provides security interception of AOP Alliance based method invocations.
*
* Delegates to a collection of {@link AuthorizationMethodInterceptor}s
*
* @author Evgeniy Cheban
* @author Josh Cummings
* @since 5.5
*/
public final class DelegatingAuthorizationMethodInterceptor implements AuthorizationMethodInterceptor {
private final List<AuthorizationMethodInterceptor> interceptors;
private final Pointcut pointcut;
/**
* Creates an instance using the provided parameters
* @param interceptors the delegate {@link AuthorizationMethodInterceptor}s to use
*/
public DelegatingAuthorizationMethodInterceptor(AuthorizationMethodInterceptor... interceptors) {
this(Arrays.asList(interceptors));
}
/**
* Creates an instance using the provided parameters
* @param interceptors the delegate {@link AuthorizationMethodInterceptor}s to use
*/
public DelegatingAuthorizationMethodInterceptor(List<AuthorizationMethodInterceptor> interceptors) {
ComposablePointcut pointcut = null;
for (AuthorizationMethodInterceptor interceptor : interceptors) {
if (pointcut == null) {
pointcut = new ComposablePointcut(interceptor.getPointcut());
}
else {
pointcut.union(interceptor.getPointcut());
}
}
this.pointcut = pointcut;
this.interceptors = interceptors;
}
/**
* Enforce security on this {@link MethodInvocation}.
* @param mi the method being invoked which requires a security decision
* @return the returned value from the {@link MethodInvocation}, possibly altered by
* the configured {@link AuthorizationMethodInterceptor}s
*/
@Override
public Object invoke(Supplier<Authentication> authentication, MethodInvocation mi) throws Throwable {
return new AuthorizationMethodInvocation(authentication, mi, this.interceptors).proceed();
}
/**
* {@inheritDoc}
*/
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
@@ -1,52 +0,0 @@
/*
* 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;
}
}
@@ -1,121 +0,0 @@
/*
* 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.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.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} may
* invoke 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<MethodInvocation> {
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;
}
/**
* Determine if an {@link Authentication} has access to a method by evaluating the
* {@link DenyAll}, {@link PermitAll}, and {@link RolesAllowed} annotations that
* {@link AuthorizationMethodInvocation} specifies.
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param methodInvocation the {@link AuthorizationMethodInvocation} to check
* @return an {@link AuthorizationDecision} or null if the JSR-250 security
* annotations is not present
*/
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation methodInvocation) {
AuthorizationManager<MethodInvocation> delegate = this.registry
.getManager((AuthorizationMethodInvocation) methodInvocation);
return delegate.check(authentication, methodInvocation);
}
private final class Jsr250AuthorizationManagerRegistry extends AbstractAuthorizationManagerRegistry {
@NonNull
@Override
AuthorizationManager<MethodInvocation> 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);
}
}
}
@@ -1,108 +0,0 @@
/*
* 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.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} may
* return the result from an invoked {@link MethodInvocation} by evaluating an expression
* from the {@link PostAuthorize} annotation.
*
* @author Evgeniy Cheban
* @since 5.5
*/
public final class PostAuthorizeAuthorizationManager implements AfterMethodAuthorizationManager<MethodInvocation> {
private final PostAuthorizeExpressionAttributeRegistry registry = new PostAuthorizeExpressionAttributeRegistry();
private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
/**
* Use this 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;
}
/**
* Determine if an {@link Authentication} has access to the returned object by
* evaluating the {@link PostAuthorize} annotation that the
* {@link AuthorizationMethodInvocation} specifies.
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param mi the {@link AuthorizationMethodInvocation} to check
* @param returnedObject the returned object to check
* @return an {@link AuthorizationDecision} or {@code null} if the
* {@link PostAuthorize} annotation is not present
*/
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation mi,
Object returnedObject) {
ExpressionAttribute attribute = this.registry.getAttribute((AuthorizationMethodInvocation) mi);
if (attribute == ExpressionAttribute.NULL_ATTRIBUTE) {
return null;
}
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication.get(), mi);
this.expressionHandler.setReturnObject(returnedObject, 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);
}
}
}
@@ -1,120 +0,0 @@
/*
* 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.Pointcut;
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.lang.NonNull;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
/**
* An {@link AuthorizationMethodInterceptor} which filters a {@code returnedObject} from
* the {@link MethodInvocation} by evaluating an expression from the {@link PostFilter}
* annotation.
*
* @author Evgeniy Cheban
* @author Josh Cummings
* @since 5.5
*/
public final class PostFilterAuthorizationMethodInterceptor implements AuthorizationMethodInterceptor {
private final PostFilterExpressionAttributeRegistry registry = new PostFilterExpressionAttributeRegistry();
private final Pointcut pointcut;
private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
/**
* Creates a {@link PostFilterAuthorizationMethodInterceptor} using the provided
* parameters
*/
public PostFilterAuthorizationMethodInterceptor() {
this.pointcut = AuthorizationMethodPointcuts.forAnnotations(PostFilter.class);
}
/**
* Use this {@link MethodSecurityExpressionHandler}.
* @param expressionHandler the {@link MethodSecurityExpressionHandler} to use
*/
public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) {
Assert.notNull(expressionHandler, "expressionHandler cannot be null");
this.expressionHandler = expressionHandler;
}
/**
* {@inheritDoc}
*/
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
/**
* Filter a {@code returnedObject} using the {@link PostFilter} annotation that the
* {@link AuthorizationMethodInvocation} specifies.
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param mi the {@link AuthorizationMethodInvocation} to check check
* @return filtered {@code returnedObject}
*/
@Override
public Object invoke(Supplier<Authentication> authentication, MethodInvocation mi) throws Throwable {
Object returnedObject = mi.proceed();
ExpressionAttribute attribute = this.registry.getAttribute((AuthorizationMethodInvocation) mi);
if (attribute == ExpressionAttribute.NULL_ATTRIBUTE) {
return returnedObject;
}
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication.get(), mi);
return this.expressionHandler.filter(returnedObject, attribute.getExpression(), ctx);
}
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 = PostFilterAuthorizationMethodInterceptor.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);
}
}
}
@@ -1,105 +0,0 @@
/*
* 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.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} may
* invoke the {@link MethodInvocation} by evaluating an expression from the
* {@link PreAuthorize} annotation.
*
* @author Evgeniy Cheban
* @since 5.5
*/
public final class PreAuthorizeAuthorizationManager implements AuthorizationManager<MethodInvocation> {
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;
}
/**
* Determine if an {@link Authentication} has access to a method by evaluating an
* expression from the {@link PreAuthorize} annotation that the
* {@link AuthorizationMethodInvocation} specifies.
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param mi the {@link AuthorizationMethodInvocation} to check
* @return an {@link AuthorizationDecision} or {@code null} if the
* {@link PreAuthorize} annotation is not present
*/
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation mi) {
ExpressionAttribute attribute = this.registry.getAttribute((AuthorizationMethodInvocation) mi);
if (attribute == ExpressionAttribute.NULL_ATTRIBUTE) {
return null;
}
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication.get(), mi);
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);
}
}
}
@@ -1,153 +0,0 @@
/*
* 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.Pointcut;
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.lang.NonNull;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
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 AuthorizationMethodInterceptor} which filters a method argument by evaluating
* an expression from the {@link PreFilter} annotation.
*
* @author Evgeniy Cheban
* @author Josh Cummings
* @since 5.5
*/
public final class PreFilterAuthorizationMethodInterceptor implements AuthorizationMethodInterceptor {
private final PreFilterExpressionAttributeRegistry registry = new PreFilterExpressionAttributeRegistry();
private final Pointcut pointcut;
private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
/**
* Creates a {@link PreFilterAuthorizationMethodInterceptor} using the provided
* parameters
*/
public PreFilterAuthorizationMethodInterceptor() {
this.pointcut = AuthorizationMethodPointcuts.forAnnotations(PreFilter.class);
}
/**
* Use this {@link MethodSecurityExpressionHandler}
* @param expressionHandler the {@link MethodSecurityExpressionHandler} to use
*/
public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) {
Assert.notNull(expressionHandler, "expressionHandler cannot be null");
this.expressionHandler = expressionHandler;
}
/**
* {@inheritDoc}
*/
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
/**
* Filter the method argument specified in the {@link PreFilter} annotation that
* {@link AuthorizationMethodInvocation} specifies.
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param mi the {@link AuthorizationMethodInvocation} to check
*/
@Override
public Object invoke(Supplier<Authentication> authentication, MethodInvocation mi) throws Throwable {
PreFilterExpressionAttribute attribute = this.registry.getAttribute((AuthorizationMethodInvocation) mi);
if (attribute == PreFilterExpressionAttribute.NULL_ATTRIBUTE) {
return mi.proceed();
}
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication.get(), mi);
Object filterTarget = findFilterTarget(attribute.filterTarget, ctx, mi);
this.expressionHandler.filter(filterTarget, attribute.getExpression(), ctx);
return mi.proceed();
}
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 = PreFilterAuthorizationMethodInterceptor.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;
}
}
}
@@ -1,77 +0,0 @@
/*
* 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.support.AopUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.NonNull;
import org.springframework.security.access.annotation.Secured;
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} may
* invoke 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<MethodInvocation> {
private final SecuredAuthorizationManagerRegistry registry = new SecuredAuthorizationManagerRegistry();
/**
* Determine if an {@link Authentication} has access to a method by evaluating the
* {@link Secured} annotation that {@link AuthorizationMethodInvocation} specifies.
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param mi the {@link AuthorizationMethodInvocation} to check
* @return an {@link AuthorizationDecision} or null if the {@link Secured} annotation
* is not present
*/
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation mi) {
AuthorizationManager<MethodInvocation> delegate = this.registry.getManager((AuthorizationMethodInvocation) mi);
return delegate.check(authentication, mi);
}
private static final class SecuredAuthorizationManagerRegistry extends AbstractAuthorizationManagerRegistry {
@NonNull
@Override
AuthorizationManager<MethodInvocation> 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);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2020 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.
@@ -64,13 +64,6 @@ public class AuthorityAuthorizationManagerTests {
.withMessage("roles cannot contain null values");
}
@Test
public void hasAnyRoleWhenCustomRolePrefixNullThenException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> AuthorityAuthorizationManager.hasAnyRole(null, new String[] { "ADMIN", "USER" }))
.withMessage("rolePrefix cannot be null");
}
@Test
public void hasAnyAuthorityWhenNullThenException() {
assertThatIllegalArgumentException().isThrownBy(() -> AuthorityAuthorizationManager.hasAnyAuthority(null))
@@ -154,17 +147,6 @@ public class AuthorityAuthorizationManagerTests {
assertThat(manager.check(authentication, object).isGranted()).isFalse();
}
@Test
public void hasAnyRoleWhenCustomRolePrefixProvidedThenUseCustomRolePrefix() {
AuthorityAuthorizationManager<Object> manager = AuthorityAuthorizationManager.hasAnyRole("CUSTOM_",
new String[] { "USER" });
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password",
"CUSTOM_USER");
Object object = new Object();
assertThat(manager.check(authentication, object).isGranted()).isTrue();
}
@Test
public void hasAnyAuthorityWhenUserHasAnyAuthorityThenGrantedDecision() {
AuthorityAuthorizationManager<Object> manager = AuthorityAuthorizationManager.hasAnyAuthority("ADMIN", "USER");
@@ -1,72 +0,0 @@
/*
* 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.util.function.Supplier;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import org.springframework.aop.Pointcut;
import org.springframework.security.authentication.TestAuthentication;
import org.springframework.security.core.Authentication;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link AuthorizationManagerAfterMethodInterceptor}.
*
* @author Evgeniy Cheban
*/
public class AuthorizationManagerAfterMethodInterceptorTests {
@Test
public void instantiateWhenMethodMatcherNullThenException() {
AfterMethodAuthorizationManager<MethodInvocation> mockAuthorizationManager = mock(
AfterMethodAuthorizationManager.class);
assertThatIllegalArgumentException()
.isThrownBy(() -> new AuthorizationManagerAfterMethodInterceptor(null, mockAuthorizationManager))
.withMessage("pointcut cannot be null");
}
@Test
public void instantiateWhenAuthorizationManagerNullThenException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new AuthorizationManagerAfterMethodInterceptor(mock(Pointcut.class), null))
.withMessage("authorizationManager cannot be null");
}
@Test
public void beforeWhenMockAuthorizationManagerThenVerifyAndReturnedObject() throws Throwable {
Supplier<Authentication> authentication = TestAuthentication::authenticatedUser;
MethodInvocation mockMethodInvocation = mock(MethodInvocation.class);
Object returnedObject = new Object();
given(mockMethodInvocation.proceed()).willReturn(returnedObject);
AfterMethodAuthorizationManager<MethodInvocation> mockAuthorizationManager = mock(
AfterMethodAuthorizationManager.class);
AuthorizationManagerAfterMethodInterceptor advice = new AuthorizationManagerAfterMethodInterceptor(
Pointcut.TRUE, mockAuthorizationManager);
Object result = advice.invoke(authentication, mockMethodInvocation);
assertThat(result).isEqualTo(returnedObject);
verify(mockAuthorizationManager).verify(authentication, mockMethodInvocation, returnedObject);
}
}
@@ -1,66 +0,0 @@
/*
* 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.util.function.Supplier;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import org.springframework.aop.Pointcut;
import org.springframework.security.authentication.TestAuthentication;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link AuthorizationManagerBeforeMethodInterceptor}.
*
* @author Evgeniy Cheban
*/
public class AuthorizationManagerBeforeMethodInterceptorTests {
@Test
public void instantiateWhenMethodMatcherNullThenException() {
assertThatIllegalArgumentException()
.isThrownBy(
() -> new AuthorizationManagerBeforeMethodInterceptor(null, mock(AuthorizationManager.class)))
.withMessage("pointcut cannot be null");
}
@Test
public void instantiateWhenAuthorizationManagerNullThenException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new AuthorizationManagerBeforeMethodInterceptor(mock(Pointcut.class), null))
.withMessage("authorizationManager cannot be null");
}
@Test
public void beforeWhenMockAuthorizationManagerThenVerify() throws Throwable {
Supplier<Authentication> authentication = TestAuthentication::authenticatedUser;
MethodInvocation mockMethodInvocation = mock(MethodInvocation.class);
AuthorizationManager<MethodInvocation> mockAuthorizationManager = mock(AuthorizationManager.class);
AuthorizationManagerBeforeMethodInterceptor advice = new AuthorizationManagerBeforeMethodInterceptor(
Pointcut.TRUE, mockAuthorizationManager);
advice.invoke(authentication, mockMethodInvocation);
verify(mockAuthorizationManager).verify(authentication, mockMethodInvocation);
}
}
@@ -1,167 +0,0 @@
/*
* 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.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.Test;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AopUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link AuthorizationMethodPointcuts}
*/
public class AuthorizationMethodPointcutsTests {
@Test
public void forAnnotationsWhenAnnotationThenClassBasedAnnotationPointcut() {
Pointcut preAuthorize = AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class);
assertThat(AopUtils.canApply(preAuthorize, ClassController.class)).isTrue();
assertThat(AopUtils.canApply(preAuthorize, NoController.class)).isFalse();
}
@Test
public void forAnnotationsWhenAnnotationThenMethodBasedAnnotationPointcut() {
Pointcut preAuthorize = AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class);
assertThat(AopUtils.canApply(preAuthorize, MethodController.class)).isTrue();
}
@Test
public void forAnnotationsWhenAnnotationThenClassInheritancePointcut() {
Pointcut preAuthorize = AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class);
assertThat(AopUtils.canApply(preAuthorize, InterfacedClassController.class)).isTrue();
}
@Test
public void forAnnotationsWhenAnnotationThenMethodInheritancePointcut() {
Pointcut preAuthorize = AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class);
assertThat(AopUtils.canApply(preAuthorize, InterfacedMethodController.class)).isTrue();
}
@Test
public void forAnnotationsWhenAnnotationThenAnnotationClassInheritancePointcut() {
Pointcut preAuthorize = AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class);
assertThat(AopUtils.canApply(preAuthorize, InterfacedAnnotationClassController.class)).isTrue();
}
@Test
public void forAnnotationsWhenAnnotationThenAnnotationMethodInheritancePointcut() {
Pointcut preAuthorize = AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class);
assertThat(AopUtils.canApply(preAuthorize, InterfacedAnnotationMethodController.class)).isTrue();
}
@PreAuthorize("hasAuthority('APP')")
public static class ClassController {
String methodOne(String paramOne) {
return "value";
}
}
public static class MethodController {
@PreAuthorize("hasAuthority('APP')")
String methodOne(String paramOne) {
return "value";
}
}
public static class NoController {
String methodOne(String paramOne) {
return "value";
}
}
@PreAuthorize("hasAuthority('APP')")
public interface ClassControllerInterface {
String methodOne(String paramOne);
}
public static class InterfacedClassController implements ClassControllerInterface {
public String methodOne(String paramOne) {
return "value";
}
}
public interface MethodControllerInterface {
@PreAuthorize("hasAuthority('APP')")
String methodOne(String paramOne);
}
public static class InterfacedMethodController implements MethodControllerInterface {
public String methodOne(String paramOne) {
return "value";
}
}
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("hasAuthority('APP')")
@interface MyAnnotation {
}
@MyAnnotation
public interface ClassAnnotationControllerInterface {
String methodOne(String paramOne);
}
public static class InterfacedAnnotationClassController implements ClassAnnotationControllerInterface {
public String methodOne(String paramOne) {
return "value";
}
}
public interface MethodAnnotationControllerInterface {
@MyAnnotation
String methodOne(String paramOne);
}
public static class InterfacedAnnotationMethodController implements MethodAnnotationControllerInterface {
public String methodOne(String paramOne) {
return "value";
}
}
}
@@ -1,103 +0,0 @@
/*
* 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.util.Arrays;
import java.util.function.Supplier;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.After;
import org.junit.Test;
import org.springframework.aop.Pointcut;
import org.springframework.security.access.intercept.method.MockMethodInvocation;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.TestAuthentication;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link DelegatingAuthorizationMethodInterceptor}.
*
* @author Evgeniy Cheban
*/
public class DelegatingAuthorizationMethodInterceptorTests {
@After
public void tearDown() {
SecurityContextHolder.clearContext();
}
@Test
public void invokeWhenAuthenticatedThenVerifyAdvicesUsage() throws Throwable {
Authentication authentication = TestAuthentication.authenticatedUser();
SecurityContextHolder.setContext(new SecurityContextImpl(authentication));
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingString");
AuthorizationMethodInterceptor interceptor = mock(AuthorizationMethodInterceptor.class);
given(interceptor.getPointcut()).willReturn(Pointcut.TRUE);
given(interceptor.invoke(any(), any(AuthorizationMethodInvocation.class))).willReturn("abc");
DelegatingAuthorizationMethodInterceptor chain = new DelegatingAuthorizationMethodInterceptor(
Arrays.asList(interceptor));
Object result = chain.invoke(mockMethodInvocation);
assertThat(result).isEqualTo("abc");
verify(interceptor).invoke(any(), any(AuthorizationMethodInvocation.class));
}
@Test
public void invokeWhenNotAuthenticatedThenAuthenticationCredentialsNotFoundException() throws Throwable {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingString");
AuthorizationMethodInterceptor first = new AuthorizationMethodInterceptor() {
@Override
public Pointcut getPointcut() {
return Pointcut.TRUE;
}
@Override
public Object invoke(Supplier<Authentication> authentication, MethodInvocation mi) {
return authentication.get();
}
};
AuthorizationMethodInterceptor second = mock(AuthorizationMethodInterceptor.class);
given(second.getPointcut()).willReturn(Pointcut.TRUE);
DelegatingAuthorizationMethodInterceptor interceptor = new DelegatingAuthorizationMethodInterceptor(
Arrays.asList(first, second));
assertThatExceptionOfType(AuthenticationCredentialsNotFoundException.class)
.isThrownBy(() -> interceptor.invoke(mockMethodInvocation))
.withMessage("An Authentication object was not found in the SecurityContext");
verify(second, times(0)).invoke(any(), any());
}
public static class TestClass {
public String doSomethingString() {
return null;
}
}
}
@@ -1,162 +0,0 @@
/*
* 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.util.Collections;
import java.util.function.Supplier;
import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import org.junit.Test;
import org.springframework.security.access.intercept.method.MockMethodInvocation;
import org.springframework.security.authentication.TestAuthentication;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.core.Authentication;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link Jsr250AuthorizationManager}.
*
* @author Evgeniy Cheban
*/
public class Jsr250AuthorizationManagerTests {
@Test
public void rolePrefixWhenNotSetThenDefaultsToRole() {
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
assertThat(manager).extracting("rolePrefix").isEqualTo("ROLE_");
}
@Test
public void setRolePrefixWhenNullThenException() {
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
assertThatIllegalArgumentException().isThrownBy(() -> manager.setRolePrefix(null))
.withMessage("rolePrefix cannot be null");
}
@Test
public void setRolePrefixWhenNotNullThenSets() {
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
manager.setRolePrefix("CUSTOM_");
assertThat(manager).extracting("rolePrefix").isEqualTo("CUSTOM_");
}
@Test
public void checkDoSomethingWhenNoJsr250AnnotationsThenNullDecision() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomething");
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
assertThat(decision).isNull();
}
@Test
public void checkPermitAllRolesAllowedAdminWhenRoleUserThenGrantedDecision() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"permitAllRolesAllowedAdmin");
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
assertThat(decision).isNotNull();
assertThat(decision.isGranted()).isTrue();
}
@Test
public void checkDenyAllRolesAllowedAdminWhenRoleAdminThenDeniedDecision() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"denyAllRolesAllowedAdmin");
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedAdmin, methodInvocation);
assertThat(decision).isNotNull();
assertThat(decision.isGranted()).isFalse();
}
@Test
public void checkRolesAllowedUserOrAdminWhenRoleUserThenGrantedDecision() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"rolesAllowedUserOrAdmin");
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
assertThat(decision).isNotNull();
assertThat(decision.isGranted()).isTrue();
}
@Test
public void checkRolesAllowedUserOrAdminWhenRoleAdminThenGrantedDecision() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"rolesAllowedUserOrAdmin");
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedAdmin, methodInvocation);
assertThat(decision).isNotNull();
assertThat(decision.isGranted()).isTrue();
}
@Test
public void checkRolesAllowedUserOrAdminWhenRoleAnonymousThenDeniedDecision() throws Exception {
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password",
"ROLE_ANONYMOUS");
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"rolesAllowedUserOrAdmin");
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
AuthorizationDecision decision = manager.check(authentication, methodInvocation);
assertThat(decision).isNotNull();
assertThat(decision.isGranted()).isFalse();
}
public static class TestClass {
public void doSomething() {
}
@DenyAll
@RolesAllowed("ADMIN")
public void denyAllRolesAllowedAdmin() {
}
@PermitAll
@RolesAllowed("ADMIN")
public void permitAllRolesAllowedAdmin() {
}
@RolesAllowed({ "USER", "ADMIN" })
public void rolesAllowedUserOrAdmin() {
}
}
}
@@ -1,136 +0,0 @@
/*
* 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.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.access.intercept.method.MockMethodInvocation;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.authentication.TestAuthentication;
import org.springframework.security.authorization.AuthorizationDecision;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link PostAuthorizeAuthorizationManager}.
*
* @author Evgeniy Cheban
*/
public class PostAuthorizeAuthorizationManagerTests {
@Test
public void setExpressionHandlerWhenNotNullThenSetsExpressionHandler() {
MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
manager.setExpressionHandler(expressionHandler);
assertThat(manager).extracting("expressionHandler").isEqualTo(expressionHandler);
}
@Test
public void setExpressionHandlerWhenNullThenException() {
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
assertThatIllegalArgumentException().isThrownBy(() -> manager.setExpressionHandler(null))
.withMessage("expressionHandler cannot be null");
}
@Test
public void checkDoSomethingWhenNoPostAuthorizeAnnotationThenNullDecision() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomething", new Class[] {}, new Object[] {});
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation, null);
assertThat(decision).isNull();
}
@Test
public void checkDoSomethingStringWhenArgIsGrantThenGrantedDecision() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingString", new Class[] { String.class }, new Object[] { "grant" });
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation, null);
assertThat(decision).isNotNull();
assertThat(decision.isGranted()).isTrue();
}
@Test
public void checkDoSomethingStringWhenArgIsNotGrantThenDeniedDecision() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingString", new Class[] { String.class }, new Object[] { "deny" });
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation, null);
assertThat(decision).isNotNull();
assertThat(decision.isGranted()).isFalse();
}
@Test
public void checkDoSomethingListWhenReturnObjectContainsGrantThenGrantedDecision() throws Exception {
List<String> list = Arrays.asList("grant", "deny");
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingList", new Class[] { List.class }, new Object[] { list });
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation, list);
assertThat(decision).isNotNull();
assertThat(decision.isGranted()).isTrue();
}
@Test
public void checkDoSomethingListWhenReturnObjectNotContainsGrantThenDeniedDecision() throws Exception {
List<String> list = Collections.singletonList("deny");
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingList", new Class[] { List.class }, new Object[] { list });
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation, list);
assertThat(decision).isNotNull();
assertThat(decision.isGranted()).isFalse();
}
public static class TestClass {
public void doSomething() {
}
@PostAuthorize("#s == 'grant'")
public String doSomethingString(String s) {
return s;
}
@PostAuthorize("returnObject.contains('grant')")
public List<String> doSomethingList(List<String> list) {
return list;
}
}
}
@@ -1,112 +0,0 @@
/*
* 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.util.Collections;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.Test;
import org.springframework.aop.MethodMatcher;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.access.intercept.method.MockMethodInvocation;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.authentication.TestAuthentication;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link PostFilterAuthorizationMethodInterceptor}.
*
* @author Evgeniy Cheban
*/
public class PostFilterAuthorizationMethodInterceptorTests {
@Test
public void setExpressionHandlerWhenNotNullThenSetsExpressionHandler() {
MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
advice.setExpressionHandler(expressionHandler);
assertThat(advice).extracting("expressionHandler").isEqualTo(expressionHandler);
}
@Test
public void setExpressionHandlerWhenNullThenException() {
PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
assertThatIllegalArgumentException().isThrownBy(() -> advice.setExpressionHandler(null))
.withMessage("expressionHandler cannot be null");
}
@Test
public void methodMatcherWhenMethodHasNotPostFilterAnnotationThenNotMatches() throws Exception {
PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
MethodMatcher methodMatcher = advice.getPointcut().getMethodMatcher();
assertThat(methodMatcher.matches(NoPostFilterClass.class.getMethod("doSomething"), NoPostFilterClass.class))
.isFalse();
}
@Test
public void methodMatcherWhenMethodHasPostFilterAnnotationThenMatches() throws Exception {
PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
MethodMatcher methodMatcher = advice.getPointcut().getMethodMatcher();
assertThat(
methodMatcher.matches(TestClass.class.getMethod("doSomethingArray", String[].class), TestClass.class))
.isTrue();
}
@Test
public void afterWhenArrayNotNullThenFilteredArray() throws Throwable {
String[] array = { "john", "bob" };
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingArrayClassLevel", new Class[] { String[].class }, new Object[] { array }) {
@Override
public Object proceed() {
return array;
}
};
PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
Object result = advice.invoke(TestAuthentication::authenticatedUser, methodInvocation);
assertThat(result).asInstanceOf(InstanceOfAssertFactories.array(String[].class)).containsOnly("john");
}
@PostFilter("filterObject == 'john'")
public static class TestClass {
@PostFilter("filterObject == 'john'")
public String[] doSomethingArray(String[] array) {
return array;
}
public String[] doSomethingArrayClassLevel(String[] array) {
return array;
}
}
public static class NoPostFilterClass {
public void doSomething() {
}
}
}
@@ -1,103 +0,0 @@
/*
* 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.util.Collections;
import org.junit.Test;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.access.intercept.method.MockMethodInvocation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.TestAuthentication;
import org.springframework.security.authorization.AuthorizationDecision;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link PreAuthorizeAuthorizationManager}.
*
* @author Evgeniy Cheban
*/
public class PreAuthorizeAuthorizationManagerTests {
@Test
public void setExpressionHandlerWhenNotNullThenSetsExpressionHandler() {
MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
manager.setExpressionHandler(expressionHandler);
assertThat(manager).extracting("expressionHandler").isEqualTo(expressionHandler);
}
@Test
public void setExpressionHandlerWhenNullThenException() {
PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
assertThatIllegalArgumentException().isThrownBy(() -> manager.setExpressionHandler(null))
.withMessage("expressionHandler cannot be null");
}
@Test
public void checkDoSomethingWhenNoPostAuthorizeAnnotationThenNullDecision() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomething", new Class[] {}, new Object[] {});
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
assertThat(decision).isNull();
}
@Test
public void checkDoSomethingStringWhenArgIsGrantThenGrantedDecision() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingString", new Class[] { String.class }, new Object[] { "grant" });
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
assertThat(decision).isNotNull();
assertThat(decision.isGranted()).isTrue();
}
@Test
public void checkDoSomethingStringWhenArgIsNotGrantThenDeniedDecision() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingString", new Class[] { String.class }, new Object[] { "deny" });
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
assertThat(decision).isNotNull();
assertThat(decision.isGranted()).isFalse();
}
public static class TestClass {
public void doSomething() {
}
@PreAuthorize("#s == 'grant'")
public String doSomethingString(String s) {
return s;
}
}
}
@@ -1,203 +0,0 @@
/*
* 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.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import org.springframework.aop.MethodMatcher;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.access.intercept.method.MockMethodInvocation;
import org.springframework.security.access.prepost.PreFilter;
import org.springframework.security.authentication.TestAuthentication;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
* Tests for {@link PreFilterAuthorizationMethodInterceptor}.
*
* @author Evgeniy Cheban
*/
public class PreFilterAuthorizationMethodInterceptorTests {
@Test
public void setExpressionHandlerWhenNotNullThenSetsExpressionHandler() {
MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
advice.setExpressionHandler(expressionHandler);
assertThat(advice).extracting("expressionHandler").isEqualTo(expressionHandler);
}
@Test
public void setExpressionHandlerWhenNullThenException() {
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
assertThatIllegalArgumentException().isThrownBy(() -> advice.setExpressionHandler(null))
.withMessage("expressionHandler cannot be null");
}
@Test
public void methodMatcherWhenMethodHasNotPreFilterAnnotationThenNotMatches() throws Exception {
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
MethodMatcher methodMatcher = advice.getPointcut().getMethodMatcher();
assertThat(methodMatcher.matches(NoPreFilterClass.class.getMethod("doSomething"), NoPreFilterClass.class))
.isFalse();
}
@Test
public void methodMatcherWhenMethodHasPreFilterAnnotationThenMatches() throws Exception {
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
MethodMatcher methodMatcher = advice.getPointcut().getMethodMatcher();
assertThat(methodMatcher.matches(TestClass.class.getMethod("doSomethingListFilterTargetMatch", List.class),
TestClass.class)).isTrue();
}
@Test
public void findFilterTargetWhenNameProvidedAndNotMatchThenException() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingListFilterTargetNotMatch", new Class[] { List.class }, new Object[] { new ArrayList<>() });
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
assertThatIllegalArgumentException()
.isThrownBy(() -> advice.invoke(TestAuthentication::authenticatedUser, methodInvocation)).withMessage(
"Filter target was null, or no argument with name 'filterTargetNotMatch' found in method.");
}
@Test
public void findFilterTargetWhenNameProvidedAndMatchAndNullThenException() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingListFilterTargetMatch", new Class[] { List.class }, new Object[] { null });
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
assertThatIllegalArgumentException()
.isThrownBy(() -> advice.invoke(TestAuthentication::authenticatedUser, methodInvocation))
.withMessage("Filter target was null, or no argument with name 'list' found in method.");
}
@Test
public void findFilterTargetWhenNameProvidedAndMatchAndNotNullThenFiltersList() throws Throwable {
List<String> list = new ArrayList<>();
list.add("john");
list.add("bob");
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingListFilterTargetMatch", new Class[] { List.class }, new Object[] { list });
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
advice.invoke(TestAuthentication::authenticatedUser, methodInvocation);
assertThat(list).hasSize(1);
assertThat(list.get(0)).isEqualTo("john");
}
@Test
public void findFilterTargetWhenNameNotProvidedAndSingleArgListNullThenException() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingListFilterTargetNotProvided", new Class[] { List.class }, new Object[] { null });
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
assertThatIllegalArgumentException()
.isThrownBy(() -> advice.invoke(TestAuthentication::authenticatedUser, methodInvocation))
.withMessage("Filter target was null. Make sure you passing the correct value in the method argument.");
}
@Test
public void findFilterTargetWhenNameNotProvidedAndSingleArgListThenFiltersList() throws Throwable {
List<String> list = new ArrayList<>();
list.add("john");
list.add("bob");
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingListFilterTargetNotProvided", new Class[] { List.class }, new Object[] { list });
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
advice.invoke(TestAuthentication::authenticatedUser, methodInvocation);
assertThat(list).hasSize(1);
assertThat(list.get(0)).isEqualTo("john");
}
@Test
public void findFilterTargetWhenNameNotProvidedAndSingleArgArrayThenException() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingArrayFilterTargetNotProvided", new Class[] { String[].class },
new Object[] { new String[] {} });
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
assertThatIllegalStateException()
.isThrownBy(() -> advice.invoke(TestAuthentication::authenticatedUser, methodInvocation)).withMessage(
"Pre-filtering on array types is not supported. Using a Collection will solve this problem.");
}
@Test
public void findFilterTargetWhenNameNotProvidedAndNotSingleArgThenException() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingTwoArgsFilterTargetNotProvided", new Class[] { String.class, List.class },
new Object[] { "", new ArrayList<>() });
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
assertThatIllegalStateException()
.isThrownBy(() -> advice.invoke(TestAuthentication::authenticatedUser, methodInvocation))
.withMessage("Unable to determine the method argument for filtering. Specify the filter target.");
}
@PreFilter("filterObject == 'john'")
public static class TestClass {
@PreFilter(value = "filterObject == 'john'", filterTarget = "filterTargetNotMatch")
public List<String> doSomethingListFilterTargetNotMatch(List<String> list) {
return list;
}
@PreFilter(value = "filterObject == 'john'", filterTarget = "list")
public List<String> doSomethingListFilterTargetMatch(List<String> list) {
return list;
}
@PreFilter("filterObject == 'john'")
public List<String> doSomethingListFilterTargetNotProvided(List<String> list) {
return list;
}
@PreFilter("filterObject == 'john'")
public String[] doSomethingArrayFilterTargetNotProvided(String[] array) {
return array;
}
public List<String> doSomethingTwoArgsFilterTargetNotProvided(String s, List<String> list) {
return list;
}
}
public static class NoPreFilterClass {
public void doSomething() {
}
}
}
@@ -1,102 +0,0 @@
/*
* 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.util.Collections;
import java.util.function.Supplier;
import org.junit.Test;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.intercept.method.MockMethodInvocation;
import org.springframework.security.authentication.TestAuthentication;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.core.Authentication;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link SecuredAuthorizationManager}.
*
* @author Evgeniy Cheban
*/
public class SecuredAuthorizationManagerTests {
@Test
public void checkDoSomethingWhenNoSecuredAnnotationThenNullDecision() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomething");
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
assertThat(decision).isNull();
}
@Test
public void checkSecuredUserOrAdminWhenRoleUserThenGrantedDecision() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"securedUserOrAdmin");
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
assertThat(decision).isNotNull();
assertThat(decision.isGranted()).isTrue();
}
@Test
public void checkSecuredUserOrAdminWhenRoleAdminThenGrantedDecision() throws Exception {
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"securedUserOrAdmin");
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
TestAuthentication::authenticatedAdmin, mockMethodInvocation, Collections.emptyList());
SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedAdmin, methodInvocation);
assertThat(decision).isNotNull();
assertThat(decision.isGranted()).isTrue();
}
@Test
public void checkSecuredUserOrAdminWhenRoleAnonymousThenDeniedDecision() throws Exception {
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password",
"ROLE_ANONYMOUS");
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"securedUserOrAdmin");
AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(authentication,
mockMethodInvocation, Collections.emptyList());
SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
AuthorizationDecision decision = manager.check(authentication, methodInvocation);
assertThat(decision).isNotNull();
assertThat(decision.isGranted()).isFalse();
}
public static class TestClass {
public void doSomething() {
}
@Secured({ "ROLE_USER", "ROLE_ADMIN" })
public void securedUserOrAdmin() {
}
}
}