├── .gitignore
├── Jenkinsfile
├── README.adoc
└── images
├── authentication.odg
├── authentication.png
├── filters.odg
├── filters.png
├── security-filters-dispatch.odg
├── security-filters-dispatch.png
├── security-filters.odg
└── security-filters.png
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | .#*
3 | *#
4 |
--------------------------------------------------------------------------------
/Jenkinsfile:
--------------------------------------------------------------------------------
1 | pipeline {
2 | agent none
3 |
4 | triggers {
5 | pollSCM 'H/10 * * * *'
6 | }
7 |
8 | options {
9 | disableConcurrentBuilds()
10 | buildDiscarder(logRotator(numToKeepStr: '14'))
11 | }
12 |
13 | stages {
14 | stage("test: baseline (jdk8)") {
15 | agent {
16 | docker {
17 | image 'adoptopenjdk/openjdk8:latest'
18 | args '-v $HOME/.m2:/tmp/jenkins-home/.m2'
19 | }
20 | }
21 | options { timeout(time: 30, unit: 'MINUTES') }
22 | steps {
23 | sh 'test/run.sh'
24 | }
25 | }
26 |
27 | }
28 |
29 | post {
30 | changed {
31 | script {
32 | slackSend(
33 | color: (currentBuild.currentResult == 'SUCCESS') ? 'good' : 'danger',
34 | channel: '#sagan-content',
35 | message: "${currentBuild.fullDisplayName} - `${currentBuild.currentResult}`\n${env.BUILD_URL}")
36 | emailext(
37 | subject: "[${currentBuild.fullDisplayName}] ${currentBuild.currentResult}",
38 | mimeType: 'text/html',
39 | recipientProviders: [[$class: 'CulpritsRecipientProvider'], [$class: 'RequesterRecipientProvider']],
40 | body: "${currentBuild.fullDisplayName} is reported as ${currentBuild.currentResult}")
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/README.adoc:
--------------------------------------------------------------------------------
1 | ---
2 | tags: [security]
3 | projects: [spring-security]
4 | ---
5 | :toc:
6 | :all: {asterisk}{asterisk}
7 | :images: https://github.com/spring-guides/top-spring-security-architecture/raw/main/images
8 |
9 | # This repository is no longer maintained.
10 |
11 | = Understanding Spring Security
12 |
13 | This guide is a primer for Spring Security, offering insight into the
14 | design and basic building blocks of the framework. We cover only the
15 | very basics of application security. However, in doing so, we can clear up
16 | some of the confusion experienced by developers who use Spring
17 | Security. To do this, we take a look at the way security is applied in
18 | web applications by using filters and, more generally, by using method
19 | annotations. Use this guide when you need a high-level understanding
20 | of how a secure application works, how it can be customized, or
21 | if you need to learn how to think about application security.
22 |
23 | This guide is not intended as a manual or recipe for solving more than
24 | the most basic problems (there are other sources for those), but it
25 | could be useful for beginners and experts alike. Spring Boot is also
26 | often referenced, because it provides some default behavior for a
27 | secure application, and it can be useful to understand how that fits in
28 | with the overall architecture.
29 |
30 | NOTE: All of the principles apply equally
31 | well to applications that do not use Spring Boot.
32 |
33 | == Authentication and Access Control
34 |
35 | Application security boils down to two more or less independent
36 | problems: authentication (who are you?) and authorization (what are
37 | you allowed to do?). Sometimes people say "`access control`" instead of
38 | "authorization", which can get confusing, but it can be helpful to
39 | think of it that way because "`authorization`" is overloaded in other
40 | places. Spring Security has an architecture that is designed to
41 | separate authentication from authorization and has strategies and
42 | extension points for both.
43 |
44 | === Authentication
45 |
46 | The main strategy interface for authentication is
47 | `AuthenticationManager`, which has only one method:
48 |
49 | ====
50 | [source,java]
51 | ----
52 | public interface AuthenticationManager {
53 |
54 | Authentication authenticate(Authentication authentication)
55 | throws AuthenticationException;
56 | }
57 | ----
58 | ====
59 |
60 | An `AuthenticationManager`
61 | can do one of 3 things in its `authenticate()` method:
62 |
63 | * Return an `Authentication` (normally with `authenticated=true`) if it can verify that the input represents a valid principal.
64 |
65 | * Throw an `AuthenticationException` if it believes that the input represents an invalid principal.
66 |
67 | * Return `null` if it cannot decide.
68 |
69 | `AuthenticationException` is a runtime exception. It is usually
70 | handled by an application in a generic way, depending on the style or
71 | purpose of the application. In other words, user code is not normally
72 | expected to catch and handle it. For example, a web UI might render a
73 | page that says that the authentication failed, and a backend HTTP
74 | service might send a 401 response, with or without a `WWW-Authenticate`
75 | header depending on the context.
76 |
77 | The most commonly used implementation of `AuthenticationManager` is
78 | `ProviderManager`, which delegates to a chain of
79 | `AuthenticationProvider` instances. An `AuthenticationProvider` is a
80 | bit like an `AuthenticationManager`, but it has an extra method to
81 | allow the caller to query whether it supports a given `Authentication`
82 | type:
83 |
84 | ====
85 | [source,java]
86 | ----
87 | public interface AuthenticationProvider {
88 |
89 | Authentication authenticate(Authentication authentication)
90 | throws AuthenticationException;
91 |
92 | boolean supports(Class> authentication);
93 | }
94 | ----
95 | ====
96 |
97 | The `Class>` argument in the `supports()` method is really `Class
98 | extends Authentication>` (it is only ever asked if it supports
99 | something that is passed into the `authenticate()` method). A
100 | `ProviderManager` can support multiple different authentication
101 | mechanisms in the same application by delegating to a chain of
102 | `AuthenticationProviders`. If a `ProviderManager` does not recognize a
103 | particular `Authentication` instance type, it is skipped.
104 |
105 | A `ProviderManager` has an optional parent, which it can consult if
106 | all providers return `null`. If the parent is not available, a
107 | `null` `Authentication` results in an `AuthenticationException`.
108 |
109 | Sometimes, an application has logical groups of protected resources
110 | (for example, all web resources that match a path pattern, such as `/api/{all}`), and
111 | each group can have its own dedicated `AuthenticationManager`. Often,
112 | each of those is a `ProviderManager`, and they share a parent. The
113 | parent is then a kind of "`global`" resource, acting as a fallback for
114 | all providers.
115 |
116 | .An `AuthenticationManager` hierarchy using `ProviderManager`
117 | image::{images}/authentication.png[ProviderManagers with a common parent,70%]
118 |
119 | === Customizing Authentication Managers
120 |
121 | Spring Security provides some configuration helpers to quickly get
122 | common authentication manager features set up in your application. The
123 | most commonly used helper is the `AuthenticationManagerBuilder`, which
124 | is great for setting up in-memory, JDBC, or LDAP user details or for
125 | adding a custom `UserDetailsService`. The following example shows an
126 | application that configures the global (parent) `AuthenticationManager`:
127 |
128 | ====
129 | [source, java]
130 | ----
131 | @Configuration
132 | public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
133 |
134 | ... // web stuff here
135 |
136 | @Autowired
137 | public void initialize(AuthenticationManagerBuilder builder, DataSource dataSource) {
138 | builder.jdbcAuthentication().dataSource(dataSource).withUser("dave")
139 | .password("secret").roles("USER");
140 | }
141 |
142 | }
143 | ----
144 | ====
145 |
146 | This example relates to a web application, but the usage of
147 | `AuthenticationManagerBuilder` is more widely applicable (see <>
148 | for more detail on how web application security is implemented). Note
149 | that the `AuthenticationManagerBuilder` is `@Autowired` into a method
150 | in a `@Bean` -- that is what makes it build the global (parent)
151 | `AuthenticationManager`. In contrast, consider the following example:
152 |
153 | ====
154 | [source, java]
155 | ----
156 | @Configuration
157 | public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
158 |
159 | @Autowired
160 | DataSource dataSource;
161 |
162 | ... // web stuff here
163 |
164 | @Override
165 | public void configure(AuthenticationManagerBuilder builder) {
166 | builder.jdbcAuthentication().dataSource(dataSource).withUser("dave")
167 | .password("secret").roles("USER");
168 | }
169 |
170 | }
171 | ----
172 | ====
173 |
174 | If we had used an `@Override` of a method in the configurer, the
175 | `AuthenticationManagerBuilder` would be used only to build a "`local`"
176 | `AuthenticationManager`, which would be a child of the global one. In a
177 | Spring Boot application, you can `@Autowired` the global one into
178 | another bean, but you cannot do that with the local one unless you
179 | explicitly expose it yourself.
180 |
181 | Spring Boot provides a default global `AuthenticationManager` (with
182 | only one user) unless you pre-empt it by providing your own bean of
183 | type `AuthenticationManager`. The default is secure enough on its own
184 | for you not to have to worry about it much, unless you actively need a
185 | custom global `AuthenticationManager`. If you do any configuration
186 | that builds an `AuthenticationManager`, you can often do it locally to
187 | the resources that you are protecting and not worry about the global
188 | default.
189 |
190 | === Authorization or Access Control
191 |
192 | Once authentication is successful, we can move on to authorization,
193 | and the core strategy here is `AccessDecisionManager`. There are three
194 | implementations provided by the framework and all three delegate to a
195 | chain of `AccessDecisionVoter` instances, a bit like the `ProviderManager`
196 | delegates to `AuthenticationProviders`.
197 |
198 | An `AccessDecisionVoter` considers an `Authentication` (representing a
199 | principal) and a secure `Object`, which has been decorated with
200 | `ConfigAttributes`:
201 |
202 | ====
203 | [source, java]
204 | ----
205 | boolean supports(ConfigAttribute attribute);
206 |
207 | boolean supports(Class> clazz);
208 |
209 | int vote(Authentication authentication, S object,
210 | Collection attributes);
211 | ----
212 | ====
213 |
214 | The `Object` is completely generic in the signatures of the
215 | `AccessDecisionManager` and `AccessDecisionVoter`. It represents
216 | anything that a user might want to access (a web resource or a method
217 | in a Java class are the two most common cases). The `ConfigAttributes`
218 | are also fairly generic, representing a decoration of the secure
219 | `Object` with some metadata that determines the level of permission
220 | required to access it. `ConfigAttribute` is an interface. It
221 | has only one method (which is quite generic and returns a `String`), so these
222 | strings encode in some way the intention of the owner of the resource,
223 | expressing rules about who is allowed to access it. A typical
224 | `ConfigAttribute` is the name of a user role (like `ROLE_ADMIN` or
225 | `ROLE_AUDIT`), and they often have special formats (like the `ROLE_`
226 | prefix) or represent expressions that need to be evaluated.
227 |
228 | Most people use the default `AccessDecisionManager`, which is
229 | `AffirmativeBased` (if any voters return affirmatively, access is granted). Any
230 | customization tends to happen in the voters, either by adding new ones
231 | or modifying the way that the existing ones work.
232 |
233 | It is very common to use `ConfigAttributes` that are Spring Expression
234 | Language (SpEL) expressions -- for example, `isFullyAuthenticated() &&
235 | hasRole('user')`. This is supported by an `AccessDecisionVoter` that
236 | can handle the expressions and create a context for them. To extend
237 | the range of expressions that can be handled requires a custom
238 | implementation of `SecurityExpressionRoot` and sometimes also
239 | `SecurityExpressionHandler`.
240 |
241 | [[web-security]]
242 | == Web Security
243 |
244 | Spring Security in the web tier (for UIs and HTTP back ends) is based
245 | on Servlet `Filters`, so it is helpful to first look at the role of
246 | `Filters` generally. The following picture shows the typical
247 | layering of the handlers for a single HTTP request.
248 |
249 | image::{images}/filters.png[Filter chain delegating to a Servlet,70%]
250 |
251 | The client sends a request to the application, and the container decides which
252 | filters and which servlet apply to it based on the path of the request
253 | URI. At most, one servlet can handle a single request, but filters form
254 | a chain, so they are ordered. In fact, a filter can veto the rest
255 | of the chain if it wants to handle the request itself. A filter can
256 | also modify the request or the response used in the downstream
257 | filters and servlet. The order of the filter chain is very important,
258 | and Spring Boot manages it through two mechanisms: `@Beans`
259 | of type `Filter` can have an `@Order` or implement `Ordered`, and
260 | they can be part of a `FilterRegistrationBean` that
261 | itself has an order as part of its API. Some off-the-shelf filters
262 | define their own constants to help signal what order they like to be
263 | in relative to each other (for example, the `SessionRepositoryFilter` from
264 | Spring Session has a `DEFAULT_ORDER` of `Integer.MIN_VALUE + 50`,
265 | which tells us it likes to be early in the chain, but it does not rule
266 | out other filters coming before it).
267 |
268 | Spring Security is installed as a single `Filter` in the chain, and
269 | its concrete type is `FilterChainProxy`, for reasons that we cover
270 | soon. In a Spring Boot application, the security filter is a `@Bean`
271 | in the `ApplicationContext`, and it is installed by default so that it
272 | is applied to every request. It is installed at a position defined by
273 | `SecurityProperties.DEFAULT_FILTER_ORDER`, which in turn is anchored
274 | by `FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER` (the
275 | maximum order that a Spring Boot application expects filters to have if they
276 | wrap the request, modifying its behavior). There is more to it than
277 | that, though: From the point of view of the container, Spring Security
278 | is a single filter, but, inside of it, there are additional filters, each
279 | playing a special role. The following image shows this relationship:
280 |
281 | .Spring Security is a single physical `Filter` but delegates processing to a chain of internal filters
282 | image::{images}/security-filters.png[Spring Security Filter,70%]
283 |
284 | In fact, there is even one more layer of indirection in the security
285 | filter: It is usually installed in the container as a
286 | `DelegatingFilterProxy`, which does not have to be a Spring
287 | `@Bean`. The proxy delegates to a `FilterChainProxy`, which is always a
288 | `@Bean`, usually with a fixed name of `springSecurityFilterChain`. It
289 | is the `FilterChainProxy` that contains all the security logic
290 | arranged internally as a chain (or chains) of filters. All the filters
291 | have the same API (they all implement the `Filter` interface from the
292 | Servlet specification), and they all have the opportunity to veto the rest of
293 | the chain.
294 |
295 | There can be multiple filter chains all managed by Spring Security in
296 | the same top level `FilterChainProxy` and all are unknown to the
297 | container. The Spring Security filter contains a list of filter
298 | chains and dispatches a request to the first chain that matches
299 | it. The following picture shows the dispatch happening based on matching
300 | the request path (`/foo/{all}` matches before `/{all}`). This is very
301 | common but not the only way to match a request. The most important
302 | feature of this dispatch process is that only one chain ever handles a
303 | request.
304 |
305 | .The Spring Security `FilterChainProxy` dispatches requests to the first chain that matches.
306 | image::{images}/security-filters-dispatch.png[Security Filter Dispatch,70%]
307 |
308 | A vanilla Spring Boot application with no custom security
309 | configuration has a several (call it n) filter chains, where usually
310 | n=6. The first (n-1) chains are there just to ignore static resource
311 | patterns, like `/css/{all}` and `/images/{all}`, and the error view:
312 | `/error`. (The paths can be controlled by the user with
313 | `security.ignored` from the `SecurityProperties` configuration
314 | bean.) The last chain matches the catch-all path (`/{all}`) and is more
315 | active, containing logic for authentication, authorization, exception
316 | handling, session handling, header writing, and so on. There are a total of
317 | 11 filters in this chain by default, but normally it is not necessary
318 | for users to concern themselves with which filters are used and when.
319 |
320 | NOTE: The fact that all filters internal to Spring Security are
321 | unknown to the container is important, especially in a Spring Boot
322 | application, where, by default, all `@Beans` of type `Filter` are registered
323 | automatically with the container. So if you want to add a
324 | custom filter to the security chain, you need to either not make it be a
325 | `@Bean` or wrap it in a `FilterRegistrationBean` that explicitly
326 | disables the container registration.
327 |
328 | === Creating and Customizing Filter Chains
329 |
330 | The default fallback filter chain in a Spring Boot application (the one with
331 | the `/{all}` request matcher) has a predefined order of
332 | `SecurityProperties.BASIC_AUTH_ORDER`. You can switch it off
333 | completely by setting `security.basic.enabled=false`, or you can use
334 | it as a fallback and define other rules with a lower order. To do
335 | the latter, add a `@Bean` of type `WebSecurityConfigurerAdapter` (or
336 | `WebSecurityConfigurer`) and decorate the class with `@Order`, as follows:
337 |
338 | ====
339 | [source,java]
340 | ----
341 | @Configuration
342 | @Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
343 | public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
344 | @Override
345 | protected void configure(HttpSecurity http) throws Exception {
346 | http.antMatcher("/match1/**")
347 | ...;
348 | }
349 | }
350 | ----
351 | ====
352 |
353 | This bean causes Spring Security to add a new filter chain and
354 | order it before the fallback.
355 |
356 | Many applications have completely different access rules for one set
357 | of resources compared to another. For example, an application that
358 | hosts a UI and a backing API might support cookie-based authentication
359 | with a redirect to a login page for the UI parts and token-based
360 | authentication with a 401 response to unauthenticated requests for the
361 | API parts. Each set of resources has its own
362 | `WebSecurityConfigurerAdapter` with a unique order and its own
363 | request matcher. If the matching rules overlap, the earliest ordered
364 | filter chain wins.
365 |
366 | === Request Matching for Dispatch and Authorization
367 |
368 | A security filter chain (or, equivalently, a
369 | `WebSecurityConfigurerAdapter`) has a request matcher that is used to
370 | decide whether to apply it to an HTTP request. Once the decision is
371 | made to apply a particular filter chain, no others are applied. However,
372 | within a filter chain, you can have more fine-grained control of
373 | authorization by setting additional matchers in the `HttpSecurity`
374 | configurer, as follows:
375 |
376 | ====
377 | [source,java]
378 | ----
379 | @Configuration
380 | @Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
381 | public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
382 | @Override
383 | protected void configure(HttpSecurity http) throws Exception {
384 | http.antMatcher("/match1/**")
385 | .authorizeRequests()
386 | .antMatchers("/match1/user").hasRole("USER")
387 | .antMatchers("/match1/spam").hasRole("SPAM")
388 | .anyRequest().isAuthenticated();
389 | }
390 | }
391 | ----
392 | ====
393 |
394 | One of the easiest mistakes to make when configuring Spring Security
395 | is to forget that these matchers apply to different processes. One is
396 | a request matcher for the whole filter chain, and the other is only to
397 | choose the access rule to apply.
398 |
399 | === Combining Application Security Rules with Actuator Rules
400 |
401 | If you use the Spring Boot Actuator for management endpoints,
402 | you probably want them to be secure, and, by default, they are. In
403 | fact, as soon as you add the Actuator to a secure application, you get
404 | an additional filter chain that applies only to the actuator
405 | endpoints. It is defined with a request matcher that matches only
406 | actuator endpoints and it has an order of
407 | `ManagementServerProperties.BASIC_AUTH_ORDER`, which is 5 fewer than
408 | the default `SecurityProperties` fallback filter, so it is consulted
409 | before the fallback.
410 |
411 | If you want your application security rules to apply to the actuator
412 | endpoints, you can add a filter chain that is ordered earlier than the actuator
413 | one and that has a request matcher that includes all actuator
414 | endpoints. If you prefer the default security settings for the
415 | actuator endpoints, the easiest thing is to add your own filter
416 | later than the actuator one, but earlier than the fallback
417 | (for example, `ManagementServerProperties.BASIC_AUTH_ORDER + 1`), as follows:
418 |
419 | ====
420 | [source,java]
421 | ----
422 | @Configuration
423 | @Order(ManagementServerProperties.BASIC_AUTH_ORDER + 1)
424 | public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
425 | @Override
426 | protected void configure(HttpSecurity http) throws Exception {
427 | http.antMatcher("/foo/**")
428 | ...;
429 | }
430 | }
431 | ----
432 | ====
433 |
434 | NOTE: Spring Security in the web tier is currently tied to the Servlet
435 | API, so it is only really applicable when running an application in a servlet
436 | container, either embedded or otherwise. It is not, however, tied to
437 | Spring MVC or the rest of the Spring web stack, so it can be used in
438 | any servlet application -- for instance, one using JAX-RS.
439 |
440 | == Method Security
441 |
442 | As well as support for securing web applications, Spring Security
443 | offers support for applying access rules to Java method
444 | executions. For Spring Security, this is just a different type of
445 | "`protected resource`". For users, it means the access rules are declared
446 | using the same format of `ConfigAttribute` strings (for example, roles or
447 | expressions) but in a different place in your code. The first step is
448 | to enable method security -- for example, in the top level configuration
449 | for our application:
450 |
451 | ====
452 | [source,java]
453 | ----
454 | @SpringBootApplication
455 | @EnableGlobalMethodSecurity(securedEnabled = true)
456 | public class SampleSecureApplication {
457 | }
458 | ----
459 | ====
460 |
461 | Then we can decorate the method resources directly:
462 |
463 | ====
464 | [source,java]
465 | ----
466 | @Service
467 | public class MyService {
468 |
469 | @Secured("ROLE_USER")
470 | public String secure() {
471 | return "Hello Security";
472 | }
473 |
474 | }
475 | ----
476 | ====
477 |
478 | This example is a service with a secure method. If Spring creates a
479 | `@Bean` of this type, it is proxied and callers have to
480 | go through a security interceptor before the method is actually
481 | executed. If access is denied, the caller gets an
482 | `AccessDeniedException` instead of the actual method result.
483 |
484 | There are other annotations that you can use on methods to enforce
485 | security constraints, notably `@PreAuthorize` and `@PostAuthorize`,
486 | which let you write expressions containing references to method
487 | parameters and return values, respectively.
488 |
489 | TIP: It is not uncommon to combine Web security and method
490 | security. The filter chain provides the user experience features, such as
491 | authentication and redirect to login pages and so on, and the method
492 | security provides protection at a more granular level.
493 |
494 | == Working with Threads
495 |
496 | Spring Security is fundamentally thread-bound, because it needs to make
497 | the current authenticated principal available to a wide variety of
498 | downstream consumers. The basic building block is the
499 | `SecurityContext`, which may contain an `Authentication` (and when a
500 | user is logged in it is an `Authentication` that is explicitly
501 | `authenticated`). You can always access and manipulate the
502 | `SecurityContext` through static convenience methods in
503 | `SecurityContextHolder`, which, in turn, manipulate a
504 | `ThreadLocal`. The following example shows such an arrangement:
505 |
506 | ====
507 | [source,java]
508 | ----
509 | SecurityContext context = SecurityContextHolder.getContext();
510 | Authentication authentication = context.getAuthentication();
511 | assert(authentication.isAuthenticated);
512 | ----
513 | ====
514 |
515 | It is *not* common for user application code to do this, but it can be
516 | useful if you, for instance, need to write a custom authentication
517 | filter (although, even then, there are base classes in Spring Security
518 | that you can use so that you could avoid needing to use the
519 | `SecurityContextHolder`).
520 |
521 | If you need access to the currently authenticated user in a web
522 | endpoint, you can use a method parameter in a `@RequestMapping`, as follows:
523 |
524 | ====
525 | [source,java]
526 | ----
527 | @RequestMapping("/foo")
528 | public String foo(@AuthenticationPrincipal User user) {
529 | ... // do stuff with user
530 | }
531 | ----
532 | ====
533 |
534 | This annotation pulls the current `Authentication` out of the
535 | `SecurityContext` and calls the `getPrincipal()` method on it to yield
536 | the method parameter. The type of the `Principal` in an
537 | `Authentication` is dependent on the `AuthenticationManager` used to
538 | validate the authentication, so this can be a useful little trick to get a type-safe reference to your user data.
539 |
540 | If Spring Security is in use, the `Principal` from the
541 | `HttpServletRequest` is of type `Authentication`, so you can also
542 | use that directly:
543 |
544 | ====
545 | [source,java]
546 | ----
547 | @RequestMapping("/foo")
548 | public String foo(Principal principal) {
549 | Authentication authentication = (Authentication) principal;
550 | User = (User) authentication.getPrincipal();
551 | ... // do stuff with user
552 | }
553 | ----
554 | ====
555 |
556 | This can sometimes be useful if you need to write code that works when
557 | Spring Security is not in use (you would need to be more defensive
558 | about loading the `Authentication` class).
559 |
560 | === Processing Secure Methods Asynchronously
561 |
562 | Since the `SecurityContext` is thread-bound, if you want to do any
563 | background processing that calls secure methods (for example, with `@Async`),
564 | you need to ensure that the context is propagated. This boils down to
565 | wrapping the `SecurityContext` with the task (`Runnable`,
566 | `Callable`, and so on) that is executed in the background. Spring Security
567 | provides some helpers to make this easier, such as wrappers for
568 | `Runnable` and `Callable`. To propagate the `SecurityContext` to
569 | `@Async` methods, you need to supply an `AsyncConfigurer` and ensure
570 | the `Executor` is of the correct type:
571 |
572 | ====
573 | [source,java]
574 | ----
575 | @Configuration
576 | public class ApplicationConfiguration extends AsyncConfigurerSupport {
577 |
578 | @Override
579 | public Executor getAsyncExecutor() {
580 | return new DelegatingSecurityContextExecutorService(Executors.newFixedThreadPool(5));
581 | }
582 |
583 | }
584 | ----
585 | ====
586 |
--------------------------------------------------------------------------------
/images/authentication.odg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spring-attic/top-spring-security-architecture/6d2dbfbd1b1d786df053fe999446702ed852327f/images/authentication.odg
--------------------------------------------------------------------------------
/images/authentication.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spring-attic/top-spring-security-architecture/6d2dbfbd1b1d786df053fe999446702ed852327f/images/authentication.png
--------------------------------------------------------------------------------
/images/filters.odg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spring-attic/top-spring-security-architecture/6d2dbfbd1b1d786df053fe999446702ed852327f/images/filters.odg
--------------------------------------------------------------------------------
/images/filters.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spring-attic/top-spring-security-architecture/6d2dbfbd1b1d786df053fe999446702ed852327f/images/filters.png
--------------------------------------------------------------------------------
/images/security-filters-dispatch.odg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spring-attic/top-spring-security-architecture/6d2dbfbd1b1d786df053fe999446702ed852327f/images/security-filters-dispatch.odg
--------------------------------------------------------------------------------
/images/security-filters-dispatch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spring-attic/top-spring-security-architecture/6d2dbfbd1b1d786df053fe999446702ed852327f/images/security-filters-dispatch.png
--------------------------------------------------------------------------------
/images/security-filters.odg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spring-attic/top-spring-security-architecture/6d2dbfbd1b1d786df053fe999446702ed852327f/images/security-filters.odg
--------------------------------------------------------------------------------
/images/security-filters.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spring-attic/top-spring-security-architecture/6d2dbfbd1b1d786df053fe999446702ed852327f/images/security-filters.png
--------------------------------------------------------------------------------