Reference: https://github.com/heartcombo/devise/wiki/OmniAuth:-Overview https://github.com/omniauth/omniauth-saml#devise-integration
Add omniauth-saml gem to ReSeeD and run bundle install
# Gemfile
gem 'omniauth-saml', '~> 2.1'
gem "omniauth-rails_csrf_protection"
$ bundle install
Add rails migration to add columns provider
and uid
to the database
$ rails g migration AddOmniauthToUsers provider:string uid:string
$ rake db:migrate
Declare the provider in the devise config file
# config/initializers/devise.rb
config.omniauth :saml,
idp_sso_service_url: ENV['SAML_IDP_SERVICE_URL'],
sp_entity_id: ENV['SAML_SP_ID'],
SAML_SERVICE_URL=http://rdms.cottagelabs.com/users/auth/saml/callback
idp_cert_fingerprint: ENV['SAML_IDP_CERT_FINGERPRINT'],
Other config options may include the following
config.omniauth :saml,
idp_sso_service_url: ENV['SAML_IDP_SERVICE_URL'],
sp_entity_id: ENV['SAML_SP_ID']
idp_cert_fingerprint: ENV['SAML_IDP_CERT_FINGERPRINT'],
# idp_cert: "",
# idp_cert_multi: {
# signing: ["ADD signing cert 1 here",
# "ADD signing cert 1 here"],
# encryption: ["Add encryption cert 1 here"]
# },
assertion_consumer_service_url: ENV['SAML_SERVICE_URL'],
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:attrname-format:basic',
single_value_compatibility: false,
attribute_statements: {
email: ['urn:oid:1.3.6.1.4.1.5923.1.1.1.6'],
name: ['urn:oid:2.16.840.1.113730.3.1.241'],
}
sp_entity_id: <Name of application|RDMS at RUB>
idp_sso_service_url: <The URL to which the authentication request should be sent|https://samltest.id/saml/idp>.
idp_cert_fingerprint:
assertion_consumer_service_url: <http://example.com/auth/saml/callback | http://example.com/users/auth/saml/callback>
Note: We need one of idp_cert_fingerprint or idp_cert or idp_cert_multi
Make user model omniauthable
Add :omniauthable, :omniauth_providers => [:saml]
to devise.
# hyrax/app/models/user.rb
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:omniauthable, :omniauth_providers => [:saml]
Add method to user model to find or create saml user
# allow omniauth (including shibboleth) logins
# this will create a local user based on an omniauth/shib login
# if they haven't logged in before
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
# Uncomment the debugger below to capture what a auth object looks like for testing
# Rails.logger.debug "auth = #{auth.inspect}"
# Rails.logger.debug "auth = #{auth}"
user.uid = auth.uid
user.email = auth.info.email
user.password = Devise.friendly_token[0, 20]
user.name = auth.info.name # assuming the user model has a name
# If you are using confirmable and the provider(s) you use validate emails,
# uncomment the line below to skip the confirmation emails.
# user.skip_confirmation!
end
end
Note: Depending on the information obtained from Shibboleth, we would likely need to update the self.from_omniauth
method.
Add custom omniauth controller to devise routes
# hyrax/config/routes.rb
devise_for :users, controllers: { omniauth_callbacks: 'callbacks' }
Implement the callback controller
Add a controller with the method saml at hyrax/app/controllers/callbacks_controller.rb
# frozen_string_literal: true
class CallbacksController < Devise::OmniauthCallbacksController
# skip_before_action :verify_authenticity_token
def saml
if current_user
redirect_to Hyrax::Engine.routes.url_helpers.dashboard_path
else
@user = User.from_omniauth(request.env["omniauth.auth"])
sign_in_saml_user
end
end
def failure
set_flash_message! :alert, :failure, kind: OmniAuth::Utils.camelize(failed_strategy.name), reason: failure_message
redirect_to after_omniauth_failure_path_for(resource_name)
end
private
def sign_in_saml_user
sign_in_and_redirect @user, event: :authentication # this will throw if @user is not activated
cookies[:login_type] = "saml"
flash[:notice] = "You are now signed in as #{@user.name} (#{@user.email})"
end
end
The Service provider metadata URL
This should be found in /users/auth/saml/metadata
The idp certificate is straightforward. It can be configured in the config/initializers/devise.rb.
As for the private key, is at as described here, under the part Generate a secure private key?
Is the IDP going to use the SPs public certificate to encrypt message and the SP, then uses the private key, to decrypt the message from the IDP?
If so, from the onelogin ruby-saml wiki (which omniauth-saml uses) we just need to add these two to the settings
settings.certificate = "SP public certificate"
settings.private_key = "SP private certificate key"
The configuration in devise, would then look like this, and fingers crossed this does the trick.
config.omniauth :saml,
idp_sso_service_url: ENV['SAML_IDP_SERVICE_URL'],
sp_entity_id: ENV['SAML_SP_ID'],
idp_cert_fingerprint: ENV['SAML_IDP_CERT_FINGERPRINT'],
# idp_cert: "",
# idp_cert_multi: {
# signing: ["ADD signing cert 1 here",
# "ADD signing cert 1 here"],
# encryption: ["Add encryption cert 1 here"]
# },
name_identifier_format: ENV['SAML_NAME_ID_FORMAT'],
assertion_consumer_service_url: ENV['SAML_SERVICE_URL'],
certificate: "SP public certificate",
private_key: "SP private certificate key"