mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-10-30 22:28:46 +00:00 
			
		
		
		
	Add Value-Type Ignore Support
Issue gh-14597
This commit is contained in:
		
							parent
							
								
									b60e037005
								
							
						
					
					
						commit
						795e44d11f
					
				| @ -30,16 +30,19 @@ import org.springframework.context.annotation.Role; | ||||
| import org.springframework.security.authorization.AuthorizationAdvisorProxyFactory; | ||||
| import org.springframework.security.authorization.method.AuthorizationAdvisor; | ||||
| import org.springframework.security.authorization.method.AuthorizeReturnObjectMethodInterceptor; | ||||
| import org.springframework.security.config.Customizer; | ||||
| 
 | ||||
| @Configuration(proxyBeanMethods = false) | ||||
| final class AuthorizationProxyConfiguration implements AopInfrastructureBean { | ||||
| 
 | ||||
| 	@Bean | ||||
| 	@Role(BeanDefinition.ROLE_INFRASTRUCTURE) | ||||
| 	static AuthorizationAdvisorProxyFactory authorizationProxyFactory(ObjectProvider<AuthorizationAdvisor> provider) { | ||||
| 	static AuthorizationAdvisorProxyFactory authorizationProxyFactory(ObjectProvider<AuthorizationAdvisor> provider, | ||||
| 			ObjectProvider<Customizer<AuthorizationAdvisorProxyFactory>> customizers) { | ||||
| 		List<AuthorizationAdvisor> advisors = new ArrayList<>(); | ||||
| 		provider.forEach(advisors::add); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		customizers.forEach((c) -> c.customize(factory)); | ||||
| 		factory.setAdvisors(advisors); | ||||
| 		return factory; | ||||
| 	} | ||||
|  | ||||
| @ -27,20 +27,22 @@ import org.springframework.beans.factory.config.BeanDefinition; | ||||
| import org.springframework.context.annotation.Bean; | ||||
| import org.springframework.context.annotation.Configuration; | ||||
| import org.springframework.context.annotation.Role; | ||||
| import org.springframework.security.authorization.ReactiveAuthorizationAdvisorProxyFactory; | ||||
| import org.springframework.security.authorization.AuthorizationAdvisorProxyFactory; | ||||
| import org.springframework.security.authorization.method.AuthorizationAdvisor; | ||||
| import org.springframework.security.authorization.method.AuthorizeReturnObjectMethodInterceptor; | ||||
| import org.springframework.security.config.Customizer; | ||||
| 
 | ||||
| @Configuration(proxyBeanMethods = false) | ||||
| final class ReactiveAuthorizationProxyConfiguration implements AopInfrastructureBean { | ||||
| 
 | ||||
| 	@Bean | ||||
| 	@Role(BeanDefinition.ROLE_INFRASTRUCTURE) | ||||
| 	static ReactiveAuthorizationAdvisorProxyFactory authorizationProxyFactory( | ||||
| 			ObjectProvider<AuthorizationAdvisor> provider) { | ||||
| 	static AuthorizationAdvisorProxyFactory authorizationProxyFactory(ObjectProvider<AuthorizationAdvisor> provider, | ||||
| 			ObjectProvider<Customizer<AuthorizationAdvisorProxyFactory>> customizers) { | ||||
| 		List<AuthorizationAdvisor> advisors = new ArrayList<>(); | ||||
| 		provider.forEach(advisors::add); | ||||
| 		ReactiveAuthorizationAdvisorProxyFactory factory = new ReactiveAuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withReactiveDefaults(); | ||||
| 		customizers.forEach((c) -> c.customize(factory)); | ||||
| 		factory.setAdvisors(advisors); | ||||
| 		return factory; | ||||
| 	} | ||||
| @ -48,7 +50,7 @@ final class ReactiveAuthorizationProxyConfiguration implements AopInfrastructure | ||||
| 	@Bean | ||||
| 	@Role(BeanDefinition.ROLE_INFRASTRUCTURE) | ||||
| 	static MethodInterceptor authorizeReturnObjectMethodInterceptor(ObjectProvider<AuthorizationAdvisor> provider, | ||||
| 			ReactiveAuthorizationAdvisorProxyFactory authorizationProxyFactory) { | ||||
| 			AuthorizationAdvisorProxyFactory authorizationProxyFactory) { | ||||
| 		AuthorizeReturnObjectMethodInterceptor interceptor = new AuthorizeReturnObjectMethodInterceptor( | ||||
| 				authorizationProxyFactory); | ||||
| 		List<AuthorizationAdvisor> advisors = new ArrayList<>(); | ||||
|  | ||||
| @ -58,6 +58,8 @@ import org.springframework.security.access.prepost.PostAuthorize; | ||||
| import org.springframework.security.access.prepost.PostFilter; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.security.access.prepost.PreFilter; | ||||
| import org.springframework.security.authorization.AuthorizationAdvisorProxyFactory; | ||||
| import org.springframework.security.authorization.AuthorizationAdvisorProxyFactory.TargetVisitor; | ||||
| import org.springframework.security.authorization.AuthorizationDecision; | ||||
| import org.springframework.security.authorization.AuthorizationEventPublisher; | ||||
| import org.springframework.security.authorization.AuthorizationManager; | ||||
| @ -66,6 +68,7 @@ import org.springframework.security.authorization.method.AuthorizationManagerBef | ||||
| import org.springframework.security.authorization.method.AuthorizeReturnObject; | ||||
| import org.springframework.security.authorization.method.MethodInvocationResult; | ||||
| import org.springframework.security.authorization.method.PrePostTemplateDefaults; | ||||
| import org.springframework.security.config.Customizer; | ||||
| import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig; | ||||
| import org.springframework.security.config.core.GrantedAuthorityDefaults; | ||||
| import org.springframework.security.config.test.SpringTestContext; | ||||
| @ -1143,6 +1146,12 @@ public class PrePostMethodSecurityConfigurationTests { | ||||
| 	@Configuration | ||||
| 	static class AuthorizeResultConfig { | ||||
| 
 | ||||
| 		@Bean | ||||
| 		@Role(BeanDefinition.ROLE_INFRASTRUCTURE) | ||||
| 		static Customizer<AuthorizationAdvisorProxyFactory> skipValueTypes() { | ||||
| 			return (f) -> f.setTargetVisitor(TargetVisitor.defaultsSkipValueTypes()); | ||||
| 		} | ||||
| 
 | ||||
| 		@Bean | ||||
| 		FlightRepository flights() { | ||||
| 			FlightRepository flights = new FlightRepository(); | ||||
| @ -1186,6 +1195,7 @@ public class PrePostMethodSecurityConfigurationTests { | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	@AuthorizeReturnObject | ||||
| 	static class Flight { | ||||
| 
 | ||||
| 		private final String id; | ||||
| @ -1216,7 +1226,6 @@ public class PrePostMethodSecurityConfigurationTests { | ||||
| 			return this.seats; | ||||
| 		} | ||||
| 
 | ||||
| 		@AuthorizeReturnObject | ||||
| 		@PostAuthorize("hasAuthority('seating:read')") | ||||
| 		@PostFilter("filterObject.name != 'Kevin Mitnick'") | ||||
| 		List<Passenger> getPassengers() { | ||||
|  | ||||
| @ -30,8 +30,10 @@ import reactor.core.publisher.Mono; | ||||
| import reactor.test.StepVerifier; | ||||
| 
 | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.beans.factory.config.BeanDefinition; | ||||
| import org.springframework.context.annotation.Bean; | ||||
| import org.springframework.context.annotation.Configuration; | ||||
| import org.springframework.context.annotation.Role; | ||||
| import org.springframework.expression.EvaluationContext; | ||||
| import org.springframework.security.access.AccessDeniedException; | ||||
| import org.springframework.security.access.expression.SecurityExpressionRoot; | ||||
| @ -42,7 +44,10 @@ import org.springframework.security.access.prepost.PostFilter; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.security.access.prepost.PreFilter; | ||||
| import org.springframework.security.authentication.TestAuthentication; | ||||
| import org.springframework.security.authorization.AuthorizationAdvisorProxyFactory; | ||||
| import org.springframework.security.authorization.AuthorizationAdvisorProxyFactory.TargetVisitor; | ||||
| import org.springframework.security.authorization.method.AuthorizeReturnObject; | ||||
| import org.springframework.security.config.Customizer; | ||||
| import org.springframework.security.config.core.GrantedAuthorityDefaults; | ||||
| import org.springframework.security.config.test.SpringTestContext; | ||||
| import org.springframework.security.config.test.SpringTestContextExtension; | ||||
| @ -238,6 +243,12 @@ public class ReactiveMethodSecurityConfigurationTests { | ||||
| 	@Configuration | ||||
| 	static class AuthorizeResultConfig { | ||||
| 
 | ||||
| 		@Bean | ||||
| 		@Role(BeanDefinition.ROLE_INFRASTRUCTURE) | ||||
| 		static Customizer<AuthorizationAdvisorProxyFactory> skipValueTypes() { | ||||
| 			return (factory) -> factory.setTargetVisitor(TargetVisitor.defaultsSkipValueTypes()); | ||||
| 		} | ||||
| 
 | ||||
| 		@Bean | ||||
| 		FlightRepository flights() { | ||||
| 			FlightRepository flights = new FlightRepository(); | ||||
| @ -282,6 +293,7 @@ public class ReactiveMethodSecurityConfigurationTests { | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	@AuthorizeReturnObject | ||||
| 	static class Flight { | ||||
| 
 | ||||
| 		private final String id; | ||||
| @ -312,7 +324,6 @@ public class ReactiveMethodSecurityConfigurationTests { | ||||
| 			return Mono.just(this.seats); | ||||
| 		} | ||||
| 
 | ||||
| 		@AuthorizeReturnObject | ||||
| 		@PostAuthorize("hasAnyAuthority('seating:read', 'airplane:read')") | ||||
| 		@PostFilter("@isNotKevin.apply(filterObject)") | ||||
| 		Flux<Passenger> getPassengers() { | ||||
|  | ||||
| @ -34,17 +34,28 @@ import java.util.SortedMap; | ||||
| import java.util.SortedSet; | ||||
| import java.util.TreeMap; | ||||
| import java.util.TreeSet; | ||||
| import java.util.function.Supplier; | ||||
| import java.util.stream.Stream; | ||||
| 
 | ||||
| import reactor.core.publisher.Flux; | ||||
| import reactor.core.publisher.Mono; | ||||
| 
 | ||||
| import org.springframework.aop.Advisor; | ||||
| import org.springframework.aop.framework.ProxyFactory; | ||||
| import org.springframework.core.annotation.AnnotationAwareOrderComparator; | ||||
| import org.springframework.lang.NonNull; | ||||
| import org.springframework.security.authorization.method.AuthorizationAdvisor; | ||||
| import org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor; | ||||
| import org.springframework.security.authorization.method.AuthorizationManagerAfterReactiveMethodInterceptor; | ||||
| import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor; | ||||
| import org.springframework.security.authorization.method.AuthorizationManagerBeforeReactiveMethodInterceptor; | ||||
| import org.springframework.security.authorization.method.AuthorizeReturnObject; | ||||
| import org.springframework.security.authorization.method.AuthorizeReturnObjectMethodInterceptor; | ||||
| import org.springframework.security.authorization.method.PostFilterAuthorizationMethodInterceptor; | ||||
| import org.springframework.security.authorization.method.PostFilterAuthorizationReactiveMethodInterceptor; | ||||
| import org.springframework.security.authorization.method.PreFilterAuthorizationMethodInterceptor; | ||||
| import org.springframework.security.authorization.method.PreFilterAuthorizationReactiveMethodInterceptor; | ||||
| import org.springframework.util.Assert; | ||||
| import org.springframework.util.ClassUtils; | ||||
| 
 | ||||
| /** | ||||
| @ -63,8 +74,7 @@ import org.springframework.util.ClassUtils; | ||||
|  * like so: | ||||
|  * | ||||
|  * <pre> | ||||
|  *     AuthorizationManagerBeforeMethodInterceptor preAuthorize = AuthorizationManagerBeforeMethodInterceptor.preAuthorize(); | ||||
|  *     AuthorizationProxyFactory proxyFactory = new AuthorizationProxyFactory(preAuthorize); | ||||
|  *     AuthorizationProxyFactory proxyFactory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
|  *     Foo foo = new Foo(); | ||||
|  *     foo.bar(); // passes | ||||
|  *     Foo securedFoo = proxyFactory.proxy(foo); | ||||
| @ -74,18 +84,56 @@ import org.springframework.util.ClassUtils; | ||||
|  * @author Josh Cummings | ||||
|  * @since 6.3 | ||||
|  */ | ||||
| public final class AuthorizationAdvisorProxyFactory implements AuthorizationProxyFactory { | ||||
| public final class AuthorizationAdvisorProxyFactory | ||||
| 		implements AuthorizationProxyFactory, Iterable<AuthorizationAdvisor> { | ||||
| 
 | ||||
| 	private List<AuthorizationAdvisor> advisors = new ArrayList<>(); | ||||
| 	private static final boolean isReactivePresent = ClassUtils.isPresent("reactor.core.publisher.Mono", null); | ||||
| 
 | ||||
| 	public AuthorizationAdvisorProxyFactory() { | ||||
| 	private static final TargetVisitor DEFAULT_VISITOR = isReactivePresent | ||||
| 			? TargetVisitor.of(new ClassVisitor(), new ReactiveTypeVisitor(), new ContainerTypeVisitor()) | ||||
| 			: TargetVisitor.of(new ClassVisitor(), new ContainerTypeVisitor()); | ||||
| 
 | ||||
| 	private static final TargetVisitor DEFAULT_VISITOR_SKIP_VALUE_TYPES = TargetVisitor.of(new ClassVisitor(), | ||||
| 			new IgnoreValueTypeVisitor(), DEFAULT_VISITOR); | ||||
| 
 | ||||
| 	private List<AuthorizationAdvisor> advisors; | ||||
| 
 | ||||
| 	private TargetVisitor visitor = DEFAULT_VISITOR; | ||||
| 
 | ||||
| 	private AuthorizationAdvisorProxyFactory(List<AuthorizationAdvisor> advisors) { | ||||
| 		this.advisors = new ArrayList<>(advisors); | ||||
| 		this.advisors.add(new AuthorizeReturnObjectMethodInterceptor(this)); | ||||
| 		setAdvisors(this.advisors); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Construct an {@link AuthorizationAdvisorProxyFactory} with the defaults needed for | ||||
| 	 * wrapping objects in Spring Security's pre-post method security support. | ||||
| 	 * @return an {@link AuthorizationAdvisorProxyFactory} for adding pre-post method | ||||
| 	 * security support | ||||
| 	 */ | ||||
| 	public static AuthorizationAdvisorProxyFactory withDefaults() { | ||||
| 		List<AuthorizationAdvisor> advisors = new ArrayList<>(); | ||||
| 		advisors.add(AuthorizationManagerBeforeMethodInterceptor.preAuthorize()); | ||||
| 		advisors.add(AuthorizationManagerAfterMethodInterceptor.postAuthorize()); | ||||
| 		advisors.add(new PreFilterAuthorizationMethodInterceptor()); | ||||
| 		advisors.add(new PostFilterAuthorizationMethodInterceptor()); | ||||
| 		advisors.add(new AuthorizeReturnObjectMethodInterceptor(this)); | ||||
| 		setAdvisors(advisors); | ||||
| 		return new AuthorizationAdvisorProxyFactory(advisors); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Construct an {@link AuthorizationAdvisorProxyFactory} with the defaults needed for | ||||
| 	 * wrapping objects in Spring Security's pre-post reactive method security support. | ||||
| 	 * @return an {@link AuthorizationAdvisorProxyFactory} for adding pre-post reactive | ||||
| 	 * method security support | ||||
| 	 */ | ||||
| 	public static AuthorizationAdvisorProxyFactory withReactiveDefaults() { | ||||
| 		List<AuthorizationAdvisor> advisors = new ArrayList<>(); | ||||
| 		advisors.add(AuthorizationManagerBeforeReactiveMethodInterceptor.preAuthorize()); | ||||
| 		advisors.add(AuthorizationManagerAfterReactiveMethodInterceptor.postAuthorize()); | ||||
| 		advisors.add(new PreFilterAuthorizationReactiveMethodInterceptor()); | ||||
| 		advisors.add(new PostFilterAuthorizationReactiveMethodInterceptor()); | ||||
| 		return new AuthorizationAdvisorProxyFactory(advisors); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| @ -111,41 +159,9 @@ public final class AuthorizationAdvisorProxyFactory implements AuthorizationProx | ||||
| 		if (target == null) { | ||||
| 			return null; | ||||
| 		} | ||||
| 		if (target instanceof Class<?> targetClass) { | ||||
| 			return proxyClass(targetClass); | ||||
| 		} | ||||
| 		if (target instanceof Iterator<?> iterator) { | ||||
| 			return proxyIterator(iterator); | ||||
| 		} | ||||
| 		if (target instanceof Queue<?> queue) { | ||||
| 			return proxyQueue(queue); | ||||
| 		} | ||||
| 		if (target instanceof List<?> list) { | ||||
| 			return proxyList(list); | ||||
| 		} | ||||
| 		if (target instanceof SortedSet<?> set) { | ||||
| 			return proxySortedSet(set); | ||||
| 		} | ||||
| 		if (target instanceof Set<?> set) { | ||||
| 			return proxySet(set); | ||||
| 		} | ||||
| 		if (target.getClass().isArray()) { | ||||
| 			return proxyArray((Object[]) target); | ||||
| 		} | ||||
| 		if (target instanceof SortedMap<?, ?> map) { | ||||
| 			return proxySortedMap(map); | ||||
| 		} | ||||
| 		if (target instanceof Iterable<?> iterable) { | ||||
| 			return proxyIterable(iterable); | ||||
| 		} | ||||
| 		if (target instanceof Map<?, ?> map) { | ||||
| 			return proxyMap(map); | ||||
| 		} | ||||
| 		if (target instanceof Stream<?> stream) { | ||||
| 			return proxyStream(stream); | ||||
| 		} | ||||
| 		if (target instanceof Optional<?> optional) { | ||||
| 			return proxyOptional(optional); | ||||
| 		Object proxied = this.visitor.visit(this, target); | ||||
| 		if (proxied != null) { | ||||
| 			return proxied; | ||||
| 		} | ||||
| 		ProxyFactory factory = new ProxyFactory(target); | ||||
| 		for (Advisor advisor : this.advisors) { | ||||
| @ -179,144 +195,318 @@ public final class AuthorizationAdvisorProxyFactory implements AuthorizationProx | ||||
| 		AnnotationAwareOrderComparator.sort(this.advisors); | ||||
| 	} | ||||
| 
 | ||||
| 	@SuppressWarnings("unchecked") | ||||
| 	private <T> T proxyCast(T target) { | ||||
| 		return (T) proxy(target); | ||||
| 	/** | ||||
| 	 * Use this visitor to navigate the proxy target's hierarchy. | ||||
| 	 * | ||||
| 	 * <p> | ||||
| 	 * This can be helpful when you want a specialized behavior for a type or set of | ||||
| 	 * types. For example, if you want to have this factory skip primitives and wrappers, | ||||
| 	 * then you can do: | ||||
| 	 * | ||||
| 	 * <pre> | ||||
| 	 * 	AuthorizationAdvisorProxyFactory proxyFactory = new AuthorizationAdvisorProxyFactory(); | ||||
| 	 * 	proxyFactory.setTargetVisitor(AuthorizationAdvisorProxyFactory.DEFAULT_VISITOR_IGNORE_VALUE_TYPES); | ||||
| 	 * </pre> | ||||
| 	 * @param visitor the visitor to use to introduce specialized behavior for a type | ||||
| 	 */ | ||||
| 	public void setTargetVisitor(TargetVisitor visitor) { | ||||
| 		Assert.notNull(visitor, "delegate cannot be null"); | ||||
| 		this.visitor = visitor; | ||||
| 	} | ||||
| 
 | ||||
| 	private Class<?> proxyClass(Class<?> targetClass) { | ||||
| 		ProxyFactory factory = new ProxyFactory(); | ||||
| 		factory.setTargetClass(targetClass); | ||||
| 		factory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass)); | ||||
| 		factory.setProxyTargetClass(!Modifier.isFinal(targetClass.getModifiers())); | ||||
| 		for (Advisor advisor : this.advisors) { | ||||
| 			factory.addAdvisors(advisor); | ||||
| 	@Override | ||||
| 	@NonNull | ||||
| 	public Iterator<AuthorizationAdvisor> iterator() { | ||||
| 		return this.advisors.iterator(); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * An interface to handle how the {@link AuthorizationAdvisorProxyFactory} should step | ||||
| 	 * through the target's object hierarchy. | ||||
| 	 * | ||||
| 	 * @author Josh Cummings | ||||
| 	 * @since 6.3 | ||||
| 	 * @see AuthorizationAdvisorProxyFactory#setTargetVisitor | ||||
| 	 */ | ||||
| 	public interface TargetVisitor { | ||||
| 
 | ||||
| 		/** | ||||
| 		 * Visit and possibly proxy this object. | ||||
| 		 * | ||||
| 		 * <p> | ||||
| 		 * Visiting may take the form of walking down this object's hierarchy and proxying | ||||
| 		 * sub-objects. | ||||
| 		 * | ||||
| 		 * <p> | ||||
| 		 * An example is a visitor that proxies the elements of a {@link List} instead of | ||||
| 		 * the list itself | ||||
| 		 * | ||||
| 		 * <p> | ||||
| 		 * Returning {@code null} implies that this visitor does not want to proxy this | ||||
| 		 * object | ||||
| 		 * @param proxyFactory the proxy factory to delegate proxying to for any | ||||
| 		 * sub-objects | ||||
| 		 * @param target the object to proxy | ||||
| 		 * @return the visited (and possibly proxied) object | ||||
| 		 */ | ||||
| 		Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object target); | ||||
| 
 | ||||
| 		/** | ||||
| 		 * The default {@link TargetVisitor}, which will proxy {@link Class} instances as | ||||
| 		 * well as instances contained in reactive types (if reactor is present), | ||||
| 		 * collection types, and other container types like {@link Optional} | ||||
| 		 */ | ||||
| 		static TargetVisitor defaults() { | ||||
| 			return AuthorizationAdvisorProxyFactory.DEFAULT_VISITOR; | ||||
| 		} | ||||
| 		return factory.getProxyClass(getClass().getClassLoader()); | ||||
| 
 | ||||
| 		/** | ||||
| 		 * The default {@link TargetVisitor} that also skips any value types (for example, | ||||
| 		 * {@link String}, {@link Integer}). This is handy for annotations like | ||||
| 		 * {@link AuthorizeReturnObject} when used at the class level | ||||
| 		 */ | ||||
| 		static TargetVisitor defaultsSkipValueTypes() { | ||||
| 			return AuthorizationAdvisorProxyFactory.DEFAULT_VISITOR_SKIP_VALUE_TYPES; | ||||
| 		} | ||||
| 
 | ||||
| 		static TargetVisitor of(TargetVisitor... visitors) { | ||||
| 			return (proxyFactory, target) -> { | ||||
| 				for (TargetVisitor visitor : visitors) { | ||||
| 					Object result = visitor.visit(proxyFactory, target); | ||||
| 					if (result != null) { | ||||
| 						return result; | ||||
| 					} | ||||
| 				} | ||||
| 				return null; | ||||
| 			}; | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	private <T> Iterable<T> proxyIterable(Iterable<T> iterable) { | ||||
| 		return () -> proxyIterator(iterable.iterator()); | ||||
| 	} | ||||
| 	private static final class IgnoreValueTypeVisitor implements TargetVisitor { | ||||
| 
 | ||||
| 	private <T> Iterator<T> proxyIterator(Iterator<T> iterator) { | ||||
| 		return new Iterator<>() { | ||||
| 			@Override | ||||
| 			public boolean hasNext() { | ||||
| 				return iterator.hasNext(); | ||||
| 		@Override | ||||
| 		public Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object object) { | ||||
| 			if (ClassUtils.isSimpleValueType(object.getClass())) { | ||||
| 				return object; | ||||
| 			} | ||||
| 			return null; | ||||
| 		} | ||||
| 
 | ||||
| 			@Override | ||||
| 			public T next() { | ||||
| 				return proxyCast(iterator.next()); | ||||
| 	} | ||||
| 
 | ||||
| 	private static final class ClassVisitor implements TargetVisitor { | ||||
| 
 | ||||
| 		@Override | ||||
| 		public Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object object) { | ||||
| 			if (object instanceof Class<?> targetClass) { | ||||
| 				ProxyFactory factory = new ProxyFactory(); | ||||
| 				factory.setTargetClass(targetClass); | ||||
| 				factory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass)); | ||||
| 				factory.setProxyTargetClass(!Modifier.isFinal(targetClass.getModifiers())); | ||||
| 				for (Advisor advisor : proxyFactory) { | ||||
| 					factory.addAdvisors(advisor); | ||||
| 				} | ||||
| 				return factory.getProxyClass(getClass().getClassLoader()); | ||||
| 			} | ||||
| 		}; | ||||
| 			return null; | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	private <T> SortedSet<T> proxySortedSet(SortedSet<T> set) { | ||||
| 		SortedSet<T> proxies = new TreeSet<>(set.comparator()); | ||||
| 		for (T toProxy : set) { | ||||
| 			proxies.add(proxyCast(toProxy)); | ||||
| 	private static final class ContainerTypeVisitor implements TargetVisitor { | ||||
| 
 | ||||
| 		@Override | ||||
| 		public Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object target) { | ||||
| 			if (target instanceof Iterator<?> iterator) { | ||||
| 				return proxyIterator(proxyFactory, iterator); | ||||
| 			} | ||||
| 			if (target instanceof Queue<?> queue) { | ||||
| 				return proxyQueue(proxyFactory, queue); | ||||
| 			} | ||||
| 			if (target instanceof List<?> list) { | ||||
| 				return proxyList(proxyFactory, list); | ||||
| 			} | ||||
| 			if (target instanceof SortedSet<?> set) { | ||||
| 				return proxySortedSet(proxyFactory, set); | ||||
| 			} | ||||
| 			if (target instanceof Set<?> set) { | ||||
| 				return proxySet(proxyFactory, set); | ||||
| 			} | ||||
| 			if (target.getClass().isArray()) { | ||||
| 				return proxyArray(proxyFactory, (Object[]) target); | ||||
| 			} | ||||
| 			if (target instanceof SortedMap<?, ?> map) { | ||||
| 				return proxySortedMap(proxyFactory, map); | ||||
| 			} | ||||
| 			if (target instanceof Iterable<?> iterable) { | ||||
| 				return proxyIterable(proxyFactory, iterable); | ||||
| 			} | ||||
| 			if (target instanceof Map<?, ?> map) { | ||||
| 				return proxyMap(proxyFactory, map); | ||||
| 			} | ||||
| 			if (target instanceof Stream<?> stream) { | ||||
| 				return proxyStream(proxyFactory, stream); | ||||
| 			} | ||||
| 			if (target instanceof Optional<?> optional) { | ||||
| 				return proxyOptional(proxyFactory, optional); | ||||
| 			} | ||||
| 			return null; | ||||
| 		} | ||||
| 		try { | ||||
| 			set.clear(); | ||||
| 			set.addAll(proxies); | ||||
| 
 | ||||
| 		@SuppressWarnings("unchecked") | ||||
| 		private <T> T proxyCast(AuthorizationProxyFactory proxyFactory, T target) { | ||||
| 			return (T) proxyFactory.proxy(target); | ||||
| 		} | ||||
| 
 | ||||
| 		private <T> Iterable<T> proxyIterable(AuthorizationProxyFactory proxyFactory, Iterable<T> iterable) { | ||||
| 			return () -> proxyIterator(proxyFactory, iterable.iterator()); | ||||
| 		} | ||||
| 
 | ||||
| 		private <T> Iterator<T> proxyIterator(AuthorizationProxyFactory proxyFactory, Iterator<T> iterator) { | ||||
| 			return new Iterator<>() { | ||||
| 				@Override | ||||
| 				public boolean hasNext() { | ||||
| 					return iterator.hasNext(); | ||||
| 				} | ||||
| 
 | ||||
| 				@Override | ||||
| 				public T next() { | ||||
| 					return proxyCast(proxyFactory, iterator.next()); | ||||
| 				} | ||||
| 			}; | ||||
| 		} | ||||
| 
 | ||||
| 		private <T> SortedSet<T> proxySortedSet(AuthorizationProxyFactory proxyFactory, SortedSet<T> set) { | ||||
| 			SortedSet<T> proxies = new TreeSet<>(set.comparator()); | ||||
| 			for (T toProxy : set) { | ||||
| 				proxies.add(proxyCast(proxyFactory, toProxy)); | ||||
| 			} | ||||
| 			try { | ||||
| 				set.clear(); | ||||
| 				set.addAll(proxies); | ||||
| 				return proxies; | ||||
| 			} | ||||
| 			catch (UnsupportedOperationException ex) { | ||||
| 				return Collections.unmodifiableSortedSet(proxies); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		private <T> Set<T> proxySet(AuthorizationProxyFactory proxyFactory, Set<T> set) { | ||||
| 			Set<T> proxies = new LinkedHashSet<>(set.size()); | ||||
| 			for (T toProxy : set) { | ||||
| 				proxies.add(proxyCast(proxyFactory, toProxy)); | ||||
| 			} | ||||
| 			try { | ||||
| 				set.clear(); | ||||
| 				set.addAll(proxies); | ||||
| 				return proxies; | ||||
| 			} | ||||
| 			catch (UnsupportedOperationException ex) { | ||||
| 				return Collections.unmodifiableSet(proxies); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		private <T> Queue<T> proxyQueue(AuthorizationProxyFactory proxyFactory, Queue<T> queue) { | ||||
| 			Queue<T> proxies = new LinkedList<>(); | ||||
| 			for (T toProxy : queue) { | ||||
| 				proxies.add(proxyCast(proxyFactory, toProxy)); | ||||
| 			} | ||||
| 			queue.clear(); | ||||
| 			queue.addAll(proxies); | ||||
| 			return proxies; | ||||
| 		} | ||||
| 		catch (UnsupportedOperationException ex) { | ||||
| 			return Collections.unmodifiableSortedSet(proxies); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private <T> Set<T> proxySet(Set<T> set) { | ||||
| 		Set<T> proxies = new LinkedHashSet<>(set.size()); | ||||
| 		for (T toProxy : set) { | ||||
| 			proxies.add(proxyCast(toProxy)); | ||||
| 		private <T> List<T> proxyList(AuthorizationProxyFactory proxyFactory, List<T> list) { | ||||
| 			List<T> proxies = new ArrayList<>(list.size()); | ||||
| 			for (T toProxy : list) { | ||||
| 				proxies.add(proxyCast(proxyFactory, toProxy)); | ||||
| 			} | ||||
| 			try { | ||||
| 				list.clear(); | ||||
| 				list.addAll(proxies); | ||||
| 				return proxies; | ||||
| 			} | ||||
| 			catch (UnsupportedOperationException ex) { | ||||
| 				return Collections.unmodifiableList(proxies); | ||||
| 			} | ||||
| 		} | ||||
| 		try { | ||||
| 			set.clear(); | ||||
| 			set.addAll(proxies); | ||||
| 
 | ||||
| 		private Object[] proxyArray(AuthorizationProxyFactory proxyFactory, Object[] objects) { | ||||
| 			List<Object> retain = new ArrayList<>(objects.length); | ||||
| 			for (Object object : objects) { | ||||
| 				retain.add(proxyFactory.proxy(object)); | ||||
| 			} | ||||
| 			Object[] proxies = (Object[]) Array.newInstance(objects.getClass().getComponentType(), retain.size()); | ||||
| 			for (int i = 0; i < retain.size(); i++) { | ||||
| 				proxies[i] = retain.get(i); | ||||
| 			} | ||||
| 			return proxies; | ||||
| 		} | ||||
| 		catch (UnsupportedOperationException ex) { | ||||
| 			return Collections.unmodifiableSet(proxies); | ||||
| 
 | ||||
| 		private <K, V> SortedMap<K, V> proxySortedMap(AuthorizationProxyFactory proxyFactory, SortedMap<K, V> entries) { | ||||
| 			SortedMap<K, V> proxies = new TreeMap<>(entries.comparator()); | ||||
| 			for (Map.Entry<K, V> entry : entries.entrySet()) { | ||||
| 				proxies.put(entry.getKey(), proxyCast(proxyFactory, entry.getValue())); | ||||
| 			} | ||||
| 			try { | ||||
| 				entries.clear(); | ||||
| 				entries.putAll(proxies); | ||||
| 				return entries; | ||||
| 			} | ||||
| 			catch (UnsupportedOperationException ex) { | ||||
| 				return Collections.unmodifiableSortedMap(proxies); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		private <K, V> Map<K, V> proxyMap(AuthorizationProxyFactory proxyFactory, Map<K, V> entries) { | ||||
| 			Map<K, V> proxies = new LinkedHashMap<>(entries.size()); | ||||
| 			for (Map.Entry<K, V> entry : entries.entrySet()) { | ||||
| 				proxies.put(entry.getKey(), proxyCast(proxyFactory, entry.getValue())); | ||||
| 			} | ||||
| 			try { | ||||
| 				entries.clear(); | ||||
| 				entries.putAll(proxies); | ||||
| 				return entries; | ||||
| 			} | ||||
| 			catch (UnsupportedOperationException ex) { | ||||
| 				return Collections.unmodifiableMap(proxies); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		private Stream<?> proxyStream(AuthorizationProxyFactory proxyFactory, Stream<?> stream) { | ||||
| 			return stream.map(proxyFactory::proxy).onClose(stream::close); | ||||
| 		} | ||||
| 
 | ||||
| 		@SuppressWarnings("OptionalUsedAsFieldOrParameterType") | ||||
| 		private Optional<?> proxyOptional(AuthorizationProxyFactory proxyFactory, Optional<?> optional) { | ||||
| 			return optional.map(proxyFactory::proxy); | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	private <T> Queue<T> proxyQueue(Queue<T> queue) { | ||||
| 		Queue<T> proxies = new LinkedList<>(); | ||||
| 		for (T toProxy : queue) { | ||||
| 			proxies.add(proxyCast(toProxy)); | ||||
| 		} | ||||
| 		queue.clear(); | ||||
| 		queue.addAll(proxies); | ||||
| 		return proxies; | ||||
| 	} | ||||
| 	private static class ReactiveTypeVisitor implements TargetVisitor { | ||||
| 
 | ||||
| 	private <T> List<T> proxyList(List<T> list) { | ||||
| 		List<T> proxies = new ArrayList<>(list.size()); | ||||
| 		for (T toProxy : list) { | ||||
| 			proxies.add(proxyCast(toProxy)); | ||||
| 		@Override | ||||
| 		@SuppressWarnings("ReactiveStreamsUnusedPublisher") | ||||
| 		public Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object target) { | ||||
| 			if (target instanceof Mono<?> mono) { | ||||
| 				return proxyMono(proxyFactory, mono); | ||||
| 			} | ||||
| 			if (target instanceof Flux<?> flux) { | ||||
| 				return proxyFlux(proxyFactory, flux); | ||||
| 			} | ||||
| 			return null; | ||||
| 		} | ||||
| 		try { | ||||
| 			list.clear(); | ||||
| 			list.addAll(proxies); | ||||
| 			return proxies; | ||||
| 		} | ||||
| 		catch (UnsupportedOperationException ex) { | ||||
| 			return Collections.unmodifiableList(proxies); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private Object[] proxyArray(Object[] objects) { | ||||
| 		List<Object> retain = new ArrayList<>(objects.length); | ||||
| 		for (Object object : objects) { | ||||
| 			retain.add(proxy(object)); | ||||
| 		private Mono<?> proxyMono(AuthorizationProxyFactory proxyFactory, Mono<?> mono) { | ||||
| 			return mono.map(proxyFactory::proxy); | ||||
| 		} | ||||
| 		Object[] proxies = (Object[]) Array.newInstance(objects.getClass().getComponentType(), retain.size()); | ||||
| 		for (int i = 0; i < retain.size(); i++) { | ||||
| 			proxies[i] = retain.get(i); | ||||
| 		} | ||||
| 		return proxies; | ||||
| 	} | ||||
| 
 | ||||
| 	private <K, V> SortedMap<K, V> proxySortedMap(SortedMap<K, V> entries) { | ||||
| 		SortedMap<K, V> proxies = new TreeMap<>(entries.comparator()); | ||||
| 		for (Map.Entry<K, V> entry : entries.entrySet()) { | ||||
| 			proxies.put(entry.getKey(), proxyCast(entry.getValue())); | ||||
| 		private Flux<?> proxyFlux(AuthorizationProxyFactory proxyFactory, Flux<?> flux) { | ||||
| 			return flux.map(proxyFactory::proxy); | ||||
| 		} | ||||
| 		try { | ||||
| 			entries.clear(); | ||||
| 			entries.putAll(proxies); | ||||
| 			return entries; | ||||
| 		} | ||||
| 		catch (UnsupportedOperationException ex) { | ||||
| 			return Collections.unmodifiableSortedMap(proxies); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private <K, V> Map<K, V> proxyMap(Map<K, V> entries) { | ||||
| 		Map<K, V> proxies = new LinkedHashMap<>(entries.size()); | ||||
| 		for (Map.Entry<K, V> entry : entries.entrySet()) { | ||||
| 			proxies.put(entry.getKey(), proxyCast(entry.getValue())); | ||||
| 		} | ||||
| 		try { | ||||
| 			entries.clear(); | ||||
| 			entries.putAll(proxies); | ||||
| 			return entries; | ||||
| 		} | ||||
| 		catch (UnsupportedOperationException ex) { | ||||
| 			return Collections.unmodifiableMap(proxies); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private Stream<?> proxyStream(Stream<?> stream) { | ||||
| 		return stream.map(this::proxy).onClose(stream::close); | ||||
| 	} | ||||
| 
 | ||||
| 	@SuppressWarnings("OptionalUsedAsFieldOrParameterType") | ||||
| 	private Optional<?> proxyOptional(Optional<?> optional) { | ||||
| 		return optional.map(this::proxy); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -1,139 +0,0 @@ | ||||
| /* | ||||
|  * Copyright 2002-2024 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; | ||||
| 
 | ||||
| import java.lang.reflect.Array; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.Iterator; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.Optional; | ||||
| import java.util.stream.Stream; | ||||
| 
 | ||||
| import reactor.core.publisher.Flux; | ||||
| import reactor.core.publisher.Mono; | ||||
| 
 | ||||
| import org.springframework.aop.framework.ProxyFactory; | ||||
| import org.springframework.security.authorization.method.AuthorizationAdvisor; | ||||
| import org.springframework.security.authorization.method.AuthorizationManagerAfterReactiveMethodInterceptor; | ||||
| import org.springframework.security.authorization.method.AuthorizationManagerBeforeReactiveMethodInterceptor; | ||||
| import org.springframework.security.authorization.method.AuthorizeReturnObjectMethodInterceptor; | ||||
| import org.springframework.security.authorization.method.PostFilterAuthorizationReactiveMethodInterceptor; | ||||
| import org.springframework.security.authorization.method.PreFilterAuthorizationReactiveMethodInterceptor; | ||||
| 
 | ||||
| /** | ||||
|  * A proxy factory for applying authorization advice to an arbitrary object. | ||||
|  * | ||||
|  * <p> | ||||
|  * For example, consider a non-Spring-managed object {@code Foo}: <pre> | ||||
|  *     class Foo { | ||||
|  *         @PreAuthorize("hasAuthority('bar:read')") | ||||
|  *         String bar() { ... } | ||||
|  *     } | ||||
|  * </pre> | ||||
|  * | ||||
|  * Use {@link ReactiveAuthorizationAdvisorProxyFactory} to wrap the instance in Spring | ||||
|  * Security's {@link org.springframework.security.access.prepost.PreAuthorize} method | ||||
|  * interceptor like so: | ||||
|  * | ||||
|  * <pre> | ||||
|  *     AuthorizationManagerBeforeMethodInterceptor preAuthorize = AuthorizationManagerBeforeMethodInterceptor.preAuthorize(); | ||||
|  *     AuthorizationProxyFactory proxyFactory = new AuthorizationProxyFactory(preAuthorize); | ||||
|  *     Foo foo = new Foo(); | ||||
|  *     foo.bar(); // passes | ||||
|  *     Foo securedFoo = proxyFactory.proxy(foo); | ||||
|  *     securedFoo.bar(); // access denied! | ||||
|  * </pre> | ||||
|  * | ||||
|  * @author Josh Cummings | ||||
|  * @since 6.3 | ||||
|  */ | ||||
| public final class ReactiveAuthorizationAdvisorProxyFactory implements AuthorizationProxyFactory { | ||||
| 
 | ||||
| 	private final AuthorizationAdvisorProxyFactory defaults = new AuthorizationAdvisorProxyFactory(); | ||||
| 
 | ||||
| 	public ReactiveAuthorizationAdvisorProxyFactory() { | ||||
| 		List<AuthorizationAdvisor> advisors = new ArrayList<>(); | ||||
| 		advisors.add(AuthorizationManagerBeforeReactiveMethodInterceptor.preAuthorize()); | ||||
| 		advisors.add(AuthorizationManagerAfterReactiveMethodInterceptor.postAuthorize()); | ||||
| 		advisors.add(new PreFilterAuthorizationReactiveMethodInterceptor()); | ||||
| 		advisors.add(new PostFilterAuthorizationReactiveMethodInterceptor()); | ||||
| 		advisors.add(new AuthorizeReturnObjectMethodInterceptor(this)); | ||||
| 		this.defaults.setAdvisors(advisors); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Proxy an object to enforce authorization advice. | ||||
| 	 * | ||||
| 	 * <p> | ||||
| 	 * Proxies any instance of a non-final class or a class that implements more than one | ||||
| 	 * interface. | ||||
| 	 * | ||||
| 	 * <p> | ||||
| 	 * If {@code target} is an {@link Iterator}, {@link Collection}, {@link Array}, | ||||
| 	 * {@link Map}, {@link Stream}, or {@link Optional}, then the element or value type is | ||||
| 	 * proxied. | ||||
| 	 * | ||||
| 	 * <p> | ||||
| 	 * If {@code target} is a {@link Class}, then {@link ProxyFactory#getProxyClass} is | ||||
| 	 * invoked instead. | ||||
| 	 * @param target the instance to proxy | ||||
| 	 * @return the proxied instance | ||||
| 	 */ | ||||
| 	@Override | ||||
| 	public Object proxy(Object target) { | ||||
| 		if (target instanceof Mono<?> mono) { | ||||
| 			return proxyMono(mono); | ||||
| 		} | ||||
| 		if (target instanceof Flux<?> flux) { | ||||
| 			return proxyFlux(flux); | ||||
| 		} | ||||
| 		return this.defaults.proxy(target); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Add advisors that should be included to each proxy created. | ||||
| 	 * | ||||
| 	 * <p> | ||||
| 	 * All advisors are re-sorted by their advisor order. | ||||
| 	 * @param advisors the advisors to add | ||||
| 	 */ | ||||
| 	public void setAdvisors(AuthorizationAdvisor... advisors) { | ||||
| 		this.defaults.setAdvisors(advisors); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Add advisors that should be included to each proxy created. | ||||
| 	 * | ||||
| 	 * <p> | ||||
| 	 * All advisors are re-sorted by their advisor order. | ||||
| 	 * @param advisors the advisors to add | ||||
| 	 */ | ||||
| 	public void setAdvisors(Collection<AuthorizationAdvisor> advisors) { | ||||
| 		this.defaults.setAdvisors(advisors); | ||||
| 	} | ||||
| 
 | ||||
| 	private Mono<?> proxyMono(Mono<?> mono) { | ||||
| 		return mono.map(this::proxy); | ||||
| 	} | ||||
| 
 | ||||
| 	private Flux<?> proxyFlux(Flux<?> flux) { | ||||
| 		return flux.map(this::proxy); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| @ -40,12 +40,14 @@ import org.springframework.aop.Pointcut; | ||||
| import org.springframework.security.access.AccessDeniedException; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.security.authentication.TestAuthentication; | ||||
| import org.springframework.security.authorization.AuthorizationAdvisorProxyFactory.TargetVisitor; | ||||
| import org.springframework.security.authorization.method.AuthorizationAdvisor; | ||||
| import org.springframework.security.core.Authentication; | ||||
| import org.springframework.security.core.context.SecurityContextHolder; | ||||
| 
 | ||||
| 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.atLeastOnce; | ||||
| import static org.mockito.Mockito.mock; | ||||
| @ -64,7 +66,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenPreAuthorizeThenHonors() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		Flight flight = new Flight(); | ||||
| 		assertThat(flight.getAltitude()).isEqualTo(35000d); | ||||
| 		Flight secured = proxy(factory, flight); | ||||
| @ -75,7 +77,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenPreAuthorizeOnInterfaceThenHonors() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		assertThat(this.alan.getFirstName()).isEqualTo("alan"); | ||||
| 		User secured = proxy(factory, this.alan); | ||||
| 		assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(secured::getFirstName); | ||||
| @ -89,7 +91,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenPreAuthorizeOnRecordThenHonors() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		HasSecret repo = new Repository("secret"); | ||||
| 		assertThat(repo.secret()).isEqualTo("secret"); | ||||
| 		HasSecret secured = proxy(factory, repo); | ||||
| @ -102,7 +104,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenImmutableListThenReturnsSecuredImmutableList() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		List<Flight> flights = List.of(this.flight); | ||||
| 		List<Flight> secured = proxy(factory, flights); | ||||
| 		secured.forEach( | ||||
| @ -114,7 +116,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenImmutableSetThenReturnsSecuredImmutableSet() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		Set<Flight> flights = Set.of(this.flight); | ||||
| 		Set<Flight> secured = proxy(factory, flights); | ||||
| 		secured.forEach( | ||||
| @ -126,7 +128,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenQueueThenReturnsSecuredQueue() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		Queue<Flight> flights = new LinkedList<>(List.of(this.flight)); | ||||
| 		Queue<Flight> secured = proxy(factory, flights); | ||||
| 		assertThat(flights.size()).isEqualTo(secured.size()); | ||||
| @ -138,7 +140,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenImmutableSortedSetThenReturnsSecuredImmutableSortedSet() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		SortedSet<User> users = Collections.unmodifiableSortedSet(new TreeSet<>(Set.of(this.alan))); | ||||
| 		SortedSet<User> secured = proxy(factory, users); | ||||
| 		secured | ||||
| @ -150,7 +152,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenImmutableSortedMapThenReturnsSecuredImmutableSortedMap() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		SortedMap<String, User> users = Collections | ||||
| 			.unmodifiableSortedMap(new TreeMap<>(Map.of(this.alan.getId(), this.alan))); | ||||
| 		SortedMap<String, User> secured = proxy(factory, users); | ||||
| @ -163,7 +165,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenImmutableMapThenReturnsSecuredImmutableMap() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		Map<String, User> users = Map.of(this.alan.getId(), this.alan); | ||||
| 		Map<String, User> secured = proxy(factory, users); | ||||
| 		secured.forEach( | ||||
| @ -175,7 +177,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenMutableListThenReturnsSecuredMutableList() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		List<Flight> flights = new ArrayList<>(List.of(this.flight)); | ||||
| 		List<Flight> secured = proxy(factory, flights); | ||||
| 		secured.forEach( | ||||
| @ -187,7 +189,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenMutableSetThenReturnsSecuredMutableSet() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		Set<Flight> flights = new HashSet<>(Set.of(this.flight)); | ||||
| 		Set<Flight> secured = proxy(factory, flights); | ||||
| 		secured.forEach( | ||||
| @ -199,7 +201,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenMutableSortedSetThenReturnsSecuredMutableSortedSet() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		SortedSet<User> users = new TreeSet<>(Set.of(this.alan)); | ||||
| 		SortedSet<User> secured = proxy(factory, users); | ||||
| 		secured.forEach((u) -> assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(u::getFirstName)); | ||||
| @ -210,7 +212,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenMutableSortedMapThenReturnsSecuredMutableSortedMap() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		SortedMap<String, User> users = new TreeMap<>(Map.of(this.alan.getId(), this.alan)); | ||||
| 		SortedMap<String, User> secured = proxy(factory, users); | ||||
| 		secured.forEach((id, u) -> assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(u::getFirstName)); | ||||
| @ -221,7 +223,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenMutableMapThenReturnsSecuredMutableMap() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		Map<String, User> users = new HashMap<>(Map.of(this.alan.getId(), this.alan)); | ||||
| 		Map<String, User> secured = proxy(factory, users); | ||||
| 		secured.forEach((id, u) -> assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(u::getFirstName)); | ||||
| @ -232,7 +234,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenPreAuthorizeForOptionalThenHonors() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		Optional<Flight> flights = Optional.of(this.flight); | ||||
| 		assertThat(flights.get().getAltitude()).isEqualTo(35000d); | ||||
| 		Optional<Flight> secured = proxy(factory, flights); | ||||
| @ -243,7 +245,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenPreAuthorizeForStreamThenHonors() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		Stream<Flight> flights = Stream.of(this.flight); | ||||
| 		Stream<Flight> secured = proxy(factory, flights); | ||||
| 		assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> secured.forEach(Flight::getAltitude)); | ||||
| @ -253,7 +255,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenPreAuthorizeForArrayThenHonors() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		Flight[] flights = { this.flight }; | ||||
| 		Flight[] secured = proxy(factory, flights); | ||||
| 		assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(secured[0]::getAltitude); | ||||
| @ -263,7 +265,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenPreAuthorizeForIteratorThenHonors() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		Iterator<Flight> flights = List.of(this.flight).iterator(); | ||||
| 		Iterator<Flight> secured = proxy(factory, flights); | ||||
| 		assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> secured.next().getAltitude()); | ||||
| @ -273,7 +275,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenPreAuthorizeForIterableThenHonors() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		Iterable<User> users = new UserRepository(); | ||||
| 		Iterable<User> secured = proxy(factory, users); | ||||
| 		assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> secured.forEach(User::getFirstName)); | ||||
| @ -282,7 +284,7 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void proxyWhenPreAuthorizeForClassThenHonors() { | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		Class<Flight> clazz = proxy(factory, Flight.class); | ||||
| 		assertThat(clazz.getSimpleName()).contains("SpringCGLIB$$"); | ||||
| 		Flight secured = proxy(factory, this.flight); | ||||
| @ -297,13 +299,30 @@ public class AuthorizationAdvisorProxyFactoryTests { | ||||
| 		AuthorizationAdvisor advisor = mock(AuthorizationAdvisor.class); | ||||
| 		given(advisor.getAdvice()).willReturn(advisor); | ||||
| 		given(advisor.getPointcut()).willReturn(Pointcut.TRUE); | ||||
| 		AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		factory.setAdvisors(advisor); | ||||
| 		Flight flight = proxy(factory, this.flight); | ||||
| 		flight.getAltitude(); | ||||
| 		verify(advisor, atLeastOnce()).getPointcut(); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void setTargetVisitorThenUses() { | ||||
| 		TargetVisitor visitor = mock(TargetVisitor.class); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		factory.setTargetVisitor(visitor); | ||||
| 		factory.proxy(new Flight()); | ||||
| 		verify(visitor).visit(any(), any()); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void setTargetVisitorIgnoreValueTypesThenIgnores() { | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| 		assertThatExceptionOfType(ClassCastException.class).isThrownBy(() -> ((Integer) factory.proxy(35)).intValue()); | ||||
| 		factory.setTargetVisitor(TargetVisitor.defaultsSkipValueTypes()); | ||||
| 		assertThat(factory.proxy(35)).isEqualTo(35); | ||||
| 	} | ||||
| 
 | ||||
| 	private Authentication authenticated(String user, String... authorities) { | ||||
| 		return TestAuthentication.authenticated(TestAuthentication.withUsername(user).authorities(authorities).build()); | ||||
| 	} | ||||
|  | ||||
| @ -52,7 +52,7 @@ public class ReactiveAuthorizationAdvisorProxyFactoryTests { | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void proxyWhenPreAuthorizeThenHonors() { | ||||
| 		ReactiveAuthorizationAdvisorProxyFactory factory = new ReactiveAuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withReactiveDefaults(); | ||||
| 		Flight flight = new Flight(); | ||||
| 		StepVerifier | ||||
| 			.create(flight.getAltitude().contextWrite(ReactiveSecurityContextHolder.withAuthentication(this.user))) | ||||
| @ -67,7 +67,7 @@ public class ReactiveAuthorizationAdvisorProxyFactoryTests { | ||||
| 	@Test | ||||
| 	public void proxyWhenPreAuthorizeOnInterfaceThenHonors() { | ||||
| 		SecurityContextHolder.getContext().setAuthentication(this.user); | ||||
| 		ReactiveAuthorizationAdvisorProxyFactory factory = new ReactiveAuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withReactiveDefaults(); | ||||
| 		StepVerifier | ||||
| 			.create(this.alan.getFirstName().contextWrite(ReactiveSecurityContextHolder.withAuthentication(this.user))) | ||||
| 			.expectNext("alan") | ||||
| @ -89,7 +89,7 @@ public class ReactiveAuthorizationAdvisorProxyFactoryTests { | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void proxyWhenPreAuthorizeOnRecordThenHonors() { | ||||
| 		ReactiveAuthorizationAdvisorProxyFactory factory = new ReactiveAuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withReactiveDefaults(); | ||||
| 		HasSecret repo = new Repository(Mono.just("secret")); | ||||
| 		StepVerifier.create(repo.secret().contextWrite(ReactiveSecurityContextHolder.withAuthentication(this.user))) | ||||
| 			.expectNext("secret") | ||||
| @ -104,7 +104,7 @@ public class ReactiveAuthorizationAdvisorProxyFactoryTests { | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void proxyWhenPreAuthorizeOnFluxThenHonors() { | ||||
| 		ReactiveAuthorizationAdvisorProxyFactory factory = new ReactiveAuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withReactiveDefaults(); | ||||
| 		Flux<Flight> flights = Flux.just(this.flight); | ||||
| 		Flux<Flight> secured = proxy(factory, flights); | ||||
| 		StepVerifier | ||||
| @ -115,7 +115,7 @@ public class ReactiveAuthorizationAdvisorProxyFactoryTests { | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void proxyWhenPreAuthorizeForClassThenHonors() { | ||||
| 		ReactiveAuthorizationAdvisorProxyFactory factory = new ReactiveAuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withReactiveDefaults(); | ||||
| 		Class<Flight> clazz = proxy(factory, Flight.class); | ||||
| 		assertThat(clazz.getSimpleName()).contains("SpringCGLIB$$"); | ||||
| 		Flight secured = proxy(factory, this.flight); | ||||
| @ -129,7 +129,7 @@ public class ReactiveAuthorizationAdvisorProxyFactoryTests { | ||||
| 		AuthorizationAdvisor advisor = mock(AuthorizationAdvisor.class); | ||||
| 		given(advisor.getAdvice()).willReturn(advisor); | ||||
| 		given(advisor.getPointcut()).willReturn(Pointcut.TRUE); | ||||
| 		ReactiveAuthorizationAdvisorProxyFactory factory = new ReactiveAuthorizationAdvisorProxyFactory(); | ||||
| 		AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withReactiveDefaults(); | ||||
| 		factory.setAdvisors(advisor); | ||||
| 		Flight flight = proxy(factory, this.flight); | ||||
| 		flight.getAltitude(); | ||||
|  | ||||
| @ -1812,12 +1812,40 @@ fun getEmailWhenProxiedThenAuthorizes() { | ||||
| ---- | ||||
| ====== | ||||
| 
 | ||||
| [NOTE] | ||||
| ==== | ||||
| `@AuthorizeReturnObject` can be placed at the class level. Note, though, that this means Spring Security will proxy any return object, including ``String``, ``Integer`` and other types. | ||||
| === Using `@AuthorizeReturnObject` at the class level | ||||
| 
 | ||||
| `@AuthorizeReturnObject` can be placed at the class level. Note, though, that this means Spring Security will attempt to proxy any return object, including ``String``, ``Integer`` and other types. | ||||
| This is often not what you want to do. | ||||
| 
 | ||||
| In most cases, you will want to annotate the individual methods. | ||||
| If you want to use `@AuthorizeReturnObject` on a class or interface whose methods return value types, like `int`, `String`, `Double` or collections of those types, then you should also publish the appropriate `AuthorizationAdvisorProxyFactory.TargetVisitor` as follows: | ||||
| 
 | ||||
| 
 | ||||
| [tabs] | ||||
| ====== | ||||
| Java:: | ||||
| + | ||||
| [source,java,role="primary"] | ||||
| ---- | ||||
| @Bean | ||||
| static Customizer<AuthorizationAdvisorProxyFactory> skipValueTypes() { | ||||
|     return (factory) -> factory.setTargetVisitor(TargetVisitor.defaultsSkipValueTypes()); | ||||
| } | ||||
| ---- | ||||
| 
 | ||||
| Kotlin:: | ||||
| + | ||||
| [source,kotlin,role="secondary"] | ||||
| ---- | ||||
| @Bean | ||||
| open fun skipValueTypes() = Customizer<AuthorizationAdvisorProxyFactory> { | ||||
|     it.setTargetVisitor(TargetVisitor.defaultsSkipValueTypes()) | ||||
| } | ||||
| ---- | ||||
| ====== | ||||
| 
 | ||||
| [TIP] | ||||
| ==== | ||||
| You can set your own `AuthorizationAdvisorProxyFactory.TargetVisitor` to customize the proxying for any set of types | ||||
| ==== | ||||
| 
 | ||||
| === Programmatically Proxying | ||||
| @ -1877,22 +1905,27 @@ Java:: | ||||
| + | ||||
| [source,java,role="primary"] | ||||
| ---- | ||||
| import org.springframework.security.authorization.AuthorizationAdvisorProxyFactory.TargetVisitor; | ||||
| import static org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor.preAuthorize; | ||||
| 
 | ||||
| // ... | ||||
| 
 | ||||
| AuthorizationProxyFactory proxyFactory = new AuthorizationProxyFactory(preAuthorize()); | ||||
| AuthorizationProxyFactory proxyFactory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
| // and if needing to skip value types | ||||
| proxyFactory.setTargetVisitor(TargetVisitor.defaultsSkipValueTypes()); | ||||
| ---- | ||||
| 
 | ||||
| Kotlin:: | ||||
| + | ||||
| [source,kotlin,role="secondary"] | ||||
| ---- | ||||
| import org.springframework.security.authorization.AuthorizationAdvisorProxyFactory.TargetVisitor; | ||||
| import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor.preAuthorize | ||||
| 
 | ||||
| // ... | ||||
| 
 | ||||
| val proxyFactory: AuthorizationProxyFactory = AuthorizationProxyFactory(preAuthorize()) | ||||
| // and if needing to skip value types | ||||
| proxyFactory.setTargetVisitor(TargetVisitor.defaultsSkipValueTypes()) | ||||
| ---- | ||||
| ====== | ||||
| 
 | ||||
| @ -1906,7 +1939,7 @@ Java:: | ||||
| ---- | ||||
| @Test | ||||
| void getEmailWhenProxiedThenAuthorizes() { | ||||
| 	AuthorizationProxyFactory proxyFactory = new AuthorizationProxyFactory(preAuthorize()); | ||||
| 	AuthorizationProxyFactory proxyFactory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
|     User user = new User("name", "email"); | ||||
|     assertThat(user.getEmail()).isNotNull(); | ||||
|     User securedUser = proxyFactory.proxy(user); | ||||
| @ -1920,7 +1953,7 @@ Kotlin:: | ||||
| ---- | ||||
| @Test | ||||
| fun getEmailWhenProxiedThenAuthorizes() { | ||||
|     val proxyFactory: AuthorizationProxyFactory = AuthorizationProxyFactory(preAuthorize()) | ||||
|     val proxyFactory: AuthorizationProxyFactory = AuthorizationAdvisorProxyFactory.withDefaults() | ||||
|     val user: User = User("name", "email") | ||||
|     assertThat(user.getEmail()).isNotNull() | ||||
|     val securedUser: User = proxyFactory.proxy(user) | ||||
| @ -1948,7 +1981,7 @@ Java:: | ||||
| ---- | ||||
| @Test | ||||
| void getEmailWhenProxiedThenAuthorizes() { | ||||
| 	AuthorizationProxyFactory proxyFactory = new AuthorizationProxyFactory(preAuthorize()); | ||||
| 	AuthorizationProxyFactory proxyFactory = AuthorizationAdvisorProxyFactory.withDefaults(); | ||||
|     List<User> users = List.of(ada, albert, marie); | ||||
|     List<User> securedUsers = proxyFactory.proxy(users); | ||||
| 	securedUsers.forEach((securedUser) -> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user