-
-
Save beneggett/f254e9d0baf7d93f46adc9d2f174eedb to your computer and use it in GitHub Desktop.
How to configurate omniauth-saml to work with multiple identity providers based on a dynamic URL path segment. A gem based on this idea has been extracted to https://github.com/salsify/omniauth-multi-provider-saml.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'omniauth' | |
require 'omniauth-saml' | |
class MultiProviderSamlHandler | |
UUID_REGEX = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/ | |
attr_reader :path_prefix, :provider_name | |
def initialize(path_prefix: OmniAuth.config.path_prefix, provider_name: 'saml') | |
@path_prefix = path_prefix | |
@provider_name = provider_name | |
# Eagerly compute these since lazy evaluation will not be threadsafe | |
@provider_path_prefix = "#{path_prefix}/#{provider_name}" | |
@saml_path_regex = /^#{@provider_path_prefix}\/(?<identity_provider_id>#{UUID_REGEX})/ | |
@request_path_regex = /#{saml_path_regex}\/?$/ | |
@callback_path_regex = /#{saml_path_regex}\/callback\/?$/ | |
end | |
def provider_options | |
{ | |
path_prefix: path_prefix, | |
name: provider_name, | |
request_path: method(:request_path?), | |
callback_path: method(:callback_path?), | |
setup: method(:setup) | |
} | |
end | |
private | |
attr_reader :provider_path_prefix, :saml_path_regex, :request_path_regex, :callback_path_regex | |
def setup(env) | |
identity_provider_uuid = extract_identity_provider_id(env) | |
if identity_provider_uuid | |
options = env['omniauth.strategy'].options | |
add_path_options(options, identity_provider_uuid) | |
add_identity_provider_options(options, identity_provider_uuid) | |
end | |
end | |
def add_path_options(options, identity_provider_uuid) | |
options.merge!( | |
request_path: "#{provider_path_prefix}/#{identity_provider_uuid}", | |
callback_path: "#{provider_path_prefix}/#{identity_provider_uuid}/callback" | |
) | |
end | |
def add_identity_provider_options(options, identity_provider_uuid) | |
# Make this real based on lookup of IdentityProvider with uuid identity_provider_uuid | |
identity_provider = IdentityProvider.find_by(uuid: identity_provider_uuid) | |
if identity_provider | |
options.merge!(identity_provider.options) | |
else | |
raise OmniAuth::Strategies::SAML::ValidationError.new('Invalid identity provider id') | |
end | |
end | |
def request_path?(env) | |
path = current_path(env) | |
!!request_path_regex.match(path) | |
end | |
def callback_path?(env) | |
path = current_path(env) | |
!!callback_path_regex.match(path) | |
end | |
def current_path(env) | |
env['PATH_INFO'] | |
end | |
def extract_identity_provider_id(env) | |
path = current_path(env) | |
match = saml_path_regex.match(path) | |
match ? match[:identity_provider_id] : nil | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'omniauth' | |
Rails.application.config.middleware.use OmniAuth::Builder do | |
saml_handler = MultiProviderSamlHandler.new(path_prefix: '/users/auth') | |
saml_options = { | |
name_identifier_format: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', | |
skip_info: true | |
}.merge(saml_handler.provider_options) | |
provider :saml, saml_options | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
MyApplication::Application.routes.draw do | |
match '/users/auth/saml/:saml_provider_id/callback', | |
via: [:get, :post], | |
to: 'omniauth_callbacks#saml', | |
as: 'user_omniauth_callback' | |
match '/users/auth/saml/:saml_provider_id', | |
via: [:get, :post], | |
to: 'omniauth_callbacks#passthru', | |
as: 'user_omniauth_authorize' | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment