Spring SAML通过单路径存放元数据实现IDP自动发现无需新增配置Bean咨询
实现方案
这个需求完全可以实现,无需每次新增IDP都修改security-context.xml配置,通过动态扫描指定目录下的元数据文件即可实现自动加载。
实现逻辑说明
你现有配置的核心问题是硬编码了每个IDP的元数据路径,每个IDP都单独定义了ExtendedMetadataDelegate Bean。我们只需要将CachingMetadataManager构造参数的元数据提供者列表,改成由程序自动扫描指定目录生成即可。
具体实现步骤
第一步:新增配置项
在你的配置文件中新增IDP元数据统一存放目录的配置,所有IDP的元数据XML文件都可以直接放到这个目录下:
# IDP元数据统一存放目录 idp.metadata.folder.path=/your/custom/path/to/idp/metadata # 原有SP元数据路径保留即可 sdp.metadata.file.path=/your/path/to/sp/metadata.xml
第二步:编写动态元数据加载工厂类
自定义FactoryBean自动扫描目录生成元数据提供者列表:
import org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider; import org.opensaml.saml2.metadata.provider.MetadataProvider; import org.opensaml.xml.parse.ParserPool; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.saml.metadata.ExtendedMetadata; import org.springframework.security.saml.metadata.ExtendedMetadataDelegate; import java.io.File; import java.util.ArrayList; import java.util.List; public class DynamicMetadataProviderFactory implements FactoryBean<List<MetadataProvider>> { @Value("${idp.metadata.folder.path}") private String idpMetadataFolder; @Value("${sdp.metadata.file.path}") private String spMetadataPath; @Autowired private ParserPool parserPool; @Override public List<MetadataProvider> getObject() throws Exception { List<MetadataProvider> providers = new ArrayList<>(); // 加载本地SP元数据,规则和原有配置完全一致 FilesystemMetadataProvider spProvider = new FilesystemMetadataProvider(new File(spMetadataPath)); spProvider.setParserPool(parserPool); ExtendedMetadata spExtMetadata = new ExtendedMetadata(); spExtMetadata.setLocal(true); spExtMetadata.setAlias("default"); spExtMetadata.setSecurityProfile("metaiop"); spExtMetadata.setSslSecurityProfile("pkix"); spExtMetadata.setSigningKey("test"); spExtMetadata.setEncryptionKey("test"); spExtMetadata.setRequireArtifactResolveSigned(false); spExtMetadata.setRequireLogoutRequestSigned(false); spExtMetadata.setRequireLogoutResponseSigned(false); spExtMetadata.setIdpDiscoveryEnabled(false); providers.add(new ExtendedMetadataDelegate(spProvider, spExtMetadata)); // 扫描IDP元数据目录下所有XML文件,自动生成IDP元数据提供者 File metadataDir = new File(idpMetadataFolder); if (metadataDir.exists() && metadataDir.isDirectory()) { File[] metadataFiles = metadataDir.listFiles((dir, name) -> name.toLowerCase().endsWith(".xml")); if (metadataFiles != null) { for (File file : metadataFiles) { FilesystemMetadataProvider idpProvider = new FilesystemMetadataProvider(file); idpProvider.setParserPool(parserPool); // 如需热加载可以添加刷新间隔配置,单位为毫秒,示例为5分钟刷新一次 // idpProvider.setMinRefreshDelay(300000); providers.add(new ExtendedMetadataDelegate(idpProvider, new ExtendedMetadata())); } } } return providers; } @Override public Class<?> getObjectType() { return List.class; } @Override public boolean isSingleton() { return true; } }
第三步:替换原有XML配置
把你原有security-context.xml里的metadata Bean配置替换为如下内容即可:
<!-- 注册动态元数据工厂 --> <b:bean id="dynamicMetadataProviderFactory" class="com.your.actual.package.DynamicMetadataProviderFactory"/> <!-- 元数据管理器直接引用动态生成的列表 --> <b:bean id="metadata" class="org.springframework.security.saml.metadata.CachingMetadataManager"> <b:constructor-arg ref="dynamicMetadataProviderFactory"/> </b:bean>
注意事项
- 保证应用进程对IDP元数据目录有读取权限
- SP元数据不要放到IDP元数据目录中,避免被误识别为IDP
- 如果需要元数据签名校验、过期校验等能力,可以在生成
ExtendedMetadataDelegate时补充对应配置即可
内容的提问来源于stack exchange,提问作者average.joe
相关产品推荐
相关产品推荐

