diff --git a/lam/HISTORY b/lam/HISTORY index 467a07b5..818f0748 100644 --- a/lam/HISTORY +++ b/lam/HISTORY @@ -1,6 +1,7 @@ June 2016 5.4 - Unix: support magic numbers for UIDs/GIDs (e.g. 389 server DNA plugin) - LAM Pro: + -> New module for 389ds unlocking and deactivation status -> Self registration: support for Google reCAPTCHA -> Password notification jobs support CC and BCC diff --git a/lam/docs/manual-sources/howto.xml b/lam/docs/manual-sources/howto.xml index 92261b2a..aa5d4039 100644 --- a/lam/docs/manual-sources/howto.xml +++ b/lam/docs/manual-sources/howto.xml @@ -2698,8 +2698,8 @@ mysql> GRANT ALL PRIVILEGES ON lam_cron.* TO 'lam_cron'@'localhost'; Show account status: If you activate this 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 - cursor over the lock icon. This function supports Unix, Samba and - PPolicy. + cursor over the lock icon. This function supports Unix, Samba, PPolicy, + Windows and 389ds locking+deactivation. diff --git a/lam/docs/manual-sources/images/userListOptionAccountStatus.png b/lam/docs/manual-sources/images/userListOptionAccountStatus.png index b9402d13..d1f550c3 100644 Binary files a/lam/docs/manual-sources/images/userListOptionAccountStatus.png and b/lam/docs/manual-sources/images/userListOptionAccountStatus.png differ diff --git a/lam/docs/manual-sources/images/userListOptionTransPrimary.png b/lam/docs/manual-sources/images/userListOptionTransPrimary.png index 685020fb..1fa83602 100644 Binary files a/lam/docs/manual-sources/images/userListOptionTransPrimary.png and b/lam/docs/manual-sources/images/userListOptionTransPrimary.png differ diff --git a/lam/graphics/unlocked.png b/lam/graphics/unlocked.png index 91891851..0b6b805f 100644 Binary files a/lam/graphics/unlocked.png and b/lam/graphics/unlocked.png differ diff --git a/lam/lib/baseModule.inc b/lam/lib/baseModule.inc index 48f219c6..157dc602 100644 --- a/lam/lib/baseModule.inc +++ b/lam/lib/baseModule.inc @@ -1267,10 +1267,9 @@ abstract class baseModule { * @param integer $length field length * @param boolean $isTextArea show as text area (default false) * @param array $autoCompleteValues values for auto-completion - * @param boolean $readOnly this field is read-only * @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 = ''; if (isset($this->attributes[$attrName][0])) { $value = $this->attributes[$attrName][0]; @@ -1296,6 +1295,28 @@ abstract class baseModule { 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('
', $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. * 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(); } + /** + * 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. * diff --git a/lam/lib/modules.inc b/lam/lib/modules.inc index 4b49c72f..1f23c449 100644 --- a/lam/lib/modules.inc +++ b/lam/lib/modules.inc @@ -1553,8 +1553,11 @@ class accountContainer { $this->module = array(); $modules = $_SESSION['config']->get_AccountModules($this->type); $search = substr($dn, 0, strpos($dn, ',')); - $searchAttrs = array('*', '+', 'creatorsName', 'createTimestamp', 'modifiersName', - 'modifyTimestamp', 'hasSubordinates', 'pwdChangedTime'); + $searchAttrs = array('*', '+'); + 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); if (!$result) { return array(array("ERROR", _("Unable to load LDAP entry:") . " " . htmlspecialchars($dn), getDefaultLDAPErrorString($_SESSION['ldap']->server()))); diff --git a/lam/lib/modules/.gitignore b/lam/lib/modules/.gitignore index d25f68ab..78c0f9c0 100644 --- a/lam/lib/modules/.gitignore +++ b/lam/lib/modules/.gitignore @@ -34,3 +34,4 @@ /zarafaGroup.inc /zarafaServer.inc /zarafaUser.inc +/locking389ds.inc diff --git a/lam/lib/modules/generalInformation.inc b/lam/lib/modules/generalInformation.inc index f8220456..968d1edf 100644 --- a/lam/lib/modules/generalInformation.inc +++ b/lam/lib/modules/generalInformation.inc @@ -3,7 +3,7 @@ $Id$ 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 it under the terms of the GNU General Public License as published by @@ -36,7 +36,7 @@ class generalInformation extends baseModule { /** * Returns true if this module can manage accounts of the current type, otherwise false. - * + * * @return boolean true if module fits */ public function can_manage() { @@ -47,7 +47,7 @@ class generalInformation extends baseModule { * Returns meta data that is interpreted by parent class * * @return array array with meta data - * + * * @see baseModule::get_metaData() */ public function get_metaData() { @@ -60,13 +60,15 @@ class generalInformation extends baseModule { $return['dependencies'] = array('depends' => array(), 'conflicts' => array()); // managed attributes $return['attributes'] = array('creatorsName', 'createTimestamp', 'modifiersName', - 'modifyTimestamp', 'hasSubordinates', 'memberOf', 'pwdChangedTime'); + 'modifyTimestamp', 'hasSubordinates', 'memberOf'); + $return['hiddenAttributes'] = array('creatorsName', 'createTimestamp', 'modifiersName', + 'modifyTimestamp', 'hasSubordinates'); return $return; } /** * Returns the HTML meta data for the main account page. - * + * * @return htmlElement HTML meta data */ public function display_html_attributes() { diff --git a/lam/lib/modules/inetOrgPerson.inc b/lam/lib/modules/inetOrgPerson.inc index 4ee458c6..c5258725 100644 --- a/lam/lib/modules/inetOrgPerson.inc +++ b/lam/lib/modules/inetOrgPerson.inc @@ -3601,28 +3601,6 @@ class inetOrgPerson extends baseModule implements passwordService { 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('
', $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. * diff --git a/lam/lib/types/user.inc b/lam/lib/types/user.inc index f24354df..36bd4624 100644 --- a/lam/lib/types/user.inc +++ b/lam/lib/types/user.inc @@ -224,9 +224,12 @@ class user extends baseType { $sambaAvailable = (($container->getAccountModule('sambaSamAccount') != null) && $container->getAccountModule('sambaSamAccount')->isExtensionEnabled()); $ppolicyAvailable = ($container->getAccountModule('ppolicyUser') != 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 ''; } + $isEditable = checkIfWriteAccessIsAllowed('user') && ($unixAvailable || $sambaAvailable || $ppolicyAvailable || $windowsAvailable || $is389dsLocked); // get locking status $unixLocked = false; if ($unixAvailable && $container->getAccountModule('posixAccount')->isLocked()) { @@ -244,8 +247,8 @@ class user extends baseType { if ($windowsAvailable && windowsUser::isDeactivated($container->getAccountModule('windowsUser')->getAttributes())) { $windowsLocked = true; } - $partiallyLocked = $unixLocked || $sambaLocked || $ppolicyLocked || $windowsLocked; - $fullyLocked = ($unixAvailable || $sambaAvailable || $ppolicyAvailable || $windowsAvailable) + $partiallyLocked = $unixLocked || $sambaLocked || $ppolicyLocked || $windowsLocked || $is389dsDeactivated || $is389dsLocked; + $fullyLocked = ($unixAvailable || $sambaAvailable || $ppolicyAvailable || $windowsAvailable || $is389dsDeactivated || $is389dsLocked) && (!$unixAvailable || $unixLocked) && (!$sambaAvailable || $sambaLocked) && (!$ppolicyAvailable || $ppolicyLocked) @@ -291,15 +294,23 @@ class user extends baseType { } $statusTable .= '' . _('Windows') . '  '; } + // 389ds locked + if ($is389dsLocked) { + $statusTable .= '' . _('Locked') . '  '; + } + // 389ds deactivated + if ($is389dsDeactivated) { + $statusTable .= '' . _('Deactivated') . '  '; + } $statusTable .= ''; $tipContent = $statusTable; - if (checkIfWriteAccessIsAllowed('user')) { + if ($isEditable) { $tipContent .= '
"hint" '; $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 = ''; - if (checkIfWriteAccessIsAllowed('user')) { + if ($isEditable) { $onClick = 'onclick="showConfirmationDialog(\'' . _('Change account status') . '\', \'' . _('Ok') . '\', \'' . _('Cancel') . '\', \'lam_accountStatusDialog\', \'inputForm\', \'lam_accountStatusResult\');"'; } return $dialogDiv . 'status   '; @@ -316,10 +327,11 @@ class user extends baseType { * @param boolean $ppolicyLocked PPolicy part is locked * @param boolean $windowsAvailable Windows part is active * @param boolean $windowsLocked Windows part is locked + * @param boolean $is389dsLocked account is locked */ - private function buildAccountStatusDialogDiv($unixAvailable, $unixLocked, $sambaAvailable, $sambaLocked, $ppolicyAvailable, $ppolicyLocked, $windowsAvailable, $windowsLocked) { - $partiallyLocked = $unixLocked || $sambaLocked || $ppolicyLocked || $windowsLocked; - $fullyLocked = ($unixAvailable || $sambaAvailable || $ppolicyAvailable || $windowsAvailable) + private function buildAccountStatusDialogDiv($unixAvailable, $unixLocked, $sambaAvailable, $sambaLocked, $ppolicyAvailable, $ppolicyLocked, $windowsAvailable, $windowsLocked, $is389dsLocked) { + $partiallyLocked = $unixLocked || $sambaLocked || $ppolicyLocked || $windowsLocked || $is389dsLocked; + $fullyLocked = ($unixAvailable || $sambaAvailable || $ppolicyAvailable || $windowsAvailable || $is389dsLocked) && (!$unixAvailable || $unixLocked) && (!$sambaAvailable || $sambaLocked) && (!$ppolicyAvailable || $ppolicyLocked) @@ -329,7 +341,7 @@ class user extends baseType { // show radio buttons for lock/unlock $radioDisabled = true; - $selectedRadio = 'lock'; + $selectedRadio = 'unlock'; $onchange = ''; if ($partiallyLocked && !$fullyLocked) { $radioDisabled = false; @@ -342,8 +354,8 @@ class user extends baseType { 'jQuery(\'#lam_accountStatusDialogUnlockDiv\').removeClass(\'hidden\');' . '};'; } - if ($fullyLocked) { - $selectedRadio = 'unlock'; + if (!$fullyLocked && !$partiallyLocked) { + $selectedRadio = 'lock'; } if (!$radioDisabled) { $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); + if ($fullyLocked || $partiallyLocked) { + $lockDiv->setCSSClasses(array('hidden')); + } $container->addElement($lockDiv, true); } // unlocking part @@ -411,9 +426,13 @@ class user extends baseType { $unlockContent->addElement(new htmlImage('../../graphics/samba.png')); $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); - if (!$fullyLocked) { + if (!$fullyLocked && !$partiallyLocked) { $unlockDiv->setCSSClasses(array('hidden')); } $container->addElement($unlockDiv, true); @@ -485,6 +504,10 @@ class user extends baseType { if (isset($_POST['lam_accountStatusUnlockWindows']) && ($_POST['lam_accountStatusUnlockWindows'] == 'on')) { $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]); $ppolicyLocked = self::isPPolicyLocked($this->entries[$i]); $windowsLocked = self::isWindowsLocked($this->entries[$i]); + $is389dsLocked = self::is389dsLocked($this->entries[$i]); + $is389dsDeactivated = self::is389dsDeactivated($this->entries[$i]); $hasLocked = ($unixAvailable && $unixLocked) || ($sambaAvailable && $sambaLocked) || ($ppolicyAvailable && $ppolicyLocked) - || ($windowsAvailable && $windowsLocked); + || ($windowsAvailable && $windowsLocked) + || $is389dsDeactivated + || $is389dsLocked; $hasUnlocked = ($unixAvailable && !$unixLocked) || ($sambaAvailable && !$sambaLocked) || ($ppolicyAvailable && !$ppolicyLocked)