Google Cloud Identity Platform (CICP) SAML 工作流失败
Google Cloud Identity Platform (CICP) SAML Workflow Fails
背景
使用具有以下配置的 Firebase Auth 和 SAML Auth Provider:
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 的 ACS https://example-app.firebaseapp.com/__/auth/handler
。
我期望发生什么
能够在 signInWithRedirect()
的 Promise 的 then
中设置断点并查看经过身份验证的用户。
实际发生了什么
流被重定向到 IdP 并处理身份验证。
IdP 发出带有自动提交加载和 multipart/form-data
表单的重定向-posting 页面:
- 内容配置:表单数据; name=SAMLResponse - 包含 base64
编码签名 SAMLResponse
- 内容配置:表单数据;
name=RelayState - 包含来自 SAML 流的中继状态
- 内容配置:表单数据; name="ssourl" - 包含
firebase 项目授权处理程序 URI
这反过来会导致 CICP 呈现和 return 一个带有脚本的页面设置
var POST_BODY=""------WebKitFormBoundary9bn7AOpnZiIRk9qZ\r\nContent....."
即它不是解析表单主体并提取 SAMLResponse 字段,而是将整个 Request.body 重播到脚本中,然后调用 fireauth.oauthhelper.widget.initialize();
这显然失败了,因为该往返然后尝试 post 将整个响应主体作为查询字符串发送到 /__/auth/handler
端点。
我怀疑此链中缺少一个简单的配置项,因为在多部分表单数据被推入 POST_BODY 并阻止 SAML 令牌转换之前,所有流程对我来说都是正常的转换为 OAuth 令牌。
问题
此(已编辑)设置中哪个配置项不正确,替换它的值的正确推导是什么?
也许 SAML 还存在其他技术问题,但至少 sign-in
方法的使用方式存在不一致之处。
根据(官方文档)[https://cloud.google.com/identity-platform/docs/how-to-enable-application-for-saml#handle-signin-with-client-sdk],您有 2 个登录选项:
1) 带弹出窗口
在这种情况下,您可以使用承诺通过 sign-in
方法检索 user credential
:
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
方法,不使用任何承诺:
firebase.auth().signInWithRedirect(provider);
然后,初始化一个"listener",在登录重定向后检索用户凭据:
// 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.
});
添加到 page/app 的 bootstrap 部分。
希望对您有所帮助。
长问题的简短回答:
Firebase Auth 和 Google CICP 中的 SAML 提供程序处理不处理 multipart/form-data
,需要在 application/x-www-form-urlencoded
中处理。
这是 SAML IdP 配置,Firebase 身份验证服务提供商配置无法处理。
背景
使用具有以下配置的 Firebase Auth 和 SAML Auth Provider:
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 的 ACS https://example-app.firebaseapp.com/__/auth/handler
。
我期望发生什么
能够在 signInWithRedirect()
的 Promise 的 then
中设置断点并查看经过身份验证的用户。
实际发生了什么
流被重定向到 IdP 并处理身份验证。
IdP 发出带有自动提交加载和 multipart/form-data
表单的重定向-posting 页面:
- 内容配置:表单数据; name=SAMLResponse - 包含 base64 编码签名 SAMLResponse
- 内容配置:表单数据; name=RelayState - 包含来自 SAML 流的中继状态
- 内容配置:表单数据; name="ssourl" - 包含 firebase 项目授权处理程序 URI
这反过来会导致 CICP 呈现和 return 一个带有脚本的页面设置
var POST_BODY=""------WebKitFormBoundary9bn7AOpnZiIRk9qZ\r\nContent....."
即它不是解析表单主体并提取 SAMLResponse 字段,而是将整个 Request.body 重播到脚本中,然后调用 fireauth.oauthhelper.widget.initialize();
这显然失败了,因为该往返然后尝试 post 将整个响应主体作为查询字符串发送到 /__/auth/handler
端点。
我怀疑此链中缺少一个简单的配置项,因为在多部分表单数据被推入 POST_BODY 并阻止 SAML 令牌转换之前,所有流程对我来说都是正常的转换为 OAuth 令牌。
问题
此(已编辑)设置中哪个配置项不正确,替换它的值的正确推导是什么?
也许 SAML 还存在其他技术问题,但至少 sign-in
方法的使用方式存在不一致之处。
根据(官方文档)[https://cloud.google.com/identity-platform/docs/how-to-enable-application-for-saml#handle-signin-with-client-sdk],您有 2 个登录选项:
1) 带弹出窗口
在这种情况下,您可以使用承诺通过 sign-in
方法检索 user credential
:
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
方法,不使用任何承诺:
firebase.auth().signInWithRedirect(provider);
然后,初始化一个"listener",在登录重定向后检索用户凭据:
// 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.
});
添加到 page/app 的 bootstrap 部分。
希望对您有所帮助。
长问题的简短回答:
Firebase Auth 和 Google CICP 中的 SAML 提供程序处理不处理 multipart/form-data
,需要在 application/x-www-form-urlencoded
中处理。
这是 SAML IdP 配置,Firebase 身份验证服务提供商配置无法处理。