mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-18 07:52:23 +01:00
(feat) optional sso debug logs according to SSO_DEBUG env var
This commit is contained in:
parent
c2f4e0f3b7
commit
67850a6f9f
@ -2,7 +2,7 @@
|
||||
|
||||
- Support for JSONPath syntax in OAuth2 SSO fields mapping
|
||||
- Basic support for OAuth2 scopes through an environment variable
|
||||
- Add debug logs for the SSO authentication process
|
||||
- Ability to enable debug logs for the SSO authentication process using `SSO_DEBUG=true`
|
||||
- Remove case sensitivity for the SSO account mapping process
|
||||
- Ability to cancel a payement schedule from the interface
|
||||
- Ability to create slots in the past
|
||||
|
@ -19,7 +19,7 @@ class API::MembersController < API::ApiController
|
||||
|
||||
def last_subscribed
|
||||
@query = User.active.with_role(:member)
|
||||
.includes(profile: [:user_avatar])
|
||||
.includes(:statistic_profile, profile: [:user_avatar])
|
||||
.where('is_allow_contact = true AND confirmed_at IS NOT NULL')
|
||||
.order('created_at desc')
|
||||
.limit(params[:last])
|
||||
|
@ -1,8 +1,13 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Handle authentication actions via OmniAuth (used by SSO providers)
|
||||
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||
require 'sso_logger'
|
||||
logger = SsoLogger.new
|
||||
|
||||
active_provider = AuthProvider.active
|
||||
define_method active_provider.strategy_name do
|
||||
logger.debug "[Users::OmniauthCallbacksController##{active_provider.strategy_name}] initiated"
|
||||
logger.info "[Users::OmniauthCallbacksController##{active_provider.strategy_name}] initiated"
|
||||
if request.env['omniauth.params'].blank?
|
||||
logger.debug 'the user has not provided any authentication token'
|
||||
@user = User.from_omniauth(request.env['omniauth.auth'])
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { Suspense } from 'react';
|
||||
|
||||
/**
|
||||
* This component is a wrapper that display a loader while the children components have their rendering suspended
|
||||
* This component is a wrapper that display a loader while the children components have their rendering suspended.
|
||||
*/
|
||||
export const Loader: React.FC = ({ children }) => {
|
||||
const loading = (
|
||||
|
@ -55,7 +55,7 @@ interface AbstractPaymentModalProps {
|
||||
/**
|
||||
* This component is an abstract modal that must be extended by each payment gateway to include its payment form.
|
||||
*
|
||||
* This component must not be called directly but must be extended for each implemented payment gateway
|
||||
* This component must not be called directly but must be extended for each implemented payment gateway.
|
||||
* @see https://reactjs.org/docs/composition-vs-inheritance.html
|
||||
*/
|
||||
export const AbstractPaymentModal: React.FC<AbstractPaymentModalProps> = ({ isOpen, toggleModal, afterSuccess, onError, cart, updateCart, currentUser, schedule, customer, logoFooter, GatewayForm, formId, className, formClassName, title, preventCgv, preventScheduleInfo, modalSize }) => {
|
||||
|
@ -9,7 +9,7 @@ interface AvatarProps {
|
||||
}
|
||||
|
||||
/**
|
||||
* This component renders the user-profile's picture or a placeholder
|
||||
* This component renders the user-profile's picture or a placeholder.
|
||||
*/
|
||||
export const Avatar: React.FC<AvatarProps> = ({ user, className }) => {
|
||||
/**
|
||||
|
@ -3,6 +3,8 @@
|
||||
# User is a physical or moral person with its authentication parameters
|
||||
# It is linked to the Profile model with hold information about this person (like address, name, etc.)
|
||||
class User < ApplicationRecord
|
||||
require 'sso_logger'
|
||||
|
||||
include NotifyWith::NotificationReceiver
|
||||
include NotifyWith::NotificationAttachedObject
|
||||
# Include default devise modules. Others available are:
|
||||
@ -201,6 +203,7 @@ class User < ApplicationRecord
|
||||
end
|
||||
|
||||
def self.from_omniauth(auth)
|
||||
logger = SsoLogger.new
|
||||
logger.debug "[User::from_omniauth] initiated with parameter #{auth}"
|
||||
active_provider = AuthProvider.active
|
||||
raise SecurityError, 'The identity provider does not match the activated one' if active_provider.strategy_name != auth.provider
|
||||
@ -309,6 +312,7 @@ class User < ApplicationRecord
|
||||
## Merge the provided User's SSO details into the current user and drop the provided user to ensure the unity
|
||||
## @param sso_user {User} the provided user will be DELETED after the merge was successful
|
||||
def merge_from_sso(sso_user)
|
||||
logger = SsoLogger.new
|
||||
logger.debug "[User::merge_from_sso] initiated with parameter #{sso_user}"
|
||||
# update the attributes to link the account to the sso account
|
||||
self.provider = sso_user.provider
|
||||
|
@ -138,7 +138,18 @@ Please, ensure you know what you're doing, as this can lead to serious security
|
||||
A comma separated list of settings that cannot be changed from the UI.
|
||||
Please refer to https://github.com/sleede/fab-manager/blob/master/app/models/setting.rb for a list of possible values.
|
||||
Only the system administrator can change them, with the command: `ENV=value rails fablab:setup:env_to_db`
|
||||
<a name="OAUTH2_SCOPE"></a>
|
||||
|
||||
OAUTH2_SCOPE
|
||||
|
||||
A comma separated list of scopes that will be requested when authenticating with OAuth2.
|
||||
<a name="SSO_DEBUG"></a>
|
||||
|
||||
SSO_DEBUG
|
||||
|
||||
If set to `true`, the SSO authentication process will print more debug logs.
|
||||
Use in accordance with LOG_LEVEL=debug.
|
||||
Please do not enable this in production, as it can expose sensitive information.
|
||||
<a name="internationalization-settings"></a>
|
||||
## Internationalization setting.
|
||||
<a name="APP_LOCALE"></a>
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
require 'omniauth-oauth2'
|
||||
require 'jsonpath'
|
||||
require 'sso_logger'
|
||||
|
||||
module OmniAuth::Strategies
|
||||
# Authentication strategy provided trough oAuth 2.0
|
||||
@ -52,58 +53,57 @@ module OmniAuth::Strategies
|
||||
|
||||
# retrieve data from various url, querying each only once
|
||||
def raw_info
|
||||
logger = SsoLogger.new
|
||||
|
||||
@raw_info ||= {}
|
||||
puts "[raw_info] @raw_infos = #{@raw_info&.to_json}"
|
||||
logger.debug "[raw_info] @raw_infos = #{@raw_info&.to_json}"
|
||||
unless @raw_info.size.positive?
|
||||
OmniAuth::Strategies::SsoOauth2Provider.active_provider.providable.o_auth2_mappings.each do |mapping|
|
||||
puts "mapping = #{mapping&.to_json}"
|
||||
unless @raw_info.key?(mapping.api_endpoint.to_sym)
|
||||
puts "api_endpoint = #{mapping.api_endpoint.to_sym}"
|
||||
puts "access_token = #{access_token&.to_json}"
|
||||
puts "token get = #{access_token.get(mapping.api_endpoint)}"
|
||||
puts "parsed = #{access_token.get(mapping.api_endpoint).parsed}"
|
||||
@raw_info[mapping.api_endpoint.to_sym] = access_token.get(mapping.api_endpoint).parsed
|
||||
end
|
||||
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
|
||||
logger = SsoLogger.new
|
||||
|
||||
@parsed_info ||= {}
|
||||
puts "[parsed_info] @parsed_info = #{@parsed_info.to_json}"
|
||||
logger.debug "[parsed_info] @parsed_info = #{@parsed_info.to_json}"
|
||||
unless @parsed_info.size.positive?
|
||||
OmniAuth::Strategies::SsoOauth2Provider.active_provider.providable.o_auth2_mappings.each do |mapping|
|
||||
|
||||
raw_data = ::JsonPath.new(mapping.api_field).on(raw_info[mapping.api_endpoint.to_sym]).first
|
||||
logger.debug "@parsed_info[#{local_sym(mapping)}] mapped from #{raw_data}"
|
||||
if mapping.transformation
|
||||
case mapping.transformation['type']
|
||||
## INTEGER
|
||||
when 'integer'
|
||||
@parsed_info[local_sym(mapping)] = map_integer(mapping.transformation,
|
||||
mapping.api_endpoint.to_sym,
|
||||
mapping.api_field)
|
||||
@parsed_info[local_sym(mapping)] = map_integer(mapping.transformation, raw_data)
|
||||
|
||||
## BOOLEAN
|
||||
when 'boolean'
|
||||
@parsed_info[local_sym(mapping)] = map_boolean(mapping.transformation,
|
||||
mapping.api_endpoint.to_sym,
|
||||
mapping.api_field)
|
||||
@parsed_info[local_sym(mapping)] = map_boolean(mapping.transformation, raw_data)
|
||||
|
||||
## DATE
|
||||
when 'date'
|
||||
@params[local_sym(mapping)] = map_date(mapping.transformation,
|
||||
mapping.api_endpoint.to_sym,
|
||||
mapping.api_field)
|
||||
@params[local_sym(mapping)] = map_date(mapping.transformation, raw_data)
|
||||
|
||||
## OTHER TRANSFORMATIONS (not supported)
|
||||
else
|
||||
@parsed_info[local_sym(mapping)] = raw_info[mapping.api_endpoint.to_sym][mapping.api_field]
|
||||
@parsed_info[local_sym(mapping)] = raw_data
|
||||
end
|
||||
|
||||
## NO TRANSFORMATION
|
||||
else
|
||||
puts "@parsed_info[#{local_sym(mapping)}] found in #{raw_info[mapping.api_endpoint.to_sym]}"
|
||||
@parsed_info[local_sym(mapping)] = ::JsonPath.new(mapping.api_field).on(raw_info[mapping.api_endpoint.to_sym]).first
|
||||
@parsed_info[local_sym(mapping)] = raw_data
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -116,38 +116,38 @@ module OmniAuth::Strategies
|
||||
(mapping.local_model + '.' + mapping.local_field).to_sym
|
||||
end
|
||||
|
||||
def map_integer(transformation, api_endpoint, api_field)
|
||||
def map_integer(transformation, raw_data)
|
||||
value = nil
|
||||
transformation['mapping'].each do |m|
|
||||
if m['from'] == raw_info[api_endpoint][api_field]
|
||||
if m['from'] == raw_data
|
||||
value = m['to']
|
||||
break
|
||||
end
|
||||
end
|
||||
# if no transformation had set any value, return the raw value
|
||||
value || raw_info[api_endpoint.to_sym][api_field]
|
||||
value || raw_data
|
||||
end
|
||||
|
||||
def map_boolean(transformation, api_endpoint, api_field)
|
||||
return false if raw_info[api_endpoint][api_field] == transformation['false_value']
|
||||
def map_boolean(transformation, raw_data)
|
||||
return false if raw_data == transformation['false_value']
|
||||
|
||||
true if raw_info[api_endpoint][api_field] == transformation['true_value']
|
||||
true if raw_data == transformation['true_value']
|
||||
end
|
||||
|
||||
def map_date(transformation, api_endpoint, api_field)
|
||||
def map_date(transformation, raw_data)
|
||||
case transformation['format']
|
||||
when 'iso8601'
|
||||
DateTime.iso8601(raw_info[api_endpoint][api_field])
|
||||
DateTime.iso8601(raw_data)
|
||||
when 'rfc2822'
|
||||
DateTime.rfc2822(raw_info[api_endpoint][api_field])
|
||||
DateTime.rfc2822(raw_data)
|
||||
when 'rfc3339'
|
||||
DateTime.rfc3339(raw_info[api_endpoint][api_field])
|
||||
DateTime.rfc3339(raw_data)
|
||||
when 'timestamp-s'
|
||||
DateTime.strptime(raw_info[api_endpoint][api_field], '%s')
|
||||
DateTime.strptime(raw_data, '%s')
|
||||
when 'timestamp-ms'
|
||||
DateTime.strptime(raw_info[api_endpoint][api_field], '%Q')
|
||||
DateTime.strptime(raw_data, '%Q')
|
||||
else
|
||||
DateTime.parse(raw_info[api_endpoint][api_field])
|
||||
DateTime.parse(raw_data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
27
lib/sso_logger.rb
Normal file
27
lib/sso_logger.rb
Normal file
@ -0,0 +1,27 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# This class provides logging functionalities for SSO authentication
|
||||
class SsoLogger
|
||||
def initialize()
|
||||
@logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
|
||||
@log_status = ENV.fetch('SSO_DEBUG') { false }
|
||||
end
|
||||
|
||||
def debug(message)
|
||||
return unless @log_status
|
||||
|
||||
@logger.tagged('SSO') { @logger.debug(message) }
|
||||
end
|
||||
|
||||
def info(message)
|
||||
@logger.tagged('SSO') { @logger.info(message) }
|
||||
end
|
||||
|
||||
def warn(message)
|
||||
@logger.tagged('SSO') { @logger.warn(message) }
|
||||
end
|
||||
|
||||
def error(message)
|
||||
@logger.tagged('SSO') { @logger.error(message) }
|
||||
end
|
||||
end
|
Loading…
x
Reference in New Issue
Block a user