Skip to content

Commit a732f09

Browse files
committed
fix: set secure response headers in any condition auf SdaSecurityConfiguration
1 parent 4f3e16c commit a732f09

15 files changed

+352
-299
lines changed

sda-commons-web-autoconfigure/src/main/java/org/sdase/commons/spring/boot/web/auth/SdaAccessDecisionManager.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
package org.sdase.commons.spring.boot.web.auth;
99

1010
import java.util.List;
11+
import org.sdase.commons.spring.boot.web.auth.management.ManagementAccessDecisionVoter;
1112
import org.sdase.commons.spring.boot.web.auth.opa.OpaAccessDecisionVoter;
1213
import org.sdase.commons.spring.boot.web.auth.opa.OpaExcludesDecisionVoter;
1314
import org.springframework.security.access.vote.UnanimousBased;
@@ -17,8 +18,9 @@
1718
public class SdaAccessDecisionManager extends UnanimousBased {
1819

1920
public SdaAccessDecisionManager(
21+
ManagementAccessDecisionVoter managementAccessDecisionVoter,
2022
OpaExcludesDecisionVoter opaExcludesDecisionVoter,
2123
OpaAccessDecisionVoter opaAccessDecisionVoter) {
22-
super(List.of(opaExcludesDecisionVoter, opaAccessDecisionVoter));
24+
super(List.of(managementAccessDecisionVoter, opaExcludesDecisionVoter, opaAccessDecisionVoter));
2325
}
2426
}

sda-commons-web-autoconfigure/src/main/java/org/sdase/commons/spring/boot/web/auth/SdaMonitoringSecurityConfiguration.java

Lines changed: 0 additions & 36 deletions
This file was deleted.

sda-commons-web-autoconfigure/src/main/java/org/sdase/commons/spring/boot/web/auth/SdaSecurityConfiguration.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
package org.sdase.commons.spring.boot.web.auth;
99

1010
import java.util.List;
11+
import java.util.Optional;
1112
import java.util.stream.Stream;
1213
import javax.servlet.http.HttpServletRequest;
14+
import org.sdase.commons.spring.boot.web.security.headers.SdaSecurityHeaders;
1315
import org.slf4j.Logger;
1416
import org.slf4j.LoggerFactory;
1517
import org.springframework.beans.factory.annotation.Value;
@@ -26,6 +28,7 @@
2628
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
2729
import org.springframework.security.oauth2.server.resource.authentication.JwtIssuerAuthenticationManagerResolver;
2830
import org.springframework.security.web.SecurityFilterChain;
31+
import org.springframework.security.web.header.writers.StaticHeadersWriter;
2932
import org.springframework.util.StringUtils;
3033

3134
@EnableWebSecurity
@@ -41,6 +44,8 @@ public class SdaSecurityConfiguration {
4144

4245
private final SdaAccessDecisionManager sdaAccessDecisionManager;
4346

47+
private final SdaSecurityHeaders sdaSecurityHeaders;
48+
4449
/**
4550
* @param issuers Comma separated string of open id discovery key sources with required issuers.
4651
* @param disableAuthentication Disables all authentication
@@ -50,10 +55,12 @@ public class SdaSecurityConfiguration {
5055
public SdaSecurityConfiguration(
5156
@Value("${auth.issuers:}") String issuers,
5257
@Value("${auth.disable:false}") boolean disableAuthentication,
53-
SdaAccessDecisionManager sdaAccessDecisionManager) {
58+
SdaAccessDecisionManager sdaAccessDecisionManager,
59+
Optional<SdaSecurityHeaders> sdaSecurityHeaders) {
5460
this.issuers = issuers;
5561
this.disableAuthentication = disableAuthentication;
5662
this.sdaAccessDecisionManager = sdaAccessDecisionManager;
63+
this.sdaSecurityHeaders = sdaSecurityHeaders.orElse(List::of);
5764
}
5865

5966
@Bean
@@ -82,7 +89,11 @@ private void oidcAuthentication(HttpSecurity http) throws Exception {
8289
authorize ->
8390
authorize.anyRequest().permitAll().accessDecisionManager(sdaAccessDecisionManager))
8491
.oauth2ResourceServer(
85-
oauth2 -> oauth2.authenticationManagerResolver(authenticationManagerResolver));
92+
oauth2 -> oauth2.authenticationManagerResolver(authenticationManagerResolver))
93+
.headers(
94+
configurer ->
95+
configurer.addHeaderWriter(
96+
new StaticHeadersWriter(sdaSecurityHeaders.getSecurityHeaders())));
8697
}
8798

8899
private AuthenticationManagerResolver<HttpServletRequest> createAuthenticationManagerResolver() {
@@ -111,7 +122,11 @@ private void noAuthentication(HttpSecurity http) throws Exception {
111122
.disable() // NOSONAR
112123
.authorizeRequests(
113124
authorize ->
114-
authorize.anyRequest().permitAll().accessDecisionManager(sdaAccessDecisionManager));
125+
authorize.anyRequest().permitAll().accessDecisionManager(sdaAccessDecisionManager))
126+
.headers(
127+
configurer ->
128+
configurer.addHeaderWriter(
129+
new StaticHeadersWriter(sdaSecurityHeaders.getSecurityHeaders())));
115130
}
116131

117132
private List<String> commaSeparatedStringToList(String issuers) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright 2022- SDA SE Open Industry Solutions (https://www.sda.se)
3+
*
4+
* Use of this source code is governed by an MIT-style
5+
* license that can be found in the LICENSE file or at
6+
* https://opensource.org/licenses/MIT.
7+
*/
8+
package org.sdase.commons.spring.boot.web.auth.management;
9+
10+
import java.util.Collection;
11+
import org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort;
12+
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
13+
import org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent;
14+
import org.springframework.context.event.EventListener;
15+
import org.springframework.security.access.AccessDecisionVoter;
16+
import org.springframework.security.access.ConfigAttribute;
17+
import org.springframework.security.core.Authentication;
18+
import org.springframework.security.web.FilterInvocation;
19+
import org.springframework.stereotype.Component;
20+
21+
public interface ManagementAccessDecisionVoter extends AccessDecisionVoter<FilterInvocation> {
22+
23+
@Override
24+
default boolean supports(ConfigAttribute attribute) {
25+
return true;
26+
}
27+
28+
@Override
29+
default boolean supports(Class<?> clazz) {
30+
return FilterInvocation.class.isAssignableFrom(clazz);
31+
}
32+
33+
@Component
34+
@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)
35+
class DifferentPortManagementAccessDecisionVoter implements ManagementAccessDecisionVoter {
36+
37+
/**
38+
* The management port discovered in {@link
39+
* #onApplicationEvent(ServletWebServerInitializedEvent)}. Initially a value that can't be an
40+
* existing port to avoid granting access by accident to the application API.
41+
*/
42+
private int managementPort = -1;
43+
44+
@EventListener
45+
public void onApplicationEvent(ServletWebServerInitializedEvent event) {
46+
if ("management".equals(event.getApplicationContext().getServerNamespace())) {
47+
this.managementPort = event.getWebServer().getPort();
48+
}
49+
}
50+
51+
@Override
52+
public int vote(
53+
Authentication authentication,
54+
FilterInvocation filterInvocation,
55+
Collection<ConfigAttribute> attributes) {
56+
int requestLocalPort = filterInvocation.getRequest().getLocalPort();
57+
return requestLocalPort == this.managementPort ? ACCESS_GRANTED : ACCESS_ABSTAIN;
58+
}
59+
}
60+
61+
@Component
62+
@ConditionalOnManagementPort(ManagementPortType.SAME)
63+
class IgnoreSamePortManagementAccessDecisionVoter implements ManagementAccessDecisionVoter {
64+
@Override
65+
public int vote(
66+
Authentication authentication,
67+
FilterInvocation filterInvocation,
68+
Collection<ConfigAttribute> attributes) {
69+
return ACCESS_ABSTAIN;
70+
}
71+
}
72+
73+
@Component
74+
@ConditionalOnManagementPort(ManagementPortType.DISABLED)
75+
class DisabledManagementAccessDecisionVoter implements ManagementAccessDecisionVoter {
76+
@Override
77+
public int vote(
78+
Authentication authentication,
79+
FilterInvocation filterInvocation,
80+
Collection<ConfigAttribute> attributes) {
81+
return ACCESS_ABSTAIN;
82+
}
83+
}
84+
}

sda-commons-web-autoconfigure/src/main/java/org/sdase/commons/spring/boot/web/security/headers/FrontendSecurityConfiguration.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
package org.sdase.commons.spring.boot.web.security.headers;
99

1010
import org.springframework.context.annotation.Bean;
11-
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
12-
import org.springframework.security.web.SecurityFilterChain;
1311

1412
/**
1513
* This filter adds headers to the response that enhance the security of web applications. Usually
@@ -34,9 +32,7 @@ public class FrontendSecurityConfiguration {
3432
public static final String FRONTEND_SECURITY_ADVICE_BEAN_NAME = "frontendHeadersAdvice";
3533

3634
@Bean(FRONTEND_SECURITY_ADVICE_BEAN_NAME)
37-
public SecurityFilterChain frontendHeadersAdvice(HttpSecurity http) throws Exception {
38-
// add specific headers for frontends
39-
http.headers(HttpHeadersAdvice::addFrontendHttpHeadersCustomizer);
40-
return http.build();
35+
public SdaSecurityHeaders sdaSecurityHeaders() {
36+
return SdaSecurityType.FRONTEND_SECURITY::headers;
4137
}
4238
}

sda-commons-web-autoconfigure/src/main/java/org/sdase/commons/spring/boot/web/security/headers/HttpHeadersAdvice.java

Lines changed: 0 additions & 67 deletions
This file was deleted.

sda-commons-web-autoconfigure/src/main/java/org/sdase/commons/spring/boot/web/security/headers/RestfulApiSecurityConfiguration.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
1111
import org.springframework.context.annotation.Bean;
1212
import org.springframework.context.annotation.Configuration;
13-
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
14-
import org.springframework.security.web.SecurityFilterChain;
1513

1614
/**
1715
* This filter adds headers to the response that enhance the security of applications that serve
@@ -27,12 +25,9 @@
2725
*/
2826
@Configuration
2927
public class RestfulApiSecurityConfiguration {
30-
3128
@Bean
3229
@ConditionalOnMissingBean(name = FrontendSecurityConfiguration.FRONTEND_SECURITY_ADVICE_BEAN_NAME)
33-
public SecurityFilterChain restfulApiHeadersAdvice(HttpSecurity http) throws Exception {
34-
// define specific headers for restful apis
35-
http.headers(HttpHeadersAdvice::addRestfulHttpHeadersCustomizer);
36-
return http.build();
30+
public SdaSecurityHeaders sdaSecurityHeaders() {
31+
return SdaSecurityType.RESTFUL_SECURITY::headers;
3732
}
3833
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* Copyright 2022- SDA SE Open Industry Solutions (https://www.sda.se)
3+
*
4+
* Use of this source code is governed by an MIT-style
5+
* license that can be found in the LICENSE file or at
6+
* https://opensource.org/licenses/MIT.
7+
*/
8+
package org.sdase.commons.spring.boot.web.security.headers;
9+
10+
import java.util.List;
11+
import org.springframework.security.web.header.Header;
12+
13+
public interface SdaSecurityHeaders {
14+
15+
List<Header> getSecurityHeaders();
16+
}

0 commit comments

Comments
 (0)