Merge pull request #538 from luckyPipewrench/sso-upgrades

Multi-provider SSO with admin UI and SAML support
This commit is contained in:
soky srm
2026-01-12 15:38:59 +01:00
committed by GitHub
50 changed files with 3273 additions and 34 deletions

View File

@@ -0,0 +1,154 @@
# frozen_string_literal: true
namespace :sso_providers do
desc "Seed SSO providers from config/auth.yml into the database"
task seed: :environment do
dry_run = ENV["DRY_RUN"] == "true"
puts "=" * 80
puts "SSO Provider Seeding Task"
puts "=" * 80
puts "Mode: #{dry_run ? 'DRY RUN (no changes will be saved)' : 'LIVE (changes will be saved)'}"
puts "Source: config/auth.yml"
puts "-" * 80
begin
# Load auth.yml safely
auth_config_path = Rails.root.join("config", "auth.yml")
unless File.exist?(auth_config_path)
puts "ERROR: config/auth.yml not found"
exit 1
end
# Use safe_load to prevent code injection
auth_config = YAML.safe_load(
ERB.new(File.read(auth_config_path)).result,
permitted_classes: [ Symbol ],
aliases: true
)
# Get providers for current environment
env_config = auth_config[Rails.env] || auth_config["default"]
providers = env_config&.dig("providers") || []
if providers.empty?
puts "WARNING: No providers found in config/auth.yml for #{Rails.env} environment"
exit 0
end
puts "Found #{providers.count} provider(s) in config/auth.yml"
puts "-" * 80
created_count = 0
updated_count = 0
skipped_count = 0
errors = []
ActiveRecord::Base.transaction do
providers.each do |provider_config|
provider_config = provider_config.deep_symbolize_keys
# Extract provider attributes
name = provider_config[:name] || provider_config[:id]
strategy = provider_config[:strategy]
unless name.present? && strategy.present?
puts "SKIP: Provider missing name or strategy: #{provider_config.inspect}"
skipped_count += 1
next
end
# Find or initialize provider
provider = SsoProvider.find_or_initialize_by(name: name)
is_new = provider.new_record?
# Build attributes hash
attributes = {
strategy: strategy,
label: provider_config[:label] || name.titleize,
icon: provider_config[:icon],
enabled: provider_config.key?(:enabled) ? provider_config[:enabled] : true,
issuer: provider_config[:issuer],
client_id: provider_config[:client_id],
redirect_uri: provider_config[:redirect_uri],
settings: provider_config[:settings] || {}
}
# Only set client_secret if provided (don't overwrite existing)
if provider_config[:client_secret].present?
attributes[:client_secret] = provider_config[:client_secret]
end
# Assign attributes
provider.assign_attributes(attributes.compact)
# Check if changed
if provider.changed?
if dry_run
puts "#{is_new ? 'CREATE' : 'UPDATE'} (dry-run): #{name} (#{strategy})"
puts " Changes: #{provider.changes.keys.join(', ')}"
else
if provider.save
puts "#{is_new ? 'CREATE' : 'UPDATE'}: #{name} (#{strategy})"
is_new ? created_count += 1 : updated_count += 1
else
error_msg = "Failed to save #{name}: #{provider.errors.full_messages.join(', ')}"
puts "ERROR: #{error_msg}"
errors << error_msg
end
end
else
puts "SKIP: #{name} (no changes)"
skipped_count += 1
end
end
# Rollback transaction if dry run
raise ActiveRecord::Rollback if dry_run
end
puts "-" * 80
puts "Summary:"
puts " Created: #{created_count}"
puts " Updated: #{updated_count}"
puts " Skipped: #{skipped_count}"
puts " Errors: #{errors.count}"
if errors.any?
puts "\nErrors encountered:"
errors.each { |error| puts " - #{error}" }
end
if dry_run
puts "\nDRY RUN: No changes were saved to the database"
puts "Run without DRY_RUN=true to apply changes"
else
puts "\nSeeding completed successfully!"
puts "Note: Clear provider cache or restart server for changes to take effect"
end
puts "=" * 80
rescue => e
puts "ERROR: #{e.class}: #{e.message}"
puts e.backtrace.first(5).join("\n")
exit 1
end
end
desc "List all SSO providers in the database"
task list: :environment do
providers = SsoProvider.order(:name)
if providers.empty?
puts "No SSO providers found in database"
else
puts "SSO Providers (#{providers.count}):"
puts "-" * 80
providers.each do |provider|
status = provider.enabled? ? "✓ enabled" : "✗ disabled"
puts "#{provider.name.ljust(20)} | #{provider.strategy.ljust(20)} | #{status}"
end
end
end
end