Skip to content
Snippets Groups Projects
Commit b1b98f7f authored by alexisben's avatar alexisben
Browse files

Merge branch 'master' of github.com:noesya/osuny

parents 41f9b075 6240941b
No related branches found
No related tags found
No related merge requests found
//= require vue/dist/vue.global.js
//= require vue/dist/vue.global.prod.js
//= require vue-draggable-next/dist/vue-draggable-next.global.js
[v-cloak]
form
form, .app-form
display: none
[data-v-app]
.spinner-border
......
......@@ -62,7 +62,7 @@ class Server::UniversitiesController < Server::ApplicationController
params.require(:university).permit(:name,
:address, :zipcode, :city, :country,
:private, :identifier, :logo, :logo_delete, :sms_sender_name,
:has_sso, :sso_target_url, :sso_cert, :sso_name_identifier_format,
:has_sso, :sso_target_url, :sso_cert, :sso_name_identifier_format, :sso_mapping,
:invoice_date, :invoice_amount)
end
end
......@@ -5,10 +5,9 @@ module User::WithOmniauth
def self.from_omniauth(university, attributes)
mapping = university.sso_mapping
email = 'pierreandre.boissinot@noesya.coop'
# email_sso_key = mapping.select { |elmt| elmt['internal_key'] == 'email' }&.first&.dig('sso_key')
email_sso_key = 'email'
# first step: we find the email (we are supposed to have an email mapping)
email_sso_key = mapping.select { |elmt| elmt['internal_key'] == 'email' }&.first&.dig('sso_key')
email = attributes.dig(email_sso_key)
return unless email
email = email.first if email.is_a?(Array)
......@@ -17,6 +16,47 @@ module User::WithOmniauth
user = User.where(university: university, email: email).first_or_create do |u|
u.password = "#{Devise.friendly_token[0,20]}!" # meets password complexity requirements
end
# update user data according to mapping & infos provided by SSO
mapping.select { |elmt| elmt['internal_key'] != 'email' }.each do |mapping_element|
user = self.update_data_for_mapping_element(user, mapping_element, attributes)
end
user.save
user
end
protected
def self.update_data_for_mapping_element(user, mapping_element, attributes)
sso_key = mapping_element['sso_key']
return user if attributes[sso_key].nil? # if not provided by sso, just return
internal_key = mapping_element['internal_key']
user = self.update_data_for_mapping_element_standard(user, mapping_element, self.get_provided_answer(attributes[sso_key]))
user
end
def self.update_data_for_mapping_element_standard(user, mapping_element, sso_value)
case mapping_element['internal_key']
when 'language'
user = self.set_best_id_for(user, mapping_element['type'], sso_value.first)
when 'role'
value = mapping_element['roles'].select { |key, val| val == sso_value.first }.first&.first
user['role'] = value if value
else
user[mapping_element['internal_key']] = sso_value.first
end
user
end
def self.get_provided_answer(value)
# SAML send an array (even for a single value) where OAuth2 send a string for single values. We harmonize to always get an array
value.is_a?(Array) ? value : [value]
end
def self.set_best_id_for(user, type, iso)
element_id = eval(type.classify).find_by(iso_code: iso)&.id
user["#{type}_id"] = element_id unless element_id.nil?
user
end
......
......@@ -6,7 +6,7 @@
%>
<div id="app" v-cloak>
<div class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
<span class="sr-only"><%= t 'loading' %></span>
</div>
<%= simple_form_for [:admin, @block] do |f| %>
<div class="row">
......
......@@ -28,16 +28,19 @@
</div>
</div>
<h3 class="mt-5"><%= t('university.sso') %></h3>
<div class="row">
<div class="col-md-6">
<h3 class="mt-5"><%= t('university.sso') %></h3>
<%= f.input :has_sso %>
<div id="sso-inputs">
<%= f.input :sso_target_url, required: true %>
<%= f.input :sso_cert, required: true %>
<%= f.input :sso_name_identifier_format, required: true %>
<%#= render 'sso_mapping', brand: brand %>
</div>
</div>
<div class="col-md-6">
<h4 class="mb-4"><%= University.human_attribute_name('sso_mapping') %></h4>
<%= render 'sso_mapping', university: university %>
</div>
</div>
......
<% mapping_keys = ['email', 'first_name', 'last_name', 'role', 'mobile_phone', 'language', 'picture_url'] %>
<%# Include vue.js before call Vue.createApp %>
<%= javascript_include_tag 'vue' %>
<div id="app" v-cloak>
<div class="spinner-border text-primary" role="status">
<span class="sr-only"><%= t('loading') %></span>
</div>
<div class="app-form">
<draggable :list="fields">
<div v-for="(field, index) in fields">
<div class="card">
<div class="card-header d-flex justify-content-between">
<a data-bs-toggle="collapse" :href="'#sso_mapping_collapse_' + index ">
{{index + 1}}. {{ field.sso_key }} -> {{ keys[field.internal_key]}}
</a>
<a
v-on:click="fields.splice(fields.indexOf(field), 1)"
title="Remove field">
<i class="far fa-trash-alt"></i>
</a>
</div>
<div class="card-body collapse pt-0" :id="'sso_mapping_collapse_' + index ">
<hr class="mt-0">
<div class="form-group">
<label for="" class="form-control-label"><%= t('university.sso_key') %> <abbr title="required">*</abbr></label>
<input
v-model="field.sso_key"
type="text" class="form-control">
</div>
<div class="form-group">
<label for="" class="form-control-label"><%= t('university.internal_key') %> <abbr title="required">*</abbr></label>
<select v-model="field.internal_key" id="" class="form-select" required>
<option v-for="(label, key) in keys" :value="key">{{ label }}</option>
</select>
</div>
<div v-if="field.internal_key === 'role'">
<hr class="mt-4">
<% User.roles.keys.each do |role| %>
<div class="form-group">
<label for="" class="form-label"><%= t("activerecord.attributes.user.roles.#{role}") %></label>
<input v-model="field.roles.<%= role %>" type="text" class="form-control">
</div>
<% end %>
</div>
</div>
</div>
</div>
</draggable>
<a v-on:click="fields.push({sso_key: 'key', internal_key: 'email', roles: {}})" class="btn btn-primary btn-sm">
<%= t('add_field') %>
</a>
</div>
<textarea name="university[sso_mapping]" id="university_sso_mapping" rows="20" cols="200" class="d-none">
{{ JSON.stringify(fields) }}
</textarea>
</div>
<script>
var app = Vue.createApp({
components: {
draggable: VueDraggableNext.VueDraggableNext,
},
data() {
return {
fields: <%= university.sso_mapping.blank? ? '[]' : university.sso_mapping.to_json.html_safe %>,
keys: <%= mapping_keys.map { |key| [key, User.human_attribute_name(key)] }.to_h.to_json.html_safe %>
}
}
});
window.addEventListener('load', function(){
setTimeout(function() {
app.mount('#app');
}, 1000);
});
</script>
......@@ -38,6 +38,7 @@ en:
one: User
other: Users
add: Add
add_field: Add field
admin:
attachment_not_available: Attachment not available
dashboard: Dashboard
......
......@@ -38,6 +38,7 @@ fr:
one: Utilisateur·rice
other: Utilisateur·rice·s
add: Ajouter
add_field: Ajouter un champ
admin:
attachment_not_available: Impossible d'accéder à l'élément
dashboard: Tableau de bord
......
......@@ -16,6 +16,7 @@ en:
public_or_private: Public/private
sms_sender_name: SMS sender name
sso_cert: Certificate
sso_mapping: Mapping
sso_name_identifier_format: Name Identifier Format
sso_target_url: Target URL
url: URL
......@@ -125,8 +126,10 @@ en:
non_profit: Association
government: Government
university:
internal_key: Internal Key
invoice_informations: Invoice informations
person:
administrator_roles: Administrator roles
taught_programs: Taught programs
sso: SSO
sso_key: SSO Key
......@@ -16,6 +16,7 @@ fr:
public_or_private: Public/privé
sms_sender_name: Nom de l'expéditeur SMS
sso_cert: Certificat
sso_mapping: Mapping
sso_name_identifier_format: Name Identifier Format
sso_target_url: URL cible
url: 'URL'
......@@ -125,8 +126,10 @@ fr:
non_profit: Association
government: Structure gouvernementale
university:
internal_key: Clé interne
invoice_informations: Données de facturation
person:
administrator_roles: Rôles administratifs
taught_programs: Formations enseignées
sso: SSO
sso_key: Clé sur le SSO
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment