Skip to content

Commit 52cc963

Browse files
committed
Update servlet architecture docs to use include-code
Also update antora.xml to include-xml in docs/src/test/resources Signed-off-by: Joe Kuhel <4983938+jkuhel@users.noreply.github.com>
1 parent 8879aa8 commit 52cc963

20 files changed

Lines changed: 1403 additions & 295 deletions

File tree

docs/antora.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ asciidoc:
1818
gh-url: "https://github.com/spring-projects/spring-security/tree/{gh-tag}"
1919
include-java: 'example$docs-src/test/java/org/springframework/security/docs'
2020
include-kotlin: 'example$docs-src/test/kotlin/org/springframework/security/kt/docs'
21+
include-xml: 'example$docs-src/test/resources/org/springframework/security/docs'

docs/modules/ROOT/pages/servlet/architecture.adoc

Lines changed: 14 additions & 295 deletions
Original file line numberDiff line numberDiff line change
@@ -51,28 +51,9 @@ image::{figures}/delegatingfilterproxy.png[]
5151
The following listing shows pseudo code of `DelegatingFilterProxy`:
5252

5353
.`DelegatingFilterProxy` Pseudo Code
54-
[tabs]
55-
======
56-
Java::
57-
+
58-
[source,java,role="primary"]
59-
----
60-
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
61-
Filter delegate = getFilterBean(someBeanName); // <1>
62-
delegate.doFilter(request, response); // <2>
63-
}
64-
----
6554

66-
Kotlin::
67-
+
68-
[source,kotlin,role="secondary"]
69-
----
70-
fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
71-
val delegate: Filter = getFilterBean(someBeanName) // <1>
72-
delegate.doFilter(request, response) // <2>
73-
}
74-
----
75-
======
55+
include-code::./SampleDelegatingFilterProxy[tag=dofilter,indent=0]
56+
7657
<1> Lazily get Filter that was registered as a Spring Bean.
7758
For the example in <<servlet-delegatingfilterproxy-figure>> `delegate` is an instance of __Bean Filter~0~__.
7859
<2> Delegate work to the Spring Bean.
@@ -155,58 +136,7 @@ However, there are times that it is beneficial to know the ordering, if you want
155136
These security filters are most often declared using an javadoc:org.springframework.security.config.annotation.web.builders.HttpSecurity[`HttpSecurity`] instance.
156137
To exemplify the above paragraph, let's consider the following security configuration:
157138

158-
[tabs]
159-
======
160-
Java::
161-
+
162-
[source,java,role="primary"]
163-
----
164-
@Configuration
165-
@EnableWebSecurity
166-
public class SecurityConfig {
167-
168-
@Bean
169-
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
170-
http
171-
.csrf(Customizer.withDefaults())
172-
.httpBasic(Customizer.withDefaults())
173-
.formLogin(Customizer.withDefaults())
174-
.authorizeHttpRequests(authorize -> authorize
175-
.anyRequest().authenticated()
176-
);
177-
178-
return http.build();
179-
}
180-
181-
}
182-
----
183-
184-
Kotlin::
185-
+
186-
[source,kotlin,role="secondary"]
187-
----
188-
import org.springframework.security.config.web.servlet.invoke
189-
190-
@Configuration
191-
@EnableWebSecurity
192-
class SecurityConfig {
193-
194-
@Bean
195-
fun filterChain(http: HttpSecurity): SecurityFilterChain {
196-
http {
197-
csrf { }
198-
httpBasic { }
199-
formLogin { }
200-
authorizeHttpRequests {
201-
authorize(anyRequest, authenticated)
202-
}
203-
}
204-
return http.build()
205-
}
206-
207-
}
208-
----
209-
======
139+
include-code::./SecurityConfig[tag=snippet,indent=0]
210140

211141
The above configuration will result in the following `Filter` ordering:
212142

@@ -233,7 +163,7 @@ If you want to see the list of filters invoked for a particular request, you can
233163
=== Printing the Security Filters
234164

235165
Often times, it is useful to see the list of security ``Filter``s that are invoked for a particular request.
236-
For example, you want to make sure that the <<adding-custom-filter,filter you have added>> is in the list of the security filters.
166+
For example, you want to make sure that the <<adding-filters-to-chain,filter you have added>> is in the list of the security filters.
237167

238168
The list of filters is printed at DEBUG level on the application startup, so you can see something like the following on the console output for example:
239169

@@ -248,7 +178,7 @@ But that is not all, you can also configure your application to print the invoca
248178
That is helpful to see if the filter you have added is invoked for a particular request or to check where an exception is coming from.
249179
To do that, you can configure your application to <<servlet-logging,log the security events>>.
250180

251-
[[adding-custom-filter]]
181+
[[adding-filters-to-chain]]
252182
=== Adding Filters to the Filter Chain
253183

254184
Most of the time, the default <<servlet-security-filters>> are enough to provide security to your application.
@@ -260,6 +190,7 @@ javadoc:org.springframework.security.config.annotation.web.builders.HttpSecurity
260190
* `#addFilterAfter(Filter, Class<?>)` adds your filter after another filter
261191
* `#addFilterAt(Filter, Class<?>)` replaces another filter with your filter
262192

193+
[[adding-custom-filter]]
263194
==== Adding a Custom Filter
264195

265196
If you are creating a filter of your own, you will need to determine its location in the filter chain.
@@ -298,39 +229,7 @@ For example, let's say that you want to add a `Filter` that gets a tenant id hea
298229

299230
First, let's create the `Filter`:
300231

301-
[source,java]
302-
----
303-
import java.io.IOException;
304-
305-
import jakarta.servlet.Filter;
306-
import jakarta.servlet.FilterChain;
307-
import jakarta.servlet.ServletException;
308-
import jakarta.servlet.ServletRequest;
309-
import jakarta.servlet.ServletResponse;
310-
import jakarta.servlet.http.HttpServletRequest;
311-
import jakarta.servlet.http.HttpServletResponse;
312-
313-
import org.springframework.security.access.AccessDeniedException;
314-
315-
public class TenantFilter implements Filter {
316-
317-
@Override
318-
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
319-
HttpServletRequest request = (HttpServletRequest) servletRequest;
320-
HttpServletResponse response = (HttpServletResponse) servletResponse;
321-
322-
String tenantId = request.getHeader("X-Tenant-Id"); <1>
323-
boolean hasAccess = isUserAllowed(tenantId); <2>
324-
if (hasAccess) {
325-
filterChain.doFilter(request, response); <3>
326-
return;
327-
}
328-
throw new AccessDeniedException("Access denied"); <4>
329-
}
330-
331-
}
332-
333-
----
232+
include-code::./TenantFilter[tag=snippet,indent=0]
334233

335234
The sample code above does the following:
336235

@@ -349,34 +248,7 @@ The previous description already gives us a clue on where to add the filter, sin
349248

350249
Based on the rule of thumb, add it after xref:servlet/authentication/anonymous.adoc[ `AnonymousAuthenticationFilter`], the last authentication filter in the chain, like so:
351250

352-
[tabs]
353-
======
354-
Java::
355-
+
356-
[source,java,role="primary"]
357-
----
358-
@Bean
359-
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
360-
http
361-
// ...
362-
.addFilterAfter(new TenantFilter(), AnonymousAuthenticationFilter.class); <1>
363-
return http.build();
364-
}
365-
----
366-
367-
Kotlin::
368-
+
369-
[source,kotlin,role="secondary"]
370-
----
371-
@Bean
372-
fun filterChain(http: HttpSecurity): SecurityFilterChain {
373-
http
374-
// ...
375-
.addFilterAfter(TenantFilter(), AnonymousAuthenticationFilter::class.java) <1>
376-
return http.build()
377-
}
378-
----
379-
======
251+
include-code::./SecurityConfig[tag=snippet,indent=0]
380252

381253
<1> Use `HttpSecurity#addFilterAfter` to add the `TenantFilter` after the `AnonymousAuthenticationFilter`.
382254

@@ -405,138 +277,31 @@ public FilterRegistrationBean<TenantFilter> tenantFilterRegistration(TenantFilte
405277

406278
This makes so that `HttpSecurity` is the only one adding it.
407279

280+
[[customizing-filter]]
408281
==== Customizing a Spring Security Filter
409282

410283
Generally, you can use a filter's DSL method to configure Spring Security's filters.
411284
For example, the simplest way to add `BasicAuthenticationFilter` is by asking the DSL to do it:
412285

413-
[tabs]
414-
======
415-
Java::
416-
+
417-
[source,java,role="primary"]
418-
----
419-
@Bean
420-
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
421-
http
422-
.httpBasic(Customizer.withDefaults())
423-
// ...
424-
425-
return http.build();
426-
}
427-
----
428-
429-
Kotlin::
430-
+
431-
[source,kotlin,role="secondary"]
432-
----
433-
@Bean
434-
fun filterChain(http: HttpSecurity): SecurityFilterChain {
435-
http {
436-
httpBasic { }
437-
// ...
438-
}
439-
440-
return http.build()
441-
}
442-
----
443-
======
444-
286+
include-code::./CustomizingFilterTests[tag=basic-default,indent=0]
445287

446288
However, in the event that you want to construct a Spring Security filter yourself, you specify it in the DSL using `addFilterAt` like so:
447289

448-
[tabs]
449-
======
450-
Java::
451-
+
452-
[source,java,role="primary"]
453-
----
454-
@Bean
455-
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
456-
BasicAuthenticationFilter basic = new BasicAuthenticationFilter();
457-
// ... configure
458-
459-
http
460-
// ...
461-
.addFilterAt(basic, BasicAuthenticationFilter.class);
462-
463-
return http.build();
464-
}
465-
----
466-
467-
Kotlin::
468-
+
469-
[source,kotlin,role="secondary"]
470-
----
471-
@Bean
472-
fun filterChain(http: HttpSecurity): SecurityFilterChain {
473-
val basic = BasicAuthenticationFilter()
474-
// ... configure
475-
476-
http
477-
// ...
478-
.addFilterAt(basic, BasicAuthenticationFilter::class.java)
479-
480-
return http.build()
481-
}
482-
----
483-
======
290+
include-code::./CustomizingFilterTests[tag=custom-filter,indent=0]
484291

485292
Note that if that filter has already been added, then Spring Security will throw an exception.
486293
For example, calling xref:servlet/authentication/passwords/basic.adoc[ `HttpSecurity#httpBasic`] adds a `BasicAuthenticationFilter` for you.
487294
So, the following arrangement fails since there are two calls that are both trying to add `BasicAuthenticationFilter`:
488295

489-
[tabs]
490-
======
491-
Java::
492-
+
493-
[source,java,role="primary"]
494-
----
495-
@Bean
496-
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
497-
BasicAuthenticationFilter basic = new BasicAuthenticationFilter();
498-
// ... configure
499-
500-
http
501-
.httpBasic(Customizer.withDefaults())
502-
// ... on no! BasicAuthenticationFilter is added twice!
503-
.addFilterAt(basic, BasicAuthenticationFilter.class);
504-
505-
return http.build();
506-
}
507-
----
508-
509-
Kotlin::
510-
+
511-
[source,kotlin,role="secondary"]
512-
----
513-
@Bean
514-
fun filterChain(http: HttpSecurity): SecurityFilterChain {
515-
val basic = BasicAuthenticationFilter()
516-
// ... configure
517-
518-
http {
519-
httpBasic { }
520-
}
521-
522-
// ... on no! BasicAuthenticationFilter is added twice!
523-
http.addFilterAt(basic, BasicAuthenticationFilter::class.java)
524-
525-
return http.build()
526-
}
527-
----
528-
======
296+
include-code::./CustomizingFilterTests[tag=incorrect,indent=0]
529297

530298
In this case, remove the call to `httpBasic` since you are constructing `BasicAuthenticationFilter` yourself.
531299

532300
[TIP]
533301
====
534302
In the event that you are unable to reconfigure `HttpSecurity` to not add a certain filter, you can typically disable the Spring Security filter by calling its DSL's `disable` method like so:
535303
536-
[source,java]
537-
----
538-
.httpBasic((basic) -> basic.disable())
539-
----
304+
include-java::./CustomizingFilterTests[tag=disable,indent=0]
540305
====
541306

542307
[[servlet-exceptiontranslationfilter]]
@@ -618,53 +383,7 @@ Or you may want to shut off this feature since you always want to redirect the u
618383
To do that, you can use the javadoc:org.springframework.security.web.savedrequest.NullRequestCache[NullRequestCache] implementation.
619384

620385
.Prevent the Request From Being Saved
621-
[tabs]
622-
======
623-
Java::
624-
+
625-
[source,java,role="primary"]
626-
----
627-
@Bean
628-
SecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
629-
RequestCache nullRequestCache = new NullRequestCache();
630-
http
631-
// ...
632-
.requestCache((cache) -> cache
633-
.requestCache(nullRequestCache)
634-
);
635-
return http.build();
636-
}
637-
----
638-
639-
Kotlin::
640-
+
641-
[source,kotlin,role="secondary"]
642-
----
643-
@Bean
644-
open fun springSecurity(http: HttpSecurity): SecurityFilterChain {
645-
val nullRequestCache = NullRequestCache()
646-
http {
647-
requestCache {
648-
requestCache = nullRequestCache
649-
}
650-
}
651-
return http.build()
652-
}
653-
----
654-
655-
XML::
656-
+
657-
[source,xml,role="secondary"]
658-
----
659-
<http auto-config="true">
660-
<!-- ... -->
661-
<request-cache ref="nullRequestCache"/>
662-
</http>
663-
664-
<b:bean id="nullRequestCache" class="org.springframework.security.web.savedrequest.NullRequestCache"/>
665-
----
666-
======
667-
386+
include-code::./SecurityConfig[tag=snippet,indent=0]
668387

669388
[[requestcacheawarefilter]]
670389
=== RequestCacheAwareFilter

0 commit comments

Comments
 (0)