2019-07-29 12:17:57 +02:00
|
|
|
# frozen_string_literal: true
|
2016-03-23 18:39:41 +01:00
|
|
|
|
2020-03-25 17:45:53 +01:00
|
|
|
# AuthProvider is a configuration record, storing parameters of an external Single-Sign On server
|
2020-03-25 10:16:47 +01:00
|
|
|
class AuthProvider < ApplicationRecord
|
2016-03-23 18:39:41 +01:00
|
|
|
# this is a simple stub used for database creation & configuration
|
|
|
|
class SimpleAuthProvider < Object
|
|
|
|
def providable_type
|
|
|
|
DatabaseProvider.name
|
|
|
|
end
|
2016-04-12 14:18:07 +02:00
|
|
|
|
|
|
|
def name
|
|
|
|
'DatabaseProvider::SimpleAuthProvider'
|
|
|
|
end
|
2016-03-23 18:39:41 +01:00
|
|
|
end
|
|
|
|
|
2022-03-30 18:01:19 +02:00
|
|
|
PROVIDABLE_TYPES = %w[DatabaseProvider OAuth2Provider OpenIdConnectProvider].freeze
|
2016-03-23 18:39:41 +01:00
|
|
|
|
2018-12-03 15:10:04 +01:00
|
|
|
belongs_to :providable, polymorphic: true, dependent: :destroy
|
2016-03-23 18:39:41 +01:00
|
|
|
accepts_nested_attributes_for :providable
|
|
|
|
|
2022-03-28 19:50:36 +02:00
|
|
|
has_many :auth_provider_mappings, dependent: :destroy
|
|
|
|
accepts_nested_attributes_for :auth_provider_mappings, allow_destroy: true
|
|
|
|
|
2022-04-11 17:27:56 +02:00
|
|
|
validates :providable_type, inclusion: { in: PROVIDABLE_TYPES }
|
|
|
|
validates :name, presence: true, uniqueness: true
|
2022-04-20 14:12:22 +02:00
|
|
|
validates_with UserUidMappedValidator, if: -> { %w[OAuth2Provider OpenIdConnectProvider].include?(providable_type) }
|
2022-04-11 17:27:56 +02:00
|
|
|
|
2016-03-23 18:39:41 +01:00
|
|
|
before_create :set_initial_state
|
|
|
|
|
2020-03-30 16:17:32 +02:00
|
|
|
def build_providable(params)
|
2016-03-23 18:39:41 +01:00
|
|
|
raise "Unknown providable_type: #{providable_type}" unless PROVIDABLE_TYPES.include?(providable_type)
|
2018-12-03 15:10:04 +01:00
|
|
|
|
2016-03-23 18:39:41 +01:00
|
|
|
self.providable = providable_type.constantize.new(params)
|
|
|
|
end
|
|
|
|
|
|
|
|
## Return the currently active provider
|
|
|
|
def self.active
|
|
|
|
local = SimpleAuthProvider.new
|
|
|
|
|
|
|
|
begin
|
|
|
|
provider = find_by(status: 'active')
|
2018-12-03 15:10:04 +01:00
|
|
|
return local if provider.nil?
|
|
|
|
|
2023-03-02 13:26:05 +01:00
|
|
|
provider
|
2016-03-23 18:39:41 +01:00
|
|
|
rescue ActiveRecord::StatementInvalid
|
|
|
|
# we fall here on database creation because the table "active_providers" still does not exists at the moment
|
2023-03-02 13:26:05 +01:00
|
|
|
local
|
2016-03-23 18:39:41 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-03-23 11:49:05 +01:00
|
|
|
## Return the previously active provider
|
|
|
|
def self.previous
|
|
|
|
find_by(status: 'previous')
|
|
|
|
end
|
|
|
|
|
2016-03-23 18:39:41 +01:00
|
|
|
## Get the provider matching the omniAuth strategy name
|
|
|
|
def self.from_strategy_name(strategy_name)
|
2018-12-03 15:10:04 +01:00
|
|
|
return SimpleAuthProvider.new if strategy_name.blank? || all.empty?
|
|
|
|
|
2016-03-23 18:39:41 +01:00
|
|
|
parsed = /^([^-]+)-(.+)$/.match(strategy_name)
|
|
|
|
ret = nil
|
2023-03-02 13:26:05 +01:00
|
|
|
all.find_each do |strategy|
|
2018-12-03 15:10:04 +01:00
|
|
|
if strategy.provider_type == parsed[1] && strategy.name.downcase.parameterize == parsed[2]
|
2016-03-23 18:39:41 +01:00
|
|
|
ret = strategy
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
ret
|
|
|
|
end
|
|
|
|
|
|
|
|
## Return the name that should be registered in OmniAuth for the corresponding strategy
|
|
|
|
def strategy_name
|
2023-03-02 13:26:05 +01:00
|
|
|
"#{provider_type}-#{name.downcase.parameterize}"
|
2016-03-23 18:39:41 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
## Return the provider type name without the "Provider" part.
|
|
|
|
## eg. DatabaseProvider will return 'database'
|
|
|
|
def provider_type
|
2023-03-02 13:26:05 +01:00
|
|
|
providable_type[0..-9]&.downcase
|
2016-03-23 18:39:41 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
## Return the user's profile fields that are currently managed from the SSO
|
|
|
|
## @return [Array]
|
|
|
|
def sso_fields
|
2022-03-28 19:50:36 +02:00
|
|
|
fields = []
|
|
|
|
auth_provider_mappings.each do |mapping|
|
2023-03-02 13:26:05 +01:00
|
|
|
fields.push("#{mapping.local_model}.#{mapping.local_field}")
|
2022-03-28 19:50:36 +02:00
|
|
|
end
|
|
|
|
fields
|
2016-03-23 18:39:41 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
## Return the link the user have to follow to edit his profile on the SSO
|
|
|
|
## @return [String]
|
|
|
|
def link_to_sso_profile
|
|
|
|
providable.profile_url
|
|
|
|
end
|
|
|
|
|
2016-09-26 12:41:59 +02:00
|
|
|
def safe_destroy
|
2023-03-02 13:26:05 +01:00
|
|
|
if status == 'active'
|
2016-09-26 12:41:59 +02:00
|
|
|
false
|
2023-03-02 13:26:05 +01:00
|
|
|
else
|
|
|
|
destroy
|
2016-09-26 12:41:59 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-03-23 18:39:41 +01:00
|
|
|
private
|
2018-12-03 15:10:04 +01:00
|
|
|
|
2016-03-23 18:39:41 +01:00
|
|
|
def set_initial_state
|
|
|
|
# the initial state of a new AuthProvider will be 'pending', except if there is currently
|
|
|
|
# no providers in the database, he we will be 'active' (see seeds.rb)
|
2018-12-03 15:10:04 +01:00
|
|
|
self.status = 'pending' unless AuthProvider.count.zero?
|
2016-03-23 18:39:41 +01:00
|
|
|
end
|
|
|
|
end
|