web.adoc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. = Web Migrations
  2. == Favor Relative URIs
  3. When redirecting to a login endpoint, Spring Security has favored absolute URIs in the past.
  4. For example, if you set your login page like so:
  5. [tabs]
  6. ======
  7. Java::
  8. +
  9. [source,java,role="primary"]
  10. ----
  11. http
  12. // ...
  13. .formLogin((form) -> form.loginPage("/my-login"))
  14. // ...
  15. ----
  16. Kotlin::
  17. +
  18. [source,kotlin,role="secondary"]
  19. ----
  20. http {
  21. formLogin {
  22. loginPage = "/my-login"
  23. }
  24. }
  25. ----
  26. Xml::
  27. +
  28. [source,kotlin,role="secondary"]
  29. ----
  30. <http ...>
  31. <form-login login-page="/my-login"/>
  32. </http>
  33. ----
  34. ======
  35. then when redirecting to `/my-login` Spring Security would use a `Location:` like the following:
  36. [source]
  37. ----
  38. 302 Found
  39. // ...
  40. Location: https://myapp.example.org/my-login
  41. ----
  42. However, this is no longer necessary given that the RFC is was based on is now obsolete.
  43. In Spring Security 7, this is changed to use a relative URI like so:
  44. [source]
  45. ----
  46. 302 Found
  47. // ...
  48. Location: /my-login
  49. ----
  50. Most applications will not notice a difference.
  51. However, in the event that this change causes problems, you can switch back to the Spring Security 6 behavior by setting the `favorRelativeUrls` value:
  52. [tabs]
  53. ======
  54. Java::
  55. +
  56. [source,java,role="primary"]
  57. ----
  58. LoginUrlAuthenticationEntryPoint entryPoint = new LoginUrlAuthenticationEntryPoint("/my-login");
  59. entryPoint.setFavorRelativeUris(false);
  60. http
  61. // ...
  62. .exceptionHandling((exceptions) -> exceptions.authenticaitonEntryPoint(entryPoint))
  63. // ...
  64. ----
  65. Kotlin::
  66. +
  67. [source,kotlin,role="secondary"]
  68. ----
  69. LoginUrlAuthenticationEntryPoint entryPoint = LoginUrlAuthenticationEntryPoint("/my-login")
  70. entryPoint.setFavorRelativeUris(false)
  71. http {
  72. exceptionHandling {
  73. authenticationEntryPoint = entryPoint
  74. }
  75. }
  76. ----
  77. Xml::
  78. +
  79. [source,xml,role="secondary"]
  80. ----
  81. <http entry-point-ref="myEntryPoint">
  82. <!-- ... -->
  83. </http>
  84. <b:bean id="myEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
  85. <b:property name="favorRelativeUris" value="true"/>
  86. </b:bean>
  87. ----
  88. ======
  89. == PortResolver
  90. Spring Security uses an API called `PortResolver` to provide a workaround for a bug in Internet Explorer.
  91. The workaround is no longer necessary and can cause users problems in some scenarios.
  92. For this reason, Spring Security 7 will remove the `PortResolver` interface.
  93. To prepare for this change, users should expose the `PortResolver.NO_OP` as a Bean named `portResolver`.
  94. This ensures that the `PortResolver` implementation that is used is a no-op (e.g. does nothing) which simulates the removal of `PortResolver`.
  95. An example configuration can be found below:
  96. [tabs]
  97. ======
  98. Java::
  99. +
  100. [source,java,role="primary"]
  101. ----
  102. @Bean
  103. PortResolver portResolver() {
  104. return PortResolver.NO_OP;
  105. }
  106. ----
  107. Kotlin::
  108. +
  109. [source,kotlin,role="secondary"]
  110. ----
  111. @Bean
  112. open fun portResolver(): PortResolver {
  113. return PortResolver.NO_OP
  114. }
  115. ----
  116. Xml::
  117. +
  118. [source,xml,role="secondary"]
  119. ----
  120. <util:constant id="portResolver"
  121. static-field="org.springframework.security.web.PortResolver.NO_OP">
  122. ----
  123. ======
  124. [[use-path-pattern]]
  125. == Use PathPatternRequestMatcher by Default
  126. In Spring Security 7, `AntPathRequestMatcher` and `MvcRequestMatcher` are no longer supported and the Java DSL requires that all URIs be absolute (less any context root).
  127. At that time, Spring Security 7 will use `PathPatternRequestMatcher` by default.
  128. To check how prepared you are for this change, you can publish this bean:
  129. [tabs]
  130. ======
  131. Java::
  132. +
  133. [source,java,role="primary"]
  134. ----
  135. @Bean
  136. PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
  137. return new PathPatternRequestMatcherBuilderFactoryBean();
  138. }
  139. ----
  140. Kotlin::
  141. +
  142. [source,kotlin,role="secondary"]
  143. ----
  144. @Bean
  145. fun requestMatcherBuilder(): PathPatternRequestMatcherBuilderFactoryBean {
  146. return PathPatternRequestMatcherBuilderFactoryBean()
  147. }
  148. ----
  149. Xml::
  150. +
  151. [source,xml,role="secondary"]
  152. ----
  153. <b:bean class="org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean"/>
  154. ----
  155. ======
  156. This will tell the Spring Security DSL to use `PathPatternRequestMatcher` for all request matchers that it constructs.
  157. In the event that you are directly constructing an object (as opposed to having the DSL construct it) that has a `setRequestMatcher` method. you should also proactively specify a `PathPatternRequestMatcher` there as well.
  158. === Migrate `exitUserUrl` and `switchUserUrl` Request Matchers in `SwitchUserFilter`
  159. `SwitchUserFilter`, constructs an `AntPathRequestMatcher` in its `setExitUserUrl` and `setSwitchUserUrl` methods.
  160. This will change to use `PathPatternRequestMatcher` in Spring Security 7.
  161. To prepare for this change, call `setExitUserMatcher` and `setSwithcUserMatcher` to provide this `PathPatternRequestMatcher` in advance.
  162. That is, change this:
  163. [tabs]
  164. ======
  165. Java::
  166. +
  167. [source,java,role="primary"]
  168. ----
  169. SwitchUserFilter switchUser = new SwitchUserFilter();
  170. // ... other configuration
  171. switchUser.setExitUserUrl("/exit/impersonate");
  172. ----
  173. Kotlin::
  174. +
  175. [source,kotlin,role="secondary"]
  176. ----
  177. val switchUser = SwitchUserFilter()
  178. // ... other configuration
  179. switchUser.setExitUserUrl("/exit/impersonate")
  180. ----
  181. ======
  182. to this:
  183. [tabs]
  184. ======
  185. Java::
  186. +
  187. [source,java,role="primary"]
  188. ----
  189. SwitchUserFilter switchUser = new SwitchUserFilter();
  190. // ... other configuration
  191. switchUser.setExitUserMatcher(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/exit/impersonate"));
  192. ----
  193. Kotlin::
  194. +
  195. [source,kotlin,role="secondary"]
  196. ----
  197. val switchUser = SwitchUserFilter()
  198. // ... other configuration
  199. switchUser.setExitUserMatcher(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/exit/impersonate"))
  200. ----
  201. ======
  202. === Migrate `filterProcessingUrl` Request Matcher in `AbstractAuthenticationProcessingFilter` Implementations
  203. Spring Security 6 converts any processing endpoint configured through `setFilterProcessingUrl` to an `AntPathRequestMatcher`.
  204. In Spring Security 7, this will change to `PathPatternRequestMatcher`.
  205. If you are directly invoking `setFilterProcessingUrl` on a filter that extends `AbstractAuthenticationProcessingFilter`, like `UsernamePasswordAuthenticationFilter`, `OAuth2LoginAuthenticationFilter`, `Saml2WebSsoAuthenticationFilter`, `OneTimeTokenAuthenticationFilter`, or `WebAuthnAuthenticationFilter`, call `setRequiredAuthenticationRequestMatcher` instead to provide this `PathPatternRequestMatcher` in advance.
  206. That is, change this:
  207. [tabs]
  208. ======
  209. Java::
  210. +
  211. [source,java,role="primary"]
  212. ----
  213. UsernamePasswordAuthenticationFilter usernamePassword = new UsernamePasswordAuthenticationFilter(authenticationManager);
  214. usernamePassword.setFilterProcessingUrl("/my/processing/url");
  215. ----
  216. Kotlin::
  217. +
  218. [source,kotlin,role="secondary"]
  219. ----
  220. val usernamePassword = UsernamePasswordAuthenticationFilter(authenticationManager)
  221. usernamePassword.setFilterProcessingUrl("/my/processing/url")
  222. ----
  223. ======
  224. to this:
  225. [tabs]
  226. ======
  227. Java::
  228. +
  229. [source,java,role="primary"]
  230. ----
  231. UsernamePasswordAuthenticationFilter usernamePassword = new UsernamePasswordAuthenticationFilter(authenticationManager);
  232. RequestMatcher requestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/my/processing/url");
  233. usernamePassword.setRequest(requestMatcher);
  234. ----
  235. Kotlin::
  236. +
  237. [source,kotlin,role="secondary"]
  238. ----
  239. val usernamePassword = UsernamePasswordAuthenticationFilter(authenticationManager)
  240. val requestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/my/processing/url")
  241. usernamePassword.setRequest(requestMatcher)
  242. ----
  243. ======
  244. [NOTE]
  245. -----
  246. Most applications use the DSL instead of setting the `filterProcessingUrl` directly on a filter instance.
  247. -----
  248. === Migrate CAS Proxy Receptor Request Matcher
  249. Spring Security 6 converts any configured `proxyReceptorUrl` to a request matcher that matches the end of the request, that is `/**/proxy/receptor`.
  250. In Spring Security 7, this pattern is not allowed and will change to using `PathPatternRequestMatcher`.
  251. Also in Spring Security 7m the URL should by absolute, excluding any context path, like so: `/proxy/receptor`.
  252. So to prepare for these change, you can use `setProxyReceptorRequestMatcher` instead of `setProxyReceptorUrl`.
  253. That is, change this:
  254. [tabs]
  255. ======
  256. Java::
  257. +
  258. [source,java,role="primary"]
  259. ----
  260. casAuthentication.setProxyReceptorUrl("/proxy/receptor");
  261. ----
  262. Kotlin::
  263. +
  264. [source,kotlin,role="secondary"]
  265. ----
  266. casAuthentication.setProxyReceptorUrl("/proxy/receptor")
  267. ----
  268. ======
  269. to this:
  270. [tabs]
  271. ======
  272. Java::
  273. +
  274. [source,java,role="primary"]
  275. ----
  276. casAuthentication.setProxyReceptorUrl(PathPatternRequestMatcher.withDefaults().matcher("/proxy/receptor"));
  277. ----
  278. Kotlin::
  279. +
  280. [source,kotlin,role="secondary"]
  281. ----
  282. casAuthentication.setProxyReceptorUrl(PathPatternRequestMatcher.withDefaults().matcher("/proxy/receptor"))
  283. ----
  284. ======
  285. == Include the Servlet Path Prefix in Authorization Rules
  286. For many applications <<use-path-pattern, the above>> will make no difference since most commonly all URIs listed are matched by the default servlet.
  287. However, if you have other servlets with servlet path prefixes, xref:servlet/authorization/authorize-http-requests.adoc[then these paths now need to be supplied separately].
  288. For example, if I have a Spring MVC controller with `@RequestMapping("/orders")` and my MVC application is deployed to `/mvc` (instead of the default servlet), then the URI for this endpoint is `/mvc/orders`.
  289. Historically, the Java DSL hasn't had a simple way to specify the servlet path prefix and Spring Security attempted to infer it.
  290. Over time, we learned that these inference would surprise developers.
  291. Instead of taking this responsibility away from developers, now it is simpler to specify the servlet path prefix like so:
  292. [method,java]
  293. ----
  294. PathPatternRequestParser.Builder servlet = PathPatternRequestParser.servletPath("/mvc");
  295. http
  296. .authorizeHttpRequests((authorize) -> authorize
  297. .requestMatchers(servlet.pattern("/orders/**").matcher()).authenticated()
  298. )
  299. ----
  300. For paths that belong to the default servlet, use `PathPatternRequestParser.path()` instead:
  301. [method,java]
  302. ----
  303. PathPatternRequestParser.Builder request = PathPatternRequestParser.path();
  304. http
  305. .authorizeHttpRequests((authorize) -> authorize
  306. .requestMatchers(request.pattern("/js/**").matcher()).authenticated()
  307. )
  308. ----
  309. Note that this doesn't address every kind of servlet since not all servlets have a path prefix.
  310. For example, expressions that match the JSP Servlet might use an ant pattern `/**/*.jsp`.
  311. There is not yet a general-purpose replacement for these, and so you are encouraged to use `RegexRequestMatcher`, like so: `regexMatcher("\\.jsp$")`.
  312. For many applications this will make no difference since most commonly all URIs listed are matched by the default servlet.
  313. [[use-redirect-to-https]]
  314. == Use RedirectToHttps Instead of Channel Security
  315. Years ago, HTTPS at large was enough of a performance and configuration concern that applications wanted to be able to decide which segments of an application would require HTTPS.
  316. `requires-channel` in XML and `requiresChannel` in Java Config allowed configurating an application with that in mind:
  317. [tabs]
  318. ======
  319. Java::
  320. +
  321. [source,java,role="primary"]
  322. ----
  323. http
  324. .requiresChannel((channel) -> channel
  325. .requestMatchers("/secure/**").requiresSecureChannel()
  326. .requestMatchers("/insecure/**").requiresInsecureChannel()
  327. )
  328. ----
  329. Kotlin::
  330. +
  331. [source,kotlin,role="secondary"]
  332. ----
  333. http {
  334. requiresChannel {
  335. secure("/secure/**")
  336. seccure("/insecure/**", "REQUIRES_INSECURE_CHANNEL")
  337. }
  338. }
  339. ----
  340. Xml::
  341. +
  342. [source,xml,role="secondary"]
  343. ----
  344. <http>
  345. <intercept-url pattern="/secure/**" access="authenticated" requires-channel="REQUIRES_SECURE_CHANNEL"/>
  346. <intercept-url pattern="/insecure/**" access="authenticated" requires-channel="REQUIRES_INSECURE_CHANNEL"/>
  347. </http>
  348. ----
  349. ======
  350. Modern applications should either always require HTTPS.
  351. However, there are times, like when developing locally, when one would like the application to use HTTP.
  352. Or, you may have continuing circumstances that require part of your application to be HTTP.
  353. In any case, you can migrate to `redirect-to-https-request-matcher-ref` and `redirectToHttps` by first constructing a `RequestMatcher` that contains all circumstances where redirecting to HTTPS is needed.
  354. Then you can reference that request matcher like so:
  355. [tabs]
  356. ======
  357. Java::
  358. +
  359. [source,java,role="primary"]
  360. ----
  361. http
  362. .redirectToHttps((https) -> https.requestMatchers("/secure/**"))
  363. // ...
  364. ----
  365. Kotlin::
  366. +
  367. [source,kotlin,role="secondary"]
  368. ----
  369. var secure: RequestMatcher = PathPatternRequestMatcher.withDefaults().pattern("/secure/**")
  370. http {
  371. redirectToHttps {
  372. requestMatchers = secure
  373. }
  374. // ...
  375. }
  376. ----
  377. Xml::
  378. +
  379. [source,xml,role="secondary"]
  380. ----
  381. <b:bean id="builder" class="org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher$Builder"/>
  382. <b:bean id="secure" class="org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher" factory-bean="builder" factory-method="matcher">
  383. <b:constructor-arg value="/secure/**"/>
  384. </b:bean>
  385. <http redirect-to-https-request-matcher-ref="secure">
  386. <intercept-url pattern="/secure/**" access="authenticated"/>
  387. <intercept-url pattern="/insecure/**" access="authenticated"/>
  388. <!-- ... -->
  389. </http>
  390. ----
  391. ======
  392. [TIP]
  393. =====
  394. If you have several circumstances where HTTP is needed, consider using `OrRequestMatcher` to combine them into a single `RequestMatcher` instance.
  395. =====