support for 389ds locking and deactivation

This commit is contained in:
Roland Gruber 2016-05-15 12:15:30 +02:00
parent 616b11e362
commit cf5132745d
11 changed files with 92 additions and 47 deletions

View File

@ -1,6 +1,7 @@
June 2016 5.4 June 2016 5.4
- Unix: support magic numbers for UIDs/GIDs (e.g. 389 server DNA plugin) - Unix: support magic numbers for UIDs/GIDs (e.g. 389 server DNA plugin)
- LAM Pro: - LAM Pro:
-> New module for 389ds unlocking and deactivation status
-> Self registration: support for Google reCAPTCHA -> Self registration: support for Google reCAPTCHA
-> Password notification jobs support CC and BCC -> Password notification jobs support CC and BCC

View File

@ -2698,8 +2698,8 @@ mysql> GRANT ALL PRIVILEGES ON lam_cron.* TO 'lam_cron'@'localhost';
<para><emphasis>Show account status:</emphasis> If you activate this <para><emphasis>Show account status:</emphasis> If you activate this
option then there will be an additional column displayed that shows if option then there will be an additional column displayed that shows if
the account is locked. You can see more details when moving the mouse the account is locked. You can see more details when moving the mouse
cursor over the lock icon. This function supports Unix, Samba and cursor over the lock icon. This function supports Unix, Samba, PPolicy,
PPolicy.</para> Windows and 389ds locking+deactivation.</para>
<screenshot> <screenshot>
<mediaobject> <mediaobject>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 760 B

After

Width:  |  Height:  |  Size: 907 B

View File

