如何为多租户应用程序(具有不同域 URL)的所有租户设置单个 SAML 应用程序?

How to setup a single SAML app for all the tenants of multi-tenant app(having different domain urls)?

应用架构:

问题:

我们需要一个可以与所有租户集成的单一 SAML 应用程序。

示例租户 URLs:tenant1.myapp.com、tenant2.myapp.com、tenant3.myapp.com 等

我们希望所有租户都与单个 SAML 应用程序集成,以对任何这些租户中存在的用户进行身份验证。

             |---------------- SAML App -----------------|
             |                     |                     |
             |                     |                     |
             |                     |                     |
          Tenant 1              Tenant 2              Tenant 3
     (tenant1.myapp.com)   (tenant2.myapp.com)   (tenant3.myapp.com)

通常情况下,我们可以为不同的租户使用不同的 SAML 应用程序,但这导致我们维护大量 SAML 应用程序,这是我们想要避免的。

我们正在尝试一些解决方案。如果任何解决方案有效,我们将在此处更新答案。同时,如果有人有什么建议,请帮忙。

我们已经找到解决这个问题的方法。 在重定向到 IdP 登录页面期间,我们将租户 URL 作为请求中的 RelayState 参数发送,该参数在从 IdP 到我们的 SP 的 SAML 断言请求正文中返回给我们。

  • 我们编写了一个 AWS Lambda(以及 API 网关)来将 SAML 断言请求重新路由到所需的租户。
  • 我们使用这个 RelayState 参数来了解这个请求来自哪个租户。
  • 我们在 SAML 应用程序中将指向我们的 lambda(SSO 路由器)的 API 网关 URL 配置为 ACS URL。

Lambda 的功能: 它从 SAML 断言请求正文中选择 RelayState 参数并将请求重定向到所需的租户 URL(存在于 RelayState 中)。

Login to the App(any Tenant) ==> Redirection to Login Page ==> (On successful login) Redirected to Lambda(SSO Router) ==> Redirected to the tenant URL(present in the RelayState)

我们已经在 Python 中编写了 Lambda。这是示例代码:

    def lambda_handler(event, context):
        body = event.get('body')
        redirect_host = body.split('RelayState=https%3A%2F%2F')[1].split('%2')[0]
        # Here the request body is urlencoded and the URL will be of the form https://tenant1.myapp.com/ - we are only picking tenant1.myapp.com from the RelayState
        redirect_url = 'https://' + redirect_host + '/saml/?acs'
        # Our SAML redirection URL is of the form https://tenant1.myapp.com/saml/?acs
        logger.info(f"Redirecting To: {redirect_url}")
        return {
            'statusCode': 307, # Status code 307 is to preserve the method by which this URL was called. Using 302 changes the method to GET whereas the SAML request comes as a POST
            'headers': {
                'Location': redirect_url,
                'Content-Type': 'application/x-www-form-urlencoded',
                'Access-Control-Allow-Origin': '*',
            },
            'body': body,
        }