From f2805935664ee2714b5543342a85678a9fe07a25 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 3 Apr 2025 11:03:29 -0600 Subject: [PATCH] Move Preparation Steps Closes gh-16873 --- docs/modules/ROOT/nav.adoc | 3 + .../authentication.adoc | 0 .../authorization.adoc | 0 .../{migration => migration-7}/oauth2.adoc | 0 docs/modules/ROOT/pages/migration-7/web.adoc | 328 +++++++++++++++++ docs/modules/ROOT/pages/migration/web.adoc | 330 ------------------ 6 files changed, 331 insertions(+), 330 deletions(-) rename docs/modules/ROOT/pages/{migration => migration-7}/authentication.adoc (100%) rename docs/modules/ROOT/pages/{migration => migration-7}/authorization.adoc (100%) rename docs/modules/ROOT/pages/{migration => migration-7}/oauth2.adoc (100%) delete mode 100644 docs/modules/ROOT/pages/migration/web.adoc diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 3fc74ae93d..d65fc977c0 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -3,8 +3,11 @@ * xref:community.adoc[Community] * xref:whats-new.adoc[What's New] * xref:migration-7/index.adoc[Preparing for 7.0] +** xref:migration-7/authentication.adoc[Authentication] +** xref:migration-7/authorization.adoc[Authorization] ** xref:migration-7/configuration.adoc[Configuration] ** xref:migration-7/ldap.adoc[LDAP] +** xref:migration-7/oauth2.adoc[OAuth 2.0] ** xref:migration-7/web.adoc[Web] * xref:migration/index.adoc[Migrating to 6] * xref:getting-spring-security.adoc[Getting Spring Security] diff --git a/docs/modules/ROOT/pages/migration/authentication.adoc b/docs/modules/ROOT/pages/migration-7/authentication.adoc similarity index 100% rename from docs/modules/ROOT/pages/migration/authentication.adoc rename to docs/modules/ROOT/pages/migration-7/authentication.adoc diff --git a/docs/modules/ROOT/pages/migration/authorization.adoc b/docs/modules/ROOT/pages/migration-7/authorization.adoc similarity index 100% rename from docs/modules/ROOT/pages/migration/authorization.adoc rename to docs/modules/ROOT/pages/migration-7/authorization.adoc diff --git a/docs/modules/ROOT/pages/migration/oauth2.adoc b/docs/modules/ROOT/pages/migration-7/oauth2.adoc similarity index 100% rename from docs/modules/ROOT/pages/migration/oauth2.adoc rename to docs/modules/ROOT/pages/migration-7/oauth2.adoc diff --git a/docs/modules/ROOT/pages/migration-7/web.adoc b/docs/modules/ROOT/pages/migration-7/web.adoc index c3c201d5a1..aa898da4fd 100644 --- a/docs/modules/ROOT/pages/migration-7/web.adoc +++ b/docs/modules/ROOT/pages/migration-7/web.adoc @@ -145,3 +145,331 @@ Xml:: ---- ====== +[[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"] +---- + +---- +====== + +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 `filterProcessingUrl` Request Matcher in `AbstractAuthenticationProcessingFilter` Implementations + +Spring Security 6 converts any processing endpoint configured through `setFilterProcessingUrl` to an `AntPathRequestMatcher`. +In Spring Security 7, this will change to `PathPatternRequestMatcher`. + +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. + +That is, change this: +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +UsernamePasswordAuthenticationFilter usernamePassword = new UsernamePasswordAuthenticationFilter(authenticationManager); +usernamePassword.setFilterProcessingUrl("/my/processing/url"); +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +val usernamePassword = UsernamePasswordAuthenticationFilter(authenticationManager) +usernamePassword.setFilterProcessingUrl("/my/processing/url") +---- +====== + +to this: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +UsernamePasswordAuthenticationFilter usernamePassword = new UsernamePasswordAuthenticationFilter(authenticationManager); +RequestMatcher requestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/my/processing/url"); +usernamePassword.setRequest(requestMatcher); +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +val usernamePassword = UsernamePasswordAuthenticationFilter(authenticationManager) +val requestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/my/processing/url") +usernamePassword.setRequest(requestMatcher) +---- +====== + +[NOTE] +----- +Most applications use the DSL instead of setting the `filterProcessingUrl` directly on a filter instance. +----- + +=== 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 <> 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"] +---- + + + + +---- +====== + +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"] +---- + + + + + + + + + +---- +====== + +[TIP] +===== +If you have several circumstances where HTTP is needed, consider using `OrRequestMatcher` to combine them into a single `RequestMatcher` instance. +===== diff --git a/docs/modules/ROOT/pages/migration/web.adoc b/docs/modules/ROOT/pages/migration/web.adoc deleted file mode 100644 index 1ea4ecbfc7..0000000000 --- a/docs/modules/ROOT/pages/migration/web.adoc +++ /dev/null @@ -1,330 +0,0 @@ -= 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"] ----- - ----- -====== - -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 `filterProcessingUrl` Request Matcher in `AbstractAuthenticationProcessingFilter` Implementations - -Spring Security 6 converts any processing endpoint configured through `setFilterProcessingUrl` to an `AntPathRequestMatcher`. -In Spring Security 7, this will change to `PathPatternRequestMatcher`. - -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. - -That is, change this: -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -UsernamePasswordAuthenticationFilter usernamePassword = new UsernamePasswordAuthenticationFilter(authenticationManager); -usernamePassword.setFilterProcessingUrl("/my/processing/url"); ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -val usernamePassword = UsernamePasswordAuthenticationFilter(authenticationManager) -usernamePassword.setFilterProcessingUrl("/my/processing/url") ----- -====== - -to this: - -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -UsernamePasswordAuthenticationFilter usernamePassword = new UsernamePasswordAuthenticationFilter(authenticationManager); -RequestMatcher requestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/my/processing/url"); -usernamePassword.setRequest(requestMatcher); ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -val usernamePassword = UsernamePasswordAuthenticationFilter(authenticationManager) -val requestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/my/processing/url") -usernamePassword.setRequest(requestMatcher) ----- -====== - -[NOTE] ------ -Most applications use the DSL instead of setting the `filterProcessingUrl` directly on a filter instance. ------ - -=== 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 <> 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"] ----- - - - - ----- -====== - -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"] ----- - - - - - - - - - ----- -====== - -[TIP] -===== -If you have several circumstances where HTTP is needed, consider using `OrRequestMatcher` to combine them into a single `RequestMatcher` instance. -=====