Spring Boot 3.4.1升级后SAML证书无法识别为PemContent问题
Spring Boot 3.4.1 SAML认证非PEM格式证书无法识别的解决方案
问题背景
从Spring Boot 3.3.6升级到3.4.1后,原SAML认证配置中的非PEM格式.cer证书无法被识别,抛出IllegalStateException: Missing certificates or unrecognized format异常。核心原因是Saml2RelyingPartyRegistrationConfiguration#readCertificate方法实现变更:
- 3.3.x版本通过
CertificateFactory.getInstance("X.509")直接读取多种X.509证书格式(包括DER编码的.cer) - 3.4.x版本改为仅支持PEM格式的
PemContent解析,导致非PEM证书无法加载
原配置示例:
spring.security.saml2: relyingparty: registration: azuread: entity-id: ArchitecturePoC assertingparty: verification: credentials: - certificate-location: "classpath:ArchitecturePoC.cer"
解决方案
方案1:将证书转换为PEM格式
这是最直接的解决方式,使用openssl工具将DER编码的.cer转换为PEM格式:
openssl x509 -inform der -in ArchitecturePoC.cer -out ArchitecturePoC.pem
修改配置文件中的证书路径:
spring.security.saml2: relyingparty: registration: azuread: entity-id: ArchitecturePoC assertingparty: verification: credentials: - certificate-location: "classpath:ArchitecturePoC.pem"
方案2:自定义证书读取逻辑(覆盖自动配置)
如果需要保留原有.cer证书格式,可以自定义RelyingPartyRegistrationRepository,沿用3.3.x版本的证书读取逻辑:
@Configuration public class CustomSaml2RelyingPartyConfig { @Bean public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() { RelyingPartyRegistration registration = RelyingPartyRegistration.withRegistrationId("azuread") .entityId("ArchitecturePoC") .assertingParty(assertingParty -> assertingParty .verification(verification -> verification .credentials(credentials -> credentials .add(credential -> credential.x509Certificate(readCertificate(new ClassPathResource("ArchitecturePoC.cer")))) ) ) ) .build(); return new InMemoryRelyingPartyRegistrationRepository(registration); } private X509Certificate readCertificate(Resource location) { Assert.state(location != null, "No certificate location specified"); Assert.state(location.exists(), () -> "Certificate location '" + location + "' does not exist"); try (InputStream inputStream = location.getInputStream()) { return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(inputStream); } catch (Exception ex) { throw new IllegalArgumentException("Failed to load certificate from " + location, ex); } } }
方案3:使用自定义器修改现有注册项
如果不想完全替换自动配置,可通过Saml2RelyingPartyRegistrationCustomizer针对特定注册项替换证书加载逻辑:
@Configuration public class Saml2CertificateCustomizer { @Bean public Saml2RelyingPartyRegistrationCustomizer certificateLoadingCustomizer() { return (registrationId, builder) -> { if ("azuread".equals(registrationId)) { X509Certificate cert = readCertificate(new ClassPathResource("ArchitecturePoC.cer")); builder.assertingParty(party -> party .verification(verification -> verification .credentials(creds -> creds.clear().add(c -> c.x509Certificate(cert))) ) ); } }; } private X509Certificate readCertificate(Resource location) { Assert.state(location != null, "No certificate location specified"); Assert.state(location.exists(), () -> "Certificate location '" + location + "' does not exist"); try (InputStream inputStream = location.getInputStream()) { return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(inputStream); } catch (Exception ex) { throw new IllegalArgumentException("Failed to load certificate from " + location, ex); } } }
方案对比
- 方案1:操作简单,无需代码修改,适合快速解决问题
- 方案2/3:保留原有证书格式,适合无法修改证书文件的场景,代码侵入性低
内容的提问来源于stack exchange,提问作者yasu1209
相关产品推荐
相关产品推荐

