mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-11-28 09:24:24 +01:00
(feat) cache auth provider config
This commit is contained in:
parent
41ed9b93f5
commit
66f740104a
@ -1,5 +1,6 @@
|
|||||||
# Ignore bundler config.
|
# Ignore bundler config.
|
||||||
config/database.yml
|
config/database.yml
|
||||||
|
config/auth_provider.yml
|
||||||
|
|
||||||
# Ignore database files.
|
# Ignore database files.
|
||||||
postgresql
|
postgresql
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -26,6 +26,7 @@
|
|||||||
# Ignore application configurations
|
# Ignore application configurations
|
||||||
/config/application.yml
|
/config/application.yml
|
||||||
/config/database.yml
|
/config/database.yml
|
||||||
|
/config/auth_provider.yml
|
||||||
.env
|
.env
|
||||||
|
|
||||||
*.DS_Store
|
*.DS_Store
|
||||||
|
@ -22,8 +22,10 @@
|
|||||||
- Fill the holes in the logical sequence of invoices references with nil invoices
|
- Fill the holes in the logical sequence of invoices references with nil invoices
|
||||||
- Updated the invoices chaining method with a more flexible model
|
- Updated the invoices chaining method with a more flexible model
|
||||||
- Fix a bug: broken display after a plan category was deleted
|
- Fix a bug: broken display after a plan category was deleted
|
||||||
- [TODO DEPLOY] `rails fablab:restore_order_number` THEN `rails fablab:fix_references`
|
|
||||||
- Fix a security issue: updated json5 to 2.2.2 to fix [CVE-2022-46175](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-46175)
|
- Fix a security issue: updated json5 to 2.2.2 to fix [CVE-2022-46175](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-46175)
|
||||||
|
- [TODO DEPLOY] `\curl -sSL https://raw.githubusercontent.com/sleede/fab-manager/master/scripts/mount-auth-provider.sh | bash`
|
||||||
|
- [TODO DEPLOY] `rails fablab:auth:write_provider`
|
||||||
|
- [TODO DEPLOY] `rails fablab:restore_order_number` THEN `rails fablab:fix_references`
|
||||||
|
|
||||||
## v5.9.1 2023 March 22
|
## v5.9.1 2023 March 22
|
||||||
|
|
||||||
|
@ -2,13 +2,12 @@
|
|||||||
|
|
||||||
# Devise controller for handling client sessions
|
# Devise controller for handling client sessions
|
||||||
class SessionsController < Devise::SessionsController
|
class SessionsController < Devise::SessionsController
|
||||||
|
|
||||||
def new
|
def new
|
||||||
active_provider = AuthProvider.active
|
active_provider = Rails.configuration.auth_provider
|
||||||
if active_provider.providable_type != DatabaseProvider.name
|
if active_provider.providable_type == 'DatabaseProvider'
|
||||||
redirect_post "/users/auth/#{active_provider.strategy_name}", params: { authenticity_token: form_authenticity_token }
|
|
||||||
else
|
|
||||||
super
|
super
|
||||||
|
else
|
||||||
|
redirect_post "/users/auth/#{active_provider.strategy_name}", params: { authenticity_token: form_authenticity_token }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -5,7 +5,7 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
|||||||
require 'sso_logger'
|
require 'sso_logger'
|
||||||
logger = SsoLogger.new
|
logger = SsoLogger.new
|
||||||
|
|
||||||
active_provider = AuthProvider.active
|
active_provider = Rails.configuration.auth_provider
|
||||||
define_method active_provider.strategy_name do
|
define_method active_provider.strategy_name do
|
||||||
logger.info "[Users::OmniauthCallbacksController##{active_provider.strategy_name}] initiated"
|
logger.info "[Users::OmniauthCallbacksController##{active_provider.strategy_name}] initiated"
|
||||||
if request.env['omniauth.params'].blank?
|
if request.env['omniauth.params'].blank?
|
||||||
@ -18,7 +18,7 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
|||||||
logger.debug 'trying to create a new user'
|
logger.debug 'trying to create a new user'
|
||||||
# If the username is mapped, we just check its uniqueness as it would break the postgresql
|
# If the username is mapped, we just check its uniqueness as it would break the postgresql
|
||||||
# unique constraint otherwise. If the name is not unique, another unique is generated
|
# unique constraint otherwise. If the name is not unique, another unique is generated
|
||||||
if active_provider.sso_fields.include?('user.username')
|
if active_provider.db.sso_fields.include?('user.username')
|
||||||
logger.debug 'the username was already in use, generating a new one'
|
logger.debug 'the username was already in use, generating a new one'
|
||||||
@user.username = generate_unique_username(@user.username)
|
@user.username = generate_unique_username(@user.username)
|
||||||
end
|
end
|
||||||
@ -26,7 +26,7 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
|||||||
# unique random string, because:
|
# unique random string, because:
|
||||||
# - if it is the same user, his email will be filled from the SSO when he merge his accounts
|
# - if it is the same user, his email will be filled from the SSO when he merge his accounts
|
||||||
# - if it is not the same user, this will prevent the raise of PG::UniqueViolation
|
# - if it is not the same user, this will prevent the raise of PG::UniqueViolation
|
||||||
if active_provider.sso_fields.include?('user.email') && email_exists?(@user.email)
|
if active_provider.db.sso_fields.include?('user.email') && email_exists?(@user.email)
|
||||||
logger.debug 'the email was already in use, marking it as duplicate'
|
logger.debug 'the email was already in use, marking it as duplicate'
|
||||||
old_mail = @user.email
|
old_mail = @user.email
|
||||||
@user.email = "<#{old_mail}>#{Devise.friendly_token}-duplicate"
|
@user.email = "<#{old_mail}>#{Devise.friendly_token}-duplicate"
|
||||||
@ -46,13 +46,13 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
|||||||
@user.email = User.find(@user.id).email
|
@user.email = User.find(@user.id).email
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
# For users imported from the SSO, we consider the SSO as a source of trust so the email is automatically validated
|
||||||
|
@user.confirmed_at = Time.current if active_provider.db.sso_fields.include?('user.email') && !email_exists?(@user.email)
|
||||||
|
|
||||||
# We BYPASS THE VALIDATION because, in case of a new user, we want to save him anyway, we'll ask him later to complete his profile (on first login).
|
# We BYPASS THE VALIDATION because, in case of a new user, we want to save him anyway, we'll ask him later to complete his profile (on first login).
|
||||||
# In case of an existing user, we trust the SSO validation as we want the SSO to have authority on users management and policy.
|
# In case of an existing user, we trust the SSO validation as we want the SSO to have authority on users management and policy.
|
||||||
logger.debug 'saving the user'
|
logger.debug 'saving the user'
|
||||||
unless @user.save(validate: false)
|
logger.error "unable to save the user, an error occurred : #{@user.errors.full_messages.join(', ')}" unless @user.save(validate: false)
|
||||||
logger.error "unable to save the user, an error occurred : #{@user.errors.full_messages.join(', ')}"
|
|
||||||
end
|
|
||||||
|
|
||||||
logger.debug 'signing-in the user and redirecting'
|
logger.debug 'signing-in the user and redirecting'
|
||||||
sign_in_and_redirect @user, event: :authentication # this will throw if @user is not activated
|
sign_in_and_redirect @user, event: :authentication # this will throw if @user is not activated
|
||||||
@ -77,7 +77,6 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
|||||||
raise e
|
raise e
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -11,6 +11,10 @@ class AuthProvider < ApplicationRecord
|
|||||||
def name
|
def name
|
||||||
'DatabaseProvider::SimpleAuthProvider'
|
'DatabaseProvider::SimpleAuthProvider'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def strategy_name
|
||||||
|
"database-#{name.downcase.parameterize}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
PROVIDABLE_TYPES = %w[DatabaseProvider OAuth2Provider OpenIdConnectProvider].freeze
|
PROVIDABLE_TYPES = %w[DatabaseProvider OAuth2Provider OpenIdConnectProvider].freeze
|
||||||
|
@ -7,8 +7,8 @@ module SingleSignOnConcern
|
|||||||
|
|
||||||
included do
|
included do
|
||||||
# enable OmniAuth authentication only if needed
|
# enable OmniAuth authentication only if needed
|
||||||
devise :omniauthable, omniauth_providers: [AuthProvider.active.strategy_name.to_sym] unless
|
devise :omniauthable, omniauth_providers: [Rails.configuration.auth_provider.strategy_name.to_sym] unless
|
||||||
AuthProvider.active.providable_type == DatabaseProvider.name
|
Rails.configuration.auth_provider.providable_type == 'DatabaseProvider'
|
||||||
|
|
||||||
## Retrieve the requested data in the User and user's Profile tables
|
## Retrieve the requested data in the User and user's Profile tables
|
||||||
## @param sso_mapping {String} must be of form 'user._field_' or 'profile._field_'. Eg. 'user.email'
|
## @param sso_mapping {String} must be of form 'user._field_' or 'profile._field_'. Eg. 'user.email'
|
||||||
@ -39,7 +39,7 @@ module SingleSignOnConcern
|
|||||||
## link the current user to the given provider (omniauth attributes hash)
|
## link the current user to the given provider (omniauth attributes hash)
|
||||||
## and remove the auth_token to mark his account as "migrated"
|
## and remove the auth_token to mark his account as "migrated"
|
||||||
def link_with_omniauth_provider(auth)
|
def link_with_omniauth_provider(auth)
|
||||||
active_provider = AuthProvider.active
|
active_provider = Rails.configuration.auth_provider
|
||||||
raise SecurityError, 'The identity provider does not match the activated one' if active_provider.strategy_name != auth.provider
|
raise SecurityError, 'The identity provider does not match the activated one' if active_provider.strategy_name != auth.provider
|
||||||
|
|
||||||
if User.where(provider: auth.provider, uid: auth.uid).size.positive?
|
if User.where(provider: auth.provider, uid: auth.uid).size.positive?
|
||||||
@ -104,7 +104,7 @@ module SingleSignOnConcern
|
|||||||
def from_omniauth(auth)
|
def from_omniauth(auth)
|
||||||
logger = SsoLogger.new
|
logger = SsoLogger.new
|
||||||
logger.debug "[User::from_omniauth] initiated with parameter #{auth}"
|
logger.debug "[User::from_omniauth] initiated with parameter #{auth}"
|
||||||
active_provider = AuthProvider.active
|
active_provider = Rails.configuration.auth_provider
|
||||||
raise SecurityError, 'The identity provider does not match the activated one' if active_provider.strategy_name != auth.provider
|
raise SecurityError, 'The identity provider does not match the activated one' if active_provider.strategy_name != auth.provider
|
||||||
|
|
||||||
where(provider: auth.provider, uid: auth.uid).first_or_create.tap do |user|
|
where(provider: auth.provider, uid: auth.uid).first_or_create.tap do |user|
|
||||||
|
@ -16,20 +16,4 @@ class OpenIdConnectProvider < ApplicationRecord
|
|||||||
validates :display, inclusion: { in: %w[page popup touch wap], allow_nil: true }
|
validates :display, inclusion: { in: %w[page popup touch wap], allow_nil: true }
|
||||||
validates :prompt, inclusion: { in: %w[none login consent select_account], allow_nil: true }
|
validates :prompt, inclusion: { in: %w[none login consent select_account], allow_nil: true }
|
||||||
validates :client_auth_method, inclusion: { in: %w[basic jwks] }
|
validates :client_auth_method, inclusion: { in: %w[basic jwks] }
|
||||||
|
|
||||||
def scope
|
|
||||||
self[:scope]&.join(' ')
|
|
||||||
end
|
|
||||||
|
|
||||||
def config
|
|
||||||
OpenIdConnectProvider.columns.map(&:name).filter { |n| !n.start_with?('client__') && n != 'profile_url' }.map do |n|
|
|
||||||
[n, send(n)]
|
|
||||||
end.push(['client_options', client_config]).to_h
|
|
||||||
end
|
|
||||||
|
|
||||||
def client_config
|
|
||||||
OpenIdConnectProvider.columns.map(&:name).filter { |n| n.start_with?('client__') }.to_h do |n|
|
|
||||||
[n.sub('client__', ''), send(n)]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
22
app/views/auth_provider/provider.json.jbuilder
Normal file
22
app/views/auth_provider/provider.json.jbuilder
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
json.partial! 'api/auth_providers/auth_provider', auth_provider: provider
|
||||||
|
|
||||||
|
# OAuth 2.0
|
||||||
|
|
||||||
|
if provider.providable_type == 'OAuth2Provider'
|
||||||
|
json.providable_attributes do
|
||||||
|
json.extract! provider.providable, :id, :base_url, :token_endpoint, :authorization_endpoint, :profile_url, :client_id, :client_secret,
|
||||||
|
:scopes
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if provider.providable_type == 'OpenIdConnectProvider'
|
||||||
|
json.providable_attributes do
|
||||||
|
json.extract! provider.providable, :id, :issuer, :discovery, :client_auth_method, :scope, :response_type, :response_mode,
|
||||||
|
:display, :prompt, :send_scope_to_token_endpoint, :client__identifier, :client__secret, :client__authorization_endpoint,
|
||||||
|
:client__token_endpoint, :client__userinfo_endpoint, :client__jwks_uri, :client__end_session_endpoint, :profile_url,
|
||||||
|
:post_logout_redirect_uri, :uid_field, :client__redirect_uri, :client__scheme, :client__host, :client__port
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -76,6 +76,9 @@ class FabManager::Application < Rails::Application
|
|||||||
# disable ANSI color escape codes in active_record if NO_COLOR is defined.
|
# disable ANSI color escape codes in active_record if NO_COLOR is defined.
|
||||||
config.colorize_logging = ENV['NO_COLOR'] ? false : true
|
config.colorize_logging = ENV['NO_COLOR'] ? false : true
|
||||||
|
|
||||||
|
require 'provider_config'
|
||||||
|
config.auth_provider = ProviderConfig.new
|
||||||
|
|
||||||
FabManager.activate_plugins!
|
FabManager.activate_plugins!
|
||||||
|
|
||||||
config.action_view.sanitized_allowed_tags = %w[a acronym hr pre table b strong i em li ul ol h1 h2 h3 h4 h5 h6 blockquote br cite sub sup ins p
|
config.action_view.sanitized_allowed_tags = %w[a acronym hr pre table b strong i em li ul ol h1 h2 h3 h4 h5 h6 blockquote br cite sub sup ins p
|
||||||
|
@ -227,17 +227,23 @@ Devise.setup do |config|
|
|||||||
# Add a new OmniAuth provider. Check the wiki for more information on setting
|
# Add a new OmniAuth provider. Check the wiki for more information on setting
|
||||||
# up on your models and hooks.
|
# up on your models and hooks.
|
||||||
# config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo'
|
# config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo'
|
||||||
Rails.application.reloader.to_prepare do
|
active_provider = Rails.configuration.auth_provider
|
||||||
active_provider = AuthProvider.active
|
unless active_provider.nil?
|
||||||
if active_provider.providable_type == OAuth2Provider.name
|
# noinspection RubyCaseWithoutElseBlockInspection
|
||||||
|
case active_provider.providable_type
|
||||||
|
when 'OAuth2Provider'
|
||||||
require_relative '../../lib/omni_auth/oauth2'
|
require_relative '../../lib/omni_auth/oauth2'
|
||||||
config.omniauth OmniAuth::Strategies::SsoOauth2Provider.name.to_sym,
|
config.omniauth active_provider.strategy_name.to_sym,
|
||||||
active_provider.providable.client_id,
|
active_provider.providable.client_id,
|
||||||
active_provider.providable.client_secret
|
active_provider.providable.client_secret,
|
||||||
elsif active_provider.providable_type == OpenIdConnectProvider.name
|
strategy_class: OmniAuth::Strategies::SsoOauth2Provider
|
||||||
|
|
||||||
|
when 'OpenIdConnectProvider'
|
||||||
require_relative '../../lib/omni_auth/openid_connect'
|
require_relative '../../lib/omni_auth/openid_connect'
|
||||||
config.omniauth OmniAuth::Strategies::SsoOpenidConnectProvider.name.to_sym,
|
config.omniauth active_provider.strategy_name.to_sym,
|
||||||
active_provider.providable.config
|
active_provider.oidc_config.merge(
|
||||||
|
strategy_class: OmniAuth::Strategies::SsoOpenidConnectProvider
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ require 'sidekiq_unique_jobs/web'
|
|||||||
require 'sidekiq-scheduler/web'
|
require 'sidekiq-scheduler/web'
|
||||||
|
|
||||||
Rails.application.routes.draw do
|
Rails.application.routes.draw do
|
||||||
if AuthProvider.active.providable_type == DatabaseProvider.name
|
if Rails.configuration.auth_provider.providable_type == 'DatabaseProvider'
|
||||||
# with local authentication we do not use omniAuth so we must differentiate the config
|
# with local authentication we do not use omniAuth so we must differentiate the config
|
||||||
devise_for :users, controllers: {
|
devise_for :users, controllers: {
|
||||||
registrations: 'registrations', sessions: 'sessions', confirmations: 'confirmations', passwords: 'passwords'
|
registrations: 'registrations', sessions: 'sessions', confirmations: 'confirmations', passwords: 'passwords'
|
||||||
|
@ -249,6 +249,9 @@ unless DatabaseProvider.count.positive?
|
|||||||
provider.providable = db_provider
|
provider.providable = db_provider
|
||||||
provider.status = 'active'
|
provider.status = 'active'
|
||||||
provider.save
|
provider.save
|
||||||
|
|
||||||
|
require 'provider_config'
|
||||||
|
ProviderConfig.write_active_provider
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5,76 +5,74 @@ require 'jsonpath'
|
|||||||
require 'sso_logger'
|
require 'sso_logger'
|
||||||
require_relative '../data_mapping/mapper'
|
require_relative '../data_mapping/mapper'
|
||||||
|
|
||||||
module OmniAuth::Strategies
|
# Authentication strategy provided trough oAuth 2.0
|
||||||
# Authentication strategy provided trough oAuth 2.0
|
class OmniAuth::Strategies::SsoOauth2Provider < OmniAuth::Strategies::OAuth2
|
||||||
class SsoOauth2Provider < OmniAuth::Strategies::OAuth2
|
include OmniAuth::DataMapping::Mapper
|
||||||
include OmniAuth::DataMapping::Mapper
|
|
||||||
|
|
||||||
def self.active_provider
|
def self.active_provider
|
||||||
active_provider = AuthProvider.active
|
active_provider = Rails.configuration.auth_provider
|
||||||
if active_provider.providable_type != OAuth2Provider.name
|
if active_provider.providable_type != 'OAuth2Provider'
|
||||||
raise "Trying to instantiate the wrong provider: Expected OAuth2Provider, received #{active_provider.providable_type}"
|
raise "Trying to instantiate the wrong provider: Expected OAuth2Provider, received #{active_provider.providable_type}"
|
||||||
end
|
|
||||||
|
|
||||||
active_provider
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Strategy name.
|
active_provider
|
||||||
option :name, active_provider.strategy_name
|
end
|
||||||
|
|
||||||
option :client_options,
|
# Strategy name.
|
||||||
site: active_provider.providable.base_url,
|
option :name, active_provider.strategy_name
|
||||||
authorize_url: active_provider.providable.authorization_endpoint,
|
|
||||||
token_url: active_provider.providable.token_endpoint
|
|
||||||
|
|
||||||
def authorize_params
|
option :client_options,
|
||||||
super.tap do |params|
|
site: active_provider.providable.base_url,
|
||||||
params[:scope] = OmniAuth::Strategies::SsoOauth2Provider.active_provider.providable.scopes
|
authorize_url: active_provider.providable.authorization_endpoint,
|
||||||
end
|
token_url: active_provider.providable.token_endpoint
|
||||||
end
|
|
||||||
|
|
||||||
def callback_url
|
def authorize_params
|
||||||
url = Rails.application.config.action_controller.default_url_options
|
super.tap do |params|
|
||||||
"#{url[:protocol]}://#{url[:host]}#{script_name}#{callback_path}"
|
params[:scope] = OmniAuth::Strategies::SsoOauth2Provider.active_provider.providable.scopes
|
||||||
end
|
|
||||||
|
|
||||||
uid { parsed_info[:'user.uid'] }
|
|
||||||
|
|
||||||
info do
|
|
||||||
{
|
|
||||||
mapping: parsed_info
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
extra do
|
|
||||||
{
|
|
||||||
raw_info: raw_info
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
# retrieve data from various url, querying each only once
|
|
||||||
def raw_info
|
|
||||||
logger = SsoLogger.new
|
|
||||||
|
|
||||||
@raw_info ||= {}
|
|
||||||
logger.debug "[raw_info] @raw_infos = #{@raw_info&.to_json}"
|
|
||||||
unless @raw_info.size.positive?
|
|
||||||
OmniAuth::Strategies::SsoOauth2Provider.active_provider.auth_provider_mappings.each do |mapping|
|
|
||||||
logger.debug "mapping = #{mapping&.to_json}"
|
|
||||||
next if @raw_info.key?(mapping.api_endpoint.to_sym)
|
|
||||||
|
|
||||||
logger.debug "api_endpoint = #{mapping.api_endpoint.to_sym}"
|
|
||||||
logger.debug "access_token = #{access_token&.to_json}"
|
|
||||||
logger.debug "token get = #{access_token.get(mapping.api_endpoint)}"
|
|
||||||
logger.debug "parsed = #{access_token.get(mapping.api_endpoint).parsed}"
|
|
||||||
@raw_info[mapping.api_endpoint.to_sym] = access_token.get(mapping.api_endpoint).parsed
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@raw_info
|
|
||||||
end
|
|
||||||
|
|
||||||
def parsed_info
|
|
||||||
mapped_info(OmniAuth::Strategies::SsoOauth2Provider.active_provider.auth_provider_mappings, raw_info)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def callback_url
|
||||||
|
url = Rails.application.config.action_controller.default_url_options
|
||||||
|
"#{url[:protocol]}://#{url[:host]}#{script_name}#{callback_path}"
|
||||||
|
end
|
||||||
|
|
||||||
|
uid { parsed_info[:'user.uid'] }
|
||||||
|
|
||||||
|
info do
|
||||||
|
{
|
||||||
|
mapping: parsed_info
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
extra do
|
||||||
|
{
|
||||||
|
raw_info: raw_info
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
# retrieve data from various url, querying each only once
|
||||||
|
def raw_info
|
||||||
|
logger = SsoLogger.new
|
||||||
|
|
||||||
|
@raw_info ||= {}
|
||||||
|
logger.debug "[raw_info] @raw_infos = #{@raw_info&.to_json}"
|
||||||
|
unless @raw_info.size.positive?
|
||||||
|
OmniAuth::Strategies::SsoOauth2Provider.active_provider.auth_provider_mappings.each do |mapping|
|
||||||
|
logger.debug "mapping = #{mapping&.to_json}"
|
||||||
|
next if @raw_info.key?(mapping.api_endpoint.to_sym)
|
||||||
|
|
||||||
|
logger.debug "api_endpoint = #{mapping.api_endpoint.to_sym}"
|
||||||
|
logger.debug "access_token = #{access_token&.to_json}"
|
||||||
|
logger.debug "token get = #{access_token.get(mapping.api_endpoint)}"
|
||||||
|
logger.debug "parsed = #{access_token.get(mapping.api_endpoint).parsed}"
|
||||||
|
@raw_info[mapping.api_endpoint.to_sym] = access_token.get(mapping.api_endpoint).parsed
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@raw_info
|
||||||
|
end
|
||||||
|
|
||||||
|
def parsed_info
|
||||||
|
mapped_info(OmniAuth::Strategies::SsoOauth2Provider.active_provider.auth_provider_mappings, raw_info)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -3,34 +3,32 @@
|
|||||||
require 'omniauth_openid_connect'
|
require 'omniauth_openid_connect'
|
||||||
require_relative '../data_mapping/mapper'
|
require_relative '../data_mapping/mapper'
|
||||||
|
|
||||||
module OmniAuth::Strategies
|
# Authentication strategy provided trough OpenID Connect
|
||||||
# Authentication strategy provided trough OpenID Connect
|
class OmniAuth::Strategies::SsoOpenidConnectProvider < OmniAuth::Strategies::OpenIDConnect
|
||||||
class SsoOpenidConnectProvider < OmniAuth::Strategies::OpenIDConnect
|
include OmniAuth::DataMapping::Mapper
|
||||||
include OmniAuth::DataMapping::Mapper
|
|
||||||
|
|
||||||
def self.active_provider
|
def self.active_provider
|
||||||
active_provider = AuthProvider.active
|
active_provider = Rails.configuration.auth_provider
|
||||||
if active_provider.providable_type != OpenIdConnectProvider.name
|
if active_provider.providable_type != 'OpenIdConnectProvider'
|
||||||
raise "Trying to instantiate the wrong provider: Expected OpenIdConnectProvider, received #{active_provider.providable_type}"
|
raise "Trying to instantiate the wrong provider: Expected OpenIdConnectProvider, received #{active_provider.providable_type}"
|
||||||
end
|
|
||||||
|
|
||||||
active_provider
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Strategy name.
|
active_provider
|
||||||
option :name, active_provider.strategy_name
|
end
|
||||||
|
|
||||||
info do
|
# Strategy name.
|
||||||
{
|
option :name, active_provider.strategy_name
|
||||||
mapping: parsed_info
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def parsed_info
|
info do
|
||||||
mapped_info(
|
{
|
||||||
OmniAuth::Strategies::SsoOpenidConnectProvider.active_provider.auth_provider_mappings,
|
mapping: parsed_info
|
||||||
user_info: user_info.raw_attributes
|
}
|
||||||
)
|
end
|
||||||
end
|
|
||||||
|
def parsed_info
|
||||||
|
mapped_info(
|
||||||
|
OmniAuth::Strategies::SsoOpenidConnectProvider.active_provider.auth_provider_mappings,
|
||||||
|
user_info: user_info.raw_attributes
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
61
lib/provider_config.rb
Normal file
61
lib/provider_config.rb
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Deals with the yml file keeping the configuration of the current authentication provider
|
||||||
|
class ProviderConfig
|
||||||
|
def initialize
|
||||||
|
@config = YAML.safe_load_file('config/auth_provider.yml').with_indifferent_access if File.exist?('config/auth_provider.yml')
|
||||||
|
end
|
||||||
|
|
||||||
|
def db
|
||||||
|
AuthProvider.find(@config[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def oidc_config
|
||||||
|
return nil unless @config[:providable_type] == 'OpenIdConnectProvider'
|
||||||
|
|
||||||
|
(@config[:providable_attributes].keys.filter { |n| !n.start_with?('client__') && n != 'profile_url' }.map do |n|
|
||||||
|
val = @config[:providable_attributes][n]
|
||||||
|
val.join(' ') if n == 'scope'
|
||||||
|
[n, val]
|
||||||
|
end).push(
|
||||||
|
['client_options', @config[:providable_attributes].keys.filter { |n| n.start_with?('client__') }.to_h do |n|
|
||||||
|
[n.sub('client__', ''), @config[:providable_attributes][n]]
|
||||||
|
end]
|
||||||
|
).to_h
|
||||||
|
end
|
||||||
|
|
||||||
|
def method_missing(method, *args)
|
||||||
|
return map_value(@config[method]) if @config.key?(method)
|
||||||
|
|
||||||
|
return map_value(@config["#{method}_attributes"]) if @config.key?("#{method}_attributes")
|
||||||
|
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
def respond_to_missing?(name)
|
||||||
|
@config.key?(name) || @config.key("#{name}_attributes")
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.write_active_provider
|
||||||
|
data = ApplicationController.render(
|
||||||
|
template: 'auth_provider/provider',
|
||||||
|
locals: { provider: AuthProvider.active },
|
||||||
|
handlers: [:jbuilder],
|
||||||
|
formats: [:json]
|
||||||
|
)
|
||||||
|
file_path = Rails.root.join('config/auth_provider.yml')
|
||||||
|
File.open(file_path, File::WRONLY | File::CREAT) do |file|
|
||||||
|
file.write(JSON.parse(data).to_yaml)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def map_value(item)
|
||||||
|
return Struct.new(*item.symbolize_keys.keys).new(*item.values) if item.is_a?(Hash)
|
||||||
|
|
||||||
|
return item.map { |v| map_value(v) } if item.is_a?(Array)
|
||||||
|
|
||||||
|
item
|
||||||
|
end
|
||||||
|
end
|
@ -41,6 +41,10 @@ namespace :fablab do
|
|||||||
User.all.each(&:generate_auth_migration_token)
|
User.all.each(&:generate_auth_migration_token)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# write the configuration to file
|
||||||
|
require 'provider_config'
|
||||||
|
ProviderConfig.write_active_provider
|
||||||
|
|
||||||
# ask the user to restart the application
|
# ask the user to restart the application
|
||||||
next if Rails.env.test?
|
next if Rails.env.test?
|
||||||
|
|
||||||
@ -71,5 +75,11 @@ namespace :fablab do
|
|||||||
task current: :environment do
|
task current: :environment do
|
||||||
puts "Current active authentication provider: #{AuthProvider.active.name}"
|
puts "Current active authentication provider: #{AuthProvider.active.name}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc 'write the provider config to a configuration file'
|
||||||
|
task write_provider: :environment do
|
||||||
|
require 'provider_config'
|
||||||
|
ProviderConfig.write_active_provider
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
36
scripts/mount-auth-provider.sh
Normal file
36
scripts/mount-auth-provider.sh
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
yq() {
|
||||||
|
docker run --rm -i -v "${PWD}:/workdir" --user "$UID" mikefarah/yq:4 "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
config()
|
||||||
|
{
|
||||||
|
echo -ne "Checking user... "
|
||||||
|
if [[ "$(whoami)" != "root" ]] && ! groups | grep docker
|
||||||
|
then
|
||||||
|
echo "Please add your current user to the docker group OR run this script as root."
|
||||||
|
echo "current user is not allowed to use docker, exiting..."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
SERVICE="$(yq eval '.services.*.image | select(. == "sleede/fab-manager*") | path | .[-2]' docker-compose.yml)"
|
||||||
|
echo -e "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
add_mount()
|
||||||
|
{
|
||||||
|
if [[ ! $(yq eval ".services.$SERVICE.volumes.[] | select (. == \"*auth_provider.yml\")" docker-compose.yml) ]]; then
|
||||||
|
# change docker-compose.yml permissions for fix yq can't modify file issue
|
||||||
|
chmod 666 docker-compose.yml
|
||||||
|
yq -i eval ".services.$SERVICE.volumes += [\"\./config/auth_provider.yml:/usr/src/app/auth_provider.yml\"]" docker-compose.yml
|
||||||
|
chmod 644 docker-compose.yml
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
proceed()
|
||||||
|
{
|
||||||
|
config
|
||||||
|
add_mount
|
||||||
|
}
|
||||||
|
|
||||||
|
proceed "$@"
|
@ -19,6 +19,7 @@ services:
|
|||||||
- ./log:/var/log/supervisor
|
- ./log:/var/log/supervisor
|
||||||
- ./plugins:/usr/src/app/plugins
|
- ./plugins:/usr/src/app/plugins
|
||||||
- ./accounting:/usr/src/app/accounting
|
- ./accounting:/usr/src/app/accounting
|
||||||
|
- ./config/auth_provider.yml:/usr/src/app/auth_provider.yml
|
||||||
depends_on:
|
depends_on:
|
||||||
- postgres
|
- postgres
|
||||||
- redis
|
- redis
|
||||||
|
Loading…
Reference in New Issue
Block a user