@ -1267,10 +1267,9 @@ abstract class baseModule {
* @param integer $length field length * @param integer $length field length
* @param boolean $isTextArea show as text area (default false) * @param boolean $isTextArea show as text area (default false)
* @param array $autoCompleteValues values for auto-completion * @param array $autoCompleteValues values for auto-completion
* @param boolean $readOnly this field is read-only
* @return mixed reference to htmlTableExtendedInputField/htmlTableExtendedInputTextarea * @return mixed reference to htmlTableExtendedInputField/htmlTableExtendedInputTextarea
*/ */
protected function &addSimpleInputTextField(&$container, $attrName, $label, $required = false, $length = null, $isTextArea = false, $autoCompleteValues = null, $readOnly = false) { protected function &addSimpleInputTextField(&$container, $attrName, $label, $required = false, $length = null, $isTextArea = false, $autoCompleteValues = null) {
$value = ''; $value = '';
if (isset($this->attributes[$attrName][0])) { if (isset($this->attributes[$attrName][0])) {
$value = $this->attributes[$attrName][0]; $value = $this->attributes[$attrName][0];
@ -1296,6 +1295,28 @@ abstract class baseModule {
return $input; return $input;
} }
/**
* Adds a simple read-only field to the given container.
*
* @param htmlTable $container parent container
* @param String $attrName attribute name
* @param String $label field label
*/
protected function addSimpleReadOnlyField(&$container, $attrName, $label) {
$val = '';
if (!empty($this->attributes[$attrName][0])) {
$values = $this->attributes[$attrName];
array_map('htmlspecialchars', $values);
$val = implode('<br>', $values);
}
$labelBox = new htmlOutputText($label);
if (!empty($this->attributes[$attrName]) && (sizeof($this->attributes[$attrName]) > 1)) {
$labelBox->alignment = htmlElement::ALIGN_TOP;
}
$container->addElement($labelBox);
$container->addElement(new htmlOutputText($val, false), true);
}
/** /**
* Adds a text input field that may contain multiple values to the given htmlTable. * Adds a text input field that may contain multiple values to the given htmlTable.
* The field name will be the same as the attribute name plus a counting number (e.g. street_0). * The field name will be the same as the attribute name plus a counting number (e.g. street_0).
@ -1598,6 +1619,18 @@ abstract class baseModule {
else return array(); else return array();
} }
/**
* Returns a list of operational LDAP attributes which are managed by this module and need to be explicitly set for LDAP search.
*
* @return array list of hidden attributes
*
* @see baseModule::get_metaData()
*/
public function getManagedHiddenAttributes() {
if (isset($this->meta['hiddenAttributes']) && is_array($this->meta['hiddenAttributes'])) return $this->meta['hiddenAttributes'];
else return array();
}
/** /**
* This function returns a list of PHP extensions (e.g. hash) which are needed by this module. * This function returns a list of PHP extensions (e.g. hash) which are needed by this module.
* *

View File

@ -1553,8 +1553,11 @@ class accountContainer {
$this->module = array(); $this->module = array();
$modules = $_SESSION['config']->get_AccountModules($this->type); $modules = $_SESSION['config']->get_AccountModules($this->type);
$search = substr($dn, 0, strpos($dn, ',')); $search = substr($dn, 0, strpos($dn, ','));
$searchAttrs = array('*', '+', 'creatorsName', 'createTimestamp', 'modifiersName', $searchAttrs = array('*', '+');
'modifyTimestamp', 'hasSubordinates', 'pwdChangedTime'); foreach ($modules as $module) {
$modTmp = new $module($this->type);
$searchAttrs = array_merge($searchAttrs, $modTmp->getManagedHiddenAttributes());
}
$result = @ldap_read($_SESSION['ldap']->server(), escapeDN($dn), escapeDN($search), $searchAttrs, 0, 0, 0, LDAP_DEREF_NEVER); $result = @ldap_read($_SESSION['ldap']->server(), escapeDN($dn), escapeDN($search), $searchAttrs, 0, 0, 0, LDAP_DEREF_NEVER);
if (!$result) { if (!$result) {
return array(array("ERROR", _("Unable to load LDAP entry:") . " " . htmlspecialchars($dn), getDefaultLDAPErrorString($_SESSION['ldap']->server()))); return array(array("ERROR", _("Unable to load LDAP entry:") . " " . htmlspecialchars($dn), getDefaultLDAPErrorString($_SESSION['ldap']->server())));

View File

@ -34,3 +34,4 @@
/zarafaGroup.inc /zarafaGroup.inc
/zarafaServer.inc /zarafaServer.inc
/zarafaUser.inc /zarafaUser.inc
/locking389ds.inc

View File

@ -3,7 +3,7 @@
$Id$ $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) 2011 Roland Gruber Copyright (C) 2011 - 2016 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
@ -60,7 +60,9 @@ class generalInformation extends baseModule {
$return['dependencies'] = array('depends' => array(), 'conflicts' => array()); $return['dependencies'] = array('depends' => array(), 'conflicts' => array());
// managed attributes // managed attributes
$return['attributes'] = array('creatorsName', 'createTimestamp', 'modifiersName', $return['attributes'] = array('creatorsName', 'createTimestamp', 'modifiersName',
'modifyTimestamp', 'hasSubordinates', 'memberOf', 'pwdChangedTime'); 'modifyTimestamp', 'hasSubordinates', 'memberOf');
$return['hiddenAttributes'] = array('creatorsName', 'createTimestamp', 'modifiersName',
'modifyTimestamp', 'hasSubordinates');
return $return; return $return;
} }

View File

@ -3601,28 +3601,6 @@ class inetOrgPerson extends baseModule implements passwordService {
return $this->isBooleanConfigOptionSet('inetOrgPerson_readOnly_' . $attrName); return $this->isBooleanConfigOptionSet('inetOrgPerson_readOnly_' . $attrName);
} }
/**
* Adds a simple read-only field to the given container.
*
* @param htmlTable $container parent container
* @param String $attrName attribute name
* @param String $label field label
*/
private function addSimpleReadOnlyField(&$container, $attrName, $label) {
$val = '';
if (!empty($this->attributes[$attrName][0])) {
$values = $this->attributes[$attrName];
array_map('htmlspecialchars', $values);
$val = implode('<br>', $values);
}
$labelBox = new htmlOutputText($label);
if (!empty($this->attributes[$attrName]) && (sizeof($this->attributes[$attrName]) > 1)) {
$labelBox->alignment = htmlElement::ALIGN_TOP;
}
$container->addElement($labelBox);
$container->addElement(new htmlOutputText($val, false), true);
}
/** /**
* Returns a list of configuration options. * Returns a list of configuration options.
* *

View File

@ -224,9 +224,12 @@ class user extends baseType {
$sambaAvailable = (($container->getAccountModule('sambaSamAccount') != null) && $container->getAccountModule('sambaSamAccount')->isExtensionEnabled()); $sambaAvailable = (($container->getAccountModule('sambaSamAccount') != null) && $container->getAccountModule('sambaSamAccount')->isExtensionEnabled());
$ppolicyAvailable = ($container->getAccountModule('ppolicyUser') != null); $ppolicyAvailable = ($container->getAccountModule('ppolicyUser') != null);
$windowsAvailable = ($container->getAccountModule('windowsUser') != null); $windowsAvailable = ($container->getAccountModule('windowsUser') != null);
if (!$unixAvailable && !$sambaAvailable && !$ppolicyAvailable && !$windowsAvailable) { $is389dsLocked = ($container->getAccountModule('locking389ds') != null) && $container->getAccountModule('locking389ds')->isLocked();
$is389dsDeactivated = ($container->getAccountModule('locking389ds') != null) && $container->getAccountModule('locking389ds')->isDeactivated();
if (!$unixAvailable && !$sambaAvailable && !$ppolicyAvailable && !$windowsAvailable && !$is389dsDeactivated && !$is389dsLocked) {
return ''; return '';
} }
$isEditable = checkIfWriteAccessIsAllowed('user') && ($unixAvailable || $sambaAvailable || $ppolicyAvailable || $windowsAvailable || $is389dsLocked);
// get locking status // get locking status
$unixLocked = false; $unixLocked = false;
if ($unixAvailable && $container->getAccountModule('posixAccount')->isLocked()) { if ($unixAvailable && $container->getAccountModule('posixAccount')->isLocked()) {
@ -244,8 +247,8 @@ class user extends baseType {
if ($windowsAvailable && windowsUser::isDeactivated($container->getAccountModule('windowsUser')->getAttributes())) { if ($windowsAvailable && windowsUser::isDeactivated($container->getAccountModule('windowsUser')->getAttributes())) {
$windowsLocked = true; $windowsLocked = true;
} }
$partiallyLocked = $unixLocked || $sambaLocked || $ppolicyLocked || $windowsLocked; $partiallyLocked = $unixLocked || $sambaLocked || $ppolicyLocked || $windowsLocked || $is389dsDeactivated || $is389dsLocked;
$fullyLocked = ($unixAvailable || $sambaAvailable || $ppolicyAvailable || $windowsAvailable) $fullyLocked = ($unixAvailable || $sambaAvailable || $ppolicyAvailable || $windowsAvailable || $is389dsDeactivated || $is389dsLocked)
&& (!$unixAvailable || $unixLocked) && (!$unixAvailable || $unixLocked)
&& (!$sambaAvailable || $sambaLocked) && (!$sambaAvailable || $sambaLocked)
&& (!$ppolicyAvailable || $ppolicyLocked) && (!$ppolicyAvailable || $ppolicyLocked)
@ -291,15 +294,23 @@ class user extends baseType {
} }
$statusTable .= '<tr><td>' . _('Windows') . '&nbsp;&nbsp;</td><td><img height=16 width=16 src=&quot;../../graphics/' . $windowsIcon . '&quot;></td></tr>'; $statusTable .= '<tr><td>' . _('Windows') . '&nbsp;&nbsp;</td><td><img height=16 width=16 src=&quot;../../graphics/' . $windowsIcon . '&quot;></td></tr>';
} }
// 389ds locked
if ($is389dsLocked) {
$statusTable .= '<tr><td>' . _('Locked') . '&nbsp;&nbsp;</td><td><img height=16 width=16 src=&quot;../../graphics/lock.png&quot;></td></tr>';
}
// 389ds deactivated
if ($is389dsDeactivated) {
$statusTable .= '<tr><td>' . _('Deactivated') . '&nbsp;&nbsp;</td><td><img height=16 width=16 src=&quot;../../graphics/lock.png&quot;></td></tr>';
}
$statusTable .= '</table>'; $statusTable .= '</table>';
$tipContent = $statusTable; $tipContent = $statusTable;
if (checkIfWriteAccessIsAllowed('user')) { if ($isEditable) {
$tipContent .= '<br><img alt=&quot;hint&quot; src=&quot;../../graphics/light.png&quot;> '; $tipContent .= '<br><img alt=&quot;hint&quot; src=&quot;../../graphics/light.png&quot;> ';
$tipContent .= _('Please click to lock/unlock this account.'); $tipContent .= _('Please click to lock/unlock this account.');
} }
$dialogDiv = $this->buildAccountStatusDialogDiv($unixAvailable, $unixLocked, $sambaAvailable, $sambaLocked, $ppolicyAvailable, $ppolicyLocked, $windowsAvailable, $windowsLocked); $dialogDiv = $this->buildAccountStatusDialogDiv($unixAvailable, $unixLocked, $sambaAvailable, $sambaLocked, $ppolicyAvailable, $ppolicyLocked, $windowsAvailable, $windowsLocked, $is389dsLocked);
$onClick = ''; $onClick = '';
if (checkIfWriteAccessIsAllowed('user')) { if ($isEditable) {
$onClick = 'onclick="showConfirmationDialog(\'' . _('Change account status') . '\', \'' . _('Ok') . '\', \'' . _('Cancel') . '\', \'lam_accountStatusDialog\', \'inputForm\', \'lam_accountStatusResult\');"'; $onClick = 'onclick="showConfirmationDialog(\'' . _('Change account status') . '\', \'' . _('Ok') . '\', \'' . _('Cancel') . '\', \'lam_accountStatusDialog\', \'inputForm\', \'lam_accountStatusResult\');"';
} }
return $dialogDiv . '<a href="#"><img id="lam_accountStatus" alt="status" ' . $onClick . ' helptitle="' . _('Account status') . '" helpdata="' . $tipContent . '" height=16 width=16 src="../../graphics/' . $icon . '"></a>&nbsp;&nbsp;&nbsp;'; return $dialogDiv . '<a href="#"><img id="lam_accountStatus" alt="status" ' . $onClick . ' helptitle="' . _('Account status') . '" helpdata="' . $tipContent . '" height=16 width=16 src="../../graphics/' . $icon . '"></a>&nbsp;&nbsp;&nbsp;';
@ -316,10 +327,11 @@ class user extends baseType {
* @param boolean $ppolicyLocked PPolicy part is locked * @param boolean $ppolicyLocked PPolicy part is locked
* @param boolean $windowsAvailable Windows part is active * @param boolean $windowsAvailable Windows part is active
* @param boolean $windowsLocked Windows part is locked * @param boolean $windowsLocked Windows part is locked
* @param boolean $is389dsLocked account is locked
*/ */
private function buildAccountStatusDialogDiv($unixAvailable, $unixLocked, $sambaAvailable, $sambaLocked, $ppolicyAvailable, $ppolicyLocked, $windowsAvailable, $windowsLocked) { private function buildAccountStatusDialogDiv($unixAvailable, $unixLocked, $sambaAvailable, $sambaLocked, $ppolicyAvailable, $ppolicyLocked, $windowsAvailable, $windowsLocked, $is389dsLocked) {
$partiallyLocked = $unixLocked || $sambaLocked || $ppolicyLocked || $windowsLocked; $partiallyLocked = $unixLocked || $sambaLocked || $ppolicyLocked || $windowsLocked || $is389dsLocked;
$fullyLocked = ($unixAvailable || $sambaAvailable || $ppolicyAvailable || $windowsAvailable) $fullyLocked = ($unixAvailable || $sambaAvailable || $ppolicyAvailable || $windowsAvailable || $is389dsLocked)
&& (!$unixAvailable || $unixLocked) && (!$unixAvailable || $unixLocked)
&& (!$sambaAvailable || $sambaLocked) && (!$sambaAvailable || $sambaLocked)
&& (!$ppolicyAvailable || $ppolicyLocked) && (!$ppolicyAvailable || $ppolicyLocked)
@ -329,7 +341,7 @@ class user extends baseType {
// show radio buttons for lock/unlock // show radio buttons for lock/unlock
$radioDisabled = true; $radioDisabled = true;
$selectedRadio = 'lock'; $selectedRadio = 'unlock';
$onchange = ''; $onchange = '';
if ($partiallyLocked && !$fullyLocked) { if ($partiallyLocked && !$fullyLocked) {
$radioDisabled = false; $radioDisabled = false;
@ -342,8 +354,8 @@ class user extends baseType {
'jQuery(\'#lam_accountStatusDialogUnlockDiv\').removeClass(\'hidden\');' . 'jQuery(\'#lam_accountStatusDialogUnlockDiv\').removeClass(\'hidden\');' .
'};'; '};';
} }
if ($fullyLocked) { if (!$fullyLocked && !$partiallyLocked) {
$selectedRadio = 'unlock'; $selectedRadio = 'lock';
} }
if (!$radioDisabled) { if (!$radioDisabled) {
$radio = new htmlRadio('lam_accountStatusAction', array(_('Lock') => 'lock', _('Unlock') => 'unlock'), $selectedRadio); $radio = new htmlRadio('lam_accountStatusAction', array(_('Lock') => 'lock', _('Unlock') => 'unlock'), $selectedRadio);
@ -389,6 +401,9 @@ class user extends baseType {
} }
$lockDiv = new htmlDiv('lam_accountStatusDialogLockDiv', $lockContent); $lockDiv = new htmlDiv('lam_accountStatusDialogLockDiv', $lockContent);
if ($fullyLocked || $partiallyLocked) {
$lockDiv->setCSSClasses(array('hidden'));
}
$container->addElement($lockDiv, true); $container->addElement($lockDiv, true);
} }
// unlocking part // unlocking part
@ -411,9 +426,13 @@ class user extends baseType {
$unlockContent->addElement(new htmlImage('../../graphics/samba.png')); $unlockContent->addElement(new htmlImage('../../graphics/samba.png'));
$unlockContent->addElement(new htmlTableExtendedInputCheckbox('lam_accountStatusUnlockWindows', true, _('Windows'), null, false), true); $unlockContent->addElement(new htmlTableExtendedInputCheckbox('lam_accountStatusUnlockWindows', true, _('Windows'), null, false), true);
} }
if ($is389dsLocked) {
$unlockContent->addElement(new htmlImage('../../graphics/security.png'));
$unlockContent->addElement(new htmlTableExtendedInputCheckbox('lam_accountStatusUnlock389ds', true, _('Unlock'), null, false), true);
}
$unlockDiv = new htmlDiv('lam_accountStatusDialogUnlockDiv', $unlockContent); $unlockDiv = new htmlDiv('lam_accountStatusDialogUnlockDiv', $unlockContent);
if (!$fullyLocked) { if (!$fullyLocked && !$partiallyLocked) {
$unlockDiv->setCSSClasses(array('hidden')); $unlockDiv->setCSSClasses(array('hidden'));
} }
$container->addElement($unlockDiv, true); $container->addElement($unlockDiv, true);
@ -485,6 +504,10 @@ class user extends baseType {
if (isset($_POST['lam_accountStatusUnlockWindows']) && ($_POST['lam_accountStatusUnlockWindows'] == 'on')) { if (isset($_POST['lam_accountStatusUnlockWindows']) && ($_POST['lam_accountStatusUnlockWindows'] == 'on')) {
$container->getAccountModule('windowsUser')->setIsDeactivated(false); $container->getAccountModule('windowsUser')->setIsDeactivated(false);
} }
// 389ds unlocking
if (isset($_POST['lam_accountStatusUnlock389ds']) && ($_POST['lam_accountStatusUnlock389ds'] == 'on')) {
$container->getAccountModule('locking389ds')->unlock(false);
}
} }
} }
} }
@ -829,10 +852,14 @@ class lamUserList extends lamList {
$sambaLocked = self::isSambaLocked($this->entries[$i]); $sambaLocked = self::isSambaLocked($this->entries[$i]);
$ppolicyLocked = self::isPPolicyLocked($this->entries[$i]); $ppolicyLocked = self::isPPolicyLocked($this->entries[$i]);
$windowsLocked = self::isWindowsLocked($this->entries[$i]); $windowsLocked = self::isWindowsLocked($this->entries[$i]);
$is389dsLocked = self::is389dsLocked($this->entries[$i]);
$is389dsDeactivated = self::is389dsDeactivated($this->entries[$i]);
$hasLocked = ($unixAvailable && $unixLocked) $hasLocked = ($unixAvailable && $unixLocked)
|| ($sambaAvailable && $sambaLocked) || ($sambaAvailable && $sambaLocked)
|| ($ppolicyAvailable && $ppolicyLocked) || ($ppolicyAvailable && $ppolicyLocked)
|| ($windowsAvailable && $windowsLocked); || ($windowsAvailable && $windowsLocked)
|| $is389dsDeactivated
|| $is389dsLocked;
$hasUnlocked = ($unixAvailable && !$unixLocked) $hasUnlocked = ($unixAvailable && !$unixLocked)
|| ($sambaAvailable && !$sambaLocked) || ($sambaAvailable && !$sambaLocked)
|| ($ppolicyAvailable && !$ppolicyLocked) || ($ppolicyAvailable && !$ppolicyLocked)