From 26f21fd5a03b1c6407cd81c58481288d06958ad3 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 4 Feb 2018 05:42:13 +0100 Subject: CAS + SAML authentication feature (#6425) * Cas authentication feature * Config * Remove class_eval + Omniauth initializer * Codeclimate review * Codeclimate review 2 * Codeclimate review 3 * Remove uid/email reconciliation * SAML authentication * Clean up code * Improve login form * Fix code style issues * Add locales --- config/initializers/omniauth.rb | 59 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 config/initializers/omniauth.rb (limited to 'config/initializers') diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb new file mode 100644 index 000000000..97f32c0a4 --- /dev/null +++ b/config/initializers/omniauth.rb @@ -0,0 +1,59 @@ +Rails.application.config.middleware.use OmniAuth::Builder do + # Vanilla omniauth stategies +end + +Devise.setup do |config| + # Devise omniauth strategies + + # CAS strategy + if ENV['CAS_ENABLED'] == 'true' + cas_options = {} + cas_options[:url] = ENV['CAS_URL'] if ENV['CAS_URL'] + cas_options[:host] = ENV['CAS_HOST'] if ENV['CAS_HOST'] + cas_options[:port] = ENV['CAS_PORT'] if ENV['CAS_PORT'] + cas_options[:ssl] = ENV['CAS_SSL'] == 'true' if ENV['CAS_SSL'] + cas_options[:validate_url] = ENV['CAS_VALIDATE_URL'] if ENV['CAS_VALIDATE_URL'] + cas_options[:callback_url] = ENV['CAS_CALLBACK_URL'] if ENV['CAS_CALLBACK_URL'] + cas_options[:logout_url] = ENV['CAS_LOGOUT_URL'] if ENV['CAS_LOGOUT_URL'] + cas_options[:login_url] = ENV['CAS_LOGIN_URL'] if ENV['CAS_LOGIN_URL'] + cas_options[:uid_field] = ENV['CAS_UID_FIELD'] || 'user' if ENV['CAS_UID_FIELD'] + cas_options[:ca_path] = ENV['CAS_CA_PATH'] if ENV['CAS_CA_PATH'] + cas_options[:disable_ssl_verification] = ENV['CAS_DISABLE_SSL_VERIFICATION'] == 'true' if ENV['CAS_DISABLE_SSL_VERIFICATION'] + cas_options[:uid_key] = ENV['CAS_UID_KEY'] || 'user' + cas_options[:name_key] = ENV['CAS_NAME_KEY'] || 'name' + cas_options[:email_key] = ENV['CAS_EMAIL_KEY'] || 'email' + cas_options[:nickname_key] = ENV['CAS_NICKNAME_KEY'] || 'nickname' + cas_options[:first_name_key] = ENV['CAS_FIRST_NAME_KEY'] || 'firstname' + cas_options[:last_name_key] = ENV['CAS_LAST_NAME_KEY'] || 'lastname' + cas_options[:location_key] = ENV['CAS_LOCATION_KEY'] || 'location' + cas_options[:image_key] = ENV['CAS_IMAGE_KEY'] || 'image' + cas_options[:phone_key] = ENV['CAS_PHONE_KEY'] || 'phone' + config.omniauth :cas, cas_options + end + + # SAML strategy + if ENV['SAML_ENABLED'] == 'true' + saml_options = {} + saml_options[:assertion_consumer_service_url] = ENV['SAML_ACS_URL'] if ENV['SAML_ACS_URL'] + saml_options[:issuer] = ENV['SAML_ISSUER'] if ENV['SAML_ISSUER'] + saml_options[:idp_sso_target_url] = ENV['SAML_IDP_SSO_TARGET_URL'] if ENV['SAML_IDP_SSO_TARGET_URL'] + saml_options[:idp_sso_target_url_runtime_params] = ENV['SAML_IDP_SSO_TARGET_PARAMS'] if ENV['SAML_IDP_SSO_TARGET_PARAMS'] # FIXME: Should be parsable Hash + saml_options[:idp_cert] = ENV['SAML_IDP_CERT'] if ENV['SAML_IDP_CERT'] + saml_options[:idp_cert_fingerprint] = ENV['SAML_IDP_CERT_FINGERPRINT'] if ENV['SAML_IDP_CERT_FINGERPRINT'] + saml_options[:idp_cert_fingerprint_validator] = ENV['SAML_IDP_CERT_FINGERPRINT_VALIDATOR'] if ENV['SAML_IDP_CERT_FINGERPRINT_VALIDATOR'] # FIXME: Should be Lambda { |fingerprint| } + saml_options[:name_identifier_format] = ENV['SAML_NAME_IDENTIFIER_FORMAT'] if ENV['SAML_NAME_IDENTIFIER_FORMAT'] + saml_options[:request_attributes] = {} + saml_options[:certificate] = ENV['SAML_CERT'] if ENV['SAML_CERT'] + saml_options[:private_key] = ENV['SAML_PRIVATE_KEY'] if ENV['SAML_PRIVATE_KEY'] + saml_options[:security] = {} + saml_options[:security][:want_assertions_signed] = ENV['SAML_SECURITY_WANT_ASSERTION_SIGNED'] == 'true' + saml_options[:security][:want_assertions_encrypted] = ENV['SAML_SECURITY_WANT_ASSERTION_ENCRYPTED'] == 'true' + saml_options[:attribute_statements] = {} + saml_options[:attribute_statements][:uid] = [ENV['SAML_ATTRIBUTES_STATEMENTS_UID']] if ENV['SAML_ATTRIBUTES_STATEMENTS_UID'] + saml_options[:attribute_statements][:email] = [ENV['SAML_ATTRIBUTES_STATEMENTS_EMAIL']] if ENV['SAML_ATTRIBUTES_STATEMENTS_EMAIL'] + saml_options[:attribute_statements][:full_name] = [ENV['SAML_ATTRIBUTES_STATEMENTS_FULL_NAME']] if ENV['SAML_ATTRIBUTES_STATEMENTS_FULL_NAME'] + saml_options[:uid_attribute] = ENV['SAML_UID_ATTRIBUTE'] if ENV['SAML_UID_ATTRIBUTE'] + config.omniauth :saml, saml_options + end + +end -- cgit From 38e0133e1b01c21a710111097102a6eb205b9b9b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 4 Feb 2018 15:05:53 +0100 Subject: Make PAM gem optional, allow configuration over environment (#6415) --- .env.production.sample | 9 +++++++++ Gemfile | 2 +- app/models/user.rb | 2 +- config/initializers/devise.rb | 27 +++++++++------------------ 4 files changed, 20 insertions(+), 20 deletions(-) (limited to 'config/initializers') diff --git a/.env.production.sample b/.env.production.sample index 777336de1..a4b689a31 100644 --- a/.env.production.sample +++ b/.env.production.sample @@ -136,6 +136,15 @@ STREAMING_CLUSTER_NUM=1 # UID=1000 # GID=1000 +# PAM authentication (optional) +# PAM_ENABLED=true +# Suffix for email address generation (nil by default) +# PAM_DEFAULT_SUFFIX=pam +# Name of the pam service (pam "auth" section is evaluated) +# PAM_DEFAULT_SERVICE=rpam +# Name of the pam service used for checking if an user can register (pam "account" section is evaluated) +# PAM_CONTROLLED_SERVICE=rpam + # Optional CAS authentication (cf. omniauth-cas) : # CAS_ENABLED=true # CAS_URL=https://sso.myserver.com/ diff --git a/Gemfile b/Gemfile index 5b6ae707d..3b39f3946 100644 --- a/Gemfile +++ b/Gemfile @@ -31,7 +31,7 @@ gem 'cld3', '~> 3.2.0' gem 'devise', '~> 4.4' gem 'devise-two-factor', '~> 3.0' -gem 'devise_pam_authenticatable2', '~> 8.0' +gem 'devise_pam_authenticatable2', '~> 8.0', install_if: -> { ENV['PAM_ENABLED'] == 'true' } gem 'omniauth-cas', '~> 1.1', install_if: -> { ENV['CAS_ENABLED'] == 'true' } gem 'omniauth-saml', '~> 1.8', install_if: -> { ENV['SAML_ENABLED'] == 'true' } gem 'omniauth', '~> 1.2' diff --git a/app/models/user.rb b/app/models/user.rb index fba478453..feaf8b26c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -52,7 +52,7 @@ class User < ApplicationRecord devise :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable - devise :pam_authenticatable + devise :pam_authenticatable if Devise.pam_authentication devise :omniauthable belongs_to :account, inverse_of: :user diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index f2f7f1ba3..ba7ad9e6c 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -315,22 +315,13 @@ Devise.setup do |config| # so you need to do it manually. For the users scope, it would be: # config.omniauth_path_prefix = '/my_engine/users/auth' - # PAM: only look for email field - config.usernamefield = nil - config.emailfield = "email" - - # authentication with pam possible - # if not enabled, all pam settings are ignored - #config.pam_authentication = true - # check if email is actually a username - config.check_at_sign = true - # suffix for email address generation (warning: without pam must provide email in the pam environment) - config.pam_default_suffix = "pam" - # name of the pam service - # pam "auth" section is evaluated - config.pam_default_service = "rpam" - # name of the pam service used for checking if an user can register - # pam "account" section is evaluated - # nil for allowing registration of pam names (not recommended) - config.pam_controlled_service = "rpam" + if ENV['PAM_ENABLED'] == 'true' + config.pam_authentication = true + config.usernamefield = nil + config.emailfield = 'email' + config.check_at_sign = true + config.pam_default_suffix = ENV.fetch('PAM_DEFAULT_SUFFIX') { nil } + config.pam_default_service = ENV.fetch('PAM_DEFAULT_SERVICE') { 'rpam' } + config.pam_controlled_service = ENV.fetch('PAM_CONTROLLED_SERVICE') { 'rpam' } + end end -- cgit