关于 firebase 身份验证:Google Cloud Identity Platform (CICP) SAML Workflow Fails

Google Cloud Identity Platform (CICP) SAML Workflow Fails

背景

使用 Firebase 身份验证和具有以下配置的 SAML 身份验证提供程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const config = {
    apiKey:"AIzaSy...",
    authDomain:"example-app.firebaseapp.com",
};

firebase.initializeApp(config);

const provider = new firebase.auth.SAMLAuthProvider('saml.example-idp');

function saml() {
    firebase.auth().signInWithRedirect(provider)
        .then((result) => {
            console.log(result);
        })
        .catch((error) => {
            console.log(error);
        });
}

SAML 上游的 CICP 配置具有服务提供者:我们的实体 id 和配置为我们的 CICP https://example-app.firebaseapp.com/__/auth/handler.

的 ACS
我期望发生的事情

能够在 signInWithRedirect() 的 Promise 的 then 中设置断点并查看经过身份验证的用户。

实际发生了什么

流被重定向到 IdP 并处理身份验证。

IdP 发出带有自动提交加载的重定向发布页面和一个 multipart/form-data 表单,其中:

  • 内容处置:表单数据; name=SAMLResponse - 包含 base64
    编码签名 SAMLResponse
  • 内容处置:表单数据;
    name=RelayState - 包含来自 SAML 流的中继状态
  • 内容处置:表单数据; name="ssourl" - 包含
    firebase 项目身份验证处理程序 URI

这反过来又会导致 CI??CP 呈现并返回一个带有设置脚本的页面

1
2
3
var POST_BODY=""------WebKitFormBoundary9bn7AOpnZiIRk9qZ\
\
Content....."

即它不是解析表单正文并提取 SAMLResponse 字段,而是将整个 Request.body 重播到脚本中,然后调用 fireauth.oauthhelper.widget.initialize();

这显然失败了,因为往返然后尝试将整个响应正文作为查询字符串发布到 /__/auth/handler 端点。

我怀疑这个链中缺少一个简单的配置项,因为在多部分表单数据被推送到 POST_BODY 并阻止将 SAML 令牌转换为 OAuth 令牌之前,所有流程对我来说都是正常的。

问题

在这个(编辑的)设置中哪个配置项不正确,替换它的值的正确派生是什么?


长问题的简短回答:

在 Firebase Auth 和 Google CICP 中处理的 SAML 提供程序不处理 multipart/form-data 并且需要在 application/x-www-form-urlencoded 中。

这是一个 SAML IdP 配置,不能由 Firebase 身份验证服务提供者配置处理。


也许 SAML 还存在一个额外的技术问题,但至少在 sign-in 方法的使用方式上有一个不一致的点。

根据(官方文档)[https://cloud.google.com/identity-platform/docs/how-to-enable-application-for-saml#handle-signin-with-client-sdk],您有 2 个登录选项:

1) 带有弹出窗口

在这种情况下,您可以使用 promise 来检索 user credentialsign-in 方法:

1
2
3
4
5
6
7
8
9
10
11
12
firebase.auth().signInWithPopup(provider)
    .then((result) => {
      // User is signed in.
      // Identity provider data available in result.additionalUserInfo.profile,
      // or from the user's ID token obtained via result.user.getIdToken()
      // as an object in the firebase.sign_in_attributes custom claim
      // This is also available via result.user.getIdTokenResult()
      // idTokenResult.claims.firebase.sign_in_attributes.
    })
    .catch((error) => {
      // Handle error.
    });

2) 使用重定向

在这种情况下,您的代码应该分成两部分。
第一个 sign-in 方法,不使用任何Promise:

1
 firebase.auth().signInWithRedirect(provider);

然后,初始化"监听器",在登录重定向后检索用户凭据:

1
2
3
4
5
6
7
8
9
10
11
12
13
// On return.
firebase.auth().getRedirectResult()
    .then((result) => {
      // User is signed in.
      // Identity provider data available in result.additionalUserInfo.profile,
      // or from the user's ID token obtained via result.user.getIdToken()
      // as an object in the firebase.sign_in_attributes custom claim
      // This is also available via result.user.getIdTokenResult()
      // idTokenResult.claims.firebase.sign_in_attributes.
    })
    .catch((error) => {
      // Handle error.
    });

要添加到您的页面/应用程序的引导部分。

希望它会有所帮助。