├── .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` (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 --------------------------------------------------------------------------------