Merge pull request #65 from LDAPAccountManager/feature/parallelEditing

Feature/parallel editing
This commit is contained in:
gruberroland 2019-05-30 17:21:50 +02:00 committed by GitHub
commit 2993588a2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 5952 additions and 5942 deletions

View File

@ -1,6 +1,7 @@
6.8 6.8
- Windows: added home drive and force password change to profile editor - Parallel editing of multiple entries in different browser tabs supported
- LAM supports the progressive web app standard which allows to install LAM as an icon on home screen - LAM supports the progressive web app standard which allows to install LAM as an icon on home screen
- Windows: added home drive and force password change to profile editor
- LAM Pro: - LAM Pro:
-> Bind DLZ: entry table can show record data (use special attribute "#records" in server profile) -> Bind DLZ: entry table can show record data (use special attribute "#records" in server profile)
- Fixed bugs: - Fixed bugs:

View File

@ -745,9 +745,8 @@ class accountContainer {
* *
* @param ConfiguredType $type account type * @param ConfiguredType $type account type
* @param string $base key in $_SESSION where this object is saved * @param string $base key in $_SESSION where this object is saved
* @param integer $randomID random ID to avoid parallel editing (default: null)
*/ */
function __construct($type, $base, $randomID = null) { function __construct($type, $base) {
if (!($type instanceof ConfiguredType)) { if (!($type instanceof ConfiguredType)) {
trigger_error('Argument of accountContainer must be ConfiguredType.', E_USER_ERROR); trigger_error('Argument of accountContainer must be ConfiguredType.', E_USER_ERROR);
} }
@ -760,7 +759,6 @@ class accountContainer {
$this->current_page=0; $this->current_page=0;
$this->subpage='attributes'; $this->subpage='attributes';
$this->isNewAccount = false; $this->isNewAccount = false;
$this->randomID = $randomID;
return 0; return 0;
} }
@ -824,8 +822,6 @@ class accountContainer {
/** send password via mail to this alternate address */ /** send password via mail to this alternate address */
private $sendPasswordViaMailAlternateAddress = null; private $sendPasswordViaMailAlternateAddress = null;
/** random ID number to avoid parallel editing of accounts in multiple browser tabs */
private $randomID = null;
/** /**
* Returns the account module with the given class name * Returns the account module with the given class name
@ -865,10 +861,6 @@ class accountContainer {
* It prints the HTML code of each account page. * It prints the HTML code of each account page.
*/ */
function continue_main() { function continue_main() {
if (!empty($_POST['account_randomID']) && ($this->randomID != $_POST['account_randomID'])) {
metaRefresh("../lists/list.php?type=" . $this->type->getId() . '&accountEditInvalidID=true');
exit();
}
$oldPage = $this->current_page; $oldPage = $this->current_page;
$oldSubpage = $this->subpage; $oldSubpage = $this->subpage;
$result = array(); $result = array();
@ -1322,7 +1314,7 @@ class accountContainer {
$passwordButton = new htmlButton('accountContainerPassword', _('Set password')); $passwordButton = new htmlButton('accountContainerPassword', _('Set password'));
$passwordButton->setIconClass('passwordButton'); $passwordButton->setIconClass('passwordButton');
$passwordButton->setOnClick('passwordShowChangeDialog(\'' . _('Set password') . '\', \'' . _('Ok') . '\', \'' $passwordButton->setOnClick('passwordShowChangeDialog(\'' . _('Set password') . '\', \'' . _('Ok') . '\', \''
. _('Cancel') . '\', \'' . _('Set random password') . '\', \'../misc/ajax.php?function=passwordChange\',\'' . _('Cancel') . '\', \'' . _('Set random password') . '\', \'../misc/ajax.php?function=passwordChange&editKey=' . htmlspecialchars($this->base) . '\',\''
. getSecurityTokenName() . '\',\'' . getSecurityTokenValue() . '\');'); . getSecurityTokenName() . '\',\'' . getSecurityTokenValue() . '\');');
$leftButtonGroup->addElement($passwordButton); $leftButtonGroup->addElement($passwordButton);
} }
@ -1377,8 +1369,7 @@ class accountContainer {
jQuery("#inputForm").validationEngine(); jQuery("#inputForm").validationEngine();
}); });
</script>'; </script>';
echo "<form id=\"inputForm\" enctype=\"multipart/form-data\" action=\"edit.php\" method=\"post\" onSubmit=\"saveScrollPosition('inputForm')\" autocomplete=\"off\">\n"; echo "<form id=\"inputForm\" enctype=\"multipart/form-data\" action=\"edit.php?editKey=" . htmlspecialchars($this->base) . "\" method=\"post\" onSubmit=\"saveScrollPosition('inputForm')\" autocomplete=\"off\">\n";
echo '<input type="hidden" name="account_randomID" value="' . $this->randomID . '">';
echo '<input type="hidden" name="' . getSecurityTokenName() . '" value="' . getSecurityTokenValue() . '">'; echo '<input type="hidden" name="' . getSecurityTokenName() . '" value="' . getSecurityTokenValue() . '">';
} }

