Skip to content

Commit f8a18fd

Browse files
eleftheriaskostya05983
authored andcommitted
Allow configuration of headers through nested builder
Issue: spring-projectsgh-5557
1 parent a116895 commit f8a18fd

File tree

5 files changed

+651
-1
lines changed

5 files changed

+651
-1
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,103 @@ public HeadersConfigurer<HttpSecurity> headers() throws Exception {
338338
return getOrApply(new HeadersConfigurer<>());
339339
}
340340

341+
/**
342+
* Adds the Security headers to the response. This is activated by default when using
343+
* {@link WebSecurityConfigurerAdapter}'s default constructor.
344+
*
345+
* <h2>Example Configurations</h2>
346+
*
347+
* Accepting the default provided by {@link WebSecurityConfigurerAdapter} or only invoking
348+
* {@link #headers()} without invoking additional methods on it, is the equivalent of:
349+
*
350+
* <pre>
351+
* &#064;Configuration
352+
* &#064;EnableWebSecurity
353+
* public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter {
354+
*
355+
* &#064;Override
356+
* protected void configure(HttpSecurity http) throws Exception {
357+
* http
358+
* .headers(headers ->
359+
* headers
360+
* .contentTypeOptions(withDefaults())
361+
* .xssProtection(withDefaults())
362+
* .cacheControl(withDefaults())
363+
* .httpStrictTransportSecurity(withDefaults())
364+
* .frameOptions(withDefaults()
365+
* );
366+
* }
367+
* }
368+
* </pre>
369+
*
370+
* You can disable the headers using the following:
371+
*
372+
* <pre>
373+
* &#064;Configuration
374+
* &#064;EnableWebSecurity
375+
* public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter {
376+
*
377+
* &#064;Override
378+
* protected void configure(HttpSecurity http) throws Exception {
379+
* http
380+
* .headers(headers -> headers.disable());
381+
* }
382+
* }
383+
* </pre>
384+
*
385+
* You can enable only a few of the headers by first invoking
386+
* {@link HeadersConfigurer#defaultsDisabled()}
387+
* and then invoking the appropriate methods on the {@link #headers()} result.
388+
* For example, the following will enable {@link HeadersConfigurer#cacheControl()} and
389+
* {@link HeadersConfigurer#frameOptions()} only.
390+
*
391+
* <pre>
392+
* &#064;Configuration
393+
* &#064;EnableWebSecurity
394+
* public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter {
395+
*
396+
* &#064;Override
397+
* protected void configure(HttpSecurity http) throws Exception {
398+
* http
399+
* .headers(headers ->
400+
* headers
401+
* .defaultsDisabled()
402+
* .cacheControl(withDefaults())
403+
* .frameOptions(withDefaults())
404+
* );
405+
* }
406+
* }
407+
* </pre>
408+
*
409+
* You can also choose to keep the defaults but explicitly disable a subset of headers.
410+
* For example, the following will enable all the default headers except
411+
* {@link HeadersConfigurer#frameOptions()}.
412+
*
413+
* <pre>
414+
* &#064;Configuration
415+
* &#064;EnableWebSecurity
416+
* public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter {
417+
*
418+
* &#064;Override
419+
* protected void configure(HttpSecurity http) throws Exception {
420+
* http
421+
* .headers(headers ->
422+
* headers
423+
* .frameOptions(frameOptions -> frameOptions.disable())
424+
* );
425+
* }
426+
* </pre>
427+
*
428+
* @param headersCustomizer the {@link Customizer} to provide more options for
429+
* the {@link HeadersConfigurer}
430+
* @return the {@link HttpSecurity} for further customizations
431+
* @throws Exception
432+
*/
433+
public HttpSecurity headers(Customizer<HeadersConfigurer<HttpSecurity>> headersCustomizer) throws Exception {
434+
headersCustomizer.customize(getOrApply(new HeadersConfigurer<>()));
435+
return HttpSecurity.this;
436+
}
437+
341438
/**
342439
* Adds a {@link CorsFilter} to be used. If a bean by the name of corsFilter is
343440
* provided, that {@link CorsFilter} is used. Else if corsConfigurationSource is

config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java

Lines changed: 187 additions & 1 deletion
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.
@@ -23,13 +23,16 @@
2323

2424
import javax.servlet.http.HttpServletRequest;
2525

26+
import org.springframework.security.config.Customizer;
2627
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
2728
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
2829
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
2930
import org.springframework.security.web.header.HeaderWriter;
3031
import org.springframework.security.web.header.HeaderWriterFilter;
3132
import org.springframework.security.web.header.writers.*;
3233
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter.ReferrerPolicy;
34+
import org.springframework.security.web.header.writers.XContentTypeOptionsHeaderWriter;
35+
import org.springframework.security.web.header.writers.XXssProtectionHeaderWriter;
3336
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
3437
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter.XFrameOptionsMode;
3538
import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -121,6 +124,26 @@ public ContentTypeOptionsConfig contentTypeOptions() {
121124
return contentTypeOptions.enable();
122125
}
123126

127+
/**
128+
* Configures the {@link XContentTypeOptionsHeaderWriter} which inserts the <a href=
129+
* "https://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx"
130+
* >X-Content-Type-Options</a>:
131+
*
132+
* <pre>
133+
* X-Content-Type-Options: nosniff
134+
* </pre>
135+
*
136+
* @param contentTypeOptionsCustomizer the {@link Customizer} to provide more options for
137+
* the {@link ContentTypeOptionsConfig}
138+
* @return the {@link HeadersConfigurer} for additional customizations
139+
* @throws Exception
140+
*/
141+
public HeadersConfigurer<H> contentTypeOptions(Customizer<ContentTypeOptionsConfig> contentTypeOptionsCustomizer)
142+
throws Exception {
143+
contentTypeOptionsCustomizer.customize(contentTypeOptions.enable());
144+
return HeadersConfigurer.this;
145+
}
146+
124147
public final class ContentTypeOptionsConfig {
125148
private XContentTypeOptionsHeaderWriter writer;
126149

@@ -174,6 +197,25 @@ public XXssConfig xssProtection() {
174197
return xssProtection.enable();
175198
}
176199

200+
/**
201+
* <strong>Note this is not comprehensive XSS protection!</strong>
202+
*
203+
* <p>
204+
* Allows customizing the {@link XXssProtectionHeaderWriter} which adds the <a href=
205+
* "https://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx"
206+
* >X-XSS-Protection header</a>
207+
* </p>
208+
*
209+
* @param xssCustomizer the {@link Customizer} to provide more options for
210+
* the {@link XXssConfig}
211+
* @return the {@link HeadersConfigurer} for additional customizations
212+
* @throws Exception
213+
*/
214+
public HeadersConfigurer<H> xssProtection(Customizer<XXssConfig> xssCustomizer) throws Exception {
215+
xssCustomizer.customize(xssProtection.enable());
216+
return HeadersConfigurer.this;
217+
}
218+
177219
public final class XXssConfig {
178220
private XXssProtectionHeaderWriter writer;
179221

@@ -268,6 +310,26 @@ public CacheControlConfig cacheControl() {
268310
return cacheControl.enable();
269311
}
270312

313+
/**
314+
* Allows customizing the {@link CacheControlHeadersWriter}. Specifically it adds the
315+
* following headers:
316+
* <ul>
317+
* <li>Cache-Control: no-cache, no-store, max-age=0, must-revalidate</li>
318+
* <li>Pragma: no-cache</li>
319+
* <li>Expires: 0</li>
320+
* </ul>
321+
*
322+
* @param cacheControlCustomizer the {@link Customizer} to provide more options for
323+
* the {@link CacheControlConfig}
324+
* @return the {@link HeadersConfigurer} for additional customizations
325+
* @throws Exception
326+
*/
327+
public HeadersConfigurer<H> cacheControl(Customizer<CacheControlConfig> cacheControlCustomizer) throws Exception {
328+
cacheControlCustomizer.customize(cacheControl.enable());
329+
return HeadersConfigurer.this;
330+
}
331+
332+
271333
public final class CacheControlConfig {
272334
private CacheControlHeadersWriter writer;
273335

@@ -319,6 +381,21 @@ public HstsConfig httpStrictTransportSecurity() {
319381
return hsts.enable();
320382
}
321383

384+
/**
385+
* Allows customizing the {@link HstsHeaderWriter} which provides support for <a
386+
* href="https://tools.ietf.org/html/rfc6797">HTTP Strict Transport Security
387+
* (HSTS)</a>.
388+
*
389+
* @param hstsCustomizer the {@link Customizer} to provide more options for
390+
* the {@link HstsConfig}
391+
* @return the {@link HeadersConfigurer} for additional customizations
392+
* @throws Exception
393+
*/
394+
public HeadersConfigurer<H> httpStrictTransportSecurity(Customizer<HstsConfig> hstsCustomizer) throws Exception {
395+
hstsCustomizer.customize(hsts.enable());
396+
return HeadersConfigurer.this;
397+
}
398+
322399
public final class HstsConfig {
323400
private HstsHeaderWriter writer;
324401

@@ -440,6 +517,19 @@ public FrameOptionsConfig frameOptions() {
440517
return frameOptions.enable();
441518
}
442519

520+
/**
521+
* Allows customizing the {@link XFrameOptionsHeaderWriter}.
522+
*
523+
* @param frameOptionsCustomizer the {@link Customizer} to provide more options for
524+
* the {@link FrameOptionsConfig}
525+
* @return the {@link HeadersConfigurer} for additional customizations
526+
* @throws Exception
527+
*/
528+
public HeadersConfigurer<H> frameOptions(Customizer<FrameOptionsConfig> frameOptionsCustomizer) throws Exception {
529+
frameOptionsCustomizer.customize(frameOptions.enable());
530+
return HeadersConfigurer.this;
531+
}
532+
443533
public final class FrameOptionsConfig {
444534
private XFrameOptionsHeaderWriter writer;
445535

@@ -516,6 +606,20 @@ public HpkpConfig httpPublicKeyPinning() {
516606
return hpkp.enable();
517607
}
518608

609+
/**
610+
* Allows customizing the {@link HpkpHeaderWriter} which provides support for <a
611+
* href="https://tools.ietf.org/html/rfc7469">HTTP Public Key Pinning (HPKP)</a>.
612+
*
613+
* @param hpkpCustomizer the {@link Customizer} to provide more options for
614+
* the {@link HpkpConfig}
615+
* @return the {@link HeadersConfigurer} for additional customizations
616+
* @throws Exception
617+
*/
618+
public HeadersConfigurer<H> httpPublicKeyPinning(Customizer<HpkpConfig> hpkpCustomizer) throws Exception {
619+
hpkpCustomizer.customize(hpkp.enable());
620+
return HeadersConfigurer.this;
621+
}
622+
519623
public final class HpkpConfig {
520624
private HpkpHeaderWriter writer;
521625

@@ -713,12 +817,57 @@ public ContentSecurityPolicyConfig contentSecurityPolicy(String policyDirectives
713817
return contentSecurityPolicy;
714818
}
715819

820+
/**
821+
* <p>
822+
* Allows configuration for <a href="https://www.w3.org/TR/CSP2/">Content Security Policy (CSP) Level 2</a>.
823+
* </p>
824+
*
825+
* <p>
826+
* Calling this method automatically enables (includes) the Content-Security-Policy header in the response
827+
* using the supplied security policy directive(s).
828+
* </p>
829+
*
830+
* <p>
831+
* Configuration is provided to the {@link ContentSecurityPolicyHeaderWriter} which supports the writing
832+
* of the two headers as detailed in the W3C Candidate Recommendation:
833+
* </p>
834+
* <ul>
835+
* <li>Content-Security-Policy</li>
836+
* <li>Content-Security-Policy-Report-Only</li>
837+
* </ul>
838+
*
839+
* @see ContentSecurityPolicyHeaderWriter
840+
* @param contentSecurityCustomizer the {@link Customizer} to provide more options for
841+
* the {@link ContentSecurityPolicyConfig}
842+
* @return the {@link HeadersConfigurer} for additional customizations
843+
* @throws Exception
844+
*/
845+
public HeadersConfigurer<H> contentSecurityPolicy(Customizer<ContentSecurityPolicyConfig> contentSecurityCustomizer)
846+
throws Exception {
847+
this.contentSecurityPolicy.writer = new ContentSecurityPolicyHeaderWriter();
848+
contentSecurityCustomizer.customize(this.contentSecurityPolicy);
849+
850+
return HeadersConfigurer.this;
851+
}
852+
716853
public final class ContentSecurityPolicyConfig {
717854
private ContentSecurityPolicyHeaderWriter writer;
718855

719856
private ContentSecurityPolicyConfig() {
720857
}
721858

859+
/**
860+
* Sets the security policy directive(s) to be used in the response header.
861+
*
862+
* @param policyDirectives the security policy directive(s)
863+
* @return the {@link ContentSecurityPolicyConfig} for additional configuration
864+
* @throws IllegalArgumentException if policyDirectives is null or empty
865+
*/
866+
public ContentSecurityPolicyConfig policyDirectives(String policyDirectives) {
867+
this.writer.setPolicyDirectives(policyDirectives);
868+
return this;
869+
}
870+
722871
/**
723872
* Enables (includes) the Content-Security-Policy-Report-Only header in the response.
724873
*
@@ -860,13 +1009,50 @@ public ReferrerPolicyConfig referrerPolicy(ReferrerPolicy policy) {
8601009
return this.referrerPolicy;
8611010
}
8621011

1012+
/**
1013+
* <p>
1014+
* Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer Policy</a>.
1015+
* </p>
1016+
*
1017+
* <p>
1018+
* Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support the writing
1019+
* of the header as detailed in the W3C Technical Report:
1020+
* </p>
1021+
* <ul>
1022+
* <li>Referrer-Policy</li>
1023+
* </ul>
1024+
*
1025+
* @see ReferrerPolicyHeaderWriter
1026+
* @param referrerPolicyCustomizer the {@link Customizer} to provide more options for
1027+
* the {@link ReferrerPolicyConfig}
1028+
* @return the {@link HeadersConfigurer} for additional customizations
1029+
* @throws Exception
1030+
*/
1031+
public HeadersConfigurer<H> referrerPolicy(Customizer<ReferrerPolicyConfig> referrerPolicyCustomizer) throws Exception {
1032+
this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter();
1033+
referrerPolicyCustomizer.customize(this.referrerPolicy);
1034+
return HeadersConfigurer.this;
1035+
}
1036+
8631037
public final class ReferrerPolicyConfig {
8641038

8651039
private ReferrerPolicyHeaderWriter writer;
8661040

8671041
private ReferrerPolicyConfig() {
8681042
}
8691043

1044+
/**
1045+
* Sets the policy to be used in the response header.
1046+
*
1047+
* @param policy a referrer policy
1048+
* @return the {@link ReferrerPolicyConfig} for additional configuration
1049+
* @throws IllegalArgumentException if policy is null
1050+
*/
1051+
public ReferrerPolicyConfig policy(ReferrerPolicy policy) {
1052+
this.writer.setPolicy(policy);
1053+
return this;
1054+
}
1055+
8701056
public HeadersConfigurer<H> and() {
8711057
return HeadersConfigurer.this;
8721058
}

0 commit comments

Comments
 (0)