Web 移行

相対 URI を優先する

ログインエンドポイントにリダイレクトする場合、Spring Security はこれまで絶対 URI を優先してきました。例: ログインページを次のように設定した場合:

  • Java

  • Kotlin

  • XML

http
    // ...
    .formLogin((form) -> form.loginPage("/my-login"))
    // ...
http {
    formLogin {
        loginPage = "/my-login"
    }
}
<http ...>
    <form-login login-page="/my-login"/>
</http>

/my-login にリダイレクトする場合、Spring Security は次のような Location: を使用します。

302 Found
// ...
Location: https://myapp.example.org/my-login

ただし、基になった RFC が廃止されたため、これはもはや必要ありません。

Spring Security 7 では、次のように相対 URI を使用するように変更されます。

302 Found
// ...
Location: /my-login

ほとんどのアプリケーションでは違いはわかりません。ただし、この変更によって問題が発生する場合は、favorRelativeUrls 値を設定して Spring Security 6 の動作に戻すことができます。

  • Java

  • Kotlin

  • XML

LoginUrlAuthenticationEntryPoint entryPoint = new LoginUrlAuthenticationEntryPoint("/my-login");
entryPoint.setFavorRelativeUris(false);
http
    // ...
    .exceptionHandling((exceptions) -> exceptions.authenticaitonEntryPoint(entryPoint))
    // ...
LoginUrlAuthenticationEntryPoint entryPoint = LoginUrlAuthenticationEntryPoint("/my-login")
entryPoint.setFavorRelativeUris(false)

http {
    exceptionHandling {
        authenticationEntryPoint = entryPoint
    }
}
<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 は、Internet Explorer のバグの回避策を提供するために、PortResolver という API を使用します。この回避策は不要になり、一部のシナリオではユーザーに問題を引き起こす可能性があります。このため、Spring Security 7 は PortResolver インターフェースを削除します。

この変更に備えて、ユーザーは PortResolver.NO_OP を portResolver という名前の Bean として公開する必要があります。これにより、使用される PortResolver 実装が no-op(つまり何もしない)となり、PortResolver の削除をシミュレートします。設定例を以下に示します。

  • Java

  • Kotlin

  • XML

@Bean
PortResolver portResolver() {
	return PortResolver.NO_OP;
}
@Bean
open fun portResolver(): PortResolver {
    return PortResolver.NO_OP
}
<util:constant id="portResolver"
    static-field="org.springframework.security.web.PortResolver.NO_OP">

デフォルトで PathPatternRequestMatcher を使用する

Spring Security 7 では、AntPathRequestMatcher と MvcRequestMatcher はサポートされなくなり、Java DSL ではすべての URI が絶対 URI(コンテキストルートを除く)であることが必須となります。その時点で、Spring Security 7 はデフォルトで PathPatternRequestMatcher を使用するようになります。

この変更に対する準備状況を確認するには、次の Bean を公開します。

  • Java

  • Kotlin

  • XML

@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
	return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
fun requestMatcherBuilder(): PathPatternRequestMatcherBuilderFactoryBean {
    return PathPatternRequestMatcherBuilderFactoryBean()
}
<b:bean class="org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean"/>

これにより、Spring Security DSL は、構築するすべてのリクエストマッチャーに PathPatternRequestMatcher を使用するように指示されます。

setRequestMatcher メソッドを持つオブジェクトを直接構築する場合 (DSL で構築するのではなく)、そこでも積極的に PathPatternRequestMatcher を指定する必要があります。

exitUserUrl および switchUserUrl リクエストマッチャーを SwitchUserFilter に移行します

SwitchUserFilter は、setExitUserUrl および setSwitchUserUrl メソッドで AntPathRequestMatcher を構築します。これは、Spring Security 7 では PathPatternRequestMatcher を使用するように変更されます。

この変更に備えて、setExitUserMatcher と setSwithcUserMatcher を呼び出して、事前にこの PathPatternRequestMatcher を用意してください。つまり、以下の変更を行います。

  • Java

  • Kotlin

SwitchUserFilter switchUser = new SwitchUserFilter();
// ... other configuration
switchUser.setExitUserUrl("/exit/impersonate");
val switchUser = SwitchUserFilter()
// ... other configuration
switchUser.setExitUserUrl("/exit/impersonate")

これに:

  • Java

  • Kotlin

SwitchUserFilter switchUser = new SwitchUserFilter();
// ... other configuration
switchUser.setExitUserMatcher(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/exit/impersonate"));
val switchUser = SwitchUserFilter()
// ... other configuration
switchUser.setExitUserMatcher(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/exit/impersonate"))

AbstractAuthenticationProcessingFilter 実装における filterProcessingUrl リクエストマッチャーの移行

Spring Security 6 は、setFilterProcessingUrl で設定された処理エンドポイントを AntPathRequestMatcher に変換します。Spring Security 7 では、これは PathPatternRequestMatcher に変更されます。

UsernamePasswordAuthenticationFilterOAuth2LoginAuthenticationFilterSaml2WebSsoAuthenticationFilterOneTimeTokenAuthenticationFilter や WebAuthnAuthenticationFilter など、AbstractAuthenticationProcessingFilter を継承するフィルターで setFilterProcessingUrl を直接呼び出す場合は、代わりに setRequiredAuthenticationRequestMatcher を呼び出して、この PathPatternRequestMatcher を事前に用意してください。

つまり、これを変更してください:

  • Java

  • Kotlin

UsernamePasswordAuthenticationFilter usernamePassword = new UsernamePasswordAuthenticationFilter(authenticationManager);
usernamePassword.setFilterProcessingUrl("/my/processing/url");
val usernamePassword = UsernamePasswordAuthenticationFilter(authenticationManager)
usernamePassword.setFilterProcessingUrl("/my/processing/url")

これに:

  • Java

  • Kotlin

UsernamePasswordAuthenticationFilter usernamePassword = new UsernamePasswordAuthenticationFilter(authenticationManager);
RequestMatcher requestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/my/processing/url");
usernamePassword.setRequest(requestMatcher);
val usernamePassword = UsernamePasswordAuthenticationFilter(authenticationManager)
val requestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/my/processing/url")
usernamePassword.setRequest(requestMatcher)
Most applications use the DSL instead of setting the `filterProcessingUrl` directly on a filter instance.

CAS プロキシレセプターリクエストマッチャーの移行

Spring Security 6 は、設定された proxyReceptorUrl を、リクエストの末尾に一致するリクエストマッチャー(つまり /**/proxy/receptor)に変換します。Spring Security 7 ではこのパターンは許可されておらず、PathPatternRequestMatcher を使用するように変更されます。また、Spring Security 7m では、URL はコンテキストパスを含まない絶対パスでなければなりません(例: /proxy/receptor)。

これらの変更に備えるために、setProxyReceptorUrl の代わりに setProxyReceptorRequestMatcher を使用できます。

つまり、これを変更してください:

  • Java

  • Kotlin

casAuthentication.setProxyReceptorUrl("/proxy/receptor");
casAuthentication.setProxyReceptorUrl("/proxy/receptor")

これに:

  • Java

  • Kotlin

casAuthentication.setProxyReceptorUrl(PathPatternRequestMatcher.withDefaults().matcher("/proxy/receptor"));
casAuthentication.setProxyReceptorUrl(PathPatternRequestMatcher.withDefaults().matcher("/proxy/receptor"))

WebInvocationPrivilegeEvaluator の移行

Spring Security の JSP タグライブラリを使用している場合、または WebInvocationPrivilegeEvaluator を直接使用している場合は、次の変更に注意してください。

  1. RequestMatcherWebInvocationPrivilegeEvaluator は AuthorizationManagerWebInvocationPrivilegeEvaluator に置き換えられて非推奨になりました

  2. HandlerMappingIntrospectorRequestTransformer は PathPatternRequestTransformer に置き換えられて非推奨になりました

これらを直接構築していない場合は、次のように PathPatternRequestTransformer を公開することで、両方の変更を事前にオプトインできます。

  • Java

  • Kotlin

  • XML

@Bean
HttpServletRequestTransformer pathPatternRequestTransformer() {
	return new PathPatternRequestTransformer();
}
@Bean
fun pathPatternRequestTransformer(): HttpServletRequestTransformer {
    return PathPatternRequestTransformer()
}
<b:bean class="org.springframework.security.web.access.PathPatternRequestTransformer"/>

Spring Security はこれを新しい実装を使用する合図とみなします。

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.

認可ルールにサーブレットパスプレフィックスを含める

多くのアプリケーションでは、リストされている URI のほとんどすべてがデフォルトのサーブレットによって一致するため、上記は違いを生じません。

ただし、サーブレットパスプレフィックスを持つ他のサーブレットがある場合は、これらのパスを個別に指定する必要があります

例: Spring MVC コントローラーと @RequestMapping("/orders") があり、MVC アプリケーションが(デフォルトのサーブレットではなく) /mvc にデプロイされている場合、このエンドポイントの URI は /mvc/orders になります。これまで、Java DSL にはサーブレットのパスプレフィックスを指定する簡単な方法がなく、Spring Security はそれを推測しようとしていました。

時間の経過とともに、これらの推論が開発者を驚かせることが分かりました。開発者からこの責任を取り除く代わりに、次のようにサーブレットパスのプレフィックスを指定する方が簡単になりました。

PathPatternRequestParser.Builder servlet = PathPatternRequestParser.withDefaults().basePath("/mvc");
http
    .authorizeHttpRequests((authorize) -> authorize
        .requestMatchers(servlet.pattern("/orders/**").matcher()).authenticated()
    )

デフォルトのサーブレットに属するパスの場合は、代わりに PathPatternRequestParser.withDefaults() を使用します。

PathPatternRequestParser.Builder request = PathPatternRequestParser.withDefaults();
http
    .authorizeHttpRequests((authorize) -> authorize
        .requestMatchers(request.pattern("/js/**").matcher()).authenticated()
    )

すべてのサーブレットがパスプレフィックスを持っているわけではないため、これはすべての種類のサーブレットに当てはまるわけではないことに注意してください。例: JSP サーブレットに一致する式では、ant パターン /*/.jsp が使用される場合があります。

これらに代わる汎用的なものはまだないため、regexMatcher("\\.jsp$") のように RegexRequestMatcher を使用することをお勧めします。

多くのアプリケーションでは、リストされている URI のほとんどすべてがデフォルトのサーブレットに一致するため、これは問題になりません。

チャネルセキュリティの代わりに RedirectToHttps を使用する

数年前、HTTPS はパフォーマンスと構成に関して大きな関心事であったため、アプリケーションのどのセグメントに HTTPS が必要かをアプリケーション側で決定する必要がありました。

XML の requires-channel と Java 構成 の requiresChannel を使用すると、それを念頭に置いてアプリケーションを構成できます。

  • Java

  • Kotlin

  • XML

http
    .requiresChannel((channel) -> channel
        .requestMatchers("/secure/**").requiresSecureChannel()
        .requestMatchers("/insecure/**").requiresInsecureChannel()
    )
http {
    requiresChannel {
        secure("/secure/**")
        seccure("/insecure/**", "REQUIRES_INSECURE_CHANNEL")
    }
}
<http>
    <intercept-url pattern="/secure/**" access="authenticated" requires-channel="REQUIRES_SECURE_CHANNEL"/>
    <intercept-url pattern="/insecure/**" access="authenticated" requires-channel="REQUIRES_INSECURE_CHANNEL"/>
</http>

現代のアプリケーションは、常に HTTPS を使用するべきです。しかし、ローカル開発など、アプリケーションで HTTP を使用したい場合もあります。あるいは、アプリケーションの一部を HTTP で動作させなければならない状況が継続的に発生する場合もあります。

いずれにせよ、HTTPS へのリダイレクトが必要なすべての状況を含む RequestMatcher をまず構築することで、redirect-to-https-request-matcher-ref および redirectToHttps に移行できます。その後、次のようにしてそのリクエストマッチャーを参照できます。

  • Java

  • Kotlin

  • XML

http
    .redirectToHttps((https) -> https.requestMatchers("/secure/**"))
    // ...
var secure: RequestMatcher = PathPatternRequestMatcher.withDefaults().pattern("/secure/**")
http {
    redirectToHttps {
        requestMatchers = secure
    }
    // ...
}
<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>

HTTP が必要な状況が複数ある場合は、OrRequestMatcher を使用して 1 つの RequestMatcher インスタンスに結合することを検討してください。

個別の setter の代わりに setCookieCustomizer を使用する

よりシンプルな API を優先して、CookieCsrfTokenRepository#setCookieCustomizer を使用すると、setCookieHttpOnlysetCookieMaxAgesetSecuresetCookieDomain を置き換えて Cookie のあらゆる側面を変更できます。

これを変更します:

  • Java

  • Kotlin

CookeCsrfTokenRepository csrf = CookeCsrfTokenRepository.withHttpOnlyFalse();
csrf.setCookieMaxAge(86400)
val csrf = CookeCsrfTokenRepository.withHttpOnlyFalse()
csrf.setCookieMaxAge(86400)

これに:

  • Java

  • Kotlin

CookeCsrfTokenRepository csrf = CookeCsrfTokenRepository.withHttpOnlyFalse();
csrf.setCookieCustomizer((c) -> c.maxAge(86400));
val csrf = CookeCsrfTokenRepository.withHttpOnlyFalse()
csrf.setCookieCustomizer { -> it.maxAge(86400) }