mirror of
https://github.com/LDAPAccountManager/lam.git
synced 2025-10-03 17:59:21 +02:00
Merge remote-tracking branch 'origin/develop' into 413-update-dependencies
This commit is contained in:
commit
45baad01cf
12 changed files with 3896 additions and 3330 deletions
|
@ -14,7 +14,8 @@
|
||||||
"ext-xmlreader": "*",
|
"ext-xmlreader": "*",
|
||||||
"ext-zip": "*",
|
"ext-zip": "*",
|
||||||
"ext-gd": "*",
|
"ext-gd": "*",
|
||||||
"ext-imagick": "*"
|
"ext-imagick": "*",
|
||||||
|
"ext-gettext": "*"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "vendor/bin/phpunit"
|
"test": "vendor/bin/phpunit"
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
ldap-account-manager (9.1.RC1-1) unstable; urgency=medium
|
ldap-account-manager (9.1-1) unstable; urgency=medium
|
||||||
|
|
||||||
* new upstream release
|
* new upstream release
|
||||||
|
|
||||||
-- Roland Gruber <post@rolandgruber.de> Tue, 25 Feb 2024 07:36:27 +0200
|
-- Roland Gruber <post@rolandgruber.de> Thu, 13 Mar 2025 07:36:27 +0200
|
||||||
|
|
||||||
ldap-account-manager (9.0-1) unstable; urgency=medium
|
ldap-account-manager (9.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
FROM debian:bookworm-slim
|
FROM debian:bookworm-slim
|
||||||
LABEL maintainer="Roland Gruber <post@rolandgruber.de>"
|
LABEL maintainer="Roland Gruber <post@rolandgruber.de>"
|
||||||
|
|
||||||
ARG LAM_RELEASE=9.1.RC1
|
ARG LAM_RELEASE=9.1
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
ENV \
|
ENV \
|
||||||
|
|
|
@ -3,7 +3,7 @@ services:
|
||||||
ldap-account-manager:
|
ldap-account-manager:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
image: ldapaccountmanager/lam:9.1.RC1
|
image: ldapaccountmanager/lam:9.1
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "8080:80"
|
- "8080:80"
|
||||||
|
|
12
lam/HISTORY
12
lam/HISTORY
|
@ -1,16 +1,20 @@
|
||||||
March 2025 9.1
|
June 2025 9.2
|
||||||
|
- Active Directory: allow to restore deleted entries in tree view (415)
|
||||||
|
|
||||||
|
|
||||||
|
13.03.2025 9.1
|
||||||
- Usability improvements (347, 348, 360, 403)
|
- Usability improvements (347, 348, 360, 403)
|
||||||
- Active Directory: deleted entries in "CN=Deleted Objects" can be shown (option in server profile, advanced settings)
|
- Active Directory: deleted entries in "CN=Deleted Objects" can be shown (option in server profile, advanced settings)
|
||||||
- Security: LAM no longer ships with any default passwords, main configuration password is requested on login if not yet set (390)
|
- Security: LAM no longer ships with any default passwords, main configuration password is requested on login if not yet set (390)
|
||||||
- Docker: support to read e.g. configuration password from file to support Docker swarm
|
- Docker: support to read e.g. configuration password from file to support Docker swarm
|
||||||
|
- LAM Pro:
|
||||||
|
-> Added support to manage DNS entries of bind-dyndb-ldap (361)
|
||||||
|
-> Unix users: support to create a group with same name for rfc2307bis (404)
|
||||||
- Fixed bugs:
|
- Fixed bugs:
|
||||||
-> Ambiguous tooltip on profile editor for Shadow users (394)
|
-> Ambiguous tooltip on profile editor for Shadow users (394)
|
||||||
-> Self service photo file enhancements (396)
|
-> Self service photo file enhancements (396)
|
||||||
-> Tree view: delete does not work in French (406)
|
-> Tree view: delete does not work in French (406)
|
||||||
-> Cron job mails: show all values for multi-value attribute wildcards (411)
|
-> Cron job mails: show all values for multi-value attribute wildcards (411)
|
||||||
- LAM Pro:
|
|
||||||
-> Added support to manage DNS entries of bind-dyndb-ldap (361)
|
|
||||||
-> Unix users: support to create a group with same name for rfc2307bis (404)
|
|
||||||
|
|
||||||
|
|
||||||
17.12.2024 9.0
|
17.12.2024 9.0
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
9.1.RC1
|
9.1
|
||||||
|
|
|
@ -543,10 +543,7 @@
|
||||||
|
|
||||||
<para>Show deleted entries: This is for Active Directory and Samba 4
|
<para>Show deleted entries: This is for Active Directory and Samba 4
|
||||||
only. It will unhide LDAP entries in "CN=Deleted Objects,DC=...". You
|
only. It will unhide LDAP entries in "CN=Deleted Objects,DC=...". You
|
||||||
can use this to browse these entries in tree view. To restore an entry
|
can use this to browse and restore these entries in tree view.</para>
|
||||||
run "Restore-ADObject -Identity GUID" in PowerShell where GUID is the
|
|
||||||
value of the "objectGUID" attribute (you might need to base64 decode
|
|
||||||
it).</para>
|
|
||||||
|
|
||||||
<para>Referential integrity overlay: Activate this checkbox if you
|
<para>Referential integrity overlay: Activate this checkbox if you
|
||||||
have any server side extension for referential integrity in place. In
|
have any server side extension for referential integrity in place. In
|
||||||
|
|
|
@ -70,6 +70,7 @@ include_once __DIR__ . '/tools/treeview.inc';
|
||||||
* @package LAM\TOOLS\TREEVIEW
|
* @package LAM\TOOLS\TREEVIEW
|
||||||
*/
|
*/
|
||||||
class TreeView {
|
class TreeView {
|
||||||
|
const AD_DELETED_DELIMITER = '\0ADEL:';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array schema attributes
|
* @var array schema attributes
|
||||||
|
@ -124,6 +125,10 @@ class TreeView {
|
||||||
$this->ensureWriteAccess();
|
$this->ensureWriteAccess();
|
||||||
$this->validateDn($dn);
|
$this->validateDn($dn);
|
||||||
return $this->deleteNode($dn);
|
return $this->deleteNode($dn);
|
||||||
|
case 'restoreNode':
|
||||||
|
$this->ensureWriteAccess();
|
||||||
|
$this->validateDn($dn);
|
||||||
|
return $this->restoreNode($dn);
|
||||||
case 'search':
|
case 'search':
|
||||||
$this->validateDn($dn);
|
$this->validateDn($dn);
|
||||||
return $this->search($dn);
|
return $this->search($dn);
|
||||||
|
@ -366,10 +371,10 @@ class TreeView {
|
||||||
$row->addVerticalSpacer('1rem');
|
$row->addVerticalSpacer('1rem');
|
||||||
}
|
}
|
||||||
$row->add(new htmlTitle(unescapeLdapSpecialCharacters($dn)));
|
$row->add(new htmlTitle(unescapeLdapSpecialCharacters($dn)));
|
||||||
$this->addActionBar($row, $dn);
|
$attributes = ldapGetDN($dn, ['*']);
|
||||||
|
$this->addActionBar($row, $dn, $attributes);
|
||||||
$row->add(new htmlDiv('ldap_actionarea_messages', new htmlOutputText('')));
|
$row->add(new htmlDiv('ldap_actionarea_messages', new htmlOutputText('')));
|
||||||
$row->add(new htmlSubTitle(_('Attributes')));
|
$row->add(new htmlSubTitle(_('Attributes')));
|
||||||
$attributes = ldapGetDN($dn, ['*']);
|
|
||||||
unset($attributes['dn']);
|
unset($attributes['dn']);
|
||||||
ksort($attributes);
|
ksort($attributes);
|
||||||
logNewMessage(LOG_DEBUG, 'LDAP attributes for ' . $dn . ': ' . print_r($attributes, true));
|
logNewMessage(LOG_DEBUG, 'LDAP attributes for ' . $dn . ': ' . print_r($attributes, true));
|
||||||
|
@ -471,11 +476,13 @@ class TreeView {
|
||||||
*
|
*
|
||||||
* @param htmlResponsiveRow $row container
|
* @param htmlResponsiveRow $row container
|
||||||
* @param string $dn entry DN
|
* @param string $dn entry DN
|
||||||
|
* @param array $attributes LDAP attributes
|
||||||
*/
|
*/
|
||||||
private function addActionBar(htmlResponsiveRow $row, string $dn): void {
|
private function addActionBar(htmlResponsiveRow $row, string $dn, array $attributes): void {
|
||||||
$buttonGroup = new htmlGroup();
|
$buttonGroup = new htmlGroup();
|
||||||
$buttonSize = '16px';
|
$buttonSize = '16px';
|
||||||
$buttonClasses = ['clickable', 'lam-margin-small', 'icon'];
|
$buttonClasses = ['clickable', 'lam-margin-small', 'icon'];
|
||||||
|
$isRestorable = isset($attributes['isdeleted'][0]) && ($attributes['isdeleted'][0] === 'TRUE') && str_contains($dn, '\0ADEL');
|
||||||
|
|
||||||
if (checkIfWriteAccessIsAllowed()) {
|
if (checkIfWriteAccessIsAllowed()) {
|
||||||
$createButton = new htmlImage('../../graphics/add.svg', $buttonSize, $buttonSize, _('Create a child entry'), _('Create a child entry'));
|
$createButton = new htmlImage('../../graphics/add.svg', $buttonSize, $buttonSize, _('Create a child entry'), _('Create a child entry'));
|
||||||
|
@ -484,6 +491,7 @@ class TreeView {
|
||||||
$createButton->setCSSClasses($buttonClasses);
|
$createButton->setCSSClasses($buttonClasses);
|
||||||
$buttonGroup->addElement($createButton);
|
$buttonGroup->addElement($createButton);
|
||||||
|
|
||||||
|
if (!$isRestorable) {
|
||||||
$deleteButton = new htmlImage('../../graphics/delete.svg', $buttonSize, $buttonSize, _('Delete'), _('Delete'));
|
$deleteButton = new htmlImage('../../graphics/delete.svg', $buttonSize, $buttonSize, _('Delete'), _('Delete'));
|
||||||
$deleteButton->setOnClick('window.lam.treeview.deleteNode(\'' . getSecurityTokenName() . '\', '
|
$deleteButton->setOnClick('window.lam.treeview.deleteNode(\'' . getSecurityTokenName() . '\', '
|
||||||
. '\'' . getSecurityTokenValue() . '\', \'' . base64_encode($dn) . '\', \'' . base64_encode(htmlspecialchars(extractRDN($dn))) . '\', '
|
. '\'' . getSecurityTokenValue() . '\', \'' . base64_encode($dn) . '\', \'' . base64_encode(htmlspecialchars(extractRDN($dn))) . '\', '
|
||||||
|
@ -492,6 +500,7 @@ class TreeView {
|
||||||
$deleteButton->setCSSClasses($buttonClasses);
|
$deleteButton->setCSSClasses($buttonClasses);
|
||||||
$buttonGroup->addElement($deleteButton);
|
$buttonGroup->addElement($deleteButton);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$refreshButton = new htmlImage('../../graphics/refresh.svg', $buttonSize, $buttonSize, _('Refresh'), _('Refresh'));
|
$refreshButton = new htmlImage('../../graphics/refresh.svg', $buttonSize, $buttonSize, _('Refresh'), _('Refresh'));
|
||||||
$refreshButton->setOnClick('mar10.Wunderbaum.getTree(\'#ldap_tree\').findKey(\'' . base64_encode($dn) . '\').loadLazy(true); '
|
$refreshButton->setOnClick('mar10.Wunderbaum.getTree(\'#ldap_tree\').findKey(\'' . base64_encode($dn) . '\').loadLazy(true); '
|
||||||
|
@ -534,7 +543,29 @@ class TreeView {
|
||||||
$exportButton->setCSSClasses($buttonClasses);
|
$exportButton->setCSSClasses($buttonClasses);
|
||||||
$buttonGroup->addElement($exportButton);
|
$buttonGroup->addElement($exportButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
$row->add($buttonGroup);
|
$row->add($buttonGroup);
|
||||||
|
|
||||||
|
if (checkIfWriteAccessIsAllowed() && $isRestorable) {
|
||||||
|
$row->addVerticalSpacer('1rem');
|
||||||
|
$row->add(new htmlSubTitle(_('Restore')));
|
||||||
|
$targetDn = extractDNSuffix(extractDNSuffix($dn));
|
||||||
|
if (!empty($attributes['lastknownparent'][0]) && !str_contains($attributes['lastknownparent'][0], self::AD_DELETED_DELIMITER)) {
|
||||||
|
$targetDn = $attributes['lastknownparent'][0];
|
||||||
|
}
|
||||||
|
$restoreTargetDn = new htmlResponsiveInputField(_('Target DN'), 'treeview-restore-dn', $targetDn);
|
||||||
|
$restoreTargetDn->showDnSelection();
|
||||||
|
$row->add($restoreTargetDn);
|
||||||
|
$row->addVerticalSpacer('0.5rem');
|
||||||
|
$restoreButton = new htmlButton('restorebutton', _('Restore'));
|
||||||
|
$rdn = explode(self::AD_DELETED_DELIMITER, $dn)[0];
|
||||||
|
$restoreButton->setOnClick('window.lam.treeview.restoreNode(\'' . getSecurityTokenName() . '\', '
|
||||||
|
. '\'' . getSecurityTokenValue() . '\', \'' . base64_encode($dn) . '\', \'' . base64_encode(htmlspecialchars($rdn)) . '\', '
|
||||||
|
. '\'' . addslashes(_('Restore')) . '\', \'' . addslashes(_('Cancel')) . '\', \'' . addslashes(_('Restore this entry')) . '\', \'' . addslashes(_('Ok')) . '\', '
|
||||||
|
. '\'' . addslashes(_('Error')) . '\');');
|
||||||
|
$restoreButton->setCSSClasses(['lam-secondary']);
|
||||||
|
$row->add($restoreButton, 12, 12, 12, 'text-center');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1359,6 +1390,38 @@ class TreeView {
|
||||||
return json_encode([]);
|
return json_encode([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores a node in LDAP.
|
||||||
|
*
|
||||||
|
* @param string $dn DN
|
||||||
|
* @return string JSON
|
||||||
|
*/
|
||||||
|
private function restoreNode(string $dn): string {
|
||||||
|
$rdn = explode(self::AD_DELETED_DELIMITER, $dn)[0];
|
||||||
|
$targetDn = $_POST['targetDn'];
|
||||||
|
$changes = [
|
||||||
|
[
|
||||||
|
'attrib' => 'isDeleted',
|
||||||
|
'modtype' => LDAP_MODIFY_BATCH_REMOVE_ALL
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'attrib' => 'distinguishedName',
|
||||||
|
'modtype' => LDAP_MODIFY_BATCH_REPLACE,
|
||||||
|
'values' => [$rdn . ',' . $targetDn]
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$success = ldap_modify_batch(getLDAPServerHandle(), $dn, $changes, getCommonLdapControls());
|
||||||
|
if ($success) {
|
||||||
|
return json_encode([]);
|
||||||
|
}
|
||||||
|
$error = getDefaultLDAPErrorString(getLDAPServerHandle());
|
||||||
|
logNewMessage(LOG_ERR, 'Tree view restore node failed: ' . $error);
|
||||||
|
return json_encode([
|
||||||
|
'errorTitle' => htmlspecialchars(sprintf(_('Was unable to restore %s.'), $rdn)),
|
||||||
|
'errorText' => $error
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops processing if DN is invalid.
|
* Stops processing if DN is invalid.
|
||||||
*
|
*
|
||||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
@ -2497,6 +2497,64 @@ window.lam.treeview.deleteNode = function (tokenName, tokenValue, dn, text, okTe
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores a node in tree view.
|
||||||
|
*
|
||||||
|
* @param tokenName security token name
|
||||||
|
* @param tokenValue security token value
|
||||||
|
* @param dn base64 encoded DN
|
||||||
|
* @param text text for dialog body
|
||||||
|
* @param okText text for OK button
|
||||||
|
* @param cancelText text for cancel button
|
||||||
|
* @param title dialog title
|
||||||
|
* @param errorOkText text for OK button in error dialog
|
||||||
|
* @param errorTitle dialog title in case of error
|
||||||
|
*/
|
||||||
|
window.lam.treeview.restoreNode = function (tokenName, tokenValue, dn, text, okText, cancelText, title, errorOkText, errorTitle) {
|
||||||
|
const textSpan = document.querySelector('.treeview-restore-entry');
|
||||||
|
textSpan.innerText = window.atob(text);
|
||||||
|
const dialogContent = document.getElementById('treeview_restore_dlg').cloneNode(true);
|
||||||
|
dialogContent.classList.remove('hidden');
|
||||||
|
const targetDn = document.getElementById('treeview-restore-dn').value;
|
||||||
|
Swal.fire({
|
||||||
|
title: title,
|
||||||
|
confirmButtonText: okText,
|
||||||
|
cancelButtonText: cancelText,
|
||||||
|
showCancelButton: true,
|
||||||
|
html: dialogContent.outerHTML,
|
||||||
|
width: '48em'
|
||||||
|
}).then(result => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
let data = new FormData();
|
||||||
|
data.append(tokenName, tokenValue);
|
||||||
|
data.append('dn', dn)
|
||||||
|
data.append('targetDn', targetDn)
|
||||||
|
fetch("../misc/ajax.php?function=treeview&command=restoreNode", {
|
||||||
|
method: 'POST',
|
||||||
|
body: data
|
||||||
|
})
|
||||||
|
.then(async response => {
|
||||||
|
const jsonData = await response.json();
|
||||||
|
window.lam.treeview.checkSession(jsonData);
|
||||||
|
const tree = mar10.Wunderbaum.getTree("#ldap_tree");
|
||||||
|
const parentNode = tree.findKey(dn).parent;
|
||||||
|
await parentNode.setActive();
|
||||||
|
parentNode.loadLazy(true);
|
||||||
|
window.lam.treeview.getNodeContent(tokenName, tokenValue, parentNode.key);
|
||||||
|
if (jsonData['errorTitle']) {
|
||||||
|
const errTextTitle = jsonData['errorTitle'];
|
||||||
|
const textSpanErrorTitle = document.querySelector('.treeview-error-title');
|
||||||
|
textSpanErrorTitle.innerText = errTextTitle;
|
||||||
|
const errText = jsonData['errorText'];
|
||||||
|
const textSpanErrorText = document.querySelector('.treeview-error-text');
|
||||||
|
textSpanErrorText.innerText = errText;
|
||||||
|
window.lam.dialog.showSimpleDialog(errorTitle, null, errorOkText, null, 'treeview_error_dlg');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the node content in tree view action area.
|
* Returns the node content in tree view action area.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
namespace LAM\TOOLS\TREEVIEW;
|
namespace LAM\TOOLS\TREEVIEW;
|
||||||
use htmlDiv;
|
use htmlDiv;
|
||||||
use htmlForm;
|
use htmlForm;
|
||||||
|
use htmlInputField;
|
||||||
use htmlJavaScript;
|
use htmlJavaScript;
|
||||||
use htmlOutputText;
|
use htmlOutputText;
|
||||||
use htmlResponsiveInputField;
|
use htmlResponsiveInputField;
|
||||||
|
@ -142,10 +143,20 @@ function showTree(): void {
|
||||||
$deleteDialogDiv = new htmlDiv('treeview_delete_dlg', $deleteDialogContent, ['hidden']);
|
$deleteDialogDiv = new htmlDiv('treeview_delete_dlg', $deleteDialogContent, ['hidden']);
|
||||||
$row->add($deleteDialogDiv);
|
$row->add($deleteDialogDiv);
|
||||||
|
|
||||||
|
$restoreDialogContent = new htmlResponsiveRow();
|
||||||
|
$restoreDialogContent->add(new htmlOutputText(_('Do you really want to restore this entry?')));
|
||||||
|
$restoreDialogContent->addVerticalSpacer('0.5rem');
|
||||||
|
$restoreDialogEntryText = new htmlOutputText('');
|
||||||
|
$restoreDialogEntryText->setCSSClasses(['treeview-restore-entry']);
|
||||||
|
$restoreDialogContent->add($restoreDialogEntryText);
|
||||||
|
$restoreDialogDiv = new htmlDiv('treeview_restore_dlg', $restoreDialogContent, ['hidden']);
|
||||||
|
$row->add($restoreDialogDiv);
|
||||||
|
|
||||||
$errorDialogContent = new htmlResponsiveRow();
|
$errorDialogContent = new htmlResponsiveRow();
|
||||||
$errorDialogEntryTitle = new htmlOutputText('');
|
$errorDialogEntryTitle = new htmlOutputText('');
|
||||||
$errorDialogEntryTitle->setCSSClasses(['treeview-error-title']);
|
$errorDialogEntryTitle->setCSSClasses(['treeview-error-title']);
|
||||||
$errorDialogContent->add($errorDialogEntryTitle);
|
$errorDialogContent->add($errorDialogEntryTitle);
|
||||||
|
$errorDialogContent->addVerticalSpacer('0.5rem');
|
||||||
$errorDialogEntryText = new htmlOutputText('');
|
$errorDialogEntryText = new htmlOutputText('');
|
||||||
$errorDialogEntryText->setCSSClasses(['treeview-error-text']);
|
$errorDialogEntryText->setCSSClasses(['treeview-error-text']);
|
||||||
$errorDialogContent->add($errorDialogEntryText);
|
$errorDialogContent->add($errorDialogEntryText);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue