# frozen_string_literal: true

# name: discourse-saml
# about: SAML Auth Provider
# version: 0.1
# author: Robin Ward
# url: https://github.com/discourse/discourse-saml

require_dependency 'auth/oauth2_authenticator'

gem 'macaddr', '1.0.0'
gem 'uuid', '2.3.7'
gem 'rexml', '3.2.5'
gem 'ruby-saml', '1.13.0'
gem "omniauth-saml", '1.9.0'

on(:before_session_destroy) do |data|
  next if !GlobalSetting.try(:saml_slo_target_url).present?
  data[:redirect_url] = Discourse.base_path + "/auth/saml/spslo"
end

module ::DiscourseSaml
  def self.is_saml_forced_domain?(email)
    return if !GlobalSetting.try(:saml_forced_domains).present?
    return if email.blank?

    GlobalSetting.saml_forced_domains.split(",").each do |domain|
      return true if email.end_with?("@#{domain}")
    end

    false
  end
end

after_initialize do
  # "SAML Forced Domains" - Prevent login via email
  on(:before_email_login) do |user|
    if ::DiscourseSaml.is_saml_forced_domain?(user.email)
      raise Discourse::InvalidAccess.new(nil, nil, custom_message: "login.use_saml_auth")
    end
  end

  # "SAML Forced Domains" - Prevent login via regular username/password
  module ::DiscourseSaml::SessionControllerExtensions
    def login_error_check(user)
      if ::DiscourseSaml.is_saml_forced_domain?(user.email)
        return { error: I18n.t("login.use_saml_auth") }
      end
      super
    end
  end
  ::SessionController.prepend(::DiscourseSaml::SessionControllerExtensions)

  # "SAML Forced Dvomains" - Prevent login via other omniauth strategies
  class ::DiscourseSaml::ForcedSamlError < StandardError; end
  on(:after_auth) do |authenticator, result|
    next if authenticator.name == "saml"
    if [result.user&.email, result.email].any? { |e| ::DiscourseSaml.is_saml_forced_domain?(e) }
      raise ::DiscourseSaml::ForcedSamlError
    end
  end
  Users::OmniauthCallbacksController.rescue_from(::DiscourseSaml::ForcedSamlError) do
    flash[:error] = I18n.t("login.use_saml_auth")
    render('failure')
  end
end

require_relative "lib/discourse_saml/saml_omniauth_strategy"
require_relative "lib/saml_authenticator"

pretty_name = GlobalSetting.try(:saml_title) || "SAML"
button_title = GlobalSetting.try(:saml_button_title) || GlobalSetting.try(:saml_title) || "with SAML"

auth_provider title: button_title,
              pretty_name: pretty_name,
              authenticator: SamlAuthenticator.new('saml')