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]] | ||||
| == 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 | ||||
| 
 | ||||
|  | @ -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. | ||||
| 
 | ||||
| ===== 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]] | ||||
| = 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. | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue