Spring SAML2 SLO中POST请求405错误的排查与解决
Spring Security SAML2单点登出(SLO)405 Method Not Allowed问题排查
我正在实现Spring Security SAML2的单点登录(SSO)和单点登出(SLO)功能,SSO已成功运行,但按照官方文档配置SLO时,出现405 Method Not Allowed状态码错误。

我已尝试以下操作,但问题仍未解决:
- 禁用CORS和CSRF
- 在过滤器中排除
/logout/saml2/slo路径
搜索相关问题时,结果大多围绕Saml2 Response展开,未找到匹配的解决方案。我已确认jks密钥库、别名及密码均正确,期望能成功完成SLO并返回SAML2 Response。
配置代码
RelyingPartyRegistrationRepository配置
@Bean public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exception { if (DomainUtil.isSSOEnabled()) { byte[] decodeCertBase64 = Base64.getDecoder().decode(spSigningCertificateBase64.trim()); char[] password = "REMOVED".toCharArray(); try (InputStream inputStream = getSamlMetadataInputStream(samlMetadata); ByteArrayInputStream certStream = new ByteArrayInputStream(decodeCertBase64); FileInputStream fileInputStream = new FileInputStream("/BDO/fedlet/fedletkeystore.jks")) { KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(fileInputStream, password); String alias = keyStore.aliases().nextElement(); RSAPrivateKey privateKey = (RSAPrivateKey) keyStore.getKey(alias, password); CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(certStream); Saml2X509Credential signingCredential = Saml2X509Credential.signing(privateKey, cert); RelyingPartyRegistration.Builder builder = RelyingPartyRegistrations.fromMetadata(inputStream) .registrationId(samlRegistrationId) .signingX509Credentials(signing -> signing.add(signingCredential)) .assertingPartyDetails(details-> details .singleLogoutServiceBinding(Saml2MessageBinding.POST) .singleLogoutServiceLocation(SAML2_LOGOUT_URL) // SAML2_LOGOUT_URL = /logout/saml2/slo, 尝试改为{baseUrl}/logout/saml2/slo仍无效 .singleLogoutServiceResponseLocation("/logout")); if (StringUtils.isNotBlank(samlEntityId)) { builder.entityId(samlEntityId); } return new InMemoryRelyingPartyRegistrationRepository(builder.build()); } catch (Exception e) { log.error("relyingPartyRegistrations() : %s".formatted(e.getMessage()), e); throw e; } } return null; }
SecurityFilterChain配置
@Bean @Order(3) SecurityFilterChain samlWebChain(HttpSecurity http, CustomUserDetailsService userDetailsServiceImp) throws Exception { try { http .authorizeHttpRequests(auth -> auth .requestMatchers("/api/**", "/error**").permitAll() .requestMatchers(LOGIN_URL, SAML2_LOGOUT_URL).permitAll() .requestMatchers("/accessDenied").permitAll() .requestMatchers("/config/**", "/common/**").authenticated() .anyRequest().access(new CustomAuthorizationManager())) .headers(headers -> headers .contentSecurityPolicy(securityPolicy -> { String cspUrl = FileUtil.getApplicationMingleUserActivityDomain(); cspUrl = cspUrl.startsWith(".") ? cspUrl.substring(1) : cspUrl; securityPolicy.policyDirectives("frame-ancestors https://*." + cspUrl + ":*"); }) .frameOptions(frameOptions -> frameOptions.sameOrigin()) ).csrf(httpSecurityCsrfConfigurer -> httpSecurityCsrfConfigurer.ignoringRequestMatchers(SAML2_LOGOUT_URL)); if (DomainUtil.isSSOEnabled()) { http .saml2Login(saml -> saml .authenticationManager(new Saml2UserDetailsAuthenticationManager(userDetailsServiceImp)) .successHandler(myAuthenticationSuccessHandler()) ) .saml2Logout(Customizer.withDefaults()); } http.exceptionHandling(e -> e.accessDeniedPage("/accessDenied")); return http.build(); } catch (Exception e) { log.error("samlWebChain() : %s".formatted(e.getMessage()), e); throw e; } }
其他尝试
我尝试在控制器中添加/logout/saml2/slo路径,请求返回200状态,但不知道如何处理接收到的XML,目前仍在处理中。若需要更多信息,可告知补充。
更新记录
更新:2024年2月22日
添加saml2metadata()配置后,从/saml2/metadata下载的SAML元数据文件中缺少SingleLogoutService,原本期望其中包含SLO URL。
更新:2024年2月23日
在singleLogoutServiceLocation中添加{baseUrl}和{registrationId}后,元数据中已包含缺失的SLO请求和响应地址,但405错误依然存在。
内容的提问来源于stack exchange,提问作者Onel Sarmiento
相关产品推荐
相关产品推荐

