Skip to content

Commit 7c59a4d

Browse files
committed
Allow configuring custom ServerHttpHeadersWriter for Kotlin DSL
Closes gh-16009
1 parent 30c9860 commit 7c59a4d

File tree

4 files changed

+144
-2
lines changed

4 files changed

+144
-2
lines changed

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

+36
Original file line numberDiff line numberDiff line change
@@ -3212,6 +3212,18 @@ public HeaderSpec writer(ServerHttpHeadersWriter serverHttpHeadersWriter) {
32123212
return this;
32133213
}
32143214

3215+
/**
3216+
* Configures custom headers writer
3217+
* @param serverHttpHeadersWriterCustomizer the {@link Customizer} to provide more
3218+
* options for the {@link ServerHttpHeadersWriterSpec}
3219+
* @return the {@link HeaderSpec} to customize
3220+
*/
3221+
public HeaderSpec serverHttpHeadersWriter(
3222+
Customizer<ServerHttpHeadersWriterSpec> serverHttpHeadersWriterCustomizer) {
3223+
serverHttpHeadersWriterCustomizer.customize(new ServerHttpHeadersWriterSpec());
3224+
return this;
3225+
}
3226+
32153227
/**
32163228
* Configures the Strict Transport Security response headers
32173229
* @return the {@link HstsSpec} to configure
@@ -3896,6 +3908,30 @@ public HeaderSpec and() {
38963908

38973909
}
38983910

3911+
/**
3912+
* Configures {@link ServerHttpHeadersWriter}
3913+
*
3914+
* @author Evgeniy Cheban
3915+
* @see #serverHttpHeadersWriter(Customizer)
3916+
*/
3917+
public final class ServerHttpHeadersWriterSpec {
3918+
3919+
private ServerHttpHeadersWriterSpec() {
3920+
}
3921+
3922+
/**
3923+
* Configures custom headers writer
3924+
* @param writer the {@link ServerHttpHeadersWriter} to provide custom headers
3925+
* writer
3926+
* @return the {@link HeaderSpec} to customize
3927+
*/
3928+
public ServerHttpHeadersWriterSpec writer(ServerHttpHeadersWriter writer) {
3929+
HeaderSpec.this.writer(writer);
3930+
return this;
3931+
}
3932+
3933+
}
3934+
38993935
}
39003936

39013937
/**

config/src/main/kotlin/org/springframework/security/config/web/server/ServerHeadersDsl.kt

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2024 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.
@@ -17,6 +17,7 @@
1717
package org.springframework.security.config.web.server
1818

1919
import org.springframework.security.web.server.header.CacheControlServerHttpHeadersWriter
20+
import org.springframework.security.web.server.header.ServerHttpHeadersWriter
2021
import org.springframework.security.web.server.header.ContentTypeOptionsServerHttpHeadersWriter
2122
import org.springframework.security.web.server.header.ReferrerPolicyServerHttpHeadersWriter
2223
import org.springframework.security.web.server.header.StrictTransportSecurityServerHttpHeadersWriter
@@ -43,6 +44,7 @@ class ServerHeadersDsl {
4344
private var crossOriginOpenerPolicy: ((ServerHttpSecurity.HeaderSpec.CrossOriginOpenerPolicySpec) -> Unit)? = null
4445
private var crossOriginEmbedderPolicy: ((ServerHttpSecurity.HeaderSpec.CrossOriginEmbedderPolicySpec) -> Unit)? = null
4546
private var crossOriginResourcePolicy: ((ServerHttpSecurity.HeaderSpec.CrossOriginResourcePolicySpec) -> Unit)? = null
47+
private var serverHttpHeadersWriter: ((ServerHttpSecurity.HeaderSpec.ServerHttpHeadersWriterSpec) -> Unit)? = null
4648

4749
private var disabled = false
4850

@@ -198,6 +200,15 @@ class ServerHeadersDsl {
198200
this.crossOriginResourcePolicy = ServerCrossOriginResourcePolicyDsl().apply(crossOriginResourcePolicyConfig).get()
199201
}
200202

203+
/**
204+
* Allows customizations for the [ServerHttpHeadersWriter] which allows writing headers just before the response is committed
205+
*
206+
* @param serverHttpHeadersWriterConfig the customization to apply to the header
207+
*/
208+
fun serverHttpHeadersWriter(serverHttpHeadersWriterConfig: ServerHttpHeadersWriterDsl.() -> Unit) {
209+
this.serverHttpHeadersWriter = ServerHttpHeadersWriterDsl().apply(serverHttpHeadersWriterConfig).get()
210+
}
211+
201212
/**
202213
* Disables HTTP response headers.
203214
*/
@@ -244,6 +255,9 @@ class ServerHeadersDsl {
244255
crossOriginResourcePolicy?.also {
245256
headers.crossOriginResourcePolicy(crossOriginResourcePolicy)
246257
}
258+
serverHttpHeadersWriter?.also {
259+
headers.serverHttpHeadersWriter(serverHttpHeadersWriter)
260+
}
247261
if (disabled) {
248262
headers.disable()
249263
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2002-2024 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.security.config.web.server
18+
19+
import org.springframework.security.web.server.header.ServerHttpHeadersWriter
20+
21+
/**
22+
* A Kotlin DSL to configure the [ServerHttpSecurity] to use custom [ServerHttpHeadersWriter] using
23+
* idiomatic Kotlin code.
24+
*
25+
* @author Evgeniy Cheban
26+
* @property writers the list of custom [ServerHttpHeadersWriter] to be used
27+
*/
28+
@ServerSecurityMarker
29+
class ServerHttpHeadersWriterDsl {
30+
31+
private var writers = mutableListOf<ServerHttpHeadersWriter>()
32+
33+
fun writer(writer: ServerHttpHeadersWriter) {
34+
writers.add(writer)
35+
}
36+
37+
internal fun get(): (ServerHttpSecurity.HeaderSpec.ServerHttpHeadersWriterSpec) -> Unit {
38+
return { writerOptions ->
39+
writers.also {
40+
writers.forEach { writer -> writerOptions.writer(writer) }
41+
}
42+
}
43+
}
44+
45+
}

config/src/test/kotlin/org/springframework/security/config/web/server/ServerHeadersDslTests.kt

+48-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2024 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.
@@ -37,6 +37,7 @@ import org.springframework.security.web.server.header.XFrameOptionsServerHttpHea
3737
import org.springframework.security.web.server.header.XXssProtectionServerHttpHeadersWriter
3838
import org.springframework.test.web.reactive.server.WebTestClient
3939
import org.springframework.web.reactive.config.EnableWebFlux
40+
import reactor.core.publisher.Mono
4041

4142
/**
4243
* Tests for [ServerHeadersDsl]
@@ -198,4 +199,50 @@ class ServerHeadersDslTests {
198199
}
199200
}
200201
}
202+
203+
@Test
204+
fun `request when custom server http headers writer configured then custom http headers added`() {
205+
this.spring.register(ServerHttpHeadersWriterCustomConfig::class.java).autowire()
206+
207+
this.client.get()
208+
.uri("/")
209+
.exchange()
210+
.expectHeader().valueEquals("CUSTOM-HEADER-1", "CUSTOM-VALUE-1")
211+
.expectHeader().valueEquals("CUSTOM-HEADER-2", "CUSTOM-VALUE-2")
212+
}
213+
214+
@Configuration
215+
@EnableWebFluxSecurity
216+
@EnableWebFlux
217+
open class ServerHttpHeadersWriterCustomConfig {
218+
@Bean
219+
open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
220+
return http {
221+
headers {
222+
serverHttpHeadersWriter {
223+
writer { exchange ->
224+
Mono.just(exchange)
225+
.doOnNext {
226+
it.response.headers.add(
227+
"CUSTOM-HEADER-1",
228+
"CUSTOM-VALUE-1"
229+
)
230+
}
231+
.then()
232+
}
233+
writer { exchange ->
234+
Mono.just(exchange)
235+
.doOnNext {
236+
it.response.headers.add(
237+
"CUSTOM-HEADER-2",
238+
"CUSTOM-VALUE-2"
239+
)
240+
}
241+
.then()
242+
}
243+
}
244+
}
245+
}
246+
}
247+
}
201248
}

0 commit comments

Comments
 (0)