View File

@ -4,10 +4,9 @@ use \LAMException;
use \phpseclib\Net\SSH2; use \phpseclib\Net\SSH2;
use \phpseclib\Crypt\RSA; use \phpseclib\Crypt\RSA;
/* /*
$Id$
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
Copyright (C) 2017 Roland Gruber Copyright (C) 2017 - 2019 Roland Gruber
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -108,7 +107,9 @@ class Remote {
$sr = @ldap_read($_SESSION['ldap']->server(), $credentials[0], "objectClass=posixAccount", array('uid'), 0, 0, 0, LDAP_DEREF_NEVER); $sr = @ldap_read($_SESSION['ldap']->server(), $credentials[0], "objectClass=posixAccount", array('uid'), 0, 0, 0, LDAP_DEREF_NEVER);
if ($sr) { if ($sr) {
$entry = @ldap_get_entries($_SESSION['ldap']->server(), $sr); $entry = @ldap_get_entries($_SESSION['ldap']->server(), $sr);
$username = $entry[0]['uid'][0]; if (!empty($entry[0]['uid'])) {
$username = $entry[0]['uid'][0];
}
} }
if (empty($username)) { if (empty($username)) {
throw new LAMException(sprintf(_("Your LAM admin user (%s) must be a valid Unix account to work with lamdaemon!"), getAbstractDN($credentials[0]))); throw new LAMException(sprintf(_("Your LAM admin user (%s) must be a valid Unix account to work with lamdaemon!"), getAbstractDN($credentials[0])));

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
Copyright (C) 2003 - 2006 Tilo Lutz Copyright (C) 2003 - 2006 Tilo Lutz
2005 - 2018 Roland Gruber 2005 - 2019 Roland Gruber
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -57,6 +57,31 @@ if (!isLoggedIn()) {
// Set correct language, codepages, .... // Set correct language, codepages, ....
setlanguage(); setlanguage();
$sessionAccountPrefix = 'editContainer';
if (isset($_GET['editKey'])) {
$sessionKey = htmlspecialchars($_GET['editKey']);
}
else {
$sessionKey = $sessionAccountPrefix . (new \DateTime(null, getTimeZone()))->getTimestamp() . getRandomNumber();
}
// cleanup account containers in session
$cleanupCandidates = array();
foreach ($_SESSION as $key => $value) {
if (strpos($key, $sessionAccountPrefix) === 0) {
$cleanupCandidates[] = $key;
}
$candidateCount = sizeof($cleanupCandidates);
if ($candidateCount > 100) {
$numToDelete = $candidateCount - 100;
natsort($cleanupCandidates);
for ($i = 0; $i < $numToDelete; $i++) {
$toDelete = array_shift($cleanupCandidates);
unset($_SESSION[$toDelete]);
}
}
}
$typeManager = new LAM\TYPES\TypeManager(); $typeManager = new LAM\TYPES\TypeManager();
//load account //load account
if (isset($_GET['DN'])) { if (isset($_GET['DN'])) {
@ -80,8 +105,8 @@ if (isset($_GET['DN'])) {
logNewMessage(LOG_ERR, 'User tried to access entry of type ' . $type->getId() . ' outside suffix ' . $suffix); logNewMessage(LOG_ERR, 'User tried to access entry of type ' . $type->getId() . ' outside suffix ' . $suffix);
die(); die();
} }
$_SESSION['account'] = new accountContainer($type, 'account', getRandomNumber()); $_SESSION[$sessionKey] = new accountContainer($type, $sessionKey);
$result = $_SESSION['account']->load_account($DN); $result = $_SESSION[$sessionKey]->load_account($DN);
if (sizeof($result) > 0) { if (sizeof($result) > 0) {
include __DIR__ . '/../../lib/adminHeader.inc'; include __DIR__ . '/../../lib/adminHeader.inc';
foreach ($result as $message) { foreach ($result as $message) {
@ -92,7 +117,7 @@ if (isset($_GET['DN'])) {
} }
} }
// new account // new account
else if (count($_POST) == 0) { elseif (empty($_POST)) {
$type = $typeManager->getConfiguredType($_GET['type']); $type = $typeManager->getConfiguredType($_GET['type']);
if ($type->isHidden()) { if ($type->isHidden()) {
logNewMessage(LOG_ERR, 'User tried to access hidden account type: ' . $type->getId()); logNewMessage(LOG_ERR, 'User tried to access hidden account type: ' . $type->getId());
@ -102,11 +127,11 @@ else if (count($_POST) == 0) {
logNewMessage(LOG_ERR, 'User tried to create entry of forbidden account type: ' . $type->getId()); logNewMessage(LOG_ERR, 'User tried to create entry of forbidden account type: ' . $type->getId());
die(); die();
} }
$_SESSION['account'] = new accountContainer($type, 'account', getRandomNumber()); $_SESSION[$sessionKey] = new accountContainer($type, $sessionKey);
$_SESSION['account']->new_account(); $_SESSION[$sessionKey]->new_account();
} }
// show account page // show account page
$_SESSION['account']->continue_main(); $_SESSION[$sessionKey]->continue_main();
?> ?>

View File

@ -11,7 +11,7 @@ use \htmlStatusMessage;
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
Copyright (C) 2003 - 2006 Tilo Lutz Copyright (C) 2003 - 2006 Tilo Lutz
Copyright (C) 2007 - 2018 Roland Gruber Copyright (C) 2007 - 2019 Roland Gruber
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -74,6 +74,14 @@ if (!empty($_POST)) {
validateSecurityToken(); validateSecurityToken();
} }
$sessionAccountPrefix = 'deleteContainer';
foreach ($_SESSION as $key => $value) {
if (strpos($key, $sessionAccountPrefix) === 0) {
unset($_SESSION[$key]);
logNewMessage(LOG_NOTICE, "del " . $key);
}
}
$typeManager = new \LAM\TYPES\TypeManager(); $typeManager = new \LAM\TYPES\TypeManager();
if (isset($_POST['type']) && ($typeManager->getConfiguredType($_POST['type']) === null)) { if (isset($_POST['type']) && ($typeManager->getConfiguredType($_POST['type']) === null)) {
@ -99,8 +107,9 @@ if (isset($_GET['type']) && isset($_SESSION['delete_dn'])) {
$users[] = substr($dn, $start, $end-$start); $users[] = substr($dn, $start, $end-$start);
} }
$sessionKey = $sessionAccountPrefix . (new \DateTime(null, getTimeZone()))->getTimestamp() . getRandomNumber();
//load account //load account
$_SESSION['account'] = new \accountContainer($type, 'account'); $_SESSION[$sessionKey] = new \accountContainer($type, $sessionKey);
// Show HTML Page // Show HTML Page
include '../lib/adminHeader.inc'; include '../lib/adminHeader.inc';
echo "<div class=\"" . $type->getScope() . "-bright smallPaddingContent\">"; echo "<div class=\"" . $type->getScope() . "-bright smallPaddingContent\">";
@ -116,8 +125,8 @@ if (isset($_GET['type']) && isset($_SESSION['delete_dn'])) {
$container->addField(new htmlOutputText($users[$i])); $container->addField(new htmlOutputText($users[$i]));
$container->addLabel(new htmlOutputText(_('DN') . ':')); $container->addLabel(new htmlOutputText(_('DN') . ':'));
$container->addField(new htmlOutputText($_SESSION['delete_dn'][$i])); $container->addField(new htmlOutputText($_SESSION['delete_dn'][$i]));
$_SESSION['account']->load_account($_SESSION['delete_dn'][$i]); $_SESSION[$sessionKey]->load_account($_SESSION['delete_dn'][$i]);
if (!$_SESSION['account']->hasOnlyVirtualChildren()) { if (!$_SESSION[$sessionKey]->hasOnlyVirtualChildren()) {
$childCount = getChildCount($_SESSION['delete_dn'][$i]); $childCount = getChildCount($_SESSION['delete_dn'][$i]);
if ($childCount > 0) { if ($childCount > 0) {
$container->addLabel(new htmlOutputText(_('Number of child entries') . ':')); $container->addLabel(new htmlOutputText(_('Number of child entries') . ':'));
@ -182,6 +191,8 @@ if (isset($_POST['delete'])) {
addSecurityTokenToMetaHTML($container); addSecurityTokenToMetaHTML($container);
$container->add(new htmlHiddenInput('type', $type->getId()), 12); $container->add(new htmlHiddenInput('type', $type->getId()), 12);
$sessionKey = $sessionAccountPrefix . (new \DateTime(null, getTimeZone()))->getTimestamp() . getRandomNumber();
$_SESSION[$sessionKey] = new \accountContainer($type, $sessionKey);
// Delete dns // Delete dns
$allOk = true; $allOk = true;
$allErrors = array(); $allErrors = array();
@ -189,10 +200,10 @@ if (isset($_POST['delete'])) {
// Set to true if an real error has happened // Set to true if an real error has happened
$stopprocessing = false; $stopprocessing = false;
// First load DN. // First load DN.
$_SESSION['account']->load_account($deleteDN); $_SESSION[$sessionKey]->load_account($deleteDN);
// get commands and changes of each attribute // get commands and changes of each attribute
$moduleNames = array_keys($_SESSION['account']->getAccountModules()); $moduleNames = array_keys($_SESSION[$sessionKey]->getAccountModules());
$modules = $_SESSION['account']->getAccountModules(); $modules = $_SESSION[$sessionKey]->getAccountModules();
$attributes = array(); $attributes = array();
$errors = array(); $errors = array();
// predelete actions // predelete actions
@ -279,7 +290,7 @@ if (isset($_POST['delete'])) {
} }
} }
if (!$stopprocessing) { if (!$stopprocessing) {
$recursive = !$_SESSION['account']->hasOnlyVirtualChildren(); $recursive = !$_SESSION[$sessionKey]->hasOnlyVirtualChildren();
$messages = deleteDN($deleteDN, $recursive); $messages = deleteDN($deleteDN, $recursive);
$errors = array_merge($errors, $messages); $errors = array_merge($errors, $messages);
if (sizeof($errors) > 0) { if (sizeof($errors) > 0) {

View File

@ -75,8 +75,12 @@ class Ajax {
if (isset($_GET['module']) && isset($_GET['scope']) && in_array($_GET['module'], getAvailableModules($_GET['scope']))) { if (isset($_GET['module']) && isset($_GET['scope']) && in_array($_GET['module'], getAvailableModules($_GET['scope']))) {
enforceUserIsLoggedIn(); enforceUserIsLoggedIn();
if (isset($_GET['useContainer']) && ($_GET['useContainer'] == '1')) { if (isset($_GET['useContainer']) && ($_GET['useContainer'] == '1')) {
if (!isset($_SESSION['account'])) die(); $sessionKey = htmlspecialchars($_GET['editKey']);
$module = $_SESSION['account']->getAccountModule($_GET['module']); if (!isset($_SESSION[$sessionKey])) {
logNewMessage(LOG_ERR, 'Unable to find account container');
die();
}
$module = $_SESSION[$sessionKey]->getAccountModule($_GET['module']);
$module->handleAjaxRequest(); $module->handleAjaxRequest();
} }
else { else {
@ -157,7 +161,8 @@ class Ajax {
* @param array $input input parameters * @param array $input input parameters
*/ */
private static function managePasswordChange($input) { private static function managePasswordChange($input) {
$return = $_SESSION['account']->setNewPassword($input); $sessionKey = htmlspecialchars($_GET['editKey']);
$return = $_SESSION[$sessionKey]->setNewPassword($input);
echo json_encode($return); echo json_encode($return);
} }