Session Loss and Empty 'user_redirect_to' Variable in SAML-based Authentication for Rails OAuth 2.0 System

huangapple go评论68阅读模式
英文:

Session Loss and Empty 'user_redirect_to' Variable in SAML-based Authentication for Rails OAuth 2.0 System

问题

我正在基于Rails开发一个基于OAuth 2.0的身份验证系统。

我正在使用Devise gem来处理用户会话和登录,Doorkeeper gem来管理OAuth 2.0工作流程。除了用户名和密码登录外,我还具有社交和企业登录功能。这些功能由OmniAuth gem处理。具体来说,对于Google登录,我正在使用omniauth-google-oauth2 gem,而对于企业登录,我们已经实现了基于SAML的Azure身份验证。

我们遇到的问题与基于SAML的工作流程有关。当客户端调用"/oauth/authorize"端点时,它会正确地重定向到登录页面,并且"session['user_redirect_to']"变量会正确设置。完成登录过程后,它应该根据"/oauth/authorize"端点中提供的回调URL将用户重定向回客户端。

这个流程对于用户名/密码登录和Google登录都运行正常。然而,当触发SAML回调时,会丢失会话,并且"session['user_redirect_to']"变量变为空。因此,应用程序无法将用户重定向回提供的回调URL。

我能够通过将"user_redirect_to"作为状态参数传递给SAML请求,并在回调时从参数中获取回调URL并将其设置回会话中来使其工作。但我知道这不是安全的做法,应该有一个更干净的解决方案可用。

我知道这有点混乱,但如果您需要更多细节,请告诉我。

英文:

I am developing an authentication system based on OAuth 2.0 on Rails.

I'm using the Devise gem to handle user sessions and login, Doorkeeper gem to manage OAuth 2.0 workflows. in addiotion to username and password login, I have social and enterprise login functionality as well. Which is handled by the OmniAuth gem. Specifically, for Google login, I'm utilizing the omniauth-google-oauth2 gem, while for enterprise login, we have implemented SAML-based authentication for Azure.

The problem we're encountering is related to the SAML-based workflows. When we call the "/oauth/authorize" endpoint from the client, it correctly redirects to the sign-in page, and the "session['user_redirect_to']" variable is properly set. After the login process is completed, it should redirect the user back to the client based on the callback URL provided in the "/oauth/authorize" endpoint.

This flow works flawlessly for both the username/password login and Google sign-in. However, when the SAML callback is triggered, the session is lost, and the "session['user_redirect_to']" variable becomes empty. As a result, the application is unable to redirect the user back to the provided callback URL.

I was able to make it work by passing user_redirect_to as a state param to the saml request and on the callback i was able to fetch the callback url from param and set it back to the session. But i know its not secure and there should be a much cleaner solution available.

i know its kind of a mess, but let me know if you need any more details

答案1

得分: 2

SAML的工作方式是,另一个站点(IDP)将会向您的应用程序进行POST请求。
在较新版本的Rails中,默认的Cookie SameSite策略将为Strict,或者至少是Lax,因为"None"会被省略。

在所有当前的浏览器中,这将使会话无效(当请求POST到我们的域时,Cookie将不会被发送)。

但是,这里有一个明确的缓解措施,以下是Chromium团队的原话:

> 问:什么是Lax + POST缓解措施?
>
> 这是为了解决某些单点登录实现中预期在跨站POST请求上需要CSRF令牌的现有Cookie使用情况而做出的特定例外情况。这只是一个临时解决方案,将来会被移除。它不会添加任何新的行为,而只是在某些情况下不适用新的SameSite=Lax默认值。具体来说,最多2分钟的Cookie将被发送到顶级跨站POST请求。然而,如果您依赖这个行为,您应该使用SameSite=None; Secure属性来更新这些Cookie,以确保它们在将来继续正常运行。

所以,我们需要:

  1. 确保使用会话存储,并显式设置Secure: true
# config/initializers/session_store.rb

Rails.application.config.session_store :cookie_store, key: '_app_session', secure: true
  1. 确保您仍然在该请求中使用SameSite None:
Rails.application.config.action_dispatch.cookies_same_site_protection = lambda { |request|
  if request.fullpath.include?("/auth/saml")
    :none
  else
    :lax
  end
}
  1. 确保您不会在初始化程序中覆盖Cookie SameSite策略:
# config/initializers/new_framework_defaults_6_1.rb
# 不要全局激活它,因为它会覆盖其他设置
# Rails.application.config.action_dispatch.cookies_same_site_protection = :lax
英文:

SAML works such that the other site (IDP) will POST back to your app.
In newer Rails versions, the Default Cookie SameSite Policy would be Strict or at least Lax, as "None" or omitted before.

In all current Browsers, that will invalidate the session (Cookie will not be sent, when a request POSTed to our domain),

BUT there is a explicit mitigation, here verbatim by Chromium Team:

> Q: What is the Lax + POST mitigation?
>
> This is a specific exception made to account for existing cookie usage
> on some Single Sign-On implementations where a CSRF token is expected
> on a cross-site POST request. This is purely a temporary solution and
> will be removed in the future. It does not add any new behavior, but
> instead is just not applying the new SameSite=Lax default in certain
> scenarios. Specifically, a cookie that is at most 2 minutes old will
> be sent on a top-level cross-site POST request. However, if you rely
> on this behavior, you should update these cookies with the
> SameSite=None; Secure attributes to ensure they continue to function
> in the future.

So, we needed to:

  1. Make sure to use a session store, and explicitly set Secure: true
# config/initializers/session_store.rb

Rails.application.config.session_store :cookie_store, key: '_app_session', secure: true
  1. Make sure you are still using the SameSite None for that request:
Rails.application.config.action_dispatch.cookies_same_site_protection = lambda { |request|
  if request.fullpath.include?("/auth/saml")
    :none
  else
    :lax
  end
}
  1. Make sure, you don't overwrite the cookie same site policy in a initializer:
# config/initializers/new_framework_defaults_6_1.rb
# don't activate that globally, as it will override the other setting
#Rails.application.config.action_dispatch.cookies_same_site_protection = :lax

huangapple
  • 本文由 发表于 2023年5月10日 20:13:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76218277.html
  • devise
  • doorkeeper
  • omniauth
  • ruby-on-rails
  • saml