From d66c9c3822b2d0e8dce204dcea0ed072fbcbe56b Mon Sep 17 00:00:00 2001
From: pabois <pierreandre.boissinot@noesya.coop>
Date: Thu, 20 Oct 2022 12:29:56 +0200
Subject: [PATCH] sso on extranets

---
 app/models/communication/extranet.rb          | 26 ++++++++++++-------
 app/models/communication/extranet/with_sso.rb | 24 +++++++++++++++++
 app/views/devise/sessions/new.html.erb        |  4 +--
 ...02138_add_sso_to_communication_extranet.rb | 11 ++++++++
 db/schema.rb                                  |  9 ++++++-
 test/fixtures/communication/extranets.yml     | 25 +++++++++++-------
 test/models/communication/extranet_test.rb    | 25 +++++++++++-------
 7 files changed, 94 insertions(+), 30 deletions(-)
 create mode 100644 app/models/communication/extranet/with_sso.rb
 create mode 100644 db/migrate/20221020102138_add_sso_to_communication_extranet.rb

diff --git a/app/models/communication/extranet.rb b/app/models/communication/extranet.rb
index 01b34fd10..2bb62c7e0 100644
--- a/app/models/communication/extranet.rb
+++ b/app/models/communication/extranet.rb
@@ -2,15 +2,22 @@
 #
 # Table name: communication_extranets
 #
-#  id                   :uuid             not null, primary key
-#  about_type           :string           indexed => [about_id]
-#  domain               :string
-#  name                 :string
-#  registration_contact :string
-#  created_at           :datetime         not null
-#  updated_at           :datetime         not null
-#  about_id             :uuid             indexed => [about_type]
-#  university_id        :uuid             not null, indexed
+#  id                          :uuid             not null, primary key
+#  about_type                  :string           indexed => [about_id]
+#  domain                      :string
+#  has_sso                     :boolean          default(FALSE)
+#  name                        :string
+#  registration_contact        :string
+#  sso_cert                    :text
+#  sso_inherit_from_university :boolean          default(FALSE)
+#  sso_mapping                 :jsonb
+#  sso_name_identifier_format  :string
+#  sso_provider                :integer          default("saml")
+#  sso_target_url              :integer          default(0)
+#  created_at                  :datetime         not null
+#  updated_at                  :datetime         not null
+#  about_id                    :uuid             indexed => [about_type]
+#  university_id               :uuid             not null, indexed
 #
 # Indexes
 #
@@ -23,6 +30,7 @@
 #
 class Communication::Extranet < ApplicationRecord
   include WithAbouts
+  include WithSso
   include WithUniversity
 
   validates_presence_of :name, :domain
diff --git a/app/models/communication/extranet/with_sso.rb b/app/models/communication/extranet/with_sso.rb
new file mode 100644
index 000000000..8ad9136c4
--- /dev/null
+++ b/app/models/communication/extranet/with_sso.rb
@@ -0,0 +1,24 @@
+module Communication::Extranet::WithSso
+  extend ActiveSupport::Concern
+
+  included do
+    enum sso_provider: { saml: 0 }, _prefix: :with_sso_via
+
+    validates :sso_cert, :sso_name_identifier_format, :sso_target_url, presence: true, if: :has_sso?
+    validate :sso_mapping_should_have_email, if: :has_sso?
+  end
+
+  # Setter to serialize data as JSON
+  def sso_mapping=(value)
+    if value.empty?
+      value = nil
+    else
+      value = JSON.parse value if value.is_a? String
+    end
+    super(value)
+  end
+
+  def sso_mapping_should_have_email
+    errors.add(:sso_mapping, :missing_email) unless (sso_mapping || []).detect { |sso_item| sso_item['internal_key'] == 'email' }
+  end
+end
diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb
index 2a6344f84..bc136ca35 100644
--- a/app/views/devise/sessions/new.html.erb
+++ b/app/views/devise/sessions/new.html.erb
@@ -10,13 +10,13 @@
   </div>
   <div class="col-md-6">
     <h2 class="mb-4"><%= t('login.already_registered') %></h2>
-    <% if current_university.has_sso? %>
+    <% if current_context.has_sso? %>
       <p><%= link_to t('login.sign_in_with_sso'), omniauth_authorize_path(resource_name, current_university.sso_provider), method: :post, class: 'btn btn-primary' %></p>
       <p><%= t('login.or') %></p>
       <a href="#collapseLoginForm" class="btn btn-primary mb-3" data-bs-toggle="collapse"><%= t('login.sign_in_with_credentials') %></a>
     <% end %>
 
-    <div class="<%= 'collapse' if current_university.has_sso? %> <%= 'show' unless alert.blank? %>" id="collapseLoginForm">
+    <div class="<%= 'collapse' if current_context.has_sso? %> <%= 'show' unless alert.blank? %>" id="collapseLoginForm">
 
       <%= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
         <div class="form-inputs">
