class User < ApplicationRecord has_secure_password has_many :sessions, dependent: :destroy normalizes :email_address, with: ->(e) { e.strip.downcase } enum :role, { admin: 0, user: 1, viewer: 2 }, default: :user validates :email_address, presence: true, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP } validates :role, presence: true before_validation :set_first_user_as_admin, on: :create def self.from_oidc(auth_hash) # Extract user info from OIDC auth hash email = auth_hash.dig('info', 'email') return nil unless email user = find_or_initialize_by(email_address: email) # Map OIDC groups to role if auth_hash.dig('extra', 'raw_info', 'groups') user.role = map_oidc_groups_to_role(auth_hash.dig('extra', 'raw_info', 'groups')) end # Don't override password for OIDC users user.save!(validate: false) if user.new_record? user end def admin? role == 'admin' end def viewer? role == 'viewer' end private def set_first_user_as_admin return if User.any? self.role = 'admin' end def self.map_oidc_groups_to_role(groups) groups = Array(groups) # Check admin groups first admin_groups = ENV['OIDC_ADMIN_GROUPS']&.split(',')&.map(&:strip) return 'admin' if admin_groups && (admin_groups & groups).any? # Check user groups user_groups = ENV['OIDC_USER_GROUPS']&.split(',')&.map(&:strip) return 'user' if user_groups && (user_groups & groups).any? # Check viewer groups viewer_groups = ENV['OIDC_VIEWER_GROUPS']&.split(',')&.map(&:strip) return 'viewer' if viewer_groups && (viewer_groups & groups).any? # Default to user if no group matches 'user' end end