Spring Security SAML使用多个子域访问同一个应用程序(相同的IP)

时间:2015-07-30 16:23:08

标签: spring-security spring-saml

我有一个应用程序可以通过多个子域访问,因为品牌和支持信息是动态显示的。我们正在转向一个SSO解决方案,现在让它变得有趣。目前我将Spring Security SAML(1.0.1)添加到Spring Security组合中,并在IdP上使用WSO2 Identity Server。它运行得很好。

当存在多个同一地址的DNS条目时,问题在于保留服务提供商端的子域。例如,假设我将以下子域发送到完全相同的地方,即guy1.mistersite.com和guy2.mistersite.com。当首次通过guy1.mistersite.com启动应用服务器时首次访问应用程序时,来自SP的AuthnRequest将在AssertionConsumerServiceURL和Issuer中指示它来自guy1.mistersite.com。好。现在,从guy2.mistersite.com尝试下一次访问,AssertionConsumerServiceURL和Issuer实际上仍然在AuthnRequest中有guy1.mistersite.com。长号。

查看代码,您可以看到它已被有效缓存 org.springframework.security.saml.metadata.MetadataGeneratorFilter。当命中processMetadataInitialization()方法时,将检查是否已设置了hostedSPName,entityAlias和defaultBaseURL。如果他们是,那么,继续前进。这是有道理的。

是继承MetadataGeneratorFilter并重写processMetadataInitialization()真的是一个有效且“安全”的解决方案吗?

我已经做了一个概念验证,并注释掉了所有的空值检查,因此每次使用此方法时都会重新建立每个值,因此在一个简单的情况下,这样可以正常工作。我想知道,因为这个bean本质上是一个单例,当一个不同的子域请求同时出现时会发生什么。有没有机会被搞砸了?该方法中的同步块是否足以防止这种考虑?

所以,是的,如果这是一种安全且理智的方式来解决这个问题,就好像我是在正确的轨道上,请告诉我!还有别的想法。我是对的,我不是什么? :)

我们正在考虑改变基础架构和子域的方法模型,所以我想继续讨论使用新类扩展Spring Security SAML的可行性。

提前感谢! ;)

以下是我对该方法的快速修复(基本上只评论了一些内容):

    protected void processMetadataInitialization(HttpServletRequest request) throws ServletException {

        // In case the hosted SP metadata weren't initialized, let's do it now
//Forcing this to reload the host SP name every time to deal with various subdomains where a user could come to for the same app (think branding for partner companies)
//        if (manager.getHostedSPName() == null) {

            synchronized (MetadataManager.class) {

//                if (manager.getHostedSPName() == null) {

                    try {

                        log.info("No default metadata configured, generating with default values, please pre-configure metadata for production use");

                        // Defaults
                        String alias = generator.getEntityAlias();
                        String baseURL = getDefaultBaseURL(request);

                        // Use default baseURL if not set
//                        if (generator.getEntityBaseURL() == null) {
                            log.warn("Generated default entity base URL {} based on values in the first server request. Please set property entityBaseURL on MetadataGenerator bean to fixate the value.", baseURL);
                            generator.setEntityBaseURL(baseURL);
//                        } else {
                            baseURL = generator.getEntityBaseURL();
//                        }

                        // Use default entityID if not set
//                        if (generator.getEntityId() == null) {
                            generator.setEntityId(getDefaultEntityID(baseURL, alias));
//                        }

                        EntityDescriptor descriptor = generator.generateMetadata();
                        ExtendedMetadata extendedMetadata = generator.generateExtendedMetadata();

                        log.info("Created default metadata for system with entityID: " + descriptor.getEntityID());
                        MetadataMemoryProvider memoryProvider = new MetadataMemoryProvider(descriptor);
                        memoryProvider.initialize();
                        MetadataProvider metadataProvider = new ExtendedMetadataDelegate(memoryProvider, extendedMetadata);

                        manager.addMetadataProvider(metadataProvider);
                        manager.setHostedSPName(descriptor.getEntityID());
                        manager.refreshMetadata();

                    } catch (MetadataProviderException e) {
                        log.error("Error generating system metadata", e);
                        throw new ServletException("Error generating system metadata", e);
                    }

//                }

            }

//        }

    }

安全配置的一部分:

    <bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter">
        <constructor-arg>
            <bean class="org.springframework.security.saml.metadata.MetadataGenerator">
                <property name="extendedMetadata">
                    <bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
                        <property name="idpDiscoveryEnabled" value="false"/>
                        <property name="signMetadata" value="false"/>
                    </bean>
                </property>
                <!-- We leave these out and values are defaulted to entityId = url that user came in on
                and entityId = <entityBaseUrl>/saml/metadata.  We have to configure a SP in WSO2 for every
                subdomain we have -->
                    <property name="wantAssertionSigned" value="false" />
            </bean>
        </constructor-arg>
    </bean>

1 个答案:

答案 0 :(得分:0)

我一直在谷歌搜索它,它已经看到两种可能的方法。根据规范,您可以将身份验证请求签名为SP,以便指定AssertionConsumerServiceURL,而不要求它作为SP元数据交换的一部分先前已发布和配置,但我不完全了解如何使用Spring执行此操作安全SAML扩展。以下是该信息的source

我自己辩论的另一个问题是覆盖MetadataGenerator中的buildSPSSODescriptor,然后查找该环境的可能子域(我们在数据库中有可用的子域),然后我将遍历该列表并创建一个条目每一个人。

就像你这样做的方式,这最后一种方式似乎也是一种黑客攻击。希望这会有所帮助。

你最终做了什么?