diff --git a/db/migrate/20221020102138_add_sso_to_communication_extranet.rb b/db/migrate/20221020102138_add_sso_to_communication_extranet.rb
new file mode 100644
index 000000000..0114f39af
--- /dev/null
+++ b/db/migrate/20221020102138_add_sso_to_communication_extranet.rb
@@ -0,0 +1,11 @@
+class AddSsoToCommunicationExtranet < ActiveRecord::Migration[6.1]
+  def change
+    add_column :communication_extranets, :has_sso, :boolean, default: false
+    add_column :communication_extranets, :sso_inherit_from_university, :boolean, default: false
+    add_column :communication_extranets, :sso_cert, :text
+    add_column :communication_extranets, :sso_mapping, :jsonb
+    add_column :communication_extranets, :sso_name_identifier_format, :string
+    add_column :communication_extranets, :sso_provider, :integer, default: 0
+    add_column :communication_extranets, :sso_target_url, :integer, default: 0
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 5876144fc..2d3b4b3f9 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 2022_10_17_142108) do
+ActiveRecord::Schema.define(version: 2022_10_20_102138) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "pgcrypto"
@@ -103,6 +103,13 @@ ActiveRecord::Schema.define(version: 2022_10_17_142108) do
     t.string "about_type"
     t.uuid "about_id"
     t.string "registration_contact"
+    t.boolean "has_sso", default: false
+    t.boolean "sso_inherit_from_university", default: false
+    t.text "sso_cert"
+    t.jsonb "sso_mapping"
+    t.string "sso_name_identifier_format"
+    t.integer "sso_provider", default: 0
+    t.integer "sso_target_url", default: 0
     t.index ["about_type", "about_id"], name: "index_communication_extranets_on_about"
     t.index ["university_id"], name: "index_communication_extranets_on_university_id"
   end
diff --git a/test/fixtures/communication/extranets.yml b/test/fixtures/communication/extranets.yml
index cba2a17ed..c1b066ad3 100644
--- a/test/fixtures/communication/extranets.yml
+++ b/test/fixtures/communication/extranets.yml
@@ -2,15 +2,22 @@
 #
 # Table name: communication_extranets
 #
-#  id                   :uuid             not null, primary key
-#  about_type           :string           indexed => [about_id]
-#  domain               :string
-#  name                 :string
-#  registration_contact :string
-#  created_at           :datetime         not null
-#  updated_at           :datetime         not null
-#  about_id             :uuid             indexed => [about_type]
-#  university_id        :uuid             not null, indexed
+#  id                          :uuid             not null, primary key
+#  about_type                  :string           indexed => [about_id]
+#  domain                      :string
+#  has_sso                     :boolean          default(FALSE)
+#  name                        :string
+#  registration_contact        :string
+#  sso_cert                    :text
+#  sso_inherit_from_university :boolean          default(FALSE)
+#  sso_mapping                 :jsonb
+#  sso_name_identifier_format  :string
+#  sso_provider                :integer          default("saml")
+#  sso_target_url              :integer          default(0)
+#  created_at                  :datetime         not null
+#  updated_at                  :datetime         not null
+#  about_id                    :uuid             indexed => [about_type]
+#  university_id               :uuid             not null, indexed
 #
 # Indexes
 #
diff --git a/test/models/communication/extranet_test.rb b/test/models/communication/extranet_test.rb
index c51aec18a..a15009595 100644
--- a/test/models/communication/extranet_test.rb
+++ b/test/models/communication/extranet_test.rb
@@ -2,15 +2,22 @@
 #
 # Table name: communication_extranets
 #
-#  id                   :uuid             not null, primary key
-#  about_type           :string           indexed => [about_id]
-#  domain               :string
-#  name                 :string
-#  registration_contact :string
-#  created_at           :datetime         not null
-#  updated_at           :datetime         not null
-#  about_id             :uuid             indexed => [about_type]
-#  university_id        :uuid             not null, indexed
+#  id                          :uuid             not null, primary key
+#  about_type                  :string           indexed => [about_id]
+#  domain                      :string
+#  has_sso                     :boolean          default(FALSE)
+#  name                        :string
+#  registration_contact        :string
+#  sso_cert                    :text
+#  sso_inherit_from_university :boolean          default(FALSE)
+#  sso_mapping                 :jsonb
+#  sso_name_identifier_format  :string
+#  sso_provider                :integer          default("saml")
+#  sso_target_url              :integer          default(0)
+#  created_at                  :datetime         not null
+#  updated_at                  :datetime         not null
+#  about_id                    :uuid             indexed => [about_type]
+#  university_id               :uuid             not null, indexed
 #
 # Indexes
 #
-- 
GitLab