使用 spring-SAML 在 Pentaho 中多租户 SSO 登录后重定向
Posted
技术标签:
【中文标题】使用 spring-SAML 在 Pentaho 中多租户 SSO 登录后重定向【英文标题】:Redirect after multi-tenant SSO login in Pentaho with spring-SAML 【发布时间】:2021-01-22 05:37:35 【问题描述】:我想使用 SAML 插件 Link(扩展 Spring SAML)配置 Pentaho 的多租户 SSO 登录。
现在我已经在 blueprint.xml 中声明了多个服务提供者 (SP) 和身份提供者 (IDP)(每个租户一个以及一个公共 SP)。然而,在登录流程结束时,我并没有被重定向到主页,而是被重定向到一个通用错误页面。
以下是 SAML 插件中 blueprint.xml 设置的示例:
<bean id="spResourceFactoryCommon" class="org.pentaho.platform.spring.security.saml.resources.MetadataResourceFactory">
<argument>
<map key-type="java.lang.String" value-type="java.lang.String">
<entry key="org.opensaml.util.resource.FilesystemResource" value="$saml.sp.metadata.filesystem.common" />
</map>
</argument>
<argument value="$saml.sp.metadata.classpath.fallback" />
</bean>
<bean id="spResourceFactoryTenant1" class="org.pentaho.platform.spring.security.saml.resources.MetadataResourceFactory">
<argument>
<map key-type="java.lang.String" value-type="java.lang.String">
<entry key="org.opensaml.util.resource.FilesystemResource" value="$saml.sp.metadata.filesystem.tenant1" />
</map>
</argument>
<argument value="$saml.sp.metadata.classpath.fallback" />
</bean>
<bean id="spResourceFactoryTenant2" class="org.pentaho.platform.spring.security.saml.resources.MetadataResourceFactory">
<argument>
<map key-type="java.lang.String" value-type="java.lang.String">
<entry key="org.opensaml.util.resource.FilesystemResource" value="$saml.sp.metadata.filesystem.tenant2" />
</map>
</argument>
<argument value="$saml.sp.metadata.classpath.fallback" />
</bean>
<bean id="idpResourceFactoryTenant1" class="org.pentaho.platform.spring.security.saml.resources.MetadataResourceFactory">
<argument>
<map key-type="java.lang.String" value-type="java.lang.String">
<entry key="org.opensaml.util.resource.FilesystemResource" value="$saml.idp.metadata.filesystem.tenant1" />
</map>
</argument>
<argument value="$saml.idp.metadata.classpath.fallback" />
</bean>
<bean id="idpResourceFactoryTenant2" class="org.pentaho.platform.spring.security.saml.resources.MetadataResourceFactory">
<argument>
<map key-type="java.lang.String" value-type="java.lang.String">
<entry key="org.opensaml.util.resource.FilesystemResource" value="$saml.idp.metadata.filesystem.tenant2" />
</map>
</argument>
<argument value="$saml.idp.metadata.classpath.fallback" />
</bean>
<!-- MetadataManager configuration - paths to metadata of IDPs and SP's -->
<bean id="metadata" class="org.springframework.security.saml.metadata.CachingMetadataManager" depends-on="pentahoSamlBootstrap">
<argument>
<list>
<!-- sp metadata with extended metadata -->
<bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
<argument>
<bean class="org.opensaml.saml2.metadata.provider.ResourceBackedMetadataProvider">
<argument>
<bean class="java.util.Timer"/>
</argument>
<argument>
<bean factory-ref="spResourceFactoryCommon" factory-method="factoryResource" />
</argument>
<property name="parserPool" ref="parserPool"/>
</bean>
</argument>
<argument>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
<property name="idpDiscoveryEnabled" value="$saml.discovery.idp.enabled"/>
<property name="requireLogoutRequestSigned" value="$ensure.incoming.logout.request.signed"/>
<property name="alias" value="pentahoCommon"/>
<property name="local" value="true"/>
</bean>
</argument>
</bean>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
<argument>
<bean class="org.opensaml.saml2.metadata.provider.ResourceBackedMetadataProvider">
<argument>
<bean class="java.util.Timer"/>
</argument>
<argument>
<bean factory-ref="spResourceFactoryTenant1" factory-method="factoryResource" />
</argument>
<property name="parserPool" ref="parserPool"/>
</bean>
</argument>
<argument>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
<property name="idpDiscoveryEnabled" value="$saml.discovery.idp.enabled"/>
<property name="requireLogoutRequestSigned" value="$ensure.incoming.logout.request.signed"/>
<property name="alias" value="tenant1sp"/>
<property name="local" value="true"/>
</bean>
</argument>
</bean>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
<argument>
<bean class="org.opensaml.saml2.metadata.provider.ResourceBackedMetadataProvider">
<argument>
<bean class="java.util.Timer"/>
</argument>
<argument>
<bean factory-ref="spResourceFactoryTenant2" factory-method="factoryResource" />
</argument>
<property name="parserPool" ref="parserPool"/>
</bean>
</argument>
<argument>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
<property name="idpDiscoveryEnabled" value="$saml.discovery.idp.enabled"/>
<property name="requireLogoutRequestSigned" value="$ensure.incoming.logout.request.signed"/>
<property name="alias" value="tenant2sp"/>
<property name="local" value="true"/>
</bean>
</argument>
</bean>
<!-- idp metadata -->
<bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
<argument>
<bean class="org.opensaml.saml2.metadata.provider.ResourceBackedMetadataProvider">
<argument>
<bean class="java.util.Timer"/>
</argument>
<argument>
<bean factory-ref="idpResourceFactoryTenant1" factory-method="factoryResource" />
</argument>
<property name="parserPool" ref="parserPool"/>
</bean>
</argument>
<argument>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
<property name="idpDiscoveryEnabled" value="$saml.discovery.idp.enabled"/>
<property name="requireLogoutRequestSigned" value="$ensure.outgoing.logout.request.signed"/>
<property name="requireLogoutResponseSigned" value="$ensure.outgoing.logout.response.signed"/>
<property name="alias" value="tenant1idp"/>
<property name="local" value="true"/>
</bean>
</argument>
</bean>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
<argument>
<bean class="org.opensaml.saml2.metadata.provider.ResourceBackedMetadataProvider">
<argument>
<bean class="java.util.Timer"/>
</argument>
<argument>
<bean factory-ref="idpResourceFactoryTenant2" factory-method="factoryResource" />
</argument>
<property name="parserPool" ref="parserPool"/>
</bean>
</argument>
<argument>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
<property name="idpDiscoveryEnabled" value="$saml.discovery.idp.enabled"/>
<property name="requireLogoutRequestSigned" value="$ensure.outgoing.logout.request.signed"/>
<property name="requireLogoutResponseSigned" value="$ensure.outgoing.logout.response.signed"/>
<property name="alias" value="tenant2idp"/>
<property name="local" value="true"/>
</bean>
</argument>
</bean>
</list>
</argument>
<property name="keyManager" ref="keyManager" />
<property name="defaultIDP" value="$saml.idp.url" />
</bean>
有了这个配置,当我去 url https://my.application.com/pentaho/alias/tenant1sp/sp?idp=tenant.1.name 我被重定向到 IDP 为租户 1 公开的登录页面。登录后,我被重定向到上一个 url,出现一般错误:see the screenshot
抱歉,出了点问题。 请重试或联系 您的系统管理员。
如果我访问 URL https://my.application.com/pentaho/Home,我将登录到 Pentaho 仪表板。这让我认为登录过程已经成功,但是在流程结束时重定向出现问题。事实上,我希望被重定向到 URL https://my.application.com/pentaho/Home 。 我可以在某处/以某种方式配置此重定向吗?
【问题讨论】:
【参考方案1】:一种变通方法似乎解决了这个问题,但是我发现它在使用 Pentaho 的公开 API 时会与 SAML 身份验证产生冲突。要使用这些 API,这个解决方案并不好。
解决方法
更改 successRedirectHandler bean 的 defaultTargetUrl 和 alwaysUseDefaultTargetUrl 属性(在 blueprint.xml 文件中声明Pentaho-SAML 插件)
<!-- Handler deciding where to redirect user after successful login -->
<bean id="successRedirectHandler" class="org.pentaho.platform.spring.security.saml.PentahoSamlAuthenticationSuccessHandler"
init-method="afterPropertiesSet">
<property name="defaultTargetUrl" value="https://my.application.com/pentaho/Home"/>
<property name="alwaysUseDefaultTargetUrl" value="true"/>
<property name="requireProxyWrapping" value="false"/>
</bean>
编辑:API 登录问题的解决 我用一个覆盖 onAuthenticationSuccess 方法的自定义类扩展了 org.pentaho.platform.spring.security.saml.PentahoSamlAuthenticationSuccessHandler 类
private String contextPath;
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws ServletException, IOException
SavedRequest savedRequest = requestCache.getRequest(request, response);
//Apply the redirect to the Pentaho console Home if and only if the original targetUrl is not a Pentaho exposed API but the home (contextPath/Home)
if (!savedRequest.getRedirectUrl().contains("API")
&& savedRequest.getRedirectUrl().contains(contextPath+"/Home"))
//The Pentaho console Home is set as defaultTargetUrl in the blueprint.xml
this.setAlwaysUseDefaultTargetUrl(true);
log.info("The request is not on a Pentaho API. Forcing the target URL to redirect to the defaultTargetUrl");
super.onAuthenticationSuccess(request, response, authentication);
//retore the original value of alwaysUseDefaultTargetUrl
this.setAlwaysUseDefaultTargetUrl(false);
【讨论】:
以上是关于使用 spring-SAML 在 Pentaho 中多租户 SSO 登录后重定向的主要内容,如果未能解决你的问题,请参考以下文章
这个标题日期从哪里来的响应? (带有Tomcat的spring-saml2)
如何在运行时在 spring-SAML 中添加新的 idp 元数据