你想要_____吗:
- a.) 从其他服务(如 Microsoft Azure Directory、OneLogin 等)启用 SAML 登录?(那么您就是 SP = 服务提供商)
- b.) 您的应用拥有用户并为其他应用提供登录服务(IDP = 身份提供者)
我想它是a)?然后取决于:它是每个客户的提供商,那么它是动态的吗?每个客户可以配置自己的 IDP,还是为整个应用程序固定一个?如果是后者,那么我强烈建议omniauth-saml
改用它,这更容易配置。
但是,如果您想使用 Enterprise Sign In Per Customer,那么我们就是这样做的。
- 第一:我从不纠结所有的具体设置和 url,Saml 可以通过“元数据 url”自动配置,我们让我们的客户指定一个元数据 uri,这个 uri 包含我们需要的所有信息,所以我们可以用提供的解析它班级:
idp_metadata_parser = OneLogin::RubySaml::IdpMetadataParser.new
settings = idp_metadata_parser.parse_remote(organisation.idp_meta_data_url)
然后我们添加我们自己的设置+路线信息给它:
settings.assertion_consumer_service_url = "https://#{request.host}/saml/consume/#{organisation.id}"
settings.issuer = "https://#{@request.host}/saml/metadata/#{organisation.id}"
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"
# You would need a normal certificate/private key to enable signature stuff
settings.certificate = File.read('config/saml/certificate.crt')
settings.private_key = File.read('config/saml/private_key.key')
# In our case customer can optional activate signature validation:
if organisation.signature_enabled?
settings.security[:authn_requests_signed] = true # Enable or not signature on AuthNRequest
settings.security[:logout_requests_signed] = true # Enable or not signature on Logout Request
settings.security[:logout_responses_signed] = true # Enable or not signature on Logout Response
settings.security[:want_assertions_signed] = true # Enable or not the requirement of signed assertion
settings.security[:metadata_signed] = true # Enable or not signature on Metadata
settings.security[:digest_method] = XMLSecurity::Document::SHA1
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
end
请求/响应
这些或多或少来自 ruby-saml 示例:
控制器:
skip_before_action :verify_authenticity_token
def init
@saml_request = OneLogin::RubySaml::Authrequest.new
redirect_url = @saml_request.create(saml_settings)
if redirect_uri
redirect_to(redirect_uri)
else
@error = t('saml_controller.error')
render 'error'
end
end
def consume
@saml_response = OneLogin::RubySaml::Response.new(params[:SAMLResponse])
@saml_response.settings = saml_settings
if @saml_response.is_valid?
# do application logic, create user/update user sign in user
sign_in(....)
session[:session_valid_for] = 12.hours.from_now.to_i
redirect_to '/'
else
redirect_to '/watcher/profile'
end
else
@error = @saml_response.errors
render 'error'
end
end
元数据
大多数客户也需要元数据 uri,以便将 SP 添加到他们的 IDP 中(并自动配置该部分),因此您还需要提供元数据,例如“/saml/#{org.id}/metadata”和返回元数据:
def metadata
meta = OneLogin::RubySaml::Metadata.new
render xml: meta.generate(saml_settings), content_type: "application/samlmetadata+xml"
end
更新:使用omniauth-saml
我们还在应用程序中使用 Omniauth saml。这很简单,但配置取决于您要集成的服务器。您将需要一个 sso 目标 url(来自另一端的使用 url)和一个证书指纹或证书以确保安全。您还可以指定“名称标识符”、电子邮件或用户名或类似的东西。
Rails.application.config.middleware.use OmniAuth::Builder do
use OmniAuth::Strategies::SAML,
idp_sso_target_url: "??",
idp_slo_target_url: "??",
idp_cert_fingerprint: "??",
name_identifier_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
# or "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" for E-Mail
issuer: "YourAppName.com"
Have a look at omniauth-saml's good Readme doc for a list of all options. You can also request more attributes from OneLogin/IDP by using the request_attributes
:
:request_attributes - Used to build the metadata file to inform the
IdP to send certain attributes along with the SAMLResponse messages.
Defaults to requesting name, first_name, last_name and email
attributes. See the OneLogin::RubySaml::AttributeService class in the
Ruby SAML gem for the available options for each attribute.
Update: Passing dynamic parameters to omniauth saml's redirect to Idp:
There seems to be no option in Omniauth-saml to have dynamic parameters, so you can try to patch/override the behavior. Omniauth-SAML is a Rack-middleware, so you only have access to the request object but not normal Rails stuff. If you trust your users (which you should not) then you can put the info in the param to omniauth: /auth/saml?something1=foo&bar=2
, or you could encrypt the parameters with ActiveSupport Message Encryptor.
If you then know how to extract the dynamic parameters from the request you can apply this patch dynamically, because Ruby!
# put this into
#
# config/initializers/omniauth_patch.rb
#
module OmniauthPatch
def additional_params_for_authn_request
# here you should have access to the current request
# try around with binding.irb what you can do
binding.irb
# return parameters you want to pass to the saml redirect
{
email: email,
# ...
}
end
end
OmniAuth::Strategies::SAML.include OmniauthPatch