SEC-3076: Add Method Level Security Meta Annotations
This commit is contained in:
		
							parent
							
								
									7708129aad
								
							
						
					
					
						commit
						cbed1d75ee
					
				|  | @ -0,0 +1,39 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright 2002-2015 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 | ||||||
|  |  * | ||||||
|  |  *      http://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.method; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @author Rob Winch | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | public class Contact { | ||||||
|  | 	private String name; | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * @param name | ||||||
|  | 	 */ | ||||||
|  | 	public Contact(String name) { | ||||||
|  | 		super(); | ||||||
|  | 		this.name = name; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * @return the name | ||||||
|  | 	 */ | ||||||
|  | 	public String getName() { | ||||||
|  | 		return name; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,29 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright 2002-2015 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 | ||||||
|  |  * | ||||||
|  |  *      http://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.method; | ||||||
|  | 
 | ||||||
|  | import java.lang.annotation.Retention; | ||||||
|  | import java.lang.annotation.RetentionPolicy; | ||||||
|  | 
 | ||||||
|  | import org.springframework.security.access.prepost.PreAuthorize; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @author Rob Winch | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @Retention(RetentionPolicy.RUNTIME) | ||||||
|  | @PreAuthorize("#contact.name == authentication.name") | ||||||
|  | public @interface ContactPermission {} | ||||||
|  | @ -0,0 +1,31 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright 2002-2015 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 | ||||||
|  |  * | ||||||
|  |  *      http://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.method; | ||||||
|  | 
 | ||||||
|  | import java.lang.annotation.Retention; | ||||||
|  | import java.lang.annotation.RetentionPolicy; | ||||||
|  | 
 | ||||||
|  | import org.springframework.security.access.prepost.PreAuthorize; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @author Rob Winch | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @Retention(RetentionPolicy.RUNTIME) | ||||||
|  | @PreAuthorize("hasRole('ADMIN')") | ||||||
|  | public @interface PreAuthorizeAdminRole { | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,30 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright 2002-2015 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 | ||||||
|  |  * | ||||||
|  |  *      http://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.method; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @author Rob Winch | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | public class PreAuthorizeServiceImpl { | ||||||
|  | 
 | ||||||
|  | 	@PreAuthorizeAdminRole | ||||||
|  | 	public void preAuthorizeAdminRole() {} | ||||||
|  | 
 | ||||||
|  | 	@ContactPermission | ||||||
|  | 	public void contactPermission(Contact contact) {} | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,67 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright 2002-2015 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 | ||||||
|  |  * | ||||||
|  |  *      http://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.method; | ||||||
|  | 
 | ||||||
|  | import org.junit.After; | ||||||
|  | import org.junit.Test; | ||||||
|  | import org.junit.runner.RunWith; | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | import org.springframework.security.access.AccessDeniedException; | ||||||
|  | import org.springframework.security.authentication.TestingAuthenticationToken; | ||||||
|  | import org.springframework.security.core.context.SecurityContextHolder; | ||||||
|  | import org.springframework.test.context.ContextConfiguration; | ||||||
|  | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * | ||||||
|  |  * @author Rob Winch | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @RunWith(SpringJUnit4ClassRunner.class) | ||||||
|  | @ContextConfiguration | ||||||
|  | public class PreAuthorizeTests { | ||||||
|  | 	@Autowired | ||||||
|  | 	PreAuthorizeServiceImpl service; | ||||||
|  | 
 | ||||||
|  | 	@After | ||||||
|  | 	public void cleanup() { | ||||||
|  | 		SecurityContextHolder.clearContext(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test(expected = AccessDeniedException.class) | ||||||
|  | 	public void preAuthorizeAdminRoleDenied() { | ||||||
|  | 		SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "pass", "ROLE_USER")); | ||||||
|  | 		service.preAuthorizeAdminRole(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test | ||||||
|  | 	public void preAuthorizeAdminRoleGranted() { | ||||||
|  | 		SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "pass", "ROLE_ADMIN")); | ||||||
|  | 		service.preAuthorizeAdminRole(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test | ||||||
|  | 	public void preAuthorizeContactPermissionGranted() { | ||||||
|  | 		SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "pass", "ROLE_ADMIN")); | ||||||
|  | 		service.contactPermission(new Contact("user")); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test(expected = AccessDeniedException.class) | ||||||
|  | 	public void preAuthorizeContactPermissionDenied() { | ||||||
|  | 		SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "pass", "ROLE_ADMIN")); | ||||||
|  | 		service.contactPermission(new Contact("admin")); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,29 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright 2002-2015 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 | ||||||
|  |  * | ||||||
|  |  *      http://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.method; | ||||||
|  | 
 | ||||||
|  | import java.lang.annotation.Retention; | ||||||
|  | import java.lang.annotation.RetentionPolicy; | ||||||
|  | 
 | ||||||
|  | import org.springframework.security.access.annotation.Secured; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @author Rob Winch | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @Retention(RetentionPolicy.RUNTIME) | ||||||
|  | @Secured("ROLE_ADMIN") | ||||||
|  | public @interface  SecuredAdminRole { } | ||||||
|  | @ -0,0 +1,26 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright 2002-2015 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 | ||||||
|  |  * | ||||||
|  |  *      http://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.method; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  | * | ||||||
|  | * @author Rob Winch | ||||||
|  | * | ||||||
|  | */ | ||||||
|  | public class SecuredServiceImpl { | ||||||
|  | 	@SecuredAdminRole | ||||||
|  | 	public void securedAdminRole() {} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,55 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright 2002-2015 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 | ||||||
|  |  * | ||||||
|  |  *      http://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.method; | ||||||
|  | 
 | ||||||
|  | import org.junit.After; | ||||||
|  | import org.junit.Test; | ||||||
|  | import org.junit.runner.RunWith; | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | import org.springframework.security.access.AccessDeniedException; | ||||||
|  | import org.springframework.security.authentication.TestingAuthenticationToken; | ||||||
|  | import org.springframework.security.core.context.SecurityContextHolder; | ||||||
|  | import org.springframework.test.context.ContextConfiguration; | ||||||
|  | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * | ||||||
|  |  * @author Rob Winch | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @RunWith(SpringJUnit4ClassRunner.class) | ||||||
|  | @ContextConfiguration | ||||||
|  | public class SecuredTests { | ||||||
|  | 	@Autowired | ||||||
|  | 	SecuredServiceImpl service; | ||||||
|  | 
 | ||||||
|  | 	@After | ||||||
|  | 	public void cleanup() { | ||||||
|  | 		SecurityContextHolder.clearContext(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test(expected = AccessDeniedException.class) | ||||||
|  | 	public void securedAdminRoleDenied() { | ||||||
|  | 		SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "pass", "ROLE_USER")); | ||||||
|  | 		service.securedAdminRole(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test | ||||||
|  | 	public void securedAdminRoleGranted() { | ||||||
|  | 		SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "pass", "ROLE_ADMIN")); | ||||||
|  | 		service.securedAdminRole(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,13 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <b:beans xmlns:b="http://www.springframework.org/schema/beans" | ||||||
|  | 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||||
|  | 	xmlns="http://www.springframework.org/schema/security" | ||||||
|  | 	xmlns:c="http://www.springframework.org/schema/c" | ||||||
|  | 	xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd | ||||||
|  | 		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> | ||||||
|  | 
 | ||||||
|  | 	<global-method-security pre-post-annotations="enabled"/> | ||||||
|  | 
 | ||||||
|  | 	<b:bean class="org.springframework.security.config.method.PreAuthorizeServiceImpl"/> | ||||||
|  | 
 | ||||||
|  | </b:beans> | ||||||
|  | @ -0,0 +1,13 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <b:beans xmlns:b="http://www.springframework.org/schema/beans" | ||||||
|  | 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||||
|  | 	xmlns="http://www.springframework.org/schema/security" | ||||||
|  | 	xmlns:c="http://www.springframework.org/schema/c" | ||||||
|  | 	xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd | ||||||
|  | 		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> | ||||||
|  | 
 | ||||||
|  | 	<global-method-security secured-annotations="enabled"/> | ||||||
|  | 
 | ||||||
|  | 	<b:bean class="org.springframework.security.config.method.SecuredServiceImpl"/> | ||||||
|  | 
 | ||||||
|  | </b:beans> | ||||||
|  | @ -369,7 +369,9 @@ This will give you access to the entire project history (including all releases | ||||||
| [[new]] | [[new]] | ||||||
| == What's new in Spring Security 4.1 | == What's new in Spring Security 4.1 | ||||||
| 
 | 
 | ||||||
| * <<test-method-meta-annotations>> | * Meta Annotation Support | ||||||
|  | ** <<test-method-meta-annotations>> | ||||||
|  | ** <<method-security-meta-annotations>> | ||||||
| 
 | 
 | ||||||
| === What's new in Spring Security 4.0 | === What's new in Spring Security 4.0 | ||||||
| 
 | 
 | ||||||
|  | @ -4727,6 +4729,29 @@ To use `hasPermission()` expressions, you have to explicitly configure a `Permis | ||||||
| 
 | 
 | ||||||
| Where `myPermissionEvaluator` is the bean which implements `PermissionEvaluator`. Usually this will be the implementation from the ACL module which is called`AclPermissionEvaluator`. See the "Contacts" sample application configuration for more details. | Where `myPermissionEvaluator` is the bean which implements `PermissionEvaluator`. Usually this will be the implementation from the ACL module which is called`AclPermissionEvaluator`. See the "Contacts" sample application configuration for more details. | ||||||
| 
 | 
 | ||||||
|  | ===== Method Security Meta Annotations | ||||||
|  | 
 | ||||||
|  | You can make use of meta annotations for method security to make your code more readable. | ||||||
|  | This is especially convenient if you find that you are repeating the same complex expression throughout your code base. | ||||||
|  | For example, consider the following: | ||||||
|  | 
 | ||||||
|  | [source,java] | ||||||
|  | ---- | ||||||
|  | @PreAuthorize("#contact.name == authentication.name") | ||||||
|  | ---- | ||||||
|  | 
 | ||||||
|  | Instead of repeating this everywhere, we can create a meta annotation that can be used instead. | ||||||
|  | 
 | ||||||
|  | [source,java] | ||||||
|  | ---- | ||||||
|  | @Retention(RetentionPolicy.RUNTIME) | ||||||
|  | @PreAuthorize("#contact.name == authentication.name") | ||||||
|  | public @interface ContactPermission {} | ||||||
|  | ---- | ||||||
|  | 
 | ||||||
|  | Meta annotations can be used for any of the Spring Security method security annotations. | ||||||
|  | In order to remain compliant with the specification JSR-250 annotations do not support meta annotations. | ||||||
|  | 
 | ||||||
| [[advanced-topics]] | [[advanced-topics]] | ||||||
| = Additional Topics | = Additional Topics | ||||||
| In this part we cover features which require a knowledge of previous chapters as well as some of the more advanced and less-commonly used features of the framework. | In this part we cover features which require a knowledge of previous chapters as well as some of the more advanced and less-commonly used features of the framework. | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue