SEC-3074: Add Test Meta Annotation Support

This commit is contained in:
Rob Winch 2015-08-19 14:01:05 -05:00
parent 55dd247660
commit 567c51e109
5 changed files with 93 additions and 19 deletions

View File

@ -249,6 +249,33 @@ final class WithUserDetailsSecurityContextFactory
}
----
[[test-method-meta-annotations]]
=== Test Meta Annotations
If you reuse the same user within your tests often, it is not ideal to have to repeatedly specify the attributes.
For example, if there are many tests related to an administrative user with the username "admin" and the roles `ROLE_USER` and `ROLE_ADMIN` you would have to write:
[source,java]
----
@WithMockUser(username="admin",roles={"USER","ADMIN"})
----
Rather than repeating this everywhere, we can use a meta annotation.
For example, we could create a meta annotation named `WithMockAdmin`:
[source,java]
----
@Retention(RetentionPolicy.RUNTIME)
@WithMockUser(value="rob",roles="ADMIN")
public @interface WithMockAdmin { }
----
Now we can use `@WithMockAdmin` in the same way as the more verbose `@WithMockUser`.
Meta annotations work with any of the testing annotations described above.
For example, this means we could create a meta annotation for `@WithUserDetails("admin")` as well.
[[test-mockmvc]]
== Spring MVC Test Integration

View File

@ -367,7 +367,11 @@ git clone https://github.com/spring-projects/spring-security.git
This will give you access to the entire project history (including all releases and branches) on your local machine.
[[new]]
== What's new in Spring Security 4.0
== What's new in Spring Security 4.1
* <<test-method-meta-annotations>>
=== What's new in Spring Security 4.0
There are http://goo.gl/ui9GCl[175+ tickets resolved] with the Spring Security 4.0 release.

View File

@ -16,10 +16,13 @@
package org.springframework.security.test.context.support;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.TypeVariable;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.security.core.context.SecurityContext;
@ -59,13 +62,10 @@ public class WithSecurityContextTestExecutionListener extends
*/
@Override
public void beforeTestMethod(TestContext testContext) throws Exception {
Annotation[] methodAnnotations = AnnotationUtils.getAnnotations(testContext
.getTestMethod());
SecurityContext securityContext = createSecurityContext(methodAnnotations,
SecurityContext securityContext = createSecurityContext(testContext.getTestMethod(),
testContext);
if (securityContext == null) {
Annotation[] classAnnotations = testContext.getTestClass().getAnnotations();
securityContext = createSecurityContext(classAnnotations, testContext);
securityContext = createSecurityContext(testContext.getTestClass(), testContext);
}
if (securityContext != null) {
TestSecurityContextHolder.setContext(securityContext);
@ -73,20 +73,20 @@ public class WithSecurityContextTestExecutionListener extends
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private SecurityContext createSecurityContext(Annotation[] annotations,
private SecurityContext createSecurityContext(AnnotatedElement annotated,
TestContext context) {
for (Annotation a : annotations) {
WithSecurityContext withUser = AnnotationUtils.findAnnotation(
a.annotationType(), WithSecurityContext.class);
if (withUser != null) {
WithSecurityContextFactory factory = createFactory(withUser, context);
try {
return factory.createSecurityContext(a);
}
catch (RuntimeException e) {
throw new IllegalStateException(
"Unable to create SecurityContext using " + a, e);
}
WithSecurityContext withUser = AnnotationUtils.findAnnotation(
annotated, WithSecurityContext.class);
if (withUser != null) {
WithSecurityContextFactory factory = createFactory(withUser, context);
Class<? extends Annotation> type = (Class<? extends Annotation>) GenericTypeResolver.resolveTypeArgument(factory.getClass(), WithSecurityContextFactory.class);
Annotation annotation = AnnotationUtils.findAnnotation(annotated, type);
try {
return factory.createSecurityContext(annotation);
}
catch (RuntimeException e) {
throw new IllegalStateException(
"Unable to create SecurityContext using " + annotation, e);
}
}
return null;

View File

@ -0,0 +1,33 @@
/*
* 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.test.web.servlet.showcase.secured;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.security.test.context.support.WithMockUser;
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@WithMockUser(value="rob",roles="ADMIN")
public @interface WithAdminRob {
}

View File

@ -64,6 +64,16 @@ public class WithUserAuthenticationTests {
.andExpect(authenticated().withUsername("user"));
}
@Test
@WithAdminRob
public void requestProtectedUrlWithAdminRob() throws Exception {
mvc.perform(get("/"))
// Ensure we got past Security
.andExpect(status().isNotFound())
// Ensure it appears we are authenticated with user
.andExpect(authenticated().withUsername("rob").withRoles("ADMIN"));
}
@Test
@WithMockUser(roles = "ADMIN")
public void requestProtectedUrlWithAdmin() throws Exception {