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
- 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
- Windows: added home drive and force password change to profile editor
- LAM Pro:
-> Bind DLZ: entry table can show record data (use special attribute "#records" in server profile)
- Fixed bugs:

View File

@ -745,9 +745,8 @@ class accountContainer {
*
* @param ConfiguredType $type account type
* @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)) {
trigger_error('Argument of accountContainer must be ConfiguredType.', E_USER_ERROR);
}
@ -760,7 +759,6 @@ class accountContainer {
$this->current_page=0;
$this->subpage='attributes';
$this->isNewAccount = false;
$this->randomID = $randomID;
return 0;
}
@ -824,8 +822,6 @@ class accountContainer {
/** send password via mail to this alternate address */
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
@ -865,10 +861,6 @@ class accountContainer {
* It prints the HTML code of each account page.
*/
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;
$oldSubpage = $this->subpage;
$result = array();
@ -1322,7 +1314,7 @@ class accountContainer {
$passwordButton = new htmlButton('accountContainerPassword', _('Set password'));
$passwordButton->setIconClass('passwordButton');
$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() . '\');');
$leftButtonGroup->addElement($passwordButton);
}
@ -1377,8 +1369,7 @@ class accountContainer {
jQuery("#inputForm").validationEngine();
});
</script>';
echo "<form id=\"inputForm\" enctype=\"multipart/form-data\" action=\"edit.php\" method=\"post\" onSubmit=\"saveScrollPosition('inputForm')\" autocomplete=\"off\">\n";
echo '<input type="hidden" name="account_randomID" value="' . $this->randomID . '">';
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="' . getSecurityTokenName() . '" value="' . getSecurityTokenValue() . '">';
}

View File

@ -4,10 +4,9 @@ use \LAMException;
use \phpseclib\Net\SSH2;
use \phpseclib\Crypt\RSA;
/*
$Id$
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
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);
if ($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)) {
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/)
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
it under the terms of the GNU General Public License as published by
@ -57,6 +57,31 @@ if (!isLoggedIn()) {
// Set correct language, codepages, ....
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();
//load account
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);
die();
}
$_SESSION['account'] = new accountContainer($type, 'account', getRandomNumber());
$result = $_SESSION['account']->load_account($DN);
$_SESSION[$sessionKey] = new accountContainer($type, $sessionKey);
$result = $_SESSION[$sessionKey]->load_account($DN);
if (sizeof($result) > 0) {
include __DIR__ . '/../../lib/adminHeader.inc';
foreach ($result as $message) {
@ -92,7 +117,7 @@ if (isset($_GET['DN'])) {
}
}
// new account
else if (count($_POST) == 0) {
elseif (empty($_POST)) {
$type = $typeManager->getConfiguredType($_GET['type']);
if ($type->isHidden()) {
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());
die();
}
$_SESSION['account'] = new accountContainer($type, 'account', getRandomNumber());
$_SESSION['account']->new_account();
$_SESSION[$sessionKey] = new accountContainer($type, $sessionKey);
$_SESSION[$sessionKey]->new_account();
}
// 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/)
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
it under the terms of the GNU General Public License as published by
@ -74,6 +74,14 @@ if (!empty($_POST)) {
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();
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);
}
$sessionKey = $sessionAccountPrefix . (new \DateTime(null, getTimeZone()))->getTimestamp() . getRandomNumber();
//load account
$_SESSION['account'] = new \accountContainer($type, 'account');
$_SESSION[$sessionKey] = new \accountContainer($type, $sessionKey);
// Show HTML Page
include '../lib/adminHeader.inc';
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->addLabel(new htmlOutputText(_('DN') . ':'));
$container->addField(new htmlOutputText($_SESSION['delete_dn'][$i]));
$_SESSION['account']->load_account($_SESSION['delete_dn'][$i]);
if (!$_SESSION['account']->hasOnlyVirtualChildren()) {
$_SESSION[$sessionKey]->load_account($_SESSION['delete_dn'][$i]);
if (!$_SESSION[$sessionKey]->hasOnlyVirtualChildren()) {
$childCount = getChildCount($_SESSION['delete_dn'][$i]);
if ($childCount > 0) {
$container->addLabel(new htmlOutputText(_('Number of child entries') . ':'));
@ -182,6 +191,8 @@ if (isset($_POST['delete'])) {
addSecurityTokenToMetaHTML($container);
$container->add(new htmlHiddenInput('type', $type->getId()), 12);
$sessionKey = $sessionAccountPrefix . (new \DateTime(null, getTimeZone()))->getTimestamp() . getRandomNumber();
$_SESSION[$sessionKey] = new \accountContainer($type, $sessionKey);
// Delete dns
$allOk = true;
$allErrors = array();
@ -189,10 +200,10 @@ if (isset($_POST['delete'])) {
// Set to true if an real error has happened
$stopprocessing = false;
// First load DN.
$_SESSION['account']->load_account($deleteDN);
$_SESSION[$sessionKey]->load_account($deleteDN);
// get commands and changes of each attribute
$moduleNames = array_keys($_SESSION['account']->getAccountModules());
$modules = $_SESSION['account']->getAccountModules();
$moduleNames = array_keys($_SESSION[$sessionKey]->getAccountModules());
$modules = $_SESSION[$sessionKey]->getAccountModules();
$attributes = array();
$errors = array();
// predelete actions
@ -279,7 +290,7 @@ if (isset($_POST['delete'])) {
}
}
if (!$stopprocessing) {
$recursive = !$_SESSION['account']->hasOnlyVirtualChildren();
$recursive = !$_SESSION[$sessionKey]->hasOnlyVirtualChildren();
$messages = deleteDN($deleteDN, $recursive);
$errors = array_merge($errors, $messages);
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']))) {
enforceUserIsLoggedIn();
if (isset($_GET['useContainer']) && ($_GET['useContainer'] == '1')) {
if (!isset($_SESSION['account'])) die();
$module = $_SESSION['account']->getAccountModule($_GET['module']);
$sessionKey = htmlspecialchars($_GET['editKey']);
if (!isset($_SESSION[$sessionKey])) {
logNewMessage(LOG_ERR, 'Unable to find account container');
die();
}
$module = $_SESSION[$sessionKey]->getAccountModule($_GET['module']);
$module->handleAjaxRequest();
}
else {
@ -157,7 +161,8 @@ class Ajax {
* @param array $input input parameters
*/
private static function managePasswordChange($input) {
$return = $_SESSION['account']->setNewPassword($input);
$sessionKey = htmlspecialchars($_GET['editKey']);
$return = $_SESSION[$sessionKey]->setNewPassword($input);
echo json_encode($return);
}