升级spring-security-saml2-service-provider 5.6.9遇404错误求助
我正在把现有应用从已停止维护的spring-security-saml2-core 1.0.10.RELEASE升级到spring-security-saml2-service-provider 5.6.9。基于GitHub示例搭建的测试应用能正常使用IDP发起登录,也能通过http://{host-name}/saml2/service-provider-metadata/{registration-id}获取SP元数据,但把相同配置整合到实际项目后出现问题:日志显示relyingParty实例配置正常,但访问上述SP元数据URL及尝试IDP发起登录都返回404错误。
配置代码
// Necessary Imports @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { private ResourceLoader resourceLoader = new DefaultResourceLoader(); @Autowired(required = false) private RelyingPartyRegistrationRepository relyingPartyRegistrationRepository; @Override protected void configure(HttpSecurity http) throws Exception { LOG.info("In the configure method"); if (isSAMLEnabled()) { LOG.info("Inside IF"); http .authorizeRequests() .anyRequest().authenticated() .and() .saml2Login(); Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationResolver = new DefaultRelyingPartyRegistrationResolver(relyingPartyRegistrationRepository); Saml2MetadataFilter filter = new Saml2MetadataFilter(relyingPartyRegistrationResolver, new OpenSamlMetadataResolver()); http.addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class); } LOG.info("Configure method done."); } @Bean public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() { LOG.info("Inside the bean method"); if (isSAMLEnabled()) { return createRelyingPartyRegistrationRepository(); } else { return null; } } private RelyingPartyRegistrationRepository createRelyingPartyRegistrationRepository() { LOG.info("Inside Repo method"); String entityId = //Appropriate Value String ssoUrl = //Appropriate Value String certificatePath = //Appropriate Value try { Resource resource = resourceLoader.getResource(certificatePath); InputStream inputStream = resource.getInputStream(); CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate certificate = (X509Certificate) cf.generateCertificate(inputStream); Saml2X509Credential credential = Saml2X509Credential.verification(certificate); RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration .withRegistrationId("okta-idp") .assertingPartyDetails(party -> party .entityId(entityId) .singleSignOnServiceLocation(ssoUrl) .wantAuthnRequestsSigned(false) .verificationX509Credentials(c -> c.add(credential)) ).build(); LOG.info("repo method successful"); return new InMemoryRelyingPartyRegistrationRepository(relyingPartyRegistration); } catch (Exception e) { LOG.info("Failed in repo method"); throw new RuntimeException("Error configuring SAML ", e); } } private boolean isSAMLEnabled() { LOG.info("Checking if SAML is enabled..."); // Logic to check if SAML is enabled, this part works fine. } }
日志信息
2024-01-29 11:36:08,200 INFO Inside the bean method 2024-01-29 11:36:08,200 INFO Checking if SAML is enabled... 2024-01-29 11:36:08,200 INFO Inside Repo method 2024-01-29 11:36:08,212 INFO repo method successful 2024-01-29 11:36:08,324 INFO In the configure method 2024-01-29 11:36:08,324 INFO Checking if SAML is enabled... 2024-01-29 11:36:08,324 INFO Inside IF 2024-01-29 11:36:08,980 INFO Configure method done.
错误信息
HTTP ERROR 404 Not Found URI: /saml2/service-provider-metadata/{registartion-id} STATUS: 404 MESSAGE: Not Found SERVLET: default
排查方向与解决方案
1. 修正请求路径拼写错误
错误日志中的URI包含拼写错误:registartion-id,正确应为registration-id,先确认实际请求的URL是否使用了正确的拼写。
2. 放开元数据端点的匿名访问权限
当前配置中.anyRequest().authenticated()会拦截所有请求,包括SP元数据URL,需要添加例外规则允许匿名访问:
http.authorizeRequests() .antMatchers("/saml2/service-provider-metadata/**").permitAll() .anyRequest().authenticated() .and() .saml2Login();
3. 解决Bean注入冲突
代码中同时存在@Autowired注入和自定义RelyingPartyRegistrationRepository Bean的逻辑,可能导致注入异常。直接在configure方法中调用Bean方法获取实例:
// 移除@Autowired的relyingPartyRegistrationRepository字段 @Override protected void configure(HttpSecurity http) throws Exception { LOG.info("In the configure method"); if (isSAMLEnabled()) { LOG.info("Inside IF"); http .authorizeRequests() .antMatchers("/saml2/service-provider-metadata/**").permitAll() .anyRequest().authenticated() .and() .saml2Login(); // 直接调用Bean方法获取实例 Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationResolver = new DefaultRelyingPartyRegistrationResolver(relyingPartyRegistrationRepository()); Saml2MetadataFilter filter = new Saml2MetadataFilter(relyingPartyRegistrationResolver, new OpenSamlMetadataResolver()); http.addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class); } LOG.info("Configure method done."); }
4. 检查多Security配置的优先级
如果项目中存在多个WebSecurityConfigurerAdapter配置类,可能会覆盖当前SAML2配置。给当前配置添加@Order(1)注解,确保它的优先级高于其他配置:
@Configuration @EnableWebSecurity @Order(1) public class SecurityConfig extends WebSecurityConfigurerAdapter { // ... 原有代码 }
5. 验证OpenSAML依赖完整性
Spring Security SAML2 5.x依赖OpenSAML库,确保项目依赖中包含完整的OpenSAML相关包(以Maven为例):
<dependency> <groupId>org.opensaml</groupId> <artifactId>opensaml-core</artifactId> <version>3.4.6</version> </dependency> <dependency> <groupId>org.opensaml</groupId> <artifactId>opensaml-saml-api</artifactId> <version>3.4.6</version> </dependency> <dependency> <groupId>org.opensaml</groupId> <artifactId>opensaml-saml-impl</artifactId> <version>3.4.6</version> </dependency>
6. 调试过滤器链加载情况
启用Spring Security的DEBUG日志,查看SAML2相关过滤器是否被正确加载:
logging.level.org.springframework.security=DEBUG
检查日志中是否存在Saml2MetadataFilter和Saml2WebSsoAuthenticationFilter的初始化记录,确认过滤器链是否包含这些组件。
内容的提问来源于stack exchange,提问作者Sid

