1616
1717package org .springframework .security .config .annotation .web .reactive ;
1818
19+ import java .lang .annotation .ElementType ;
20+ import java .lang .annotation .Retention ;
21+ import java .lang .annotation .RetentionPolicy ;
22+ import java .lang .annotation .Target ;
1923import java .net .URI ;
2024
2125import org .junit .jupiter .api .Test ;
2630import org .springframework .context .ApplicationContext ;
2731import org .springframework .context .annotation .Bean ;
2832import org .springframework .context .annotation .Configuration ;
33+ import org .springframework .security .authentication .TestingAuthenticationToken ;
2934import org .springframework .security .authentication .password .CompromisedPasswordDecision ;
3035import org .springframework .security .authentication .password .CompromisedPasswordException ;
3136import org .springframework .security .authentication .password .ReactiveCompromisedPasswordChecker ;
3439import org .springframework .security .config .test .SpringTestContextExtension ;
3540import org .springframework .security .config .users .ReactiveAuthenticationTestConfiguration ;
3641import org .springframework .security .config .web .server .ServerHttpSecurity ;
42+ import org .springframework .security .core .Authentication ;
43+ import org .springframework .security .core .annotation .AnnotationTemplateExpressionDefaults ;
44+ import org .springframework .security .core .annotation .AuthenticationPrincipal ;
3745import org .springframework .security .core .userdetails .MapReactiveUserDetailsService ;
3846import org .springframework .security .core .userdetails .PasswordEncodedUser ;
47+ import org .springframework .security .core .userdetails .ReactiveUserDetailsService ;
3948import org .springframework .security .core .userdetails .User ;
4049import org .springframework .security .core .userdetails .UserDetails ;
4150import org .springframework .security .web .server .DefaultServerRedirectStrategy ;
4251import org .springframework .security .web .server .SecurityWebFilterChain ;
4352import org .springframework .test .web .reactive .server .WebTestClient ;
4453import org .springframework .util .LinkedMultiValueMap ;
4554import org .springframework .util .MultiValueMap ;
55+ import org .springframework .web .bind .annotation .GetMapping ;
56+ import org .springframework .web .bind .annotation .RestController ;
4657import org .springframework .web .reactive .config .EnableWebFlux ;
4758import org .springframework .web .reactive .function .BodyInserters ;
4859import org .springframework .web .server .adapter .WebHttpHandlerBuilder ;
4960
5061import static org .assertj .core .api .Assertions .assertThat ;
5162import static org .springframework .security .test .web .reactive .server .SecurityMockServerConfigurers .csrf ;
63+ import static org .springframework .security .test .web .reactive .server .SecurityMockServerConfigurers .mockAuthentication ;
64+ import static org .springframework .security .test .web .reactive .server .SecurityMockServerConfigurers .springSecurity ;
5265
5366/**
5467 * Tests for {@link ServerHttpSecurityConfiguration}.
@@ -67,7 +80,10 @@ void setup(ApplicationContext context) {
6780 if (!context .containsBean (WebHttpHandlerBuilder .WEB_HANDLER_BEAN_NAME )) {
6881 return ;
6982 }
70- this .webClient = WebTestClient .bindToApplicationContext (context ).configureClient ().build ();
83+ this .webClient = WebTestClient .bindToApplicationContext (context )
84+ .apply (springSecurity ())
85+ .configureClient ()
86+ .build ();
7187 }
7288
7389 @ Test
@@ -146,6 +162,27 @@ void loginWhenCompromisedPasswordAndRedirectIfPasswordExceptionThenRedirectedToR
146162 // @formatter:on
147163 }
148164
165+ @ Test
166+ public void metaAnnotationWhenTemplateDefaultsBeanThenResolvesExpression () throws Exception {
167+ this .spring .register (MetaAnnotationPlaceholderConfig .class ).autowire ();
168+ Authentication user = new TestingAuthenticationToken ("user" , "password" , "ROLE_USER" );
169+ this .webClient .mutateWith (mockAuthentication (user ))
170+ .get ()
171+ .uri ("/hi" )
172+ .exchange ()
173+ .expectStatus ()
174+ .isOk ()
175+ .expectBody (String .class )
176+ .isEqualTo ("Hi, Stranger!" );
177+ Authentication harold = new TestingAuthenticationToken ("harold" , "password" , "ROLE_USER" );
178+ this .webClient .mutateWith (mockAuthentication (harold ))
179+ .get ()
180+ .uri ("/hi" )
181+ .exchange ()
182+ .expectBody (String .class )
183+ .isEqualTo ("Hi, Harold!" );
184+ }
185+
149186 @ Configuration
150187 static class SubclassConfig extends ServerHttpSecurityConfiguration {
151188
@@ -237,4 +274,61 @@ public Mono<CompromisedPasswordDecision> check(String password) {
237274
238275 }
239276
277+ @ Retention (RetentionPolicy .RUNTIME )
278+ @ Target (ElementType .PARAMETER )
279+ @ AuthenticationPrincipal (expression = "#this.equals('{value}')" )
280+ @interface IsUser {
281+
282+ String value () default "user" ;
283+
284+ }
285+
286+ @ RestController
287+ static class TestController {
288+
289+ @ GetMapping ("/hi" )
290+ String ifUser (@ IsUser ("harold" ) boolean isHarold ) {
291+ if (isHarold ) {
292+ return "Hi, Harold!" ;
293+ }
294+ else {
295+ return "Hi, Stranger!" ;
296+ }
297+ }
298+
299+ }
300+
301+ @ Configuration
302+ @ EnableWebFlux
303+ @ EnableWebFluxSecurity
304+ static class MetaAnnotationPlaceholderConfig {
305+
306+ @ Bean
307+ SecurityWebFilterChain filterChain (ServerHttpSecurity http ) {
308+ // @formatter:off
309+ http
310+ .authorizeExchange ((authorize ) -> authorize .anyExchange ().authenticated ())
311+ .httpBasic (Customizer .withDefaults ());
312+ // @formatter:on
313+ return http .build ();
314+ }
315+
316+ @ Bean
317+ ReactiveUserDetailsService userDetailsService () {
318+ return new MapReactiveUserDetailsService (
319+ User .withUsername ("user" ).password ("password" ).authorities ("app" ).build ());
320+ }
321+
322+ @ Bean
323+ TestController testController () {
324+ return new TestController ();
325+ }
326+
327+ @ Bean
328+ AnnotationTemplateExpressionDefaults templateExpressionDefaults () {
329+ return new AnnotationTemplateExpressionDefaults ();
330+ }
331+
332+ }
333+
240334}
0 commit comments