16
16
17
17
package org .springframework .security .config .annotation .web .reactive ;
18
18
19
+ import java .lang .annotation .ElementType ;
20
+ import java .lang .annotation .Retention ;
21
+ import java .lang .annotation .RetentionPolicy ;
22
+ import java .lang .annotation .Target ;
19
23
import java .net .URI ;
20
24
21
25
import org .junit .jupiter .api .Test ;
26
30
import org .springframework .context .ApplicationContext ;
27
31
import org .springframework .context .annotation .Bean ;
28
32
import org .springframework .context .annotation .Configuration ;
33
+ import org .springframework .security .authentication .TestingAuthenticationToken ;
29
34
import org .springframework .security .authentication .password .CompromisedPasswordDecision ;
30
35
import org .springframework .security .authentication .password .CompromisedPasswordException ;
31
36
import org .springframework .security .authentication .password .ReactiveCompromisedPasswordChecker ;
34
39
import org .springframework .security .config .test .SpringTestContextExtension ;
35
40
import org .springframework .security .config .users .ReactiveAuthenticationTestConfiguration ;
36
41
import 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 ;
37
45
import org .springframework .security .core .userdetails .MapReactiveUserDetailsService ;
38
46
import org .springframework .security .core .userdetails .PasswordEncodedUser ;
47
+ import org .springframework .security .core .userdetails .ReactiveUserDetailsService ;
39
48
import org .springframework .security .core .userdetails .User ;
40
49
import org .springframework .security .core .userdetails .UserDetails ;
41
50
import org .springframework .security .web .server .DefaultServerRedirectStrategy ;
42
51
import org .springframework .security .web .server .SecurityWebFilterChain ;
43
52
import org .springframework .test .web .reactive .server .WebTestClient ;
44
53
import org .springframework .util .LinkedMultiValueMap ;
45
54
import org .springframework .util .MultiValueMap ;
55
+ import org .springframework .web .bind .annotation .GetMapping ;
56
+ import org .springframework .web .bind .annotation .RestController ;
46
57
import org .springframework .web .reactive .config .EnableWebFlux ;
47
58
import org .springframework .web .reactive .function .BodyInserters ;
48
59
import org .springframework .web .server .adapter .WebHttpHandlerBuilder ;
49
60
50
61
import static org .assertj .core .api .Assertions .assertThat ;
51
62
import 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 ;
52
65
53
66
/**
54
67
* Tests for {@link ServerHttpSecurityConfiguration}.
@@ -67,7 +80,10 @@ void setup(ApplicationContext context) {
67
80
if (!context .containsBean (WebHttpHandlerBuilder .WEB_HANDLER_BEAN_NAME )) {
68
81
return ;
69
82
}
70
- this .webClient = WebTestClient .bindToApplicationContext (context ).configureClient ().build ();
83
+ this .webClient = WebTestClient .bindToApplicationContext (context )
84
+ .apply (springSecurity ())
85
+ .configureClient ()
86
+ .build ();
71
87
}
72
88
73
89
@ Test
@@ -146,6 +162,27 @@ void loginWhenCompromisedPasswordAndRedirectIfPasswordExceptionThenRedirectedToR
146
162
// @formatter:on
147
163
}
148
164
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
+
149
186
@ Configuration
150
187
static class SubclassConfig extends ServerHttpSecurityConfiguration {
151
188
@@ -237,4 +274,61 @@ public Mono<CompromisedPasswordDecision> check(String password) {
237
274
238
275
}
239
276
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
+
240
334
}
0 commit comments