|
@@ -1,523 +0,0 @@
|
|
|
-= Web Migrations
|
|
|
-
|
|
|
-== Favor Relative URIs
|
|
|
-
|
|
|
-When redirecting to a login endpoint, Spring Security has favored absolute URIs in the past.
|
|
|
-For example, if you set your login page like so:
|
|
|
-
|
|
|
-[tabs]
|
|
|
-======
|
|
|
-Java::
|
|
|
-+
|
|
|
-[source,java,role="primary"]
|
|
|
-----
|
|
|
-http
|
|
|
- // ...
|
|
|
- .formLogin((form) -> form.loginPage("/my-login"))
|
|
|
- // ...
|
|
|
-----
|
|
|
-
|
|
|
-Kotlin::
|
|
|
-+
|
|
|
-[source,kotlin,role="secondary"]
|
|
|
-----
|
|
|
-http {
|
|
|
- formLogin {
|
|
|
- loginPage = "/my-login"
|
|
|
- }
|
|
|
-}
|
|
|
-----
|
|
|
-
|
|
|
-Xml::
|
|
|
-+
|
|
|
-[source,kotlin,role="secondary"]
|
|
|
-----
|
|
|
-<http ...>
|
|
|
- <form-login login-page="/my-login"/>
|
|
|
-</http>
|
|
|
-----
|
|
|
-======
|
|
|
-
|
|
|
-then when redirecting to `/my-login` Spring Security would use a `Location:` like the following:
|
|
|
-
|
|
|
-[source]
|
|
|
-----
|
|
|
-302 Found
|
|
|
-// ...
|
|
|
-Location: https://myapp.example.org/my-login
|
|
|
-----
|
|
|
-
|
|
|
-However, this is no longer necessary given that the RFC is was based on is now obsolete.
|
|
|
-
|
|
|
-In Spring Security 7, this is changed to use a relative URI like so:
|
|
|
-
|
|
|
-[source]
|
|
|
-----
|
|
|
-302 Found
|
|
|
-// ...
|
|
|
-Location: /my-login
|
|
|
-----
|
|
|
-
|
|
|
-Most applications will not notice a difference.
|
|
|
-However, in the event that this change causes problems, you can switch back to the Spring Security 6 behavior by setting the `favorRelativeUrls` value:
|
|
|
-
|
|
|
-[tabs]
|
|
|
-======
|
|
|
-Java::
|
|
|
-+
|
|
|
-[source,java,role="primary"]
|
|
|
-----
|
|
|
-LoginUrlAuthenticationEntryPoint entryPoint = new LoginUrlAuthenticationEntryPoint("/my-login");
|
|
|
-entryPoint.setFavorRelativeUris(false);
|
|
|
-http
|
|
|
- // ...
|
|
|
- .exceptionHandling((exceptions) -> exceptions.authenticaitonEntryPoint(entryPoint))
|
|
|
- // ...
|
|
|
-----
|
|
|
-
|
|
|
-Kotlin::
|
|
|
-+
|
|
|
-[source,kotlin,role="secondary"]
|
|
|
-----
|
|
|
-LoginUrlAuthenticationEntryPoint entryPoint = LoginUrlAuthenticationEntryPoint("/my-login")
|
|
|
-entryPoint.setFavorRelativeUris(false)
|
|
|
-
|
|
|
-http {
|
|
|
- exceptionHandling {
|
|
|
- authenticationEntryPoint = entryPoint
|
|
|
- }
|
|
|
-}
|
|
|
-----
|
|
|
-
|
|
|
-Xml::
|
|
|
-+
|
|
|
-[source,xml,role="secondary"]
|
|
|
-----
|
|
|
-<http entry-point-ref="myEntryPoint">
|
|
|
- <!-- ... -->
|
|
|
-</http>
|
|
|
-
|
|
|
-<b:bean id="myEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
|
|
|
- <b:property name="favorRelativeUris" value="true"/>
|
|
|
-</b:bean>
|
|
|
-----
|
|
|
-======
|
|
|
-
|
|
|
-== PortResolver
|
|
|
-
|
|
|
-Spring Security uses an API called `PortResolver` to provide a workaround for a bug in Internet Explorer.
|
|
|
-The workaround is no longer necessary and can cause users problems in some scenarios.
|
|
|
-For this reason, Spring Security 7 will remove the `PortResolver` interface.
|
|
|
-
|
|
|
-To prepare for this change, users should expose the `PortResolver.NO_OP` as a Bean named `portResolver`.
|
|
|
-This ensures that the `PortResolver` implementation that is used is a no-op (e.g. does nothing) which simulates the removal of `PortResolver`.
|
|
|
-An example configuration can be found below:
|
|
|
-
|
|
|
-[tabs]
|
|
|
-======
|
|
|
-Java::
|
|
|
-+
|
|
|
-[source,java,role="primary"]
|
|
|
-----
|
|
|
-@Bean
|
|
|
-PortResolver portResolver() {
|
|
|
- return PortResolver.NO_OP;
|
|
|
-}
|
|
|
-----
|
|
|
-
|
|
|
-Kotlin::
|
|
|
-+
|
|
|
-[source,kotlin,role="secondary"]
|
|
|
-----
|
|
|
-@Bean
|
|
|
-open fun portResolver(): PortResolver {
|
|
|
- return PortResolver.NO_OP
|
|
|
-}
|
|
|
-----
|
|
|
-
|
|
|
-Xml::
|
|
|
-+
|
|
|
-[source,xml,role="secondary"]
|
|
|
-----
|
|
|
-
|
|
|
-<util:constant id="portResolver"
|
|
|
- static-field="org.springframework.security.web.PortResolver.NO_OP">
|
|
|
-----
|
|
|
-======
|
|
|
-
|
|
|
-[[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 `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"))
|
|
|
-----
|
|
|
-======
|
|
|
-
|
|
|
-=== Migrate your WebInvocationPrivilegeEvaluator
|
|
|
-
|
|
|
-If you are using Spring Security's JSP Taglibs or are using `WebInvocationPrivilegeEvaluator` directly, be aware of the following changes:
|
|
|
-
|
|
|
-1. `RequestMatcherWebInvocationPrivilegeEvaluator` is deprecated in favor of `AuthorizationManagerWebInvocationPrivilegeEvaluator`
|
|
|
-2. `HandlerMappingIntrospectorRequestTransformer` is deprecated in favor of `PathPatternRequestTransformer`
|
|
|
-
|
|
|
-If you are not constructing these directly, you can opt-in to both changes in advance by publishing a `PathPatternRequestTransformer` like so:
|
|
|
-
|
|
|
-[tabs]
|
|
|
-======
|
|
|
-Java::
|
|
|
-+
|
|
|
-[source,java,role="primary"]
|
|
|
-----
|
|
|
-@Bean
|
|
|
-HttpServletRequestTransformer pathPatternRequestTransformer() {
|
|
|
- return new PathPatternRequestTransformer();
|
|
|
-}
|
|
|
-----
|
|
|
-
|
|
|
-Kotlin::
|
|
|
-+
|
|
|
-[source,kotlin,role="secondary"]
|
|
|
-----
|
|
|
-@Bean
|
|
|
-fun pathPatternRequestTransformer(): HttpServletRequestTransformer {
|
|
|
- return PathPatternRequestTransformer()
|
|
|
-}
|
|
|
-----
|
|
|
-
|
|
|
-Xml::
|
|
|
-+
|
|
|
-[source,xml,role="secondary"]
|
|
|
-----
|
|
|
-<b:bean class="org.springframework.security.web.access.PathPatternRequestTransformer"/>
|
|
|
-----
|
|
|
-======
|
|
|
-
|
|
|
-Spring Security will take this as a signal to use the new implementations.
|
|
|
-
|
|
|
-[[NOTE]]
|
|
|
-----
|
|
|
-One difference you may notice is that `AuthorizationManagerWebPrivilegeInvocationEvaluator` allows the authentication to be `null` if the authorization rule is `permitAll`.
|
|
|
-
|
|
|
-Test your endpoints that `permitAll` in case JSP requests using this same require should not, in fact, be permitted.
|
|
|
-----
|
|
|
-
|
|
|
-== 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.withDefaults().basePath("/mvc");
|
|
|
-http
|
|
|
- .authorizeHttpRequests((authorize) -> authorize
|
|
|
- .requestMatchers(servlet.pattern("/orders/**").matcher()).authenticated()
|
|
|
- )
|
|
|
-----
|
|
|
-
|
|
|
-
|
|
|
-For paths that belong to the default servlet, use `PathPatternRequestParser.withDefaults()` instead:
|
|
|
-
|
|
|
-[method,java]
|
|
|
-----
|
|
|
-PathPatternRequestParser.Builder request = PathPatternRequestParser.withDefaults();
|
|
|
-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.
|
|
|
-=====
|