class SamlUserBuilder def initialize(auth_hash, account_id) @auth_hash = auth_hash @account_id = account_id @saml_settings = AccountSamlSettings.find_by(account_id: account_id) end def perform @user = find_or_create_user add_user_to_account if @user.persisted? @user end private def find_or_create_user user = User.from_email(auth_attribute('email')) if user confirm_user_if_required(user) convert_existing_user_to_saml(user) return user end create_user end def confirm_user_if_required(user) return if user.confirmed? user.skip_confirmation! user.save! end def convert_existing_user_to_saml(user) return if user.provider == 'saml' user.update!(provider: 'saml') end def create_user full_name = [auth_attribute('first_name'), auth_attribute('last_name')].compact.join(' ') fallback_name = auth_attribute('name') || auth_attribute('email').split('@').first User.create( email: auth_attribute('email'), name: (full_name.presence || fallback_name), display_name: auth_attribute('first_name'), provider: 'saml', uid: uid, password: SecureRandom.hex(32), confirmed_at: Time.current ) end def add_user_to_account account = Account.find_by(id: @account_id) return unless account # Create account_user if not exists account_user = AccountUser.find_or_create_by( user: @user, account: account ) # Set default role as agent if not set account_user.update(role: 'agent') if account_user.role.blank? # Handle role mappings if configured apply_role_mappings(account_user, account) end def apply_role_mappings(account_user, account) matching_mapping = find_matching_role_mapping(account) return unless matching_mapping if matching_mapping['role'] account_user.update(role: matching_mapping['role']) elsif matching_mapping['custom_role_id'] account_user.update(custom_role_id: matching_mapping['custom_role_id']) end end def find_matching_role_mapping(_account) return if @saml_settings&.role_mappings.blank? saml_groups.each do |group| mapping = @saml_settings.role_mappings[group] return mapping if mapping.present? end nil end def auth_attribute(key, fallback = nil) @auth_hash.dig('info', key) || fallback end def uid @auth_hash['uid'] end def saml_groups # Groups can come from different attributes depending on IdP @auth_hash.dig('extra', 'raw_info', 'groups') || @auth_hash.dig('extra', 'raw_info', 'Group') || @auth_hash.dig('extra', 'raw_info', 'memberOf') || [] end end