123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- = Web Migrations
- [[use-path-pattern]]
- == Use PathPatternRequestMatcher by Default
- 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).
- At that time, Spring Security 7 will use `PathPatternRequestMatcher` by default.
- To check how prepared you are for this change, you can publish this bean:
- [tabs]
- ======
- Java::
- +
- [source,java,role="primary"]
- ----
- @Bean
- PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
- return new PathPatternRequestMatcherBuilderFactoryBean();
- }
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- @Bean
- fun requestMatcherBuilder(): PathPatternRequestMatcherBuilderFactoryBean {
- return PathPatternRequestMatcherBuilderFactoryBean()
- }
- ----
- Xml::
- +
- [source,xml,role="secondary"]
- ----
- <b:bean class="org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean"/>
- ----
- ======
- This will tell the Spring Security DSL to use `PathPatternRequestMatcher` for all request matchers that it constructs.
- 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.
- === Migrate `exitUserUrl` and `switchUserUrl` Request Matchers in `SwitchUserFilter`
- `SwitchUserFilter`, constructs an `AntPathRequestMatcher` in its `setExitUserUrl` and `setSwitchUserUrl` methods.
- This will change to use `PathPatternRequestMatcher` in Spring Security 7.
- To prepare for this change, call `setExitUserMatcher` and `setSwithcUserMatcher` to provide this `PathPatternRequestMatcher` in advance.
- That is, change this:
- [tabs]
- ======
- Java::
- +
- [source,java,role="primary"]
- ----
- SwitchUserFilter switchUser = new SwitchUserFilter();
- // ... other configuration
- switchUser.setExitUserUrl("/exit/impersonate");
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- val switchUser = SwitchUserFilter()
- // ... other configuration
- switchUser.setExitUserUrl("/exit/impersonate")
- ----
- ======
- to this:
- [tabs]
- ======
- Java::
- +
- [source,java,role="primary"]
- ----
- SwitchUserFilter switchUser = new SwitchUserFilter();
- // ... other configuration
- switchUser.setExitUserMatcher(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/exit/impersonate"));
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- val switchUser = SwitchUserFilter()
- // ... other configuration
- switchUser.setExitUserMatcher(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/exit/impersonate"))
- ----
- ======
- === Migrate CAS Proxy Receptor Request Matcher
- Spring Security 6 converts any configured `proxyReceptorUrl` to a request matcher that matches the end of the request, that is `/**/proxy/receptor`.
- In Spring Security 7, this pattern is not allowed and will change to using `PathPatternRequestMatcher`.
- Also in Spring Security 7m the URL should by absolute, excluding any context path, like so: `/proxy/receptor`.
- So to prepare for these change, you can use `setProxyReceptorRequestMatcher` instead of `setProxyReceptorUrl`.
- That is, change this:
- [tabs]
- ======
- Java::
- +
- [source,java,role="primary"]
- ----
- casAuthentication.setProxyReceptorUrl("/proxy/receptor");
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- casAuthentication.setProxyReceptorUrl("/proxy/receptor")
- ----
- ======
- to this:
- [tabs]
- ======
- Java::
- +
- [source,java,role="primary"]
- ----
- casAuthentication.setProxyReceptorUrl(PathPatternRequestMatcher.withDefaults().matcher("/proxy/receptor"));
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- casAuthentication.setProxyReceptorUrl(PathPatternRequestMatcher.withDefaults().matcher("/proxy/receptor"))
- ----
- ======
- == Include the Servlet Path Prefix in Authorization Rules
- For many applications <<use-path-pattern, the above>> will make no difference since most commonly all URIs listed are matched by the default servlet.
- 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].
- 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`.
- Historically, the Java DSL hasn't had a simple way to specify the servlet path prefix and Spring Security attempted to infer it.
- Over time, we learned that these inference would surprise developers.
- Instead of taking this responsibility away from developers, now it is simpler to specify the servlet path prefix like so:
- [method,java]
- ----
- PathPatternRequestParser.Builder servlet = PathPatternRequestParser.servletPath("/mvc");
- http
- .authorizeHttpRequests((authorize) -> authorize
- .requestMatchers(servlet.pattern("/orders/**").matcher()).authenticated()
- )
- ----
- For paths that belong to the default servlet, use `PathPatternRequestParser.path()` instead:
- [method,java]
- ----
- PathPatternRequestParser.Builder request = PathPatternRequestParser.path();
- http
- .authorizeHttpRequests((authorize) -> authorize
- .requestMatchers(request.pattern("/js/**").matcher()).authenticated()
- )
- ----
- Note that this doesn't address every kind of servlet since not all servlets have a path prefix.
- For example, expressions that match the JSP Servlet might use an ant pattern `/**/*.jsp`.
- There is not yet a general-purpose replacement for these, and so you are encouraged to use `RegexRequestMatcher`, like so: `regexMatcher("\\.jsp$")`.
- For many applications this will make no difference since most commonly all URIs listed are matched by the default servlet.
- [[use-redirect-to-https]]
- == Use RedirectToHttps Instead of Channel Security
- 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.
- `requires-channel` in XML and `requiresChannel` in Java Config allowed configurating an application with that in mind:
- [tabs]
- ======
- Java::
- +
- [source,java,role="primary"]
- ----
- http
- .requiresChannel((channel) -> channel
- .requestMatchers("/secure/**").requiresSecureChannel()
- .requestMatchers("/insecure/**").requiresInsecureChannel()
- )
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- http {
- requiresChannel {
- secure("/secure/**")
- seccure("/insecure/**", "REQUIRES_INSECURE_CHANNEL")
- }
- }
- ----
- Xml::
- +
- [source,xml,role="secondary"]
- ----
- <http>
- <intercept-url pattern="/secure/**" access="authenticated" requires-channel="REQUIRES_SECURE_CHANNEL"/>
- <intercept-url pattern="/insecure/**" access="authenticated" requires-channel="REQUIRES_INSECURE_CHANNEL"/>
- </http>
- ----
- ======
- Modern applications should either always require HTTPS.
- However, there are times, like when developing locally, when one would like the application to use HTTP.
- Or, you may have continuing circumstances that require part of your application to be HTTP.
- 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.
- Then you can reference that request matcher like so:
- [tabs]
- ======
- Java::
- +
- [source,java,role="primary"]
- ----
- http
- .redirectToHttps((https) -> https.requestMatchers("/secure/**"))
- // ...
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- var secure: RequestMatcher = PathPatternRequestMatcher.withDefaults().pattern("/secure/**")
- http {
- redirectToHttps {
- requestMatchers = secure
- }
- // ...
- }
- ----
- Xml::
- +
- [source,xml,role="secondary"]
- ----
- <b:bean id="builder" class="org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher$Builder"/>
- <b:bean id="secure" class="org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher" factory-bean="builder" factory-method="matcher">
- <b:constructor-arg value="/secure/**"/>
- </b:bean>
- <http redirect-to-https-request-matcher-ref="secure">
- <intercept-url pattern="/secure/**" access="authenticated"/>
- <intercept-url pattern="/insecure/**" access="authenticated"/>
- <!-- ... -->
- </http>
- ----
- ======
- [TIP]
- =====
- If you have several circumstances where HTTP is needed, consider using `OrRequestMatcher` to combine them into a single `RequestMatcher` instance.
- =====
|