diff --git a/data/conf/phpfpm/crons/keycloak-sync.php b/data/conf/phpfpm/crons/keycloak-sync.php
index cdc5a6e99..8c2e66584 100644
--- a/data/conf/phpfpm/crons/keycloak-sync.php
+++ b/data/conf/phpfpm/crons/keycloak-sync.php
@@ -154,17 +154,6 @@ while (true) {
logMsg("warning", "No email address in keycloak found for user " . $user['name']);
continue;
}
- if (!isset($user['attributes'])){
- logMsg("warning", "No attributes in keycloak found for user " . $user['email']);
- continue;
- }
- if (!isset($user['attributes']['mailcow_template']) ||
- !is_array($user['attributes']['mailcow_template']) ||
- count($user['attributes']['mailcow_template']) == 0) {
- logMsg("warning", "No mailcow_template in keycloak found for user " . $user['email']);
- continue;
- }
- $mailcow_template = $user['attributes']['mailcow_template'];
// try get mailbox user
$stmt = $pdo->prepare("SELECT
@@ -178,20 +167,22 @@ while (true) {
$row = $stmt->fetch(PDO::FETCH_ASSOC);
// check if matching attribute mapping exists
- $mbox_template = null;
- foreach ($iam_settings['mappers'] as $index => $mapper){
- if (in_array($mapper, $user['attributes']['mailcow_template'])) {
- $mbox_template = $mapper;
- break;
- }
- }
- if (!$mbox_template){
- logMsg("warning", "No matching attribute mapping found for user " . $user['email']);
- continue;
- }
+ $user_template = $user['attributes']['mailcow_template'][0];
+ $mapper_key = array_search($user_template, $iam_settings['mappers']);
$_SESSION['access_all_exception'] = '1';
if (!$row && intval($iam_settings['import_users']) == 1){
+ if ($mapper_key === false){
+ if (!empty($iam_settings['default_template'])) {
+ $mbox_template = $iam_settings['default_template'];
+ logMsg("warning", "Using default template for user " . $user['email']);
+ } else {
+ logMsg("warning", "No matching attribute mapping found for user " . $user['email']);
+ continue;
+ }
+ } else {
+ $mbox_template = $iam_settings['templates'][$mapper_key];
+ }
// mailbox user does not exist, create...
logMsg("info", "Creating user " . $user['email']);
$create_res = mailbox('add', 'mailbox_from_template', array(
@@ -206,6 +197,11 @@ while (true) {
continue;
}
} else if ($row && intval($iam_settings['periodic_sync']) == 1) {
+ if ($mapper_key === false){
+ logMsg("warning", "No matching attribute mapping found for user " . $user['email']);
+ continue;
+ }
+ $mbox_template = $iam_settings['templates'][$mapper_key];
// mailbox user does exist, sync attribtues...
logMsg("info", "Syncing attributes for user " . $user['email']);
mailbox('edit', 'mailbox_from_template', array(
diff --git a/data/conf/phpfpm/crons/ldap-sync.php b/data/conf/phpfpm/crons/ldap-sync.php
index 17000997c..648f46c95 100644
--- a/data/conf/phpfpm/crons/ldap-sync.php
+++ b/data/conf/phpfpm/crons/ldap-sync.php
@@ -137,17 +137,8 @@ foreach ($response as $user) {
$row = $stmt->fetch(PDO::FETCH_ASSOC);
// check if matching attribute mapping exists
- $mbox_template = null;
- foreach ($iam_settings['mappers'] as $index => $mapper){
- if ($mapper == $mailcow_template) {
- $mbox_template = $iam_settings['templates'][$index];
- break;
- }
- }
- if (!$mbox_template){
- logMsg("warning", "No matching attribute mapping found for user " . $user[$iam_settings['username_field']][0]);
- continue;
- }
+ $user_template = $user_res[$iam_settings['attribute_field']][0];
+ $mapper_key = array_search($user_template, $iam_settings['mappers']);
if (empty($user[$iam_settings['username_field']][0])){
logMsg("warning", "Skipping user " . $user['displayname'][0] . " due to empty LDAP ". $iam_settings['username_field'] . " property.");
@@ -156,6 +147,16 @@ foreach ($response as $user) {
$_SESSION['access_all_exception'] = '1';
if (!$row && intval($iam_settings['import_users']) == 1){
+ if ($mapper_key === false){
+ if (!empty($iam_settings['default_template'])) {
+ $mbox_template = $iam_settings['default_template'];
+ } else {
+ logMsg("warning", "No matching attribute mapping found for user " . $user[$iam_settings['username_field']][0]);
+ continue;
+ }
+ } else {
+ $mbox_template = $iam_settings['templates'][$mapper_key];
+ }
// mailbox user does not exist, create...
logMsg("info", "Creating user " . $user[$iam_settings['username_field']][0]);
$create_res = mailbox('add', 'mailbox_from_template', array(
@@ -170,6 +171,11 @@ foreach ($response as $user) {
continue;
}
} else if ($row && intval($iam_settings['periodic_sync']) == 1) {
+ if ($mapper_key === false){
+ logMsg("warning", "No matching attribute mapping found for user " . $user[$iam_settings['username_field']][0]);
+ continue;
+ }
+ $mbox_template = $iam_settings['templates'][$mapper_key];
// mailbox user does exist, sync attribtues...
logMsg("info", "Syncing attributes for user " . $user[$iam_settings['username_field']][0]);
mailbox('edit', 'mailbox_from_template', array(
diff --git a/data/web/inc/functions.auth.inc.php b/data/web/inc/functions.auth.inc.php
index 7fd535be1..f432c3834 100644
--- a/data/web/inc/functions.auth.inc.php
+++ b/data/web/inc/functions.auth.inc.php
@@ -529,12 +529,18 @@ function keycloak_mbox_login_rest($user, $pass, $extra = null){
// check if matching attribute exist
if (empty($iam_settings['mappers']) || !$user_template || $mapper_key === false) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $user, '*', 'No matching attribute mapping was found'),
- 'msg' => 'generic_server_error'
- );
- return false;
+ if (!empty($iam_settings['default_template'])) {
+ $mbox_template = $iam_settings['default_template'];
+ } else {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $user, '*', 'No matching attribute mapping was found'),
+ 'msg' => 'generic_server_error'
+ );
+ return false;
+ }
+ } else {
+ $mbox_template = $iam_settings['templates'][$mapper_key];
}
// create mailbox
@@ -544,7 +550,7 @@ function keycloak_mbox_login_rest($user, $pass, $extra = null){
'local_part' => explode('@', $user)[0],
'name' => $user_res['name'],
'authsource' => 'keycloak',
- 'template' => $iam_settings['templates'][$mapper_key]
+ 'template' => $mbox_template
));
$_SESSION['access_all_exception'] = '0';
if (!$create_res){
@@ -636,12 +642,18 @@ function ldap_mbox_login($user, $pass, $extra = null){
// check if matching attribute exist
if (empty($iam_settings['mappers']) || !$user_template || $mapper_key === false) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $user, '*', 'No matching attribute mapping was found'),
- 'msg' => 'generic_server_error'
- );
- return false;
+ if (!empty($iam_settings['default_tempalte'])) {
+ $mbox_template = $iam_settings['default_tempalte'];
+ } else {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $user, '*', 'No matching attribute mapping was found'),
+ 'msg' => 'generic_server_error'
+ );
+ return false;
+ }
+ } else {
+ $mbox_template = $iam_settings['templates'][$mapper_key];
}
// create mailbox
@@ -651,7 +663,7 @@ function ldap_mbox_login($user, $pass, $extra = null){
'local_part' => explode('@', $user)[0],
'name' => $user_res['displayname'][0],
'authsource' => 'ldap',
- 'template' => $iam_settings['templates'][$mapper_key]
+ 'template' => $mbox_template
));
$_SESSION['access_all_exception'] = '0';
if (!$create_res){
diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php
index 5b67dd1e4..3593ff2c4 100644
--- a/data/web/inc/functions.inc.php
+++ b/data/web/inc/functions.inc.php
@@ -2387,8 +2387,16 @@ function identity_provider($_action = null, $_data = null, $_extra = null) {
}
$pdo->commit();
+ // add default template
+ if (isset($_data['default_template'])) {
+ $_data['default_template'] = (empty($_data['default_template'])) ? "" : $_data['default_template'];
+ $stmt = $pdo->prepare("INSERT INTO identity_provider (`key`, `value`) VALUES ('default_template', :value) ON DUPLICATE KEY UPDATE `value` = VALUES(`value`);");
+ $stmt->bindParam(':value', $_data['default_template']);
+ $stmt->execute();
+ }
+
// add mappers
- if ($_data['mappers'] && $_data['templates']){
+ if (isset($_data['mappers']) && isset($_data['templates'])){
$_data['mappers'] = (!is_array($_data['mappers'])) ? array($_data['mappers']) : $_data['mappers'];
$_data['templates'] = (!is_array($_data['templates'])) ? array($_data['templates']) : $_data['templates'];
@@ -2714,13 +2722,19 @@ function identity_provider($_action = null, $_data = null, $_extra = null) {
}
if (empty($iam_settings['mappers']) || empty($user_template) || $mapper_key === false){
- clear_session();
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $info['email'], 'No matching attribute mapping was found'),
- 'msg' => 'login_failed'
- );
- return false;
+ if (!empty($iam_settings['default_template'])) {
+ $mbox_template = $iam_settings['default_template'];
+ } else {
+ clear_session();
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $info['email'], 'No matching attribute mapping was found'),
+ 'msg' => 'login_failed'
+ );
+ return false;
+ }
+ } else {
+ $mbox_template = $iam_settings['templates'][$mapper_key];
}
// create mailbox
@@ -2730,7 +2744,7 @@ function identity_provider($_action = null, $_data = null, $_extra = null) {
'local_part' => explode('@', $info['email'])[0],
'name' => $info['name'],
'authsource' => $iam_settings['authsource'],
- 'template' => $iam_settings['templates'][$mapper_key]
+ 'template' => $mbox_template
));
$_SESSION['access_all_exception'] = '0';
if (!$create_res){
diff --git a/data/web/js/site/admin.js b/data/web/js/site/admin.js
index 5a5f37955..90c00002a 100644
--- a/data/web/js/site/admin.js
+++ b/data/web/js/site/admin.js
@@ -711,7 +711,7 @@ jQuery(function($){
// App links
// setup eventlistener
setAppHideEvent();
- function setAppHideEvent(){
+ function setAppHideEvent(){
$('.app_hide').off('change');
$('.app_hide').on('change', function (e) {
var value = $(this).is(':checked') ? '1' : '0';
@@ -756,13 +756,13 @@ jQuery(function($){
$('.iam_test_connection').click(async function(e){
e.preventDefault();
var data = { attr: $('form[data-id="' + $(this).data('id') + '"]').serializeObject() };
- var res = await fetch("/api/v1/edit/identity-provider-test", {
+ var res = await fetch("/api/v1/edit/identity-provider-test", {
headers: {
"Content-Type": "application/json",
},
- method:'POST',
- cache:'no-cache',
- body: JSON.stringify(data)
+ method:'POST',
+ cache:'no-cache',
+ body: JSON.stringify(data)
});
res = await res.json();
if (res.type === 'success'){
@@ -772,79 +772,22 @@ jQuery(function($){
});
$('.iam_rolemap_add_keycloak').click(async function(e){
- e.preventDefault();
-
- var parent = $('#iam_keycloak_mapping_list')
- $(parent).children().last().clone().appendTo(parent);
- var newChild = $(parent).children().last();
- $(newChild).find('input').val('');
- $(newChild).find('.dropdown-toggle').remove();
- $(newChild).find('.dropdown-menu').remove();
- $(newChild).find('.bs-title-option').remove();
- $(newChild).find('select').selectpicker('destroy');
- $(newChild).find('select').selectpicker();
-
- $('.iam_keycloak_rolemap_del').off('click');
- $('.iam_keycloak_rolemap_del').click(async function(e){
- e.preventDefault();
- if ($(this).parent().parent().parent().parent().children().length > 1)
- $(this).parent().parent().parent().remove();
- });
+ addAttributeMappingRow('#iam_keycloak_mapping_list', '.iam_keycloak_rolemap_del', e);
});
$('.iam_rolemap_add_generic').click(async function(e){
- e.preventDefault();
-
- var parent = $('#iam_generic_mapping_list')
- $(parent).children().last().clone().appendTo(parent);
- var newChild = $(parent).children().last();
- $(newChild).find('input').val('');
- $(newChild).find('.dropdown-toggle').remove();
- $(newChild).find('.dropdown-menu').remove();
- $(newChild).find('.bs-title-option').remove();
- $(newChild).find('select').selectpicker('destroy');
- $(newChild).find('select').selectpicker();
-
- $('.iam_generic_rolemap_del').off('click');
- $('.iam_generic_rolemap_del').click(async function(e){
- e.preventDefault();
- if ($(this).parent().parent().parent().parent().children().length > 1)
- $(this).parent().parent().parent().remove();
- });
+ addAttributeMappingRow('#iam_generic_mapping_list', '.iam_generic_rolemap_del', e);
});
$('.iam_rolemap_add_ldap').click(async function(e){
- e.preventDefault();
-
- var parent = $('#iam_ldap_mapping_list')
- $(parent).children().last().clone().appendTo(parent);
- var newChild = $(parent).children().last();
- $(newChild).find('input').val('');
- $(newChild).find('.dropdown-toggle').remove();
- $(newChild).find('.dropdown-menu').remove();
- $(newChild).find('.bs-title-option').remove();
- $(newChild).find('select').selectpicker('destroy');
- $(newChild).find('select').selectpicker();
-
- $('.iam_ldap_rolemap_del').off('click');
- $('.iam_ldap_rolemap_del').click(async function(e){
- e.preventDefault();
- if ($(this).parent().parent().parent().parent().children().length > 1)
- $(this).parent().parent().parent().remove();
- });
+ addAttributeMappingRow('#iam_ldap_mapping_list', '.iam_ldap_rolemap_del', e);
});
$('.iam_keycloak_rolemap_del').click(async function(e){
- e.preventDefault();
- if ($(this).parent().parent().parent().parent().children().length > 1)
- $(this).parent().parent().parent().remove();
+ deleteAttributeMappingRow(this, e);
});
$('.iam_generic_rolemap_del').click(async function(e){
- e.preventDefault();
- if ($(this).parent().parent().parent().parent().children().length > 1)
- $(this).parent().parent().parent().remove();
+ deleteAttributeMappingRow(this, e);
});
$('.iam_ldap_rolemap_del').click(async function(e){
- e.preventDefault();
- if ($(this).parent().parent().parent().parent().children().length > 1)
- $(this).parent().parent().parent().remove();
+ deleteAttributeMappingRow(this, e);
});
// selecting identity provider
$('#iam_provider').on('change', function(){
@@ -863,4 +806,31 @@ jQuery(function($){
$('#keycloak_settings').addClass('d-none');
}
});
+ function addAttributeMappingRow(list_id, del_class, e) {
+ e.preventDefault();
+
+ var parent = $(list_id)
+ $(parent).children().last().clone().appendTo(parent);
+ var newChild = $(parent).children().last();
+ $(newChild).find('input').val('');
+ $(newChild).find('input').val('').prop('required', true);
+ $(newChild).find('.dropdown-toggle').remove();
+ $(newChild).find('.dropdown-menu').remove();
+ $(newChild).find('.bs-title-option').remove();
+ $(newChild).find('select').selectpicker('destroy');
+ $(newChild).find('select').selectpicker();
+ $(newChild).find('select').selectpicker().prop('required', true);
+
+ $(del_class).off('click');
+ $(del_class).click(async function(e){
+ deleteAttributeMappingRow(this, e);
+ });
+ }
+ function deleteAttributeMappingRow(elem, e) {
+ e.preventDefault();
+ if(!$(elem).parent().parent().parent().find('select').prop('required'))
+ return true;
+ if ($(elem).parent().parent().parent().parent().children().length > 1)
+ $(elem).parent().parent().parent().remove();
+ }
});
diff --git a/data/web/lang/lang.de-de.json b/data/web/lang/lang.de-de.json
index 0857bc5f7..45c6e9f50 100644
--- a/data/web/lang/lang.de-de.json
+++ b/data/web/lang/lang.de-de.json
@@ -215,6 +215,8 @@
"iam_client_id": "Client ID",
"iam_client_secret": "Client Secret",
"iam_client_scopes": "Client Scopes",
+ "iam_default_template": "Standardvorlage",
+ "iam_default_template_description": "Falls für einen Benutzer kein Template hinterlegt ist, wird die Standardvorlage zum Erstellen der Mailbox verwendet, jedoch nicht zum Aktualisieren der Mailbox.",
"iam_description": "Konfiguriere einen externen Identity Provider für die Authentifizierung
Die Mailboxen der Benutzer werden bei ihrer ersten Anmeldung automatisch erstellt, vorausgesetzt, dass ein Attribut Mapping festgelegt wurde.",
"iam_extra_permission": "Damit die folgenden Einstellungen funktionieren, benötigt der mailcow Client in Keycloak ein Service-Konto und die Berechtigung view-users.",
"iam_host": "Host",
diff --git a/data/web/lang/lang.en-gb.json b/data/web/lang/lang.en-gb.json
index 64baade92..1876836de 100644
--- a/data/web/lang/lang.en-gb.json
+++ b/data/web/lang/lang.en-gb.json
@@ -222,6 +222,8 @@
"iam_client_id": "Client ID",
"iam_client_secret": "Client Secret",
"iam_client_scopes": "Client Scopes",
+ "iam_default_template": "Default Template",
+ "iam_default_template_description": "If no template is assigned to a user, the default template will be used for creating the mailbox, but not for updating the mailbox.",
"iam_description": "Configure an external Provider for Authentication
User's mailboxes will be automatically created upon their first login, provided that an attribute mapping has been set.",
"iam_extra_permission": "For the following settings to work, the mailcow client in Keycloak needs a Service account and the permission to view-users.",
"iam_host": "Host",
diff --git a/data/web/templates/admin/tab-config-identity-provider.twig b/data/web/templates/admin/tab-config-identity-provider.twig
index 4a85b42fc..9d4dcd286 100644
--- a/data/web/templates/admin/tab-config-identity-provider.twig
+++ b/data/web/templates/admin/tab-config-identity-provider.twig
@@ -93,6 +93,27 @@