mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-10-31 06:38:42 +00:00 
			
		
		
		
	Revert AuthorizationManager Method Security
This commit is contained in:
		
							parent
							
								
									b352c8f1da
								
							
						
					
					
						commit
						163b5943ca
					
				| @ -38,7 +38,6 @@ dependencies { | |||||||
| 	optional'org.springframework:spring-websocket' | 	optional'org.springframework:spring-websocket' | ||||||
| 	optional 'org.jetbrains.kotlin:kotlin-reflect' | 	optional 'org.jetbrains.kotlin:kotlin-reflect' | ||||||
| 	optional 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' | 	optional 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' | ||||||
| 	optional 'javax.annotation:jsr250-api' |  | ||||||
| 
 | 
 | ||||||
| 	provided 'javax.servlet:javax.servlet-api' | 	provided 'javax.servlet:javax.servlet-api' | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,87 +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.config.annotation.method.configuration; |  | ||||||
| 
 |  | ||||||
| import java.lang.annotation.Documented; |  | ||||||
| import java.lang.annotation.ElementType; |  | ||||||
| import java.lang.annotation.Retention; |  | ||||||
| import java.lang.annotation.RetentionPolicy; |  | ||||||
| import java.lang.annotation.Target; |  | ||||||
| 
 |  | ||||||
| import org.springframework.context.annotation.AdviceMode; |  | ||||||
| import org.springframework.context.annotation.Configuration; |  | ||||||
| import org.springframework.context.annotation.Import; |  | ||||||
| import org.springframework.core.Ordered; |  | ||||||
| import org.springframework.security.access.annotation.Secured; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Enables Spring Security Method Security. |  | ||||||
|  * @author Evgeniy Cheban |  | ||||||
|  * @since 5.5 |  | ||||||
|  */ |  | ||||||
| @Retention(RetentionPolicy.RUNTIME) |  | ||||||
| @Target(ElementType.TYPE) |  | ||||||
| @Documented |  | ||||||
| @Import(MethodSecuritySelector.class) |  | ||||||
| @Configuration |  | ||||||
| public @interface EnableMethodSecurity { |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Determines if Spring Security's {@link Secured} annotation should be enabled. |  | ||||||
| 	 * Default is false. |  | ||||||
| 	 * @return true if {@link Secured} annotation should be enabled false otherwise |  | ||||||
| 	 */ |  | ||||||
| 	boolean securedEnabled() default false; |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Determines if JSR-250 annotations should be enabled. Default is false. |  | ||||||
| 	 * @return true if JSR-250 should be enabled false otherwise |  | ||||||
| 	 */ |  | ||||||
| 	boolean jsr250Enabled() default false; |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed to |  | ||||||
| 	 * standard Java interface-based proxies. The default is {@code false}. <strong> |  | ||||||
| 	 * Applicable only if {@link #mode()} is set to {@link AdviceMode#PROXY}</strong>. |  | ||||||
| 	 * <p> |  | ||||||
| 	 * Note that setting this attribute to {@code true} will affect <em>all</em> |  | ||||||
| 	 * Spring-managed beans requiring proxying, not just those marked with |  | ||||||
| 	 * {@code @Cacheable}. For example, other beans marked with Spring's |  | ||||||
| 	 * {@code @Transactional} annotation will be upgraded to subclass proxying at the same |  | ||||||
| 	 * time. This approach has no negative impact in practice unless one is explicitly |  | ||||||
| 	 * expecting one type of proxy vs another, e.g. in tests. |  | ||||||
| 	 * @return true if subclass-based (CGLIB) proxies are to be created |  | ||||||
| 	 */ |  | ||||||
| 	boolean proxyTargetClass() default false; |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Indicate how security advice should be applied. The default is |  | ||||||
| 	 * {@link AdviceMode#PROXY}. |  | ||||||
| 	 * @see AdviceMode |  | ||||||
| 	 * @return the {@link AdviceMode} to use |  | ||||||
| 	 */ |  | ||||||
| 	AdviceMode mode() default AdviceMode.PROXY; |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Indicate the ordering of the execution of the security advisor when multiple |  | ||||||
| 	 * advices are applied at a specific joinpoint. The default is |  | ||||||
| 	 * {@link Ordered#LOWEST_PRECEDENCE}. |  | ||||||
| 	 * @return the order the security advisor should be applied |  | ||||||
| 	 */ |  | ||||||
| 	int order() default Ordered.LOWEST_PRECEDENCE; |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -1,195 +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.config.annotation.method.configuration; |  | ||||||
| 
 |  | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Map; |  | ||||||
| 
 |  | ||||||
| import org.springframework.aop.support.DefaultPointcutAdvisor; |  | ||||||
| import org.springframework.beans.factory.InitializingBean; |  | ||||||
| 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.ImportAware; |  | ||||||
| import org.springframework.context.annotation.Role; |  | ||||||
| import org.springframework.core.annotation.AnnotationAttributes; |  | ||||||
| import org.springframework.core.type.AnnotationMetadata; |  | ||||||
| import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; |  | ||||||
| import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler; |  | ||||||
| import org.springframework.security.authorization.method.AuthorizationMethodInterceptor; |  | ||||||
| import org.springframework.security.authorization.method.AuthorizationMethodInterceptors; |  | ||||||
| import org.springframework.security.authorization.method.DelegatingAuthorizationMethodInterceptor; |  | ||||||
| import org.springframework.security.authorization.method.Jsr250AuthorizationManager; |  | ||||||
| import org.springframework.security.authorization.method.PostAuthorizeAuthorizationManager; |  | ||||||
| import org.springframework.security.authorization.method.PostFilterAuthorizationMethodInterceptor; |  | ||||||
| import org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager; |  | ||||||
| import org.springframework.security.authorization.method.PreFilterAuthorizationMethodInterceptor; |  | ||||||
| import org.springframework.security.authorization.method.SecuredAuthorizationManager; |  | ||||||
| import org.springframework.security.config.core.GrantedAuthorityDefaults; |  | ||||||
| import org.springframework.util.Assert; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Base {@link Configuration} for enabling Spring Security Method Security. |  | ||||||
|  * |  | ||||||
|  * @author Evgeniy Cheban |  | ||||||
|  * @author Josh Cummings |  | ||||||
|  * @see EnableMethodSecurity |  | ||||||
|  * @since 5.5 |  | ||||||
|  */ |  | ||||||
| @Configuration(proxyBeanMethods = false) |  | ||||||
| @Role(BeanDefinition.ROLE_INFRASTRUCTURE) |  | ||||||
| final class MethodSecurityConfiguration implements ImportAware, InitializingBean { |  | ||||||
| 
 |  | ||||||
| 	private MethodSecurityExpressionHandler methodSecurityExpressionHandler; |  | ||||||
| 
 |  | ||||||
| 	private GrantedAuthorityDefaults grantedAuthorityDefaults; |  | ||||||
| 
 |  | ||||||
| 	private AuthorizationMethodInterceptor interceptor; |  | ||||||
| 
 |  | ||||||
| 	private AnnotationAttributes enableMethodSecurity; |  | ||||||
| 
 |  | ||||||
| 	@Bean |  | ||||||
| 	@Role(BeanDefinition.ROLE_INFRASTRUCTURE) |  | ||||||
| 	DefaultPointcutAdvisor methodSecurityAdvisor() { |  | ||||||
| 		AuthorizationMethodInterceptor interceptor = getInterceptor(); |  | ||||||
| 		DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(interceptor.getPointcut(), interceptor); |  | ||||||
| 		advisor.setOrder(order()); |  | ||||||
| 		return advisor; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private MethodSecurityExpressionHandler getMethodSecurityExpressionHandler() { |  | ||||||
| 		if (this.methodSecurityExpressionHandler == null) { |  | ||||||
| 			DefaultMethodSecurityExpressionHandler methodSecurityExpressionHandler = new DefaultMethodSecurityExpressionHandler(); |  | ||||||
| 			if (this.grantedAuthorityDefaults != null) { |  | ||||||
| 				methodSecurityExpressionHandler.setDefaultRolePrefix(this.grantedAuthorityDefaults.getRolePrefix()); |  | ||||||
| 			} |  | ||||||
| 			this.methodSecurityExpressionHandler = methodSecurityExpressionHandler; |  | ||||||
| 		} |  | ||||||
| 		return this.methodSecurityExpressionHandler; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@Autowired(required = false) |  | ||||||
| 	void setMethodSecurityExpressionHandler(MethodSecurityExpressionHandler methodSecurityExpressionHandler) { |  | ||||||
| 		this.methodSecurityExpressionHandler = methodSecurityExpressionHandler; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@Autowired(required = false) |  | ||||||
| 	void setGrantedAuthorityDefaults(GrantedAuthorityDefaults grantedAuthorityDefaults) { |  | ||||||
| 		this.grantedAuthorityDefaults = grantedAuthorityDefaults; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private AuthorizationMethodInterceptor getInterceptor() { |  | ||||||
| 		if (this.interceptor != null) { |  | ||||||
| 			return this.interceptor; |  | ||||||
| 		} |  | ||||||
| 		List<AuthorizationMethodInterceptor> interceptors = new ArrayList<>(); |  | ||||||
| 		interceptors.addAll(createDefaultAuthorizationMethodBeforeAdvice()); |  | ||||||
| 		interceptors.addAll(createDefaultAuthorizationMethodAfterAdvice()); |  | ||||||
| 		return new DelegatingAuthorizationMethodInterceptor(interceptors); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private List<AuthorizationMethodInterceptor> createDefaultAuthorizationMethodBeforeAdvice() { |  | ||||||
| 		List<AuthorizationMethodInterceptor> beforeAdvices = new ArrayList<>(); |  | ||||||
| 		beforeAdvices.add(getPreFilterAuthorizationMethodBeforeAdvice()); |  | ||||||
| 		beforeAdvices.add(getPreAuthorizeAuthorizationMethodBeforeAdvice()); |  | ||||||
| 		if (securedEnabled()) { |  | ||||||
| 			beforeAdvices.add(getSecuredAuthorizationMethodBeforeAdvice()); |  | ||||||
| 		} |  | ||||||
| 		if (jsr250Enabled()) { |  | ||||||
| 			beforeAdvices.add(getJsr250AuthorizationMethodBeforeAdvice()); |  | ||||||
| 		} |  | ||||||
| 		return beforeAdvices; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private PreFilterAuthorizationMethodInterceptor getPreFilterAuthorizationMethodBeforeAdvice() { |  | ||||||
| 		PreFilterAuthorizationMethodInterceptor interceptor = new PreFilterAuthorizationMethodInterceptor(); |  | ||||||
| 		interceptor.setExpressionHandler(getMethodSecurityExpressionHandler()); |  | ||||||
| 		return interceptor; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private AuthorizationMethodInterceptor getPreAuthorizeAuthorizationMethodBeforeAdvice() { |  | ||||||
| 		PreAuthorizeAuthorizationManager authorizationManager = new PreAuthorizeAuthorizationManager(); |  | ||||||
| 		authorizationManager.setExpressionHandler(getMethodSecurityExpressionHandler()); |  | ||||||
| 		return AuthorizationMethodInterceptors.preAuthorize(authorizationManager); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private AuthorizationMethodInterceptor getSecuredAuthorizationMethodBeforeAdvice() { |  | ||||||
| 		return AuthorizationMethodInterceptors.secured(new SecuredAuthorizationManager()); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private AuthorizationMethodInterceptor getJsr250AuthorizationMethodBeforeAdvice() { |  | ||||||
| 		Jsr250AuthorizationManager authorizationManager = new Jsr250AuthorizationManager(); |  | ||||||
| 		if (this.grantedAuthorityDefaults != null) { |  | ||||||
| 			authorizationManager.setRolePrefix(this.grantedAuthorityDefaults.getRolePrefix()); |  | ||||||
| 		} |  | ||||||
| 		return AuthorizationMethodInterceptors.jsr250(authorizationManager); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@Autowired(required = false) |  | ||||||
| 	void setAuthorizationMethodInterceptor(AuthorizationMethodInterceptor interceptor) { |  | ||||||
| 		this.interceptor = interceptor; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private List<AuthorizationMethodInterceptor> createDefaultAuthorizationMethodAfterAdvice() { |  | ||||||
| 		List<AuthorizationMethodInterceptor> afterAdvices = new ArrayList<>(); |  | ||||||
| 		afterAdvices.add(getPostFilterAuthorizationMethodAfterAdvice()); |  | ||||||
| 		afterAdvices.add(getPostAuthorizeAuthorizationMethodAfterAdvice()); |  | ||||||
| 		return afterAdvices; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private AuthorizationMethodInterceptor getPostFilterAuthorizationMethodAfterAdvice() { |  | ||||||
| 		PostFilterAuthorizationMethodInterceptor interceptor = new PostFilterAuthorizationMethodInterceptor(); |  | ||||||
| 		interceptor.setExpressionHandler(getMethodSecurityExpressionHandler()); |  | ||||||
| 		return interceptor; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private AuthorizationMethodInterceptor getPostAuthorizeAuthorizationMethodAfterAdvice() { |  | ||||||
| 		PostAuthorizeAuthorizationManager authorizationManager = new PostAuthorizeAuthorizationManager(); |  | ||||||
| 		authorizationManager.setExpressionHandler(getMethodSecurityExpressionHandler()); |  | ||||||
| 		return AuthorizationMethodInterceptors.postAuthorize(authorizationManager); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@Override |  | ||||||
| 	public void setImportMetadata(AnnotationMetadata importMetadata) { |  | ||||||
| 		Map<String, Object> attributes = importMetadata.getAnnotationAttributes(EnableMethodSecurity.class.getName()); |  | ||||||
| 		this.enableMethodSecurity = AnnotationAttributes.fromMap(attributes); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@Override |  | ||||||
| 	public void afterPropertiesSet() throws Exception { |  | ||||||
| 		if (!securedEnabled() && !jsr250Enabled()) { |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
| 		Assert.isNull(this.interceptor, |  | ||||||
| 				"You have specified your own advice, meaning that the annotation attributes securedEnabled and jsr250Enabled will be ignored. Please choose one or the other."); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private boolean securedEnabled() { |  | ||||||
| 		return this.enableMethodSecurity.getBoolean("securedEnabled"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private boolean jsr250Enabled() { |  | ||||||
| 		return this.enableMethodSecurity.getBoolean("jsr250Enabled"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private int order() { |  | ||||||
| 		return this.enableMethodSecurity.getNumber("order"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -1,50 +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.config.annotation.method.configuration; |  | ||||||
| 
 |  | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.List; |  | ||||||
| 
 |  | ||||||
| import org.springframework.context.annotation.AdviceMode; |  | ||||||
| import org.springframework.context.annotation.AdviceModeImportSelector; |  | ||||||
| import org.springframework.context.annotation.AutoProxyRegistrar; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Dynamically determines which imports to include using the {@link EnableMethodSecurity} |  | ||||||
|  * annotation. |  | ||||||
|  * |  | ||||||
|  * @author Evgeniy Cheban |  | ||||||
|  * @since 5.5 |  | ||||||
|  */ |  | ||||||
| final class MethodSecuritySelector extends AdviceModeImportSelector<EnableMethodSecurity> { |  | ||||||
| 
 |  | ||||||
| 	@Override |  | ||||||
| 	protected String[] selectImports(AdviceMode adviceMode) { |  | ||||||
| 		if (adviceMode == AdviceMode.PROXY) { |  | ||||||
| 			return getProxyImports(); |  | ||||||
| 		} |  | ||||||
| 		throw new IllegalStateException("AdviceMode '" + adviceMode + "' is not supported"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private String[] getProxyImports() { |  | ||||||
| 		List<String> result = new ArrayList<>(); |  | ||||||
| 		result.add(AutoProxyRegistrar.class.getName()); |  | ||||||
| 		result.add(MethodSecurityConfiguration.class.getName()); |  | ||||||
| 		return result.toArray(new String[0]); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -1,416 +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.config.annotation.method.configuration; |  | ||||||
| 
 |  | ||||||
| import java.io.Serializable; |  | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.Arrays; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.function.Supplier; |  | ||||||
| 
 |  | ||||||
| import org.aopalliance.intercept.MethodInvocation; |  | ||||||
| import org.junit.Rule; |  | ||||||
| import org.junit.Test; |  | ||||||
| import org.junit.runner.RunWith; |  | ||||||
| 
 |  | ||||||
| import org.springframework.aop.Pointcut; |  | ||||||
| import org.springframework.aop.support.JdkRegexpMethodPointcut; |  | ||||||
| import org.springframework.beans.factory.BeanCreationException; |  | ||||||
| import org.springframework.beans.factory.annotation.Autowired; |  | ||||||
| import org.springframework.context.annotation.Bean; |  | ||||||
| import org.springframework.security.access.AccessDeniedException; |  | ||||||
| import org.springframework.security.access.PermissionEvaluator; |  | ||||||
| import org.springframework.security.access.annotation.BusinessService; |  | ||||||
| import org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl; |  | ||||||
| import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; |  | ||||||
| import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler; |  | ||||||
| import org.springframework.security.authorization.AuthorizationDecision; |  | ||||||
| import org.springframework.security.authorization.AuthorizationManager; |  | ||||||
| import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor; |  | ||||||
| import org.springframework.security.authorization.method.AuthorizationMethodInterceptor; |  | ||||||
| import org.springframework.security.config.test.SpringTestRule; |  | ||||||
| import org.springframework.security.core.Authentication; |  | ||||||
| import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners; |  | ||||||
| import org.springframework.security.test.context.support.WithAnonymousUser; |  | ||||||
| import org.springframework.security.test.context.support.WithMockUser; |  | ||||||
| import org.springframework.test.context.junit4.SpringRunner; |  | ||||||
| 
 |  | ||||||
| import static org.assertj.core.api.Assertions.assertThat; |  | ||||||
| import static org.assertj.core.api.Assertions.assertThatExceptionOfType; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Tests for {@link MethodSecurityConfiguration}. |  | ||||||
|  * |  | ||||||
|  * @author Evgeniy Cheban |  | ||||||
|  */ |  | ||||||
| @RunWith(SpringRunner.class) |  | ||||||
| @SecurityTestExecutionListeners |  | ||||||
| public class MethodSecurityConfigurationTests { |  | ||||||
| 
 |  | ||||||
| 	@Rule |  | ||||||
| 	public final SpringTestRule spring = new SpringTestRule(); |  | ||||||
| 
 |  | ||||||
| 	@Autowired(required = false) |  | ||||||
| 	MethodSecurityService methodSecurityService; |  | ||||||
| 
 |  | ||||||
| 	@Autowired(required = false) |  | ||||||
| 	BusinessService businessService; |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser(roles = "ADMIN") |  | ||||||
| 	@Test |  | ||||||
| 	public void preAuthorizeWhenRoleAdminThenAccessDeniedException() { |  | ||||||
| 		this.spring.register(MethodSecurityServiceConfig.class).autowire(); |  | ||||||
| 		assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::preAuthorize) |  | ||||||
| 				.withMessage("Access Denied"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithAnonymousUser |  | ||||||
| 	@Test |  | ||||||
| 	public void preAuthorizePermitAllWhenRoleAnonymousThenPasses() { |  | ||||||
| 		this.spring.register(MethodSecurityServiceConfig.class).autowire(); |  | ||||||
| 		String result = this.methodSecurityService.preAuthorizePermitAll(); |  | ||||||
| 		assertThat(result).isNull(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithAnonymousUser |  | ||||||
| 	@Test |  | ||||||
| 	public void preAuthorizeNotAnonymousWhenRoleAnonymousThenAccessDeniedException() { |  | ||||||
| 		this.spring.register(MethodSecurityServiceConfig.class).autowire(); |  | ||||||
| 		assertThatExceptionOfType(AccessDeniedException.class) |  | ||||||
| 				.isThrownBy(this.methodSecurityService::preAuthorizeNotAnonymous).withMessage("Access Denied"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser |  | ||||||
| 	@Test |  | ||||||
| 	public void preAuthorizeNotAnonymousWhenRoleUserThenPasses() { |  | ||||||
| 		this.spring.register(MethodSecurityServiceConfig.class).autowire(); |  | ||||||
| 		this.methodSecurityService.preAuthorizeNotAnonymous(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser |  | ||||||
| 	@Test |  | ||||||
| 	public void securedWhenRoleUserThenAccessDeniedException() { |  | ||||||
| 		this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire(); |  | ||||||
| 		assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::secured) |  | ||||||
| 				.withMessage("Access Denied"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser(roles = "ADMIN") |  | ||||||
| 	@Test |  | ||||||
| 	public void securedWhenRoleAdminThenPasses() { |  | ||||||
| 		this.spring.register(MethodSecurityServiceConfig.class).autowire(); |  | ||||||
| 		String result = this.methodSecurityService.secured(); |  | ||||||
| 		assertThat(result).isNull(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser(roles = "ADMIN") |  | ||||||
| 	@Test |  | ||||||
| 	public void securedUserWhenRoleAdminThenAccessDeniedException() { |  | ||||||
| 		this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire(); |  | ||||||
| 		assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::securedUser) |  | ||||||
| 				.withMessage("Access Denied"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser |  | ||||||
| 	@Test |  | ||||||
| 	public void securedUserWhenRoleUserThenPasses() { |  | ||||||
| 		this.spring.register(MethodSecurityServiceConfig.class).autowire(); |  | ||||||
| 		String result = this.methodSecurityService.securedUser(); |  | ||||||
| 		assertThat(result).isNull(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser |  | ||||||
| 	@Test |  | ||||||
| 	public void preAuthorizeAdminWhenRoleUserThenAccessDeniedException() { |  | ||||||
| 		this.spring.register(MethodSecurityServiceConfig.class).autowire(); |  | ||||||
| 		assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::preAuthorizeAdmin) |  | ||||||
| 				.withMessage("Access Denied"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser(roles = "ADMIN") |  | ||||||
| 	@Test |  | ||||||
| 	public void preAuthorizeAdminWhenRoleAdminThenPasses() { |  | ||||||
| 		this.spring.register(MethodSecurityServiceConfig.class).autowire(); |  | ||||||
| 		this.methodSecurityService.preAuthorizeAdmin(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser |  | ||||||
| 	@Test |  | ||||||
| 	public void postHasPermissionWhenParameterIsNotGrantThenAccessDeniedException() { |  | ||||||
| 		this.spring.register(CustomPermissionEvaluatorConfig.class, MethodSecurityServiceConfig.class).autowire(); |  | ||||||
| 		assertThatExceptionOfType(AccessDeniedException.class) |  | ||||||
| 				.isThrownBy(() -> this.methodSecurityService.postHasPermission("deny")).withMessage("Access Denied"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser |  | ||||||
| 	@Test |  | ||||||
| 	public void postHasPermissionWhenParameterIsGrantThenPasses() { |  | ||||||
| 		this.spring.register(CustomPermissionEvaluatorConfig.class, MethodSecurityServiceConfig.class).autowire(); |  | ||||||
| 		String result = this.methodSecurityService.postHasPermission("grant"); |  | ||||||
| 		assertThat(result).isNull(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser |  | ||||||
| 	@Test |  | ||||||
| 	public void postAnnotationWhenParameterIsNotGrantThenAccessDeniedException() { |  | ||||||
| 		this.spring.register(MethodSecurityServiceConfig.class).autowire(); |  | ||||||
| 		assertThatExceptionOfType(AccessDeniedException.class) |  | ||||||
| 				.isThrownBy(() -> this.methodSecurityService.postAnnotation("deny")).withMessage("Access Denied"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser |  | ||||||
| 	@Test |  | ||||||
| 	public void postAnnotationWhenParameterIsGrantThenPasses() { |  | ||||||
| 		this.spring.register(MethodSecurityServiceConfig.class).autowire(); |  | ||||||
| 		String result = this.methodSecurityService.postAnnotation("grant"); |  | ||||||
| 		assertThat(result).isNull(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser("bob") |  | ||||||
| 	@Test |  | ||||||
| 	public void methodReturningAListWhenPrePostFiltersConfiguredThenFiltersList() { |  | ||||||
| 		this.spring.register(BusinessServiceConfig.class).autowire(); |  | ||||||
| 		List<String> names = new ArrayList<>(); |  | ||||||
| 		names.add("bob"); |  | ||||||
| 		names.add("joe"); |  | ||||||
| 		names.add("sam"); |  | ||||||
| 		List<?> result = this.businessService.methodReturningAList(names); |  | ||||||
| 		assertThat(result).hasSize(1); |  | ||||||
| 		assertThat(result.get(0)).isEqualTo("bob"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser("bob") |  | ||||||
| 	@Test |  | ||||||
| 	public void methodReturningAnArrayWhenPostFilterConfiguredThenFiltersArray() { |  | ||||||
| 		this.spring.register(BusinessServiceConfig.class).autowire(); |  | ||||||
| 		List<String> names = new ArrayList<>(); |  | ||||||
| 		names.add("bob"); |  | ||||||
| 		names.add("joe"); |  | ||||||
| 		names.add("sam"); |  | ||||||
| 		Object[] result = this.businessService.methodReturningAnArray(names.toArray()); |  | ||||||
| 		assertThat(result).hasSize(1); |  | ||||||
| 		assertThat(result[0]).isEqualTo("bob"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser("bob") |  | ||||||
| 	@Test |  | ||||||
| 	public void securedUserWhenCustomBeforeAdviceConfiguredAndNameBobThenPasses() { |  | ||||||
| 		this.spring.register(CustomAuthorizationManagerBeforeAdviceConfig.class, MethodSecurityServiceConfig.class) |  | ||||||
| 				.autowire(); |  | ||||||
| 		String result = this.methodSecurityService.securedUser(); |  | ||||||
| 		assertThat(result).isNull(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser("joe") |  | ||||||
| 	@Test |  | ||||||
| 	public void securedUserWhenCustomBeforeAdviceConfiguredAndNameNotBobThenAccessDeniedException() { |  | ||||||
| 		this.spring.register(CustomAuthorizationManagerBeforeAdviceConfig.class, MethodSecurityServiceConfig.class) |  | ||||||
| 				.autowire(); |  | ||||||
| 		assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::securedUser) |  | ||||||
| 				.withMessage("Access Denied"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser("bob") |  | ||||||
| 	@Test |  | ||||||
| 	public void securedUserWhenCustomAfterAdviceConfiguredAndNameBobThenGranted() { |  | ||||||
| 		this.spring.register(CustomAuthorizationManagerAfterAdviceConfig.class, MethodSecurityServiceConfig.class) |  | ||||||
| 				.autowire(); |  | ||||||
| 		String result = this.methodSecurityService.securedUser(); |  | ||||||
| 		assertThat(result).isEqualTo("granted"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser("joe") |  | ||||||
| 	@Test |  | ||||||
| 	public void securedUserWhenCustomAfterAdviceConfiguredAndNameNotBobThenAccessDeniedException() { |  | ||||||
| 		this.spring.register(CustomAuthorizationManagerAfterAdviceConfig.class, MethodSecurityServiceConfig.class) |  | ||||||
| 				.autowire(); |  | ||||||
| 		assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::securedUser) |  | ||||||
| 				.withMessage("Access Denied for User 'joe'"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser(roles = "ADMIN") |  | ||||||
| 	@Test |  | ||||||
| 	public void jsr250WhenRoleAdminThenAccessDeniedException() { |  | ||||||
| 		this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire(); |  | ||||||
| 		assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::jsr250) |  | ||||||
| 				.withMessage("Access Denied"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithAnonymousUser |  | ||||||
| 	@Test |  | ||||||
| 	public void jsr250PermitAllWhenRoleAnonymousThenPasses() { |  | ||||||
| 		this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire(); |  | ||||||
| 		String result = this.methodSecurityService.jsr250PermitAll(); |  | ||||||
| 		assertThat(result).isNull(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser(roles = "ADMIN") |  | ||||||
| 	@Test |  | ||||||
| 	public void rolesAllowedUserWhenRoleAdminThenAccessDeniedException() { |  | ||||||
| 		this.spring.register(BusinessServiceConfig.class).autowire(); |  | ||||||
| 		assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.businessService::rolesAllowedUser) |  | ||||||
| 				.withMessage("Access Denied"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser |  | ||||||
| 	@Test |  | ||||||
| 	public void rolesAllowedUserWhenRoleUserThenPasses() { |  | ||||||
| 		this.spring.register(BusinessServiceConfig.class).autowire(); |  | ||||||
| 		this.businessService.rolesAllowedUser(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser(roles = { "ADMIN", "USER" }) |  | ||||||
| 	@Test |  | ||||||
| 	public void manyAnnotationsWhenMeetsConditionsThenReturnsFilteredList() throws Exception { |  | ||||||
| 		List<String> names = Arrays.asList("harold", "jonathan", "pete", "bo"); |  | ||||||
| 		this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire(); |  | ||||||
| 		List<String> filtered = this.methodSecurityService.manyAnnotations(new ArrayList<>(names)); |  | ||||||
| 		assertThat(filtered).hasSize(2); |  | ||||||
| 		assertThat(filtered).containsExactly("harold", "jonathan"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser |  | ||||||
| 	@Test |  | ||||||
| 	public void manyAnnotationsWhenUserThenFails() { |  | ||||||
| 		List<String> names = Arrays.asList("harold", "jonathan", "pete", "bo"); |  | ||||||
| 		this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire(); |  | ||||||
| 		assertThatExceptionOfType(AccessDeniedException.class) |  | ||||||
| 				.isThrownBy(() -> this.methodSecurityService.manyAnnotations(new ArrayList<>(names))); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser |  | ||||||
| 	@Test |  | ||||||
| 	public void manyAnnotationsWhenShortListThenFails() { |  | ||||||
| 		List<String> names = Arrays.asList("harold", "jonathan", "pete"); |  | ||||||
| 		this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire(); |  | ||||||
| 		assertThatExceptionOfType(AccessDeniedException.class) |  | ||||||
| 				.isThrownBy(() -> this.methodSecurityService.manyAnnotations(new ArrayList<>(names))); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@WithMockUser(roles = "ADMIN") |  | ||||||
| 	@Test |  | ||||||
| 	public void manyAnnotationsWhenAdminThenFails() { |  | ||||||
| 		List<String> names = Arrays.asList("harold", "jonathan", "pete", "bo"); |  | ||||||
| 		this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire(); |  | ||||||
| 		assertThatExceptionOfType(AccessDeniedException.class) |  | ||||||
| 				.isThrownBy(() -> this.methodSecurityService.manyAnnotations(new ArrayList<>(names))); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@Test |  | ||||||
| 	public void configureWhenCustomAdviceAndSecureEnabledThenException() { |  | ||||||
| 		assertThatExceptionOfType(BeanCreationException.class).isThrownBy(() -> this.spring |  | ||||||
| 				.register(CustomAuthorizationManagerBeforeAdviceConfig.class, MethodSecurityServiceEnabledConfig.class) |  | ||||||
| 				.autowire()); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@EnableMethodSecurity |  | ||||||
| 	static class MethodSecurityServiceConfig { |  | ||||||
| 
 |  | ||||||
| 		@Bean |  | ||||||
| 		MethodSecurityService methodSecurityService() { |  | ||||||
| 			return new MethodSecurityServiceImpl(); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@EnableMethodSecurity(jsr250Enabled = true) |  | ||||||
| 	static class BusinessServiceConfig { |  | ||||||
| 
 |  | ||||||
| 		@Bean |  | ||||||
| 		BusinessService businessService() { |  | ||||||
| 			return new ExpressionProtectedBusinessServiceImpl(); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@EnableMethodSecurity(securedEnabled = true, jsr250Enabled = true) |  | ||||||
| 	static class MethodSecurityServiceEnabledConfig { |  | ||||||
| 
 |  | ||||||
| 		@Bean |  | ||||||
| 		MethodSecurityService methodSecurityService() { |  | ||||||
| 			return new MethodSecurityServiceImpl(); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@EnableMethodSecurity |  | ||||||
| 	static class CustomPermissionEvaluatorConfig { |  | ||||||
| 
 |  | ||||||
| 		@Bean |  | ||||||
| 		MethodSecurityExpressionHandler methodSecurityExpressionHandler() { |  | ||||||
| 			DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler(); |  | ||||||
| 			expressionHandler.setPermissionEvaluator(new PermissionEvaluator() { |  | ||||||
| 				@Override |  | ||||||
| 				public boolean hasPermission(Authentication authentication, Object targetDomainObject, |  | ||||||
| 						Object permission) { |  | ||||||
| 					return "grant".equals(targetDomainObject); |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				@Override |  | ||||||
| 				public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, |  | ||||||
| 						Object permission) { |  | ||||||
| 					throw new UnsupportedOperationException(); |  | ||||||
| 				} |  | ||||||
| 			}); |  | ||||||
| 			return expressionHandler; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@EnableMethodSecurity |  | ||||||
| 	static class CustomAuthorizationManagerBeforeAdviceConfig { |  | ||||||
| 
 |  | ||||||
| 		@Bean |  | ||||||
| 		AuthorizationMethodInterceptor customBeforeAdvice() { |  | ||||||
| 			JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut(); |  | ||||||
| 			pointcut.setPattern(".*MethodSecurityServiceImpl.*securedUser"); |  | ||||||
| 			AuthorizationManager<MethodInvocation> authorizationManager = (a, |  | ||||||
| 					o) -> new AuthorizationDecision("bob".equals(a.get().getName())); |  | ||||||
| 			return new AuthorizationManagerBeforeMethodInterceptor(pointcut, authorizationManager); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@EnableMethodSecurity |  | ||||||
| 	static class CustomAuthorizationManagerAfterAdviceConfig { |  | ||||||
| 
 |  | ||||||
| 		@Bean |  | ||||||
| 
 |  | ||||||
| 		AuthorizationMethodInterceptor customAfterAdvice() { |  | ||||||
| 			JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut(); |  | ||||||
| 			pointcut.setPattern(".*MethodSecurityServiceImpl.*securedUser"); |  | ||||||
| 			AuthorizationMethodInterceptor interceptor = new AuthorizationMethodInterceptor() { |  | ||||||
| 				@Override |  | ||||||
| 				public Pointcut getPointcut() { |  | ||||||
| 					return pointcut; |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				@Override |  | ||||||
| 				public Object invoke(Supplier<Authentication> authentication, MethodInvocation mi) { |  | ||||||
| 					Authentication auth = authentication.get(); |  | ||||||
| 					if ("bob".equals(auth.getName())) { |  | ||||||
| 						return "granted"; |  | ||||||
| 					} |  | ||||||
| 					throw new AccessDeniedException("Access Denied for User '" + auth.getName() + "'"); |  | ||||||
| 				} |  | ||||||
| 			}; |  | ||||||
| 			return interceptor; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -16,16 +16,12 @@ | |||||||
| 
 | 
 | ||||||
| package org.springframework.security.config.annotation.method.configuration; | package org.springframework.security.config.annotation.method.configuration; | ||||||
| 
 | 
 | ||||||
| import java.util.List; |  | ||||||
| 
 |  | ||||||
| import javax.annotation.security.DenyAll; | import javax.annotation.security.DenyAll; | ||||||
| import javax.annotation.security.PermitAll; | import javax.annotation.security.PermitAll; | ||||||
| 
 | 
 | ||||||
| import org.springframework.security.access.annotation.Secured; | import org.springframework.security.access.annotation.Secured; | ||||||
| import org.springframework.security.access.prepost.PostAuthorize; | 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.PreAuthorize; | ||||||
| import org.springframework.security.access.prepost.PreFilter; |  | ||||||
| import org.springframework.security.core.Authentication; | import org.springframework.security.core.Authentication; | ||||||
| import org.springframework.security.core.parameters.P; | import org.springframework.security.core.parameters.P; | ||||||
| 
 | 
 | ||||||
| @ -73,11 +69,4 @@ public interface MethodSecurityService { | |||||||
| 	@PostAuthorize("#o?.contains('grant')") | 	@PostAuthorize("#o?.contains('grant')") | ||||||
| 	String postAnnotation(@P("o") String object); | 	String postAnnotation(@P("o") String object); | ||||||
| 
 | 
 | ||||||
| 	@PreFilter("filterObject.length > 3") |  | ||||||
| 	@PreAuthorize("hasRole('ADMIN')") |  | ||||||
| 	@Secured("ROLE_USER") |  | ||||||
| 	@PostFilter("filterObject.length > 5") |  | ||||||
| 	@PostAuthorize("returnObject.size > 1") |  | ||||||
| 	List<String> manyAnnotations(List<String> array); |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -16,8 +16,6 @@ | |||||||
| 
 | 
 | ||||||
| package org.springframework.security.config.annotation.method.configuration; | package org.springframework.security.config.annotation.method.configuration; | ||||||
| 
 | 
 | ||||||
| import java.util.List; |  | ||||||
| 
 |  | ||||||
| import org.springframework.security.core.Authentication; | import org.springframework.security.core.Authentication; | ||||||
| import org.springframework.security.core.context.SecurityContextHolder; | import org.springframework.security.core.context.SecurityContextHolder; | ||||||
| 
 | 
 | ||||||
| @ -88,9 +86,4 @@ public class MethodSecurityServiceImpl implements MethodSecurityService { | |||||||
| 		return null; | 		return null; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override |  | ||||||
| 	public List<String> manyAnnotations(List<String> object) { |  | ||||||
| 		return object; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -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"); |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  * you may not use this file except in compliance with 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 | 	 * @return the new instance | ||||||
| 	 */ | 	 */ | ||||||
| 	public static <T> AuthorityAuthorizationManager<T> hasAnyRole(String... roles) { | 	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.notEmpty(roles, "roles cannot be empty"); | ||||||
| 		Assert.noNullElements(roles, "roles cannot contain null values"); | 		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); | 		return new AuthorityAuthorizationManager<>(authorities); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private static String[] toNamedRolesArray(String rolePrefix, String[] roles) { | 	private static String[] toNamedRolesArray(String... roles) { | ||||||
| 		String[] result = new String[roles.length]; | 		String[] result = new String[roles.length]; | ||||||
| 		for (int i = 0; i < roles.length; i++) { | 		for (int i = 0; i < roles.length; i++) { | ||||||
| 			result[i] = rolePrefix + roles[i]; | 			result[i] = ROLE_PREFIX + roles[i]; | ||||||
| 		} | 		} | ||||||
| 		return result; | 		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"); |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  * you may not use this file except in compliance with 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"); | 				.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 | 	@Test | ||||||
| 	public void hasAnyAuthorityWhenNullThenException() { | 	public void hasAnyAuthorityWhenNullThenException() { | ||||||
| 		assertThatIllegalArgumentException().isThrownBy(() -> AuthorityAuthorizationManager.hasAnyAuthority(null)) | 		assertThatIllegalArgumentException().isThrownBy(() -> AuthorityAuthorizationManager.hasAnyAuthority(null)) | ||||||
| @ -154,17 +147,6 @@ public class AuthorityAuthorizationManagerTests { | |||||||
| 		assertThat(manager.check(authentication, object).isGranted()).isFalse(); | 		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 | 	@Test | ||||||
| 	public void hasAnyAuthorityWhenUserHasAnyAuthorityThenGrantedDecision() { | 	public void hasAnyAuthorityWhenUserHasAnyAuthorityThenGrantedDecision() { | ||||||
| 		AuthorityAuthorizationManager<Object> manager = AuthorityAuthorizationManager.hasAnyAuthority("ADMIN", "USER"); | 		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() { |  | ||||||
| 
 |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -6,185 +6,6 @@ It provides support for JSR-250 annotation security as well as the framework's o | |||||||
| From 3.0 you can also make use of new <<el-access,expression-based annotations>>. | From 3.0 you can also make use of new <<el-access,expression-based annotations>>. | ||||||
| You can apply security to a single bean, using the `intercept-methods` element to decorate the bean declaration, or you can secure multiple beans across the entire service layer using the AspectJ style pointcuts. | You can apply security to a single bean, using the `intercept-methods` element to decorate the bean declaration, or you can secure multiple beans across the entire service layer using the AspectJ style pointcuts. | ||||||
| 
 | 
 | ||||||
| === EnableMethodSecurity |  | ||||||
| 
 |  | ||||||
| In 5.5, we can enable annotation-based security using the `@EnableMethodSecurity` annotation on any `@Configuration` instance. |  | ||||||
| 
 |  | ||||||
| [NOTE] |  | ||||||
| For earlier versions, please read about similar support with <<jc-enable-global-method-security, @EnableGlobalMethodSecurity>>. |  | ||||||
| 
 |  | ||||||
| For example, the following would enable Spring Security's `@PreAuthorize` annotation: |  | ||||||
| 
 |  | ||||||
| [source,java] |  | ||||||
| ---- |  | ||||||
| @EnableMethodSecurity |  | ||||||
| public class MethodSecurityConfig { |  | ||||||
| 	// ... |  | ||||||
| } |  | ||||||
| ---- |  | ||||||
| 
 |  | ||||||
| Adding an annotation to a method (on a class or interface) would then limit the access to that method accordingly. |  | ||||||
| Spring Security's native annotatino support defines a set of attributes for the method. |  | ||||||
| These will be passed to the `DefaultAuthorizationMethodInterceptorChain` for it to make the actual decision: |  | ||||||
| 
 |  | ||||||
| [source,java] |  | ||||||
| ---- |  | ||||||
| public interface BankService { |  | ||||||
| 
 |  | ||||||
| 	@PreAuthorize("hasRole('USER')") |  | ||||||
|     Account readAccount(Long id); |  | ||||||
| 
 |  | ||||||
| 	@PreAuthorize("hasRole('USER')") |  | ||||||
|     Account[] findAccounts(); |  | ||||||
| 
 |  | ||||||
| 	@PreAuthorize("hasRole('TELLER')") |  | ||||||
|     Account post(Account account, double amount); |  | ||||||
| } |  | ||||||
| ---- |  | ||||||
| 
 |  | ||||||
| You can enable support for Spring Security's `@Secured` annotation using: |  | ||||||
| 
 |  | ||||||
| [source,java] |  | ||||||
| ---- |  | ||||||
| @EnableMethodSecurity(secureEnabled = true) |  | ||||||
| public class MethodSecurityConfig { |  | ||||||
| 	// ... |  | ||||||
| } |  | ||||||
| ---- |  | ||||||
| 
 |  | ||||||
| or JSR-250 using: |  | ||||||
| 
 |  | ||||||
| [source,java] |  | ||||||
| ---- |  | ||||||
| @EnableMethodSecurity(jsr250Enabled = true) |  | ||||||
| public class MethodSecurityConfig { |  | ||||||
| 	// ... |  | ||||||
| } |  | ||||||
| ---- |  | ||||||
| 
 |  | ||||||
| ==== Customizing Authorization |  | ||||||
| 
 |  | ||||||
| Spring Security's `@PreAuthorize`, `@PostAuthorize`, `@PreFilter`, and `@PostFilter` ship with rich expression-based support. |  | ||||||
| 
 |  | ||||||
| If you need to customize the way that expressions are handled, you can expose a custom `MethodSecurityExpressionHandler`, like so: |  | ||||||
| 
 |  | ||||||
| [source,java] |  | ||||||
| ---- |  | ||||||
| @Bean |  | ||||||
| MethodSecurityExpressionHandler methodSecurityExpressionHandler() { |  | ||||||
|     DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler(); |  | ||||||
|     handler.setTrustResolver(myCustomTrustResolver); |  | ||||||
|     return handler; |  | ||||||
| } |  | ||||||
| ---- |  | ||||||
| 
 |  | ||||||
| Also, for role-based authorization, Spring Security adds a default `ROLE_` prefix, which is uses when evaluating expressions like `hasRole`. |  | ||||||
| 
 |  | ||||||
| You can configure the authorization rules to use a different prefix by exposing a `GrantedAuthorityDefaults` bean, like so: |  | ||||||
| 
 |  | ||||||
| [source,java] |  | ||||||
| ---- |  | ||||||
| @Bean |  | ||||||
| GrantedAuthorityDefaults grantedAuthorityDefaults() { |  | ||||||
| 	return new GrantedAuthorityDefaults("MYPREFIX_"); |  | ||||||
| } |  | ||||||
| ---- |  | ||||||
| 
 |  | ||||||
| ==== Custom Authorization Managers |  | ||||||
| 
 |  | ||||||
| Method authorization is a combination of before- and after-method authorization. |  | ||||||
| 
 |  | ||||||
| [NOTE] |  | ||||||
| Before-method authorization is performed before the method is invoked. |  | ||||||
| If that authorization denies access, the method is not invoked and an `AccessDeniedException` is thrown |  | ||||||
| After-method authorization is performed after the method is invoked, but before the method returns to the caller. |  | ||||||
| If that authorization denies access, the value is not returned and an `AccessDeniedException` is thrown |  | ||||||
| 
 |  | ||||||
| To recreate what Spring Security does by default, you would publish the following bean: |  | ||||||
| 
 |  | ||||||
| [source,java] |  | ||||||
| ---- |  | ||||||
| @Bean |  | ||||||
| public List<AuthorizationMethodInterceptor> methodSecurity() { |  | ||||||
| 	return new DelegatingAuthorizationMethodInterceptor( |  | ||||||
| 			new PreFilterAuthorizationMethodInterceptor(), // before-method |  | ||||||
|             AuthorizationMethodInterceptors.preAuthorize(), // before-method |  | ||||||
|             new PostFilterAuthorizationMethodInterceptor(), // after-method |  | ||||||
|             AuthorizationMethodInterceptors.postAuthorize() // after-method |  | ||||||
| 	); |  | ||||||
| } |  | ||||||
| ---- |  | ||||||
| 
 |  | ||||||
| [NOTE] |  | ||||||
| Keep in mind that publishing a list of `AuthorizationMethodInterceptor`s will completely replace any Spring Security defaults. |  | ||||||
| 
 |  | ||||||
| Interceptors are invoked in the order that they are declared. |  | ||||||
| 
 |  | ||||||
| You may want to only support `@PreAuthorize` in your application, in which case you can do the following: |  | ||||||
| 
 |  | ||||||
| [source,java] |  | ||||||
| ---- |  | ||||||
| @Bean |  | ||||||
| public AuthorizationMethodInterceptor methodSecurity() { |  | ||||||
| 	return AuthorizationMethodInterceptors.preAuthorize(); |  | ||||||
| } |  | ||||||
| ---- |  | ||||||
| 
 |  | ||||||
| Or, you may have a custom before-method `AuthorizationManager` that you want to add to the list. |  | ||||||
| 
 |  | ||||||
| In this case, you will need to tell Spring Security both the `AuthorizationManager` and to which methods and classes your authorization manager applies. |  | ||||||
| 
 |  | ||||||
| Spring Security integrates with Spring AOP to achieve this. |  | ||||||
| Thus, you can configure Spring Security to support `@PreAuthorize`, `@PostAuthorize`, and your own `AuthorizationManager` like so: |  | ||||||
| 
 |  | ||||||
| [source,java] |  | ||||||
| ---- |  | ||||||
| @Bean |  | ||||||
| public AuthorizationMethodInterceptor methodSecurity() { |  | ||||||
| 	JdkRegexpMethodPointcut pattern = new JdkRegexpMethodPointcut(); |  | ||||||
| 	pattern.setPattern("org.mycompany.myapp.service.*"); |  | ||||||
| 	AuthorizationManager<MethodInvocation> rule = AuthorityAuthorizationManager.isAuthenticated(); |  | ||||||
| 	return new DelegatingAuthorizationMethodInterceptor( |  | ||||||
| 			AuthorizationMethodInterceptors.preAuthorize(), |  | ||||||
|             new AuthorizationManagerBeforeMethodInterceptor(pattern, rule), |  | ||||||
|             AuthorizationMethodInterceptors.postAuthorize() |  | ||||||
| 	); |  | ||||||
| } |  | ||||||
| ---- |  | ||||||
| 
 |  | ||||||
| The same can be done for after-method authorization and `AfterMethodAuthorizationManager`. |  | ||||||
| After-method authorization is generally concerned with analysing the return value to verify access. |  | ||||||
| 
 |  | ||||||
| For example, you might have a method that confirms that the account requested actually belongs to the logged-in user like so: |  | ||||||
| 
 |  | ||||||
| [source,java] |  | ||||||
| ---- |  | ||||||
| public interface BankService { |  | ||||||
| 
 |  | ||||||
| 	@PreAuthorize("hasRole('USER')") |  | ||||||
| 	@PostAuthorize("returnObject.owner == authentication.name") |  | ||||||
| 	Account readAccount(Long id); |  | ||||||
| } |  | ||||||
| ---- |  | ||||||
| 
 |  | ||||||
| You can supply your own `AuthorizationMethodInterceptor` to customize how access to the return value is evaluated. |  | ||||||
| 
 |  | ||||||
| For example, instead of embedding a great deal of logic into the `@PostAuthorize` SpEL expression, you may want to wire your own `@Bean`. |  | ||||||
| In that case, you can configure it like so: |  | ||||||
| 
 |  | ||||||
| [source,java] |  | ||||||
| ---- |  | ||||||
| @Bean |  | ||||||
| public AuthorizationMethodInterceptor methodSecurity |  | ||||||
| 		(AfterMethodAuthorizationManager<MethodInvocation> rules) { |  | ||||||
| 	AnnotationMethodMatcher pattern = new AnnotationMethodMatcher(MySecurityAnnotation.class); |  | ||||||
| 	return new DelegatingAuthorizationMethodInterceptor( |  | ||||||
| 			AuthorizationMethodInterceptors.preAuthorize(), |  | ||||||
| 			new AuthorizationManagerAfterMethodInterceptor(pattern, rules)); |  | ||||||
| } |  | ||||||
| ---- |  | ||||||
| 
 |  | ||||||
| [[jc-enable-global-method-security]] |  | ||||||
| === EnableGlobalMethodSecurity | === EnableGlobalMethodSecurity | ||||||
| 
 | 
 | ||||||
| We can enable annotation-based security using the `@EnableGlobalMethodSecurity` annotation on any `@Configuration` instance. | We can enable annotation-based security using the `@EnableGlobalMethodSecurity` annotation on any `@Configuration` instance. | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user