From c2118f4830020631ab228c59c8b9247a13655ae6 Mon Sep 17 00:00:00 2001 From: guillaume Date: Fri, 1 Feb 2019 19:00:44 +0100 Subject: [PATCH 1/3] Improve authentication --- client/components/main/layouts.jade | 6 +- client/components/main/layouts.js | 127 +++++++++++--------- client/components/settings/settingBody.jade | 19 +++ client/components/settings/settingBody.js | 37 +++++- models/settings.js | 11 +- server/migrations.js | 24 ++++ server/publications/settings.js | 12 +- 7 files changed, 169 insertions(+), 67 deletions(-) diff --git a/client/components/main/layouts.jade b/client/components/main/layouts.jade index 55ee2686a..a6115ec12 100644 --- a/client/components/main/layouts.jade +++ b/client/components/main/layouts.jade @@ -23,10 +23,8 @@ template(name="userFormsLayout") br section.auth-dialog +Template.dynamic(template=content) - +connectionMethod - if isCas - .at-form - button#cas(class='at-btn submit' type='submit') {{casSignInLabel}} + if currentSetting.displayAuthenticationMethod + +connectionMethod div.at-form-lang select.select-lang.js-userform-set-language each languages diff --git a/client/components/main/layouts.js b/client/components/main/layouts.js index a50d167e3..2e0575688 100644 --- a/client/components/main/layouts.js +++ b/client/components/main/layouts.js @@ -20,13 +20,19 @@ const validator = { }, }; -Template.userFormsLayout.onCreated(() => { - Meteor.subscribe('setting'); +Template.userFormsLayout.onCreated(function() { + const instance = this; + instance.currentSetting = new ReactiveVar(); + Meteor.subscribe('setting', { + onReady() { + instance.currentSetting.set(Settings.findOne()); + return this.stop(); + } + }); }); Template.userFormsLayout.onRendered(() => { - AccountsTemplates.state.form.keys = new Proxy(AccountsTemplates.state.form.keys, validator); const i18nTag = navigator.language; @@ -37,12 +43,10 @@ Template.userFormsLayout.onRendered(() => { }); Template.userFormsLayout.helpers({ - currentSetting() { - return Settings.findOne(); + return Template.instance().currentSetting.get(); }, - afterBodyStart() { return currentSetting.customHTMLafterBodyStart; }, @@ -75,17 +79,6 @@ Template.userFormsLayout.helpers({ const curLang = T9n.getLanguage() || 'en'; return t9nTag === curLang; }, -/* - isCas() { - return Meteor.settings.public && - Meteor.settings.public.cas && - Meteor.settings.public.cas.loginUrl; - }, - - casSignInLabel() { - return TAPi18n.__('casSignIn', {}, T9n.getLanguage() || 'en'); - }, -*/ }); Template.userFormsLayout.events({ @@ -94,49 +87,9 @@ Template.userFormsLayout.events({ T9n.setLanguage(i18nTagToT9n(i18nTag)); evt.preventDefault(); }, - 'click button#cas'() { - Meteor.loginWithCas(function() { - if (FlowRouter.getRouteName() === 'atSignIn') { - FlowRouter.go('/'); - } - }); - }, - 'click #at-btn'(event) { - /* All authentication method can be managed/called here. - !! DON'T FORGET to correctly fill the fields of the user during its creation if necessary authenticationMethod : String !! - */ - const authenticationMethodSelected = $('.select-authentication').val(); - // Local account - if (authenticationMethodSelected === 'password') { - return; - } - - // Stop submit #at-pwd-form - event.preventDefault(); - event.stopImmediatePropagation(); - - const email = $('#at-field-username_and_email').val(); - const password = $('#at-field-password').val(); - - // Ldap account - if (authenticationMethodSelected === 'ldap') { - // Check if the user can use the ldap connection - Meteor.subscribe('user-authenticationMethod', email, { - onReady() { - const user = Users.findOne(); - if (user === undefined || user.authenticationMethod === 'ldap') { - // Use the ldap connection package - Meteor.loginWithLDAP(email, password, function(error) { - if (!error) { - // Connection - return FlowRouter.go('/'); - } - return error; - }); - } - return this.stop(); - }, - }); + 'click #at-btn'(event, instance) { + if (FlowRouter.getRouteName() === 'atSignIn') { + authentication(event, instance); } }, }); @@ -146,3 +99,57 @@ Template.defaultLayout.events({ Modal.close(); }, }); + +async function authentication(event, instance) { + const match = $('#at-field-username_and_email').val(); + const password = $('#at-field-password').val(); + + if (!match || !password) return; + + const result = await getAuthenticationMethod(instance.currentSetting.get(), match); + + if (result === 'password') return; + + // Stop submit #at-pwd-form + event.preventDefault(); + event.stopImmediatePropagation(); + + if (result === 'ldap') { + return Meteor.loginWithLDAP(match, password, function() { + FlowRouter.go('/'); + }); + } + + if (result === 'cas') { + return Meteor.loginWithCas(function() { + FlowRouter.go('/'); + }); + } +} + +function getAuthenticationMethod({displayAuthenticationMethod, defaultAuthenticationMethod}, match) { + if (displayAuthenticationMethod) { + return $('.select-authentication').val(); + } + return getUserAuthenticationMethod(defaultAuthenticationMethod, match); +} + +function getUserAuthenticationMethod(defaultAuthenticationMethod, match) { + return new Promise((resolve, reject) => { + try { + Meteor.subscribe('user-authenticationMethod', match, { + onReady() { + const user = Users.findOne(); + + const authenticationMethod = user + ? user.authenticationMethod + : defaultAuthenticationMethod; + + resolve(authenticationMethod); + }, + }); + } catch(error) { + resolve(defaultAuthenticationMethod); + } + }) +} diff --git a/client/components/settings/settingBody.jade b/client/components/settings/settingBody.jade index 153649fcf..220dbb508 100644 --- a/client/components/settings/settingBody.jade +++ b/client/components/settings/settingBody.jade @@ -141,6 +141,16 @@ template(name='layoutSettings') span {{_ 'yes'}} input.form-control#hide-logo(type="radio" name="hideLogo" value="false" checked="{{#unless currentSetting.hideLogo}}checked{{/unless}}") span {{_ 'no'}} + li.layout-form + .title {{_ 'display-authentication-method'}} + .form-group.flex + input.form-control#display-authentication-method(type="radio" name="displayAuthenticationMethod" value="true" checked="{{#if currentSetting.displayAuthenticationMethod}}checked{{/if}}") + span {{_ 'yes'}} + input.form-control#display-authentication-method(type="radio" name="displayAuthenticationMethod" value="false" checked="{{#unless currentSetting.displayAuthenticationMethod}}checked{{/unless}}") + span {{_ 'no'}} + li.layout-form + .title {{_ 'default-authentication-method'}} + +selectAuthenticationMethod(authenticationMethod=currentSetting.defaultAuthenticationMethod) li.layout-form .title {{_ 'custom-product-name'}} .form-group @@ -153,3 +163,12 @@ template(name='layoutSettings') textarea#customHTMLbeforeBodyEnd.form-control= currentSetting.customHTMLbeforeBodyEnd li button.js-save-layout.primary {{_ 'save'}} + + +template(name='selectAuthenticationMethod') + select#defaultAuthenticationMethod + each authentications + if isSelected value + option(value="{{value}}" selected) {{_ value}} + else + option(value="{{value}}") {{_ value}} \ No newline at end of file diff --git a/client/components/settings/settingBody.js b/client/components/settings/settingBody.js index 4f07c84c4..1d05a8c77 100644 --- a/client/components/settings/settingBody.js +++ b/client/components/settings/settingBody.js @@ -62,6 +62,9 @@ BlazeComponent.extendComponent({ toggleHideLogo() { $('#hide-logo').toggleClass('is-checked'); }, + toggleDisplayAuthenticationMethod() { + $('#display-authentication-method').toggleClass('is-checked'); + }, switchMenu(event) { const target = $(event.target); if (!target.hasClass('active')) { @@ -140,17 +143,20 @@ BlazeComponent.extendComponent({ const productName = $('#product-name').val().trim(); const hideLogoChange = ($('input[name=hideLogo]:checked').val() === 'true'); + const displayAuthenticationMethod = ($('input[name=displayAuthenticationMethod]:checked').val() === 'true'); + const defaultAuthenticationMethod = $('#defaultAuthenticationMethod').val(); const customHTMLafterBodyStart = $('#customHTMLafterBodyStart').val().trim(); const customHTMLbeforeBodyEnd = $('#customHTMLbeforeBodyEnd').val().trim(); try { - Settings.update(Settings.findOne()._id, { $set: { productName, hideLogo: hideLogoChange, customHTMLafterBodyStart, customHTMLbeforeBodyEnd, + displayAuthenticationMethod, + defaultAuthenticationMethod }, }); } catch (e) { @@ -190,6 +196,7 @@ BlazeComponent.extendComponent({ 'click button.js-send-smtp-test-email': this.sendSMTPTestEmail, 'click a.js-toggle-hide-logo': this.toggleHideLogo, 'click button.js-save-layout': this.saveLayout, + 'click a.js-toggle-display-authentication-method': this.toggleDisplayAuthenticationMethod }]; }, }).register('setting'); @@ -262,3 +269,31 @@ BlazeComponent.extendComponent({ }]; }, }).register('announcementSettings'); + + +Template.selectAuthenticationMethod.onCreated(function() { + this.authenticationMethods = new ReactiveVar([]); + + Meteor.call('getAuthenticationsEnabled', (_, result) => { + if (result) { + // TODO : add a management of different languages + // (ex {value: ldap, text: TAPi18n.__('ldap', {}, T9n.getLanguage() || 'en')}) + this.authenticationMethods.set([ + {value: 'password'}, + // Gets only the authentication methods availables + ...Object.entries(result).filter((e) => e[1]).map((e) => ({value: e[0]})), + ]); + } + }); +}); + +Template.selectAuthenticationMethod.helpers({ + authentications() { + return Template.instance().authenticationMethods.get(); + }, + isSelected(match) { + console.log('this : ', this); + console.log('instance : ', Template.instance()); + return Template.instance().data.authenticationMethod === match; + } +}); \ No newline at end of file diff --git a/models/settings.js b/models/settings.js index 674c99a02..5dd28448f 100644 --- a/models/settings.js +++ b/models/settings.js @@ -40,6 +40,14 @@ Settings.attachSchema(new SimpleSchema({ type: String, optional: true, }, + displayAuthenticationMethod: { + type: Boolean, + optional: true, + }, + defaultAuthenticationMethod: { + type: String, + optional: false, + }, hideLogo: { type: Boolean, optional: true, @@ -85,7 +93,8 @@ if (Meteor.isServer) { const from = `Boards Support `; const defaultSetting = {disableRegistration: false, mailServer: { username: '', password: '', host: '', port: '', enableTLS: false, from, - }, createdAt: now, modifiedAt: now}; + }, createdAt: now, modifiedAt: now, displayAuthenticationMethod: true, + defaultAuthenticationMethod: 'password'}; Settings.insert(defaultSetting); } const newSetting = Settings.findOne(); diff --git a/server/migrations.js b/server/migrations.js index 2512b40c1..a18ebd718 100644 --- a/server/migrations.js +++ b/server/migrations.js @@ -398,3 +398,27 @@ Migrations.add('add-custom-html-before-body-end', () => { }, }, noValidateMulti); }); + +Migrations.add('add-displayAuthenticationMethod', () => { + Settings.update({ + displayAuthenticationMethod: { + $exists: false, + }, + }, { + $set: { + displayAuthenticationMethod: true, + }, + }, noValidateMulti) +}); + +Migrations.add('add-defaultAuthenticationMethod', () => { + Settings.update({ + defaultAuthenticationMethod: { + $exists: false, + }, + }, { + $set: { + defaultAuthenticationMethod: 'password', + }, + }, noValidateMulti) +}); \ No newline at end of file diff --git a/server/publications/settings.js b/server/publications/settings.js index 573a79b47..4e587f4ce 100644 --- a/server/publications/settings.js +++ b/server/publications/settings.js @@ -1,5 +1,15 @@ Meteor.publish('setting', () => { - return Settings.find({}, {fields:{disableRegistration: 1, productName: 1, hideLogo: 1, customHTMLafterBodyStart: 1, customHTMLbeforeBodyEnd: 1}}); + return Settings.find({}, { + fields:{ + disableRegistration: 1, + productName: 1, + hideLogo: 1, + customHTMLafterBodyStart: 1, + customHTMLbeforeBodyEnd: 1, + displayAuthenticationMethod: 1, + defaultAuthenticationMethod: 1 + } + }); }); Meteor.publish('mailServer', function () { From de9965213ae32f4c314dd1a791891e01d12da1dd Mon Sep 17 00:00:00 2001 From: Lauri Ojansivu Date: Fri, 1 Feb 2019 21:26:04 +0200 Subject: [PATCH 2/3] - Fix lint errors. Thanks to xet7 ! --- client/components/main/layouts.js | 8 ++++---- client/components/settings/settingBody.js | 15 +++++---------- models/settings.js | 2 +- server/migrations.js | 6 +++--- server/publications/settings.js | 4 ++-- 5 files changed, 15 insertions(+), 20 deletions(-) diff --git a/client/components/main/layouts.js b/client/components/main/layouts.js index 2e0575688..73da80e5d 100644 --- a/client/components/main/layouts.js +++ b/client/components/main/layouts.js @@ -28,7 +28,7 @@ Template.userFormsLayout.onCreated(function() { onReady() { instance.currentSetting.set(Settings.findOne()); return this.stop(); - } + }, }); }); @@ -140,16 +140,16 @@ function getUserAuthenticationMethod(defaultAuthenticationMethod, match) { Meteor.subscribe('user-authenticationMethod', match, { onReady() { const user = Users.findOne(); - + const authenticationMethod = user ? user.authenticationMethod : defaultAuthenticationMethod; - + resolve(authenticationMethod); }, }); } catch(error) { resolve(defaultAuthenticationMethod); } - }) + }); } diff --git a/client/components/settings/settingBody.js b/client/components/settings/settingBody.js index 1d05a8c77..2f58d5515 100644 --- a/client/components/settings/settingBody.js +++ b/client/components/settings/settingBody.js @@ -156,7 +156,7 @@ BlazeComponent.extendComponent({ customHTMLafterBodyStart, customHTMLbeforeBodyEnd, displayAuthenticationMethod, - defaultAuthenticationMethod + defaultAuthenticationMethod, }, }); } catch (e) { @@ -171,17 +171,14 @@ BlazeComponent.extendComponent({ sendSMTPTestEmail() { Meteor.call('sendSMTPTestEmail', (err, ret) => { - if (!err && ret) { /* eslint-disable no-console */ + if (!err && ret) { const message = `${TAPi18n.__(ret.message)}: ${ret.email}`; - console.log(message); alert(message); } else { const reason = err.reason || ''; const message = `${TAPi18n.__(err.error)}\n${reason}`; - console.log(message, err); alert(message); } - /* eslint-enable no-console */ }); }, @@ -196,7 +193,7 @@ BlazeComponent.extendComponent({ 'click button.js-send-smtp-test-email': this.sendSMTPTestEmail, 'click a.js-toggle-hide-logo': this.toggleHideLogo, 'click button.js-save-layout': this.saveLayout, - 'click a.js-toggle-display-authentication-method': this.toggleDisplayAuthenticationMethod + 'click a.js-toggle-display-authentication-method': this.toggleDisplayAuthenticationMethod, }]; }, }).register('setting'); @@ -292,8 +289,6 @@ Template.selectAuthenticationMethod.helpers({ return Template.instance().authenticationMethods.get(); }, isSelected(match) { - console.log('this : ', this); - console.log('instance : ', Template.instance()); return Template.instance().data.authenticationMethod === match; - } -}); \ No newline at end of file + }, +}); diff --git a/models/settings.js b/models/settings.js index 5dd28448f..4fcc36ac9 100644 --- a/models/settings.js +++ b/models/settings.js @@ -93,7 +93,7 @@ if (Meteor.isServer) { const from = `Boards Support `; const defaultSetting = {disableRegistration: false, mailServer: { username: '', password: '', host: '', port: '', enableTLS: false, from, - }, createdAt: now, modifiedAt: now, displayAuthenticationMethod: true, + }, createdAt: now, modifiedAt: now, displayAuthenticationMethod: true, defaultAuthenticationMethod: 'password'}; Settings.insert(defaultSetting); } diff --git a/server/migrations.js b/server/migrations.js index a18ebd718..8dcd892ad 100644 --- a/server/migrations.js +++ b/server/migrations.js @@ -408,7 +408,7 @@ Migrations.add('add-displayAuthenticationMethod', () => { $set: { displayAuthenticationMethod: true, }, - }, noValidateMulti) + }, noValidateMulti); }); Migrations.add('add-defaultAuthenticationMethod', () => { @@ -420,5 +420,5 @@ Migrations.add('add-defaultAuthenticationMethod', () => { $set: { defaultAuthenticationMethod: 'password', }, - }, noValidateMulti) -}); \ No newline at end of file + }, noValidateMulti); +}); diff --git a/server/publications/settings.js b/server/publications/settings.js index 4e587f4ce..a8f8a9693 100644 --- a/server/publications/settings.js +++ b/server/publications/settings.js @@ -7,8 +7,8 @@ Meteor.publish('setting', () => { customHTMLafterBodyStart: 1, customHTMLbeforeBodyEnd: 1, displayAuthenticationMethod: 1, - defaultAuthenticationMethod: 1 - } + defaultAuthenticationMethod: 1, + }, }); }); From ec453b89b8238adcbb9334e1d006675aa8a7fe06 Mon Sep 17 00:00:00 2001 From: guillaume Date: Thu, 7 Feb 2019 11:38:04 +0100 Subject: [PATCH 3/3] Fix lints --- client/components/main/layouts.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/client/components/main/layouts.js b/client/components/main/layouts.js index 73da80e5d..6f7c914a0 100644 --- a/client/components/main/layouts.js +++ b/client/components/main/layouts.js @@ -114,16 +114,21 @@ async function authentication(event, instance) { event.preventDefault(); event.stopImmediatePropagation(); - if (result === 'ldap') { - return Meteor.loginWithLDAP(match, password, function() { + switch (result) { + case 'ldap': + Meteor.loginWithLDAP(match, password, function() { FlowRouter.go('/'); }); - } + break; - if (result === 'cas') { - return Meteor.loginWithCas(function() { + case 'cas': + Meteor.loginWithCas(function() { FlowRouter.go('/'); }); + break; + + default: + break; } } @@ -135,7 +140,7 @@ function getAuthenticationMethod({displayAuthenticationMethod, defaultAuthentica } function getUserAuthenticationMethod(defaultAuthenticationMethod, match) { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { try { Meteor.subscribe('user-authenticationMethod', match, { onReady() {