Skip to content

Commit ff707d0

Browse files
committed
Add UserWebTestClientConfigurer
Closes gh-35042
1 parent 1b30b46 commit ff707d0

File tree

2 files changed

+129
-2
lines changed

2 files changed

+129
-2
lines changed
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright 2002-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.test.web.reactive.server;
18+
19+
import java.security.cert.X509Certificate;
20+
21+
import org.jspecify.annotations.Nullable;
22+
import reactor.core.publisher.Mono;
23+
24+
import org.springframework.http.client.reactive.ClientHttpConnector;
25+
import org.springframework.http.server.reactive.SslInfo;
26+
import org.springframework.util.Assert;
27+
import org.springframework.web.server.ServerWebExchange;
28+
import org.springframework.web.server.WebFilter;
29+
import org.springframework.web.server.WebFilterChain;
30+
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
31+
32+
/**
33+
* {@link WebTestClientConfigurer} that modifies WebFlux mock server requests
34+
* by setting their {@link SslInfo}.
35+
*
36+
* <p>You can apply the configurer to a {@link WebTestClient.Builder}:
37+
*
38+
* <pre class="code">
39+
* WebTestClient client = webTestClientBuilder
40+
* .apply(UserWebTestClientConfigurer.x509(certificate))
41+
* .build();
42+
* </pre>
43+
*
44+
* <p>Or mutate an already built {@link WebTestClient}:
45+
*
46+
* <pre class="code">
47+
* WebTestClient newClient =
48+
* client.mutateWith(UserWebTestClientConfigurer.x509(certificate));
49+
* </pre>
50+
*
51+
* <p><strong>Note:</strong> This configurer is applicable only to WebFlux mock
52+
* server setup. For a {@code WebTestClient.Builder} with a liver server setup,
53+
* or a non-WebFlux, mock server, {@link IllegalStateException} is raised.
54+
*
55+
* <p>For tests with a MockMvc server, refer to a similar facility to set the
56+
* user identity per request through Spring Security's
57+
* {@code SecurityMockMvcRequestPostProcessors}.
58+
*
59+
* @author Rossen Stoyanchev
60+
* @since 7.0
61+
*/
62+
public final class UserWebTestClientConfigurer implements WebTestClientConfigurer {
63+
64+
private final SslInfo info;
65+
66+
67+
private UserWebTestClientConfigurer(SslInfo info) {
68+
this.info = info;
69+
}
70+
71+
72+
@Override
73+
public void afterConfigurerAdded(
74+
WebTestClient.Builder builder, @Nullable WebHttpHandlerBuilder httpHandlerBuilder,
75+
@Nullable ClientHttpConnector connector) {
76+
77+
Assert.state(httpHandlerBuilder != null, "This configurer is applicable only to a mock WebFlux server");
78+
httpHandlerBuilder.filters(filters -> filters.add(0, new UserWebFilter()));
79+
}
80+
81+
82+
/**
83+
* Create a configurer with the given {@link X509Certificate X509 certificate(s)}.
84+
*/
85+
public static UserWebTestClientConfigurer x509(X509Certificate... certificates) {
86+
return sslInfo(SslInfo.from("1", certificates));
87+
}
88+
89+
/**
90+
* Create a configurer with the given {@link SslInfo}.
91+
*/
92+
public static UserWebTestClientConfigurer sslInfo(SslInfo info) {
93+
return new UserWebTestClientConfigurer(info);
94+
}
95+
96+
97+
private final class UserWebFilter implements WebFilter {
98+
99+
@Override
100+
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
101+
102+
exchange = exchange.mutate()
103+
.request(builder -> builder.sslInfo(UserWebTestClientConfigurer.this.info))
104+
.build();
105+
106+
return chain.filter(exchange);
107+
}
108+
}
109+
110+
}

spring-test/src/test/java/org/springframework/test/web/reactive/server/MockServerSpecTests.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.junit.jupiter.api.Test;
2323
import reactor.core.publisher.Mono;
2424

25+
import org.springframework.cglib.core.internal.Function;
2526
import org.springframework.core.io.buffer.DataBuffer;
2627
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
2728
import org.springframework.http.server.reactive.SslInfo;
@@ -94,9 +95,25 @@ public void beforeServerCreated(WebHttpHandlerBuilder builder) {
9495

9596
@Test
9697
void sslInfo() {
98+
testSslInfo(info -> this.serverSpec.sslInfo(info).build());
99+
}
100+
101+
@Test
102+
void sslInfoViaWebTestClientConfigurer() {
103+
testSslInfo(info -> this.serverSpec.configureClient().apply(UserWebTestClientConfigurer.sslInfo(info)).build());
104+
}
105+
106+
@Test
107+
void sslInfoViaMutate() {
108+
testSslInfo(info -> this.serverSpec.build().mutateWith(UserWebTestClientConfigurer.sslInfo(info)));
109+
}
110+
111+
private void testSslInfo(Function<SslInfo, WebTestClient> function) {
97112
SslInfo info = SslInfo.from("123");
98-
this.serverSpec.sslInfo(info).build().get().uri("/").exchange().expectStatus().isOk();
99-
assertThat(this.serverSpec.getSavedSslInfo()).isSameAs(info);
113+
function.apply(info).get().uri("/").exchange().expectStatus().isOk();
114+
115+
SslInfo actual = this.serverSpec.getSavedSslInfo();
116+
assertThat(actual).isSameAs(info);
100117
}
101118

102119

0 commit comments

Comments
 (0)