diff --git a/docs/manual/src/docs/asciidoc/_includes/test.adoc b/docs/manual/src/docs/asciidoc/_includes/test.adoc index 7d6ac58f4a..0d21746ed2 100644 --- a/docs/manual/src/docs/asciidoc/_includes/test.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/test.adoc @@ -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 diff --git a/docs/manual/src/docs/asciidoc/index.adoc b/docs/manual/src/docs/asciidoc/index.adoc index c454e251bf..b9493012d8 100644 --- a/docs/manual/src/docs/asciidoc/index.adoc +++ b/docs/manual/src/docs/asciidoc/index.adoc @@ -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 + +* <> + +=== What's new in Spring Security 4.0 There are http://goo.gl/ui9GCl[175+ tickets resolved] with the Spring Security 4.0 release. diff --git a/test/src/main/java/org/springframework/security/test/context/support/WithSecurityContextTestExecutionListener.java b/test/src/main/java/org/springframework/security/test/context/support/WithSecurityContextTestExecutionListener.java index 8c6a02417b..1b24f43d11 100644 --- a/test/src/main/java/org/springframework/security/test/context/support/WithSecurityContextTestExecutionListener.java +++ b/test/src/main/java/org/springframework/security/test/context/support/WithSecurityContextTestExecutionListener.java @@ -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 type = (Class) 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; diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithAdminRob.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithAdminRob.java new file mode 100644 index 0000000000..6a491be925 --- /dev/null +++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithAdminRob.java @@ -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 { +} diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserAuthenticationTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserAuthenticationTests.java index 6791264d4f..29fde6580c 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserAuthenticationTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserAuthenticationTests.java @@ -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 {