Skip to content

Commit

Permalink
Add SAML authenticatable
Browse files Browse the repository at this point in the history
  • Loading branch information
wwelling committed Jun 28, 2024
1 parent 65a9f00 commit 289eb96
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 1 deletion.
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ gem 'omniauth-identity'
gem 'omniauth-lti', git: "https://github.com/avalonmediasystem/omniauth-lti.git", tag: 'avalon-r4'
gem 'omniauth-ldap'

gem 'devise_saml_authenticatable'

# Media Access & Transcoding
gem 'active_encode', '~> 0.7.0'
gem 'audio_waveform-ruby', '~> 1.0.7', require: 'audio_waveform'
Expand Down
3 changes: 2 additions & 1 deletion app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ class User < ActiveRecord::Base
# :confirmable, :lockable, :timeoutable
# Registration is controlled via settings.yml
devise_list = [ :database_authenticatable, :invitable, :omniauthable,
:recoverable, :rememberable, :trackable, :validatable ]
:recoverable, :rememberable, :trackable, :validatable,
:saml_authenticatable ]
devise_list << :registerable if Settings.auth.registerable
devise_list << { authentication_keys: [:login] }

Expand Down
3 changes: 3 additions & 0 deletions config/attribute-map.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# attribute-map.yml
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "user_name"
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "email"
93 changes: 93 additions & 0 deletions config/initializers/devise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -341,4 +341,97 @@
# so you need to do it manually. For the users scope, it would be:
# config.omniauth_path_prefix = '/my_engine/users/auth'
OmniAuth.config.logger = Rails.logger

# ==> Configuration for :saml_authenticatable

# Create user if the user does not exist. (Default is false)
# Can also accept a proc, for ex:
# Devise.saml_create_user = Proc.new do |model_class, saml_response, auth_value|
# model_class == Admin
# end
config.saml_create_user = true

# Update the attributes of the user after a successful login. (Default is false)
# Can also accept a proc, for ex:
# Devise.saml_update_user = Proc.new do |model_class, saml_response, auth_value|
# model_class == Admin
# end
config.saml_update_user = true

# Lambda that is called if Devise.saml_update_user and/or Devise.saml_create_user are true.
# Receives the model object, saml_response and auth_value, and defines how the object's values are
# updated with regards to the SAML response.
# config.saml_update_resource_hook = -> (user, saml_response, auth_value) {
# saml_response.attributes.resource_keys.each do |key|
# user.send "#{key}=", saml_response.attribute_value_by_resource_key(key)
# end
#
# if (Devise.saml_use_subject)
# user.send "#{Devise.saml_default_user_key}=", auth_value
# end
#
# user.save!
# }

# Lambda that is called to resolve the saml_response and auth_value into the correct user object.
# Receives a copy of the ActiveRecord::Model, saml_response and auth_value. Is expected to return
# one instance of the provided model that is the matched account, or nil if none exists.
# config.saml_resource_locator = -> (model, saml_response, auth_value) {
# model.find_by(Devise.saml_default_user_key => auth_value)
# }

# Set the default user key. The user will be looked up by this key. Make
# sure that the Authentication Response includes the attribute.
config.saml_default_user_key = :email

# Optional. This stores the session index defined by the IDP during login. If provided it will be used as a salt
# for the user's session to facilitate an IDP initiated logout request.
config.saml_session_index_key = :session_index

# You can set this value to use Subject or SAML assertion as info to which email will be compared.
# If you don't set it then email will be extracted from SAML assertion attributes.
# config.saml_use_subject = true

# You can implement IdP settings with the options to support multiple IdPs and use the request object by setting this value to the name of a class that implements a ::settings method
# which takes an IdP entity id and a request object as arguments and returns a hash of idp settings for the corresponding IdP.
# config.idp_settings_adapter = "MyIdPSettingsAdapter"
config.idp_settings_adapter = nil

# You provide you own method to find the idp_entity_id in a SAML message in the case of multiple IdPs
# by setting this to the name of a custom reader class, or use the default.
# config.idp_entity_id_reader = "DeviseSamlAuthenticatable::DefaultIdpEntityIdReader"

# You can set the name of a class that takes the response for a failed SAML request and the strategy,
# and implements a #handle method. This method can then redirect the user, return error messages, etc.
# config.saml_failed_callback = "MySamlFailedCallbacksHandler"

# You can customize the named routes generated in case of named route collisions with
# other Devise modules or libraries. Set the saml_route_helper_prefix to a string that will
# be appended to the named route.
# If saml_route_helper_prefix = 'saml' then the new_user_session route becomes new_saml_user_session
# config.saml_route_helper_prefix = 'saml'

# You can add allowance for clock drift between the sp and idp.
# This is a time in seconds.
# config.allowed_clock_drift_in_seconds = 0

# In SAML responses, validate that the identity provider has included an InResponseTo
# header that matches the ID of the SAML request. (Default is false)
# config.saml_validate_in_response_to = false

config.saml_sign_out_success_url = ENV['SAML_SP_ENTITY_ID'] || "http://localhost:3000"

# Configure with your SAML settings (see ruby-saml's README for more information: https://github.com/onelogin/ruby-saml).
config.saml_configure do |settings|
settings.assertion_consumer_service_url = ENV['SAML_ASSERTION_CONSUMER_SERVICE_URL'] || "http://localhost:3000/users/saml/auth"
settings.assertion_consumer_service_binding = ENV['SAML_ASSERTION_CONSUMER_SERVICE_BINDING'] || "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
settings.issuer = ENV['SAML_ISSUER'] || "http://localhost:3000/users/saml/metadata"
settings.name_identifier_format = ENV['SAML_NAME_IDENTIFIER_FORMAT'] || "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
settings.sp_entity_id = ENV['SAML_SP_ENTITY_ID'] || "http://localhost:3000"
settings.authn_context = ENV['SAML_AUTHN_CONTEXT'] || "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"
settings.idp_slo_service_url = ENV['SAML_IDP_SLO_SERVICE_URL'] || "https://login.microsoftonline.com/68f381e3-46da-47b9-ba57-6f322b8f0da1/saml2"
settings.idp_sso_service_url = ENV['SAML_IDP_SSO_SERVICE_URL'] || "https://login.microsoftonline.com/68f381e3-46da-47b9-ba57-6f322b8f0da1/saml2"
settings.idp_cert_fingerprint = ENV['SAML_IDP_CERT_FINGERPRINT'] || "00:A1:2B:3C:44:55:6F:A7:88:CC:DD:EE:22:33:44:55:D6:77:8F:99"
settings.idp_cert_fingerprint_algorithm = ENV['SAML_IDP_CERT_FINGERPRINT_ALGORITHM'] || "http://www.w3.org/2000/09/xmldsig#sha1"
end
end
5 changes: 5 additions & 0 deletions db/migrate/20240625133800_add_session_index_to_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddSessionIndexToUsers < ActiveRecord::Migration[6.1]
def change
add_column :users, :session_index, :string
end
end
1 change: 1 addition & 0 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@
create_table "users", force: :cascade do |t|
t.string "username", null: false
t.string "email", null: false
t.string "session_index"
t.datetime "created_at"
t.datetime "updated_at"
t.string "provider"
Expand Down

0 comments on commit 289eb96

Please sign in to comment.