Ruby SAML 的次要版本和补丁版本可能会引入破坏性变更。请阅读 UPGRADING.md 以获取有关升级到新 Ruby SAML 版本的指导。
CVE-2025-66568 和 CVE-2025-66567 影响 ruby-saml < 1.18.0 版本(包括 1.12.4),请升级到 1.18.1
CVE-2025-54572 影响 ruby-saml < 1.18.1 版本
存在影响 ruby-saml < 1.18.0 的严重漏洞,其中两个允许绕过 SAML 身份验证(CVE-2025-25291、CVE-2025-25292、CVE-2025-25293)。请升级到已修复的版本(1.18.0)
如果您认为您在本 gem 中发现了安全漏洞,请通过电子邮件向维护者报告: [email protected]
感谢以下赞助商为保障开源生态系统安全所做的贡献:
一个用于访问 Google 搜索结果的实时 API。它为您处理代理、解决验证码,并解析所有丰富的结构化数据
用于构建、扩展和交付安全软件的完整开发者平台。
简化消息队列和流处理。将服务器管理交给专家,让您专注于构建出色的应用程序。
Ruby SAML 库用于实现 SAML 授权的客户端,即它提供了一种管理来自身份提供者的授权初始化和确认请求的方法。
SAML 授权是一个两步过程,您需要为两者都实现支持。
我们创建了一个使用此库最新版本的 Rails 4 演示项目: ruby-saml-example
ruby-saml 库提供了帮助缓解此风险的工具,但实现必要的逻辑
是您的责任。 请参阅
防止重放攻击 获取更多
指导。以下 Ruby 版本已通过 CI 测试:
为了使用 Ruby SAML,您需要安装该 gem(手动或使用 Bundler), 并在您的 Ruby 应用程序中引入该库:
使用 Gemfile
# latest stable
gem 'ruby-saml', '~> 1.18.0'
# or track master for bleeding-edge
gem 'ruby-saml', :github => 'saml-toolkits/ruby-saml'
使用 RubyGems
gem install ruby-saml
您可能需要整个 Ruby SAML gem:
require 'onelogin/ruby-saml'
或仅单独安装所需组件:
require 'onelogin/ruby-saml/authrequest'
此 gem 使用 Nokogiri 作为依赖项,而 Nokogiri 1.6 已放弃对 Ruby 1.8.x 的支持。 在 Ruby 1.8.7 上安装此 gem 时,如果尚未安装或指定,你需要确保安装或指定 1.6 之前的 Nokogiri 版本。
使用 Gemfile
gem 'nokogiri', '~> 1.5.10'
使用 RubyGems
gem install nokogiri --version '~> 1.5.10'
在排查 SAML 集成问题时,检查此 gem 业务逻辑的输出会非常有帮助。默认情况下,当该 gem 在 Rails 上下文中使用时,日志消息会输出到 RAILS_DEFAULT_LOGGER;当该 gem 在 Rails 之外使用时,日志消息会输出到 STDOUT。
要覆盖默认行为并控制日志消息的目标位置,请向该 gem 的日志单例提供一个 Ruby Logger 对象:
OneLogin::RubySaml::Logging.logger = Logger.new('/var/log/ruby-saml.log')
这是您将从身份提供者处收到的第一个请求。它将通过您声明的 SAML 初始化点对应的特定 URL 访问您的应用程序。对此初始化的响应是重定向回身份提供者,其形式可能如下所示(暂时忽略 saml_settings 方法调用):
def init
request = OneLogin::RubySaml::Authrequest.new
redirect_to(request.create(saml_settings))
end
如果 SP 知道谁应在 IdP 中进行身份验证,它可以按如下方式提供该信息:
def init
request = OneLogin::RubySaml::Authrequest.new
saml_settings.name_identifier_value_requested = "[email protected]"
saml_settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
redirect_to(request.create(saml_settings))
end
一旦你重定向回身份提供者,它将确保用户已获得授权,并重定向回你的应用程序以供最终使用。
这看起来可能像这样(authorize_success 和 authorize_failure
方法特定于你的应用程序):
def consume
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], :settings => saml_settings)
# We validate the SAML Response and check if the user already exists in the system
if response.is_valid?
# authorize_success, log the user
session[:userid] = response.nameid
session[:attributes] = response.attributes
else
authorize_failure # This method shows an error message
# List of errors is available in response.errors array
end
end
在上面的内容中,有一些假设,其中之一是 response.nameid 是一个电子邮件地址。
这一切都通过 saml_settings 方法中指定的设置来处理。
这可以按照以下方式实现:
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse])
response.settings = saml_settings
如果 SAMLResponse 的断言未加密,你可以在初始化 Response 时不传入 :settings 参数,之后再设置它。如果 SAMLResponse 包含加密断言,你需要在 initialize 方法中提供 settings,以便使用服务提供者私钥解密来获取解密后的断言。
如果你不确定预期情况,请始终使用前一种方式(在 initialize 时设置 settings)。
def saml_settings
settings = OneLogin::RubySaml::Settings.new
settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
settings.sp_entity_id = "http://#{request.host}/saml/metadata"
settings.idp_entity_id = "https://app.onelogin.com/saml/metadata/#{OneLoginAppId}"
settings.idp_sso_service_url = "https://app.onelogin.com/trust/saml2/http-post/sso/#{OneLoginAppId}"
settings.idp_sso_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" # or :post, :redirect
settings.idp_slo_service_url = "https://app.onelogin.com/trust/saml2/http-redirect/slo/#{OneLoginAppId}"
settings.idp_slo_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" # or :post, :redirect
settings.idp_cert_fingerprint = OneLoginAppCertFingerPrint
settings.idp_cert_fingerprint_algorithm = "http://www.w3.org/2000/09/xmldsig#sha1"
settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
# Optional for most SAML IdPs
settings.authn_context = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"
# or as an array
settings.authn_context = [
"urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
"urn:oasis:names:tc:SAML:2.0:ac:classes:Password"
]
# Optional bindings (defaults to Redirect for logout POST for ACS)
settings.single_logout_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" # or :post, :redirect
settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" # or :post, :redirect
settings
end
自 1.11.0 版本起,使用 settings.issuer 已被弃用,建议改用 settings.sp_entity_id
通过向 OneLogin::RubySaml::Response.new() 传递参数,可以跳过某些断言验证。
例如,你可以通过使用不同的选项初始化响应来跳过 AuthnStatement、Conditions、Recipient 或 SubjectConfirmation
验证: