From 09c9efa4068a065b45864607fd833e808a9db1fe Mon Sep 17 00:00:00 2001
From: Davide Depau <davide@rev.ng>
Date: Fri, 7 Apr 2023 12:08:34 +0200
Subject: [PATCH] Apply rev.ng customizations

---
 lib/saml_authenticator.rb | 76 ++++++++++++++++++++++++++-------------
 1 file changed, 52 insertions(+), 24 deletions(-)

diff --git a/lib/saml_authenticator.rb b/lib/saml_authenticator.rb
index 1cd5b1f..7d9c1c1 100644
--- a/lib/saml_authenticator.rb
+++ b/lib/saml_authenticator.rb
@@ -78,7 +78,7 @@ class SamlAuthenticator < ::Auth::ManagedAuthenticator
         want_assertions_signed: !!setting(:want_assertions_signed),
         logout_requests_signed: !!setting(:logout_requests_signed),
         logout_responses_signed: !!setting(:logout_responses_signed),
-        signature_method: XMLSecurity::Document::RSA_SHA1,
+        signature_method: XMLSecurity::Document::RSA_SHA256,
       },
       idp_slo_session_destroy:
         proc do |env, session|
@@ -91,9 +91,28 @@ class SamlAuthenticator < ::Auth::ManagedAuthenticator
     )
   end
 
+  # Only match by the NameID
+  def match_by_email
+    false
+  end
+
+  def match_by_username
+    false
+  end
+
+  def is_anonymous?(email)
+    email.start_with?("anonymous+") && email.end_with?("@rev.ng")
+  end
+
   def primary_email_verified?(auth_token)
     attributes = OneLogin::RubySaml::Attributes.new(auth_token.extra&.[](:raw_info) || {})
 
+    email = attributes.single("email")
+    return false if is_anonymous?(email)
+
+    email_verified = attributes.single("emailVerified")
+    return email_verified == "true" if attributes.include?("emailVerified")
+
     group_attribute = setting(:groups_attribute)
     if setting(:validate_email_fields).present? && attributes.multi(group_attribute).present?
       validate_email_fields = setting(:validate_email_fields).split("|").map(&:downcase)
@@ -110,12 +129,16 @@ class SamlAuthenticator < ::Auth::ManagedAuthenticator
     extra_data = auth.extra || {}
     attributes = extra_data[:raw_info] || OneLogin::RubySaml::Attributes.new
 
+    log("after_authenticate: auth: #{auth.inspect}")
+    log("after_authenticate: attributes: #{attributes.inspect}")
+    log("after_authenticate: extra_data: #{extra_data.inspect}")
+    log("after_authenticate: uid: #{attributes.single("uid")}, #{auth[:uid]}")
+
     auth[:uid] = attributes.single("uid") || auth[:uid] if setting(:use_attributes_uid)
     uid = auth[:uid]
 
-    auth.info[:email] ||= uid if uid.to_s&.include?("@")
-
-    auth.info[:nickname] = uid.to_s if uid && setting(:use_attributes_uid)
+    auth.info[:username] = attributes.single("username")
+    auth.info[:nickname] = attributes.single("username")
 
     auth.extra = { "raw_info" => attributes.attributes }
     result = super
@@ -133,22 +156,31 @@ class SamlAuthenticator < ::Auth::ManagedAuthenticator
 
     result.skip_email_validation = true if setting(:skip_email_validation)
 
-    if result.user.blank?
-      result.username = "" if setting(:clear_username)
-      result.user = auto_create_account(result, uid) if setting(:auto_create_account) &&
-        result.email_valid
+    email = attributes.single("email")
+
+    if not is_anonymous?(email)
+      if result.user.blank?
+        result.username = "" if setting(:clear_username)
+        result.user = auto_create_account(result, uid) if setting(:auto_create_account) &&
+          result.email_valid
+      else
+        user = result.user
+        sync_groups(user, attributes, info)
+        sync_custom_fields(user, attributes, info)
+        sync_moderator(user, attributes)
+        sync_admin(user, attributes)
+        sync_trust_level(user, attributes)
+        sync_locale(user, attributes)
+      end
     else
-      user = result.user
-      sync_groups(user, attributes, info)
-      sync_custom_fields(user, attributes, info)
-      sync_moderator(user, attributes)
-      sync_admin(user, attributes)
-      sync_trust_level(user, attributes)
-      sync_locale(user, attributes)
+      result.failed = true
+      result.failed_reason = "Anonymous users cannot access Discourse. " +
+        "Convert your account to a regular account to continue."
     end
 
     result.overrides_username = setting(:omit_username)
     result.overrides_email = setting(:sync_email)
+    result.overrides_name = true
 
     result
   end
@@ -278,8 +310,8 @@ class SamlAuthenticator < ::Auth::ManagedAuthenticator
   def sync_moderator(user, attributes)
     return unless setting(:sync_moderator)
 
-    is_moderator_attribute = setting(:moderator_attribute) || "isModerator"
-    is_moderator = %w[1 true].include?(attributes.single(is_moderator_attribute).to_s.downcase)
+    roles = attributes.multi("roles") || []
+    is_moderator = roles.include?("discourse-moderator") or roles.include?("discourse-admin")
 
     return if user.moderator == is_moderator
 
@@ -290,8 +322,8 @@ class SamlAuthenticator < ::Auth::ManagedAuthenticator
   def sync_admin(user, attributes)
     return unless setting(:sync_admin)
 
-    is_admin_attribute = setting(:admin_attribute) || "isAdmin"
-    is_admin = %w[1 true].include?(attributes.single(is_admin_attribute).to_s.downcase)
+    roles = attributes.multi("roles") || []
+    is_admin = roles.include?("discourse-admin")
 
     return if user.admin == is_admin
 
@@ -369,10 +401,6 @@ class SamlAuthenticator < ::Auth::ManagedAuthenticator
   end
 
   def resolve_username(username, name, email, uid)
-    suggester_input = [username, name]
-    suggester_input << email if SiteSetting.use_email_for_username_and_name_suggestions
-    suggester_input << uid
-
-    UserNameSuggester.suggest(*suggester_input)
+    username
   end
 end
-- 
GitLab