Skip to content

Commit a288ce4

Browse files
eleftheriasrwinch
authored andcommitted
Support nested builder in DSL for reactive apps
Fixes: gh-7107
1 parent ab6440d commit a288ce4

File tree

27 files changed

+1991
-205
lines changed

27 files changed

+1991
-205
lines changed

config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java

+678
Large diffs are not rendered by default.

config/src/test/java/org/springframework/security/config/web/server/AuthorizeExchangeSpecTests.java

+44-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -92,6 +92,39 @@ public void antMatchersWhenPatternsThenAnyMethod() {
9292
.expectStatus().isUnauthorized();
9393
}
9494

95+
@Test
96+
public void antMatchersWhenPatternsInLambdaThenAnyMethod() throws Exception {
97+
this.http
98+
.csrf(ServerHttpSecurity.CsrfSpec::disable)
99+
.authorizeExchange(exchanges ->
100+
exchanges
101+
.pathMatchers("/a", "/b").denyAll()
102+
.anyExchange().permitAll()
103+
);
104+
105+
WebTestClient client = buildClient();
106+
107+
client.get()
108+
.uri("/a")
109+
.exchange()
110+
.expectStatus().isUnauthorized();
111+
112+
client.get()
113+
.uri("/b")
114+
.exchange()
115+
.expectStatus().isUnauthorized();
116+
117+
client.post()
118+
.uri("/a")
119+
.exchange()
120+
.expectStatus().isUnauthorized();
121+
122+
client.post()
123+
.uri("/b")
124+
.exchange()
125+
.expectStatus().isUnauthorized();
126+
}
127+
95128
@Test(expected = IllegalStateException.class)
96129
public void antMatchersWhenNoAccessAndAnotherMatcherThenThrowsException() {
97130
this.http
@@ -117,6 +150,16 @@ public void buildWhenMatcherDefinedWithNoAccessThenThrowsException() {
117150
this.http.build();
118151
}
119152

153+
@Test(expected = IllegalStateException.class)
154+
public void buildWhenMatcherDefinedWithNoAccessInLambdaThenThrowsException() throws Exception {
155+
this.http
156+
.authorizeExchange(exchanges ->
157+
exchanges
158+
.pathMatchers("/incomplete")
159+
);
160+
this.http.build();
161+
}
162+
120163
private WebTestClient buildClient() {
121164
return WebTestClientBuilder.bindToWebFilters(this.http.build()).build();
122165
}

config/src/test/java/org/springframework/security/config/web/server/CorsSpecTests.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -74,6 +74,14 @@ public void corsWhenEnabledThenAccessControlAllowOriginAndSecurityHeaders() {
7474
assertHeaders();
7575
}
7676

77+
@Test
78+
public void corsWhenEnabledInLambdaThenAccessControlAllowOriginAndSecurityHeaders() throws Exception {
79+
this.http.cors(cors -> cors.configurationSource(this.source));
80+
this.expectedHeaders.set("Access-Control-Allow-Origin", "*");
81+
this.expectedHeaders.set("X-Frame-Options", "DENY");
82+
assertHeaders();
83+
}
84+
7785
@Test
7886
public void corsWhenCorsConfigurationSourceBeanThenAccessControlAllowOriginAndSecurityHeaders() {
7987
when(this.context.getBeanNamesForType(any(ResolvableType.class))).thenReturn(new String[] {"source"}, new String[0]);

config/src/test/java/org/springframework/security/config/web/server/ExceptionHandlingSpecTests.java

+102-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,6 +26,8 @@
2626
import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
2727
import org.springframework.test.web.reactive.server.WebTestClient;
2828

29+
import static org.springframework.security.config.Customizer.withDefaults;
30+
2931
/**
3032
* @author Denys Ivano
3133
* @since 5.0.5
@@ -56,6 +58,29 @@ public void defaultAuthenticationEntryPoint() {
5658
.expectHeader().valueMatches("WWW-Authenticate", "Basic.*");
5759
}
5860

61+
@Test
62+
public void requestWhenExceptionHandlingWithDefaultsInLambdaThenDefaultAuthenticationEntryPointUsed()
63+
throws Exception {
64+
SecurityWebFilterChain securityWebFilter = this.http
65+
.authorizeExchange(exchanges ->
66+
exchanges
67+
.anyExchange().authenticated()
68+
)
69+
.exceptionHandling(withDefaults())
70+
.build();
71+
72+
WebTestClient client = WebTestClientBuilder
73+
.bindToWebFilters(securityWebFilter)
74+
.build();
75+
76+
client
77+
.get()
78+
.uri("/test")
79+
.exchange()
80+
.expectStatus().isUnauthorized()
81+
.expectHeader().valueMatches("WWW-Authenticate", "Basic.*");
82+
}
83+
5984
@Test
6085
public void customAuthenticationEntryPoint() {
6186
SecurityWebFilterChain securityWebFilter = this.http
@@ -80,6 +105,31 @@ public void customAuthenticationEntryPoint() {
80105
.expectHeader().valueMatches("Location", ".*");
81106
}
82107

108+
@Test
109+
public void requestWhenCustomAuthenticationEntryPointInLambdaThenCustomAuthenticationEntryPointUsed() throws Exception {
110+
SecurityWebFilterChain securityWebFilter = this.http
111+
.authorizeExchange(exchanges ->
112+
exchanges
113+
.anyExchange().authenticated()
114+
)
115+
.exceptionHandling(exceptionHandling ->
116+
exceptionHandling
117+
.authenticationEntryPoint(redirectServerAuthenticationEntryPoint("/auth"))
118+
)
119+
.build();
120+
121+
WebTestClient client = WebTestClientBuilder
122+
.bindToWebFilters(securityWebFilter)
123+
.build();
124+
125+
client
126+
.get()
127+
.uri("/test")
128+
.exchange()
129+
.expectStatus().isFound()
130+
.expectHeader().valueMatches("Location", ".*");
131+
}
132+
83133
@Test
84134
public void defaultAccessDeniedHandler() {
85135
SecurityWebFilterChain securityWebFilter = this.http
@@ -104,6 +154,30 @@ public void defaultAccessDeniedHandler() {
104154
.expectStatus().isForbidden();
105155
}
106156

157+
@Test
158+
public void requestWhenExceptionHandlingWithDefaultsInLambdaThenDefaultAccessDeniedHandlerUsed()
159+
throws Exception {
160+
SecurityWebFilterChain securityWebFilter = this.http
161+
.httpBasic(withDefaults())
162+
.authorizeExchange(exchanges ->
163+
exchanges
164+
.anyExchange().hasRole("ADMIN")
165+
)
166+
.exceptionHandling(withDefaults())
167+
.build();
168+
169+
WebTestClient client = WebTestClientBuilder
170+
.bindToWebFilters(securityWebFilter)
171+
.build();
172+
173+
client
174+
.get()
175+
.uri("/admin")
176+
.headers(headers -> headers.setBasicAuth("user", "password"))
177+
.exchange()
178+
.expectStatus().isForbidden();
179+
}
180+
107181
@Test
108182
public void customAccessDeniedHandler() {
109183
SecurityWebFilterChain securityWebFilter = this.http
@@ -129,6 +203,33 @@ public void customAccessDeniedHandler() {
129203
.expectStatus().isBadRequest();
130204
}
131205

206+
@Test
207+
public void requestWhenCustomAccessDeniedHandlerInLambdaThenCustomAccessDeniedHandlerUsed()
208+
throws Exception {
209+
SecurityWebFilterChain securityWebFilter = this.http
210+
.httpBasic(withDefaults())
211+
.authorizeExchange(exchanges ->
212+
exchanges
213+
.anyExchange().hasRole("ADMIN")
214+
)
215+
.exceptionHandling(exceptionHandling ->
216+
exceptionHandling
217+
.accessDeniedHandler(httpStatusServerAccessDeniedHandler(HttpStatus.BAD_REQUEST))
218+
)
219+
.build();
220+
221+
WebTestClient client = WebTestClientBuilder
222+
.bindToWebFilters(securityWebFilter)
223+
.build();
224+
225+
client
226+
.get()
227+
.uri("/admin")
228+
.headers(headers -> headers.setBasicAuth("user", "password"))
229+
.exchange()
230+
.expectStatus().isBadRequest();
231+
}
232+
132233
private ServerAuthenticationEntryPoint redirectServerAuthenticationEntryPoint(String location) {
133234
return new RedirectServerAuthenticationEntryPoint(location);
134235
}

config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java

+78
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import static org.mockito.BDDMockito.given;
4747
import static org.mockito.Mockito.mock;
4848
import static org.mockito.Mockito.verifyZeroInteractions;
49+
import static org.springframework.security.config.Customizer.withDefaults;
4950

5051
/**
5152
* @author Rob Winch
@@ -96,6 +97,49 @@ public void defaultLoginPage() {
9697
.assertLogout();
9798
}
9899

100+
@Test
101+
public void formLoginWhenDefaultsInLambdaThenCreatesDefaultLoginPage() throws Exception {
102+
SecurityWebFilterChain securityWebFilter = this.http
103+
.authorizeExchange(exchanges ->
104+
exchanges
105+
.anyExchange().authenticated()
106+
)
107+
.formLogin(withDefaults())
108+
.build();
109+
110+
WebTestClient webTestClient = WebTestClientBuilder
111+
.bindToWebFilters(securityWebFilter)
112+
.build();
113+
114+
WebDriver driver = WebTestClientHtmlUnitDriverBuilder
115+
.webTestClientSetup(webTestClient)
116+
.build();
117+
118+
DefaultLoginPage loginPage = HomePage.to(driver, DefaultLoginPage.class)
119+
.assertAt();
120+
121+
loginPage = loginPage.loginForm()
122+
.username("user")
123+
.password("invalid")
124+
.submit(DefaultLoginPage.class)
125+
.assertError();
126+
127+
HomePage homePage = loginPage.loginForm()
128+
.username("user")
129+
.password("password")
130+
.submit(HomePage.class);
131+
132+
homePage.assertAt();
133+
134+
loginPage = DefaultLogoutPage.to(driver)
135+
.assertAt()
136+
.logout();
137+
138+
loginPage
139+
.assertAt()
140+
.assertLogout();
141+
}
142+
99143
@Test
100144
public void customLoginPage() {
101145
SecurityWebFilterChain securityWebFilter = this.http
@@ -128,6 +172,40 @@ public void customLoginPage() {
128172
homePage.assertAt();
129173
}
130174

175+
@Test
176+
public void formLoginWhenCustomLoginPageInLambdaThenUsed() throws Exception {
177+
SecurityWebFilterChain securityWebFilter = this.http
178+
.authorizeExchange(exchanges ->
179+
exchanges
180+
.pathMatchers("/login").permitAll()
181+
.anyExchange().authenticated()
182+
)
183+
.formLogin(formLogin ->
184+
formLogin
185+
.loginPage("/login")
186+
)
187+
.build();
188+
189+
WebTestClient webTestClient = WebTestClient
190+
.bindToController(new CustomLoginPageController(), new WebTestClientBuilder.Http200RestController())
191+
.webFilter(new WebFilterChainProxy(securityWebFilter))
192+
.build();
193+
194+
WebDriver driver = WebTestClientHtmlUnitDriverBuilder
195+
.webTestClientSetup(webTestClient)
196+
.build();
197+
198+
CustomLoginPage loginPage = HomePage.to(driver, CustomLoginPage.class)
199+
.assertAt();
200+
201+
HomePage homePage = loginPage.loginForm()
202+
.username("user")
203+
.password("password")
204+
.submit(HomePage.class);
205+
206+
homePage.assertAt();
207+
}
208+
131209
@Test
132210
public void authenticationSuccess() {
133211
SecurityWebFilterChain securityWebFilter = this.http

0 commit comments

Comments
 (0)