1
0
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:
Sylvain 2022-01-17 15:24:07 +01:00
parent c2f4e0f3b7
commit 67850a6f9f
10 changed files with 88 additions and 41 deletions

View File

@ -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

View File

@ -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])

View File

@ -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'])

View File

@ -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 = (

View File

@ -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 }) => {

View File

@ -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 }) => {
/**

View File

@ -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

View File

@ -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>

View File

@ -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
View 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