index.adoc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. [[servlet-architecture]]
  2. = Servlet Security: The Big Picture
  3. :figures: images/servlet/architecture
  4. :icondir: images/icons
  5. This section discusses Spring Security's high level architecture within Servlet based applications.
  6. We build on this high level understanding within <<servlet-authentication>>, <<servlet-authorization>>, <<servlet-exploits>> sections of the reference.
  7. // FIXME: Add links to other sections of architecture
  8. [[servlet-filters-review]]
  9. == A Review of ``Filter``s
  10. Spring Security's Servlet support is based on Servlet ``Filter``s, so it is helpful to look at the role of ``Filter``s generally first.
  11. The picture below shows the typical layering of the handlers for a single HTTP request.
  12. .FilterChain
  13. [[servlet-filterchain-figure]]
  14. image::{figures}/filterchain.png[]
  15. The client sends a request to the application, and the container creates a `FilterChain` which contains the ``Filter``s and `Servlet` that should process the `HttpServletRequest` based on the path of the request URI.
  16. In a Spring MVC application the `Servlet` is an instance of {spring-framework-reference-url}web.html#mvc-servlet[`DispatcherServlet`].
  17. At most one `Servlet` can handle a single `HttpServletRequest` and `HttpServletResponse`.
  18. However, more than one `Filter` can be used to:
  19. * Prevent downstream ``Filter``s or the `Servlet` from being invoked.
  20. In this instance the `Filter` will typically write the `HttpServletResponse`.
  21. * Modify the `HttpServletRequest` or `HttpServletResponse` used by the downstream ``Filter``s and `Servlet`
  22. The power of the `Filter` comes from the `FilterChain` that is passed into it.
  23. .`FilterChain` Usage Example
  24. ====
  25. .Java
  26. [source,java,role="primary"]
  27. ----
  28. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
  29. // do something before the rest of the application
  30. chain.doFilter(request, response); // invoke the rest of the application
  31. // do something after the rest of the application
  32. }
  33. ----
  34. .Kotlin
  35. [source,kotlin,role="secondary"]
  36. ----
  37. fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
  38. // do something before the rest of the application
  39. chain.doFilter(request, response) // invoke the rest of the application
  40. // do something after the rest of the application
  41. }
  42. ----
  43. ====
  44. Since a `Filter` only impacts downstream ``Filter``s and the `Servlet`, the order each `Filter` is invoked is extremely important.
  45. [[servlet-delegatingfilterproxy]]
  46. == DelegatingFilterProxy
  47. Spring provides a `Filter` implementation named {spring-framework-api-url}org/springframework/web/filter/DelegatingFilterProxy.html[`DelegatingFilterProxy`] that allows bridging between the Servlet container's lifecycle and Spring's `ApplicationContext`.
  48. The Servlet container allows registering ``Filter``s using its own standards, but it is not aware of Spring defined Beans.
  49. `DelegatingFilterProxy` can be registered via standard Servlet container mechanisms, but delegate all the work to a Spring Bean that implements `Filter`.
  50. Here is a picture of how `DelegatingFilterProxy` fits into the <<servlet-filters-review,``Filter``s and the `FilterChain`>>.
  51. .DelegatingFilterProxy
  52. [[servlet-delegatingfilterproxy-figure]]
  53. image::{figures}/delegatingfilterproxy.png[]
  54. `DelegatingFilterProxy` looks up __Bean Filter~0~__ from the `ApplicationContext` and then invokes __Bean Filter~0~__.
  55. The pseudo code of `DelegatingFilterProxy` can be seen below.
  56. .`DelegatingFilterProxy` Pseudo Code
  57. ====
  58. .Java
  59. [source,java,role="primary",subs="+quotes,+macros"]
  60. ----
  61. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
  62. // Lazily get Filter that was registered as a Spring Bean
  63. // For the example in <<servlet-delegatingfilterproxy-figure>> `delegate` is an instance of __Bean Filter~0~__
  64. Filter delegate = getFilterBean(someBeanName);
  65. // delegate work to the Spring Bean
  66. delegate.doFilter(request, response);
  67. }
  68. ----
  69. .Kotlin
  70. [source,kotlin,role="secondary",subs="+quotes,+macros"]
  71. ----
  72. fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
  73. // Lazily get Filter that was registered as a Spring Bean
  74. // For the example in <<servlet-delegatingfilterproxy-figure>> `delegate` is an instance of __Bean Filter~0~__
  75. val delegate: Filter = getFilterBean(someBeanName)
  76. // delegate work to the Spring Bean
  77. delegate.doFilter(request, response)
  78. }
  79. ----
  80. ====
  81. Another benefit of `DelegatingFilterProxy` is that it allows delaying looking `Filter` bean instances up.
  82. This is important because the container needs to register the `Filter` instances before the container can startup.
  83. However, Spring typically uses a `ContextLoaderListener` to load the Spring Beans which will not be done until after the `Filter` instances need to be registered.
  84. [[servlet-filterchainproxy]]
  85. == FilterChainProxy
  86. Spring Security's Servlet support is contained within `FilterChainProxy`.
  87. `FilterChainProxy` is a special `Filter` provided by Spring Security that allows delegating to many `Filter` instances through <<servlet-securityfilterchain,`SecurityFilterChain`>>.
  88. Since `FilterChainProxy` is a Bean, it is typically wrapped in a <<servlet-delegatingfilterproxy>>.
  89. .FilterChainProxy
  90. [[servlet-filterchainproxy-figure]]
  91. image::{figures}/filterchainproxy.png[]
  92. [[servlet-securityfilterchain]]
  93. == SecurityFilterChain
  94. {security-api-url}org/springframework/security/web/SecurityFilterChain.html[`SecurityFilterChain`] is used by <<servlet-filterchainproxy>> to determine which Spring Security ``Filter``s should be invoked for this request.
  95. .SecurityFilterChain
  96. [[servlet-securityfilterchain-figure]]
  97. image::{figures}/securityfilterchain.png[]
  98. The <<servlet-security-filters,Security Filters>> in `SecurityFilterChain` are typically Beans, but they are registered with `FilterChainProxy` instead of <<servlet-delegatingfilterproxy>>.
  99. `FilterChainProxy` provides a number of advantages to registering directly with the Servlet container or <<servlet-delegatingfilterproxy>>.
  100. First, it provides a starting point for all of Spring Security's Servlet support.
  101. For that reason, if you are attempting to troubleshoot Spring Security's Servlet support, adding a debug point in `FilterChainProxy` is a great place to start.
  102. Second, since `FilterChainProxy` is central to Spring Security usage it can perform tasks that are not viewed as optional.
  103. // FIXME: Add a link to SecurityContext
  104. For example, it clears out the `SecurityContext` to avoid memory leaks.
  105. It also applies Spring Security's <<servlet-httpfirewall,`HttpFirewall`>> to protect applications against certain types of attacks.
  106. In addition, it provides more flexibility in determining when a `SecurityFilterChain` should be invoked.
  107. In a Servlet container, ``Filter``s are invoked based upon the URL alone.
  108. // FIXME: Link to RequestMatcher
  109. However, `FilterChainProxy` can determine invocation based upon anything in the `HttpServletRequest` by leveraging the `RequestMatcher` interface.
  110. In fact, `FilterChainProxy` can be used to determine which `SecurityFilterChain` should be used.
  111. This allows providing a totally separate configuration for different _slices_ of your application.
  112. .Multiple SecurityFilterChain
  113. [[servlet-multi-securityfilterchain-figure]]
  114. image::{figures}/multi-securityfilterchain.png[]
  115. In the <<servlet-multi-securityfilterchain-figure>> Figure `FilterChainProxy` decides which `SecurityFilterChain` should be used.
  116. Only the first `SecurityFilterChain` that matches will be invoked.
  117. If a URL of `/api/messages/` is requested, it will first match on ``SecurityFilterChain~0~``'s pattern of `+/api/**+`, so only `SecurityFilterChain~0~` will be invoked even though it also matches on ``SecurityFilterChain~n~``.
  118. If a URL of `/messages/` is requested, it will not match on ``SecurityFilterChain~0~``'s pattern of `+/api/**+`, so `FilterChainProxy` will continue trying each `SecurityFilterChain`.
  119. Assuming that no other, `SecurityFilterChain` instances match `SecurityFilterChain~n~` will be invoked.
  120. // FIXME add link to pattern matching
  121. Notice that `SecurityFilterChain~0~` has only three security ``Filter``s instances configured.
  122. However, `SecurityFilterChain~n~` has four security ``Filter``s configured.
  123. It is important to note that each `SecurityFilterChain` can be unique and configured in isolation.
  124. In fact, a `SecurityFilterChain` might have zero security ``Filter``s if the application wants Spring Security to ignore certain requests.
  125. // FIXME: add link to configuring multiple `SecurityFilterChain` instances
  126. [[servlet-security-filters]]
  127. == Security Filters
  128. The Security Filters are inserted into the <<servlet-filterchainproxy>> with the <<servlet-securityfilterchain>> API.
  129. The <<servlet-filters-review,order of ``Filter``>>s matters.
  130. It is typically not necessary to know the ordering of Spring Security's ``Filter``s.
  131. However, there are times that it is beneficial to know the ordering
  132. Below is a comprehensive list of Spring Security Filter ordering:
  133. * ChannelProcessingFilter
  134. * WebAsyncManagerIntegrationFilter
  135. * SecurityContextPersistenceFilter
  136. * HeaderWriterFilter
  137. * CorsFilter
  138. * CsrfFilter
  139. * LogoutFilter
  140. * OAuth2AuthorizationRequestRedirectFilter
  141. * Saml2WebSsoAuthenticationRequestFilter
  142. * X509AuthenticationFilter
  143. * AbstractPreAuthenticatedProcessingFilter
  144. * CasAuthenticationFilter
  145. * OAuth2LoginAuthenticationFilter
  146. * Saml2WebSsoAuthenticationFilter
  147. * <<servlet-authentication-usernamepasswordauthenticationfilter,`UsernamePasswordAuthenticationFilter`>>
  148. * OpenIDAuthenticationFilter
  149. * DefaultLoginPageGeneratingFilter
  150. * DefaultLogoutPageGeneratingFilter
  151. * ConcurrentSessionFilter
  152. * <<servlet-authentication-digest,`DigestAuthenticationFilter`>>
  153. * BearerTokenAuthenticationFilter
  154. * <<servlet-authentication-basic,`BasicAuthenticationFilter`>>
  155. * RequestCacheAwareFilter
  156. * SecurityContextHolderAwareRequestFilter
  157. * JaasApiIntegrationFilter
  158. * RememberMeAuthenticationFilter
  159. * AnonymousAuthenticationFilter
  160. * OAuth2AuthorizationCodeGrantFilter
  161. * SessionManagementFilter
  162. * <<servlet-exceptiontranslationfilter,`ExceptionTranslationFilter`>>
  163. * <<servlet-authorization-filtersecurityinterceptor,`FilterSecurityInterceptor`>>
  164. * SwitchUserFilter
  165. [[servlet-exceptiontranslationfilter]]
  166. == Handling Security Exceptions
  167. The {security-api-url}org/springframework/security/web/access/ExceptionTranslationFilter.html[`ExceptionTranslationFilter`] allows translation of {security-api-url}org/springframework/security/access/AccessDeniedException.html[`AccessDeniedException`] and {security-api-url}/org/springframework/security/core/AuthenticationException.html[`AuthenticationException`] into HTTP responses.
  168. `ExceptionTranslationFilter` is inserted into the <<servlet-filterchainproxy>> as one of the <<servlet-security-filters>>.
  169. image::{figures}/exceptiontranslationfilter.png[]
  170. * image:{icondir}/number_1.png[] First, the `ExceptionTranslationFilter` invokes `FilterChain.doFilter(request, response)` to invoke the rest of the application.
  171. * image:{icondir}/number_2.png[] If the user is not authenticated or it is an `AuthenticationException`, then __Start Authentication__.
  172. ** The <<servlet-authentication-securitycontextholder>> is cleared out.
  173. ** The `HttpServletRequest` is saved in the {security-api-url}org/springframework/security/web/savedrequest/RequestCache.html[`RequestCache`].
  174. When the user successfully authenticates, the `RequestCache` is used to replay the original request.
  175. // FIXME: add link to authentication success
  176. ** The `AuthenticationEntryPoint` is used to request credentials from the client.
  177. For example, it might redirect to a log in page or send a `WWW-Authenticate` header.
  178. // FIXME: link to AuthenticationEntryPoint
  179. * image:{icondir}/number_3.png[] Otherwise if it is an `AccessDeniedException`, then __Access Denied__.
  180. The `AccessDeniedHandler` is invoked to handle access denied.
  181. // FIXME: link to AccessDeniedHandler
  182. [NOTE]
  183. ====
  184. If the application does not throw an `AccessDeniedException` or an `AuthenticationException`, then `ExceptionTranslationFilter` does not do anything.
  185. ====
  186. The pseudocode for `ExceptionTranslationFilter` looks something like this:
  187. .ExceptionTranslationFilter pseudocode
  188. [source,java]
  189. ----
  190. try {
  191. filterChain.doFilter(request, response); // <1>
  192. } catch (AccessDeniedException | AuthenticationException ex) {
  193. if (!authenticated || ex instanceof AuthenticationException) {
  194. startAuthentication(); // <2>
  195. } else {
  196. accessDenied(); // <3>
  197. }
  198. }
  199. ----
  200. <1> You will recall from <<servlet-filters-review>> that invoking `FilterChain.doFilter(request, response)` is the equivalent of invoking the rest of the application.
  201. This means that if another part of the application, (i.e. <<servlet-authorization-filtersecurityinterceptor,`FilterSecurityInterceptor`>> or method security) throws an `AuthenticationException` or `AccessDeniedException` it will be caught and handled here.
  202. <2> If the user is not authenticated or it is an `AuthenticationException`, then __Start Authentication__.
  203. <3> Otherwise, __Access Denied__