Skip to content

Commit f280593

Browse files
committed
Move Preparation Steps
Closes gh-16873
1 parent 09b7571 commit f280593

File tree

6 files changed

+331
-330
lines changed

6 files changed

+331
-330
lines changed

docs/modules/ROOT/nav.adoc

+3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
* xref:community.adoc[Community]
44
* xref:whats-new.adoc[What's New]
55
* xref:migration-7/index.adoc[Preparing for 7.0]
6+
** xref:migration-7/authentication.adoc[Authentication]
7+
** xref:migration-7/authorization.adoc[Authorization]
68
** xref:migration-7/configuration.adoc[Configuration]
79
** xref:migration-7/ldap.adoc[LDAP]
10+
** xref:migration-7/oauth2.adoc[OAuth 2.0]
811
** xref:migration-7/web.adoc[Web]
912
* xref:migration/index.adoc[Migrating to 6]
1013
* xref:getting-spring-security.adoc[Getting Spring Security]

docs/modules/ROOT/pages/migration-7/web.adoc

+328
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,331 @@ Xml::
145145
----
146146
======
147147

148+
[[use-path-pattern]]
149+
== Use PathPatternRequestMatcher by Default
150+
151+
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).
152+
At that time, Spring Security 7 will use `PathPatternRequestMatcher` by default.
153+
154+
To check how prepared you are for this change, you can publish this bean:
155+
156+
[tabs]
157+
======
158+
Java::
159+
+
160+
[source,java,role="primary"]
161+
----
162+
@Bean
163+
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
164+
return new PathPatternRequestMatcherBuilderFactoryBean();
165+
}
166+
----
167+
168+
Kotlin::
169+
+
170+
[source,kotlin,role="secondary"]
171+
----
172+
@Bean
173+
fun requestMatcherBuilder(): PathPatternRequestMatcherBuilderFactoryBean {
174+
return PathPatternRequestMatcherBuilderFactoryBean()
175+
}
176+
----
177+
178+
Xml::
179+
+
180+
[source,xml,role="secondary"]
181+
----
182+
<b:bean class="org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean"/>
183+
----
184+
======
185+
186+
This will tell the Spring Security DSL to use `PathPatternRequestMatcher` for all request matchers that it constructs.
187+
188+
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.
189+
190+
=== Migrate `exitUserUrl` and `switchUserUrl` Request Matchers in `SwitchUserFilter`
191+
192+
`SwitchUserFilter`, constructs an `AntPathRequestMatcher` in its `setExitUserUrl` and `setSwitchUserUrl` methods.
193+
This will change to use `PathPatternRequestMatcher` in Spring Security 7.
194+
195+
To prepare for this change, call `setExitUserMatcher` and `setSwithcUserMatcher` to provide this `PathPatternRequestMatcher` in advance.
196+
That is, change this:
197+
198+
[tabs]
199+
======
200+
Java::
201+
+
202+
[source,java,role="primary"]
203+
----
204+
SwitchUserFilter switchUser = new SwitchUserFilter();
205+
// ... other configuration
206+
switchUser.setExitUserUrl("/exit/impersonate");
207+
----
208+
209+
Kotlin::
210+
+
211+
[source,kotlin,role="secondary"]
212+
----
213+
val switchUser = SwitchUserFilter()
214+
// ... other configuration
215+
switchUser.setExitUserUrl("/exit/impersonate")
216+
----
217+
======
218+
219+
to this:
220+
221+
[tabs]
222+
======
223+
Java::
224+
+
225+
[source,java,role="primary"]
226+
----
227+
SwitchUserFilter switchUser = new SwitchUserFilter();
228+
// ... other configuration
229+
switchUser.setExitUserMatcher(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/exit/impersonate"));
230+
----
231+
232+
Kotlin::
233+
+
234+
[source,kotlin,role="secondary"]
235+
----
236+
val switchUser = SwitchUserFilter()
237+
// ... other configuration
238+
switchUser.setExitUserMatcher(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/exit/impersonate"))
239+
----
240+
======
241+
242+
=== Migrate `filterProcessingUrl` Request Matcher in `AbstractAuthenticationProcessingFilter` Implementations
243+
244+
Spring Security 6 converts any processing endpoint configured through `setFilterProcessingUrl` to an `AntPathRequestMatcher`.
245+
In Spring Security 7, this will change to `PathPatternRequestMatcher`.
246+
247+
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.
248+
249+
That is, change this:
250+
[tabs]
251+
======
252+
Java::
253+
+
254+
[source,java,role="primary"]
255+
----
256+
UsernamePasswordAuthenticationFilter usernamePassword = new UsernamePasswordAuthenticationFilter(authenticationManager);
257+
usernamePassword.setFilterProcessingUrl("/my/processing/url");
258+
----
259+
260+
Kotlin::
261+
+
262+
[source,kotlin,role="secondary"]
263+
----
264+
val usernamePassword = UsernamePasswordAuthenticationFilter(authenticationManager)
265+
usernamePassword.setFilterProcessingUrl("/my/processing/url")
266+
----
267+
======
268+
269+
to this:
270+
271+
[tabs]
272+
======
273+
Java::
274+
+
275+
[source,java,role="primary"]
276+
----
277+
UsernamePasswordAuthenticationFilter usernamePassword = new UsernamePasswordAuthenticationFilter(authenticationManager);
278+
RequestMatcher requestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/my/processing/url");
279+
usernamePassword.setRequest(requestMatcher);
280+
----
281+
282+
Kotlin::
283+
+
284+
[source,kotlin,role="secondary"]
285+
----
286+
val usernamePassword = UsernamePasswordAuthenticationFilter(authenticationManager)
287+
val requestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/my/processing/url")
288+
usernamePassword.setRequest(requestMatcher)
289+
----
290+
======
291+
292+
[NOTE]
293+
-----
294+
Most applications use the DSL instead of setting the `filterProcessingUrl` directly on a filter instance.
295+
-----
296+
297+
=== Migrate CAS Proxy Receptor Request Matcher
298+
299+
Spring Security 6 converts any configured `proxyReceptorUrl` to a request matcher that matches the end of the request, that is `/**/proxy/receptor`.
300+
In Spring Security 7, this pattern is not allowed and will change to using `PathPatternRequestMatcher`.
301+
Also in Spring Security 7m the URL should by absolute, excluding any context path, like so: `/proxy/receptor`.
302+
303+
So to prepare for these change, you can use `setProxyReceptorRequestMatcher` instead of `setProxyReceptorUrl`.
304+
305+
That is, change this:
306+
[tabs]
307+
======
308+
Java::
309+
+
310+
[source,java,role="primary"]
311+
----
312+
casAuthentication.setProxyReceptorUrl("/proxy/receptor");
313+
----
314+
315+
Kotlin::
316+
+
317+
[source,kotlin,role="secondary"]
318+
----
319+
casAuthentication.setProxyReceptorUrl("/proxy/receptor")
320+
----
321+
======
322+
323+
to this:
324+
325+
[tabs]
326+
======
327+
Java::
328+
+
329+
[source,java,role="primary"]
330+
----
331+
casAuthentication.setProxyReceptorUrl(PathPatternRequestMatcher.withDefaults().matcher("/proxy/receptor"));
332+
----
333+
334+
Kotlin::
335+
+
336+
[source,kotlin,role="secondary"]
337+
----
338+
casAuthentication.setProxyReceptorUrl(PathPatternRequestMatcher.withDefaults().matcher("/proxy/receptor"))
339+
----
340+
======
341+
342+
== Include the Servlet Path Prefix in Authorization Rules
343+
344+
For many applications <<use-path-pattern, the above>> will make no difference since most commonly all URIs listed are matched by the default servlet.
345+
346+
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].
347+
348+
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`.
349+
Historically, the Java DSL hasn't had a simple way to specify the servlet path prefix and Spring Security attempted to infer it.
350+
351+
Over time, we learned that these inference would surprise developers.
352+
Instead of taking this responsibility away from developers, now it is simpler to specify the servlet path prefix like so:
353+
354+
[method,java]
355+
----
356+
PathPatternRequestParser.Builder servlet = PathPatternRequestParser.servletPath("/mvc");
357+
http
358+
.authorizeHttpRequests((authorize) -> authorize
359+
.requestMatchers(servlet.pattern("/orders/**").matcher()).authenticated()
360+
)
361+
----
362+
363+
364+
For paths that belong to the default servlet, use `PathPatternRequestParser.path()` instead:
365+
366+
[method,java]
367+
----
368+
PathPatternRequestParser.Builder request = PathPatternRequestParser.path();
369+
http
370+
.authorizeHttpRequests((authorize) -> authorize
371+
.requestMatchers(request.pattern("/js/**").matcher()).authenticated()
372+
)
373+
----
374+
375+
Note that this doesn't address every kind of servlet since not all servlets have a path prefix.
376+
For example, expressions that match the JSP Servlet might use an ant pattern `/**/*.jsp`.
377+
378+
There is not yet a general-purpose replacement for these, and so you are encouraged to use `RegexRequestMatcher`, like so: `regexMatcher("\\.jsp$")`.
379+
380+
For many applications this will make no difference since most commonly all URIs listed are matched by the default servlet.
381+
382+
[[use-redirect-to-https]]
383+
== Use RedirectToHttps Instead of Channel Security
384+
385+
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.
386+
387+
`requires-channel` in XML and `requiresChannel` in Java Config allowed configurating an application with that in mind:
388+
389+
[tabs]
390+
======
391+
Java::
392+
+
393+
[source,java,role="primary"]
394+
----
395+
http
396+
.requiresChannel((channel) -> channel
397+
.requestMatchers("/secure/**").requiresSecureChannel()
398+
.requestMatchers("/insecure/**").requiresInsecureChannel()
399+
)
400+
----
401+
402+
Kotlin::
403+
+
404+
[source,kotlin,role="secondary"]
405+
----
406+
http {
407+
requiresChannel {
408+
secure("/secure/**")
409+
seccure("/insecure/**", "REQUIRES_INSECURE_CHANNEL")
410+
}
411+
}
412+
----
413+
414+
Xml::
415+
+
416+
[source,xml,role="secondary"]
417+
----
418+
<http>
419+
<intercept-url pattern="/secure/**" access="authenticated" requires-channel="REQUIRES_SECURE_CHANNEL"/>
420+
<intercept-url pattern="/insecure/**" access="authenticated" requires-channel="REQUIRES_INSECURE_CHANNEL"/>
421+
</http>
422+
----
423+
======
424+
425+
Modern applications should either always require HTTPS.
426+
However, there are times, like when developing locally, when one would like the application to use HTTP.
427+
Or, you may have continuing circumstances that require part of your application to be HTTP.
428+
429+
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.
430+
Then you can reference that request matcher like so:
431+
432+
[tabs]
433+
======
434+
Java::
435+
+
436+
[source,java,role="primary"]
437+
----
438+
http
439+
.redirectToHttps((https) -> https.requestMatchers("/secure/**"))
440+
// ...
441+
----
442+
443+
Kotlin::
444+
+
445+
[source,kotlin,role="secondary"]
446+
----
447+
var secure: RequestMatcher = PathPatternRequestMatcher.withDefaults().pattern("/secure/**")
448+
http {
449+
redirectToHttps {
450+
requestMatchers = secure
451+
}
452+
// ...
453+
}
454+
----
455+
456+
Xml::
457+
+
458+
[source,xml,role="secondary"]
459+
----
460+
<b:bean id="builder" class="org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher$Builder"/>
461+
<b:bean id="secure" class="org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher" factory-bean="builder" factory-method="matcher">
462+
<b:constructor-arg value="/secure/**"/>
463+
</b:bean>
464+
<http redirect-to-https-request-matcher-ref="secure">
465+
<intercept-url pattern="/secure/**" access="authenticated"/>
466+
<intercept-url pattern="/insecure/**" access="authenticated"/>
467+
<!-- ... -->
468+
</http>
469+
----
470+
======
471+
472+
[TIP]
473+
=====
474+
If you have several circumstances where HTTP is needed, consider using `OrRequestMatcher` to combine them into a single `RequestMatcher` instance.
475+
=====

0 commit comments

Comments
 (0)