From 7cd00189337f0be04134b51432770524e5c73264 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Wed, 2 Sep 2015 16:39:30 +0000 Subject: [PATCH] --- lam/HISTORY | 4 ++ lam/lib/modules/ldapPublicKey.inc | 105 ++++++++++++++++++++++++++---- lam/lib/modules/windowsUser.inc | 94 +++++++++++++++++++++++++- 3 files changed, 189 insertions(+), 14 deletions(-) diff --git a/lam/HISTORY b/lam/HISTORY index 0c031f72..e37f1903 100644 --- a/lam/HISTORY +++ b/lam/HISTORY @@ -1,3 +1,7 @@ +December 2015 5.2 + - SSH public key: added possibility to add/remove SSH extension + + 31.08.2015 5.1 - IMAP: support Windows users - SSH public key: check uploaded files if in right format diff --git a/lam/lib/modules/ldapPublicKey.inc b/lam/lib/modules/ldapPublicKey.inc index 1ac6a5ec..89413758 100644 --- a/lam/lib/modules/ldapPublicKey.inc +++ b/lam/lib/modules/ldapPublicKey.inc @@ -38,6 +38,17 @@ class ldapPublicKey extends baseModule { /** session variable for existing keys in self service */ const SESS_KEY_LIST = 'ldapPublicKey_keyList'; + /** + * Creates a new sambaSamAccount object. + * + * @param string $scope account type (user, group, host) + */ + function __construct($scope) { + // call parent constructor + parent::__construct($scope); + $this->autoAddObjectClasses = false; + } + /** * Returns true if this module can manage accounts of the current type, otherwise false. * @@ -80,7 +91,15 @@ class ldapPublicKey extends baseModule { "Headline" => _("File upload"), 'attr' => 'sshPublicKey', "Text" => _("Upload a file with one or more keys. Each line contains one key.") ), + 'autoAdd' => array( + "Headline" => _("Automatically add this extension"), + "Text" => _("This will enable the extension automatically if this profile is loaded.") + ), ); + // profile options + $profileContainer = new htmlTable(); + $profileContainer->addElement(new htmlTableExtendedInputCheckbox('ldapPublicKey_addExt', false, _('Automatically add this extension'), 'autoAdd'), true); + $return['profile_options'] = $profileContainer; // upload fields $return['upload_columns'] = array( array( @@ -117,17 +136,28 @@ class ldapPublicKey extends baseModule { */ function display_html_attributes() { $return = new htmlTable(); - $this->addMultiValueInputTextField($return, 'sshPublicKey', _('SSH public key'), false, '16384', false, null, '50'); - // file upload - $return->addElement(new htmlSpacer(null, '20px'), true); - $return->addElement(new htmlOutputText(_('Upload file'))); - $uploadGroup = new htmlGroup(); - $uploadGroup->addElement(new htmlInputFileUpload('sshPublicKeyFile')); - $uploadGroup->addElement(new htmlSpacer('1px', null)); - $uploadGroup->addElement(new htmlButton('sshPublicKeyFileSubmit', _('Upload'))); - $uploadGroup->addElement(new htmlSpacer('5px', null)); - $uploadGroup->addElement(new htmlHelpLink('upload')); - $return->addElement($uploadGroup); + if (in_array('ldapPublicKey', $this->attributes['objectClass'])) { + $this->addMultiValueInputTextField($return, 'sshPublicKey', _('SSH public key'), false, '16384', false, null, '50'); + // file upload + $return->addElement(new htmlSpacer(null, '20px'), true); + $return->addElement(new htmlOutputText(_('Upload file'))); + $uploadGroup = new htmlGroup(); + $uploadGroup->addElement(new htmlInputFileUpload('sshPublicKeyFile')); + $uploadGroup->addElement(new htmlSpacer('1px', null)); + $uploadGroup->addElement(new htmlButton('sshPublicKeyFileSubmit', _('Upload'))); + $uploadGroup->addElement(new htmlSpacer('5px', null)); + $uploadGroup->addElement(new htmlHelpLink('upload')); + $return->addElement($uploadGroup, true); + + $return->addElement(new htmlSpacer(null, '30px'), true); + + $remButton = new htmlButton('remObjectClass', _('Remove SSH public key extension')); + $remButton->colspan = 3; + $return->addElement($remButton); + } + else { + $return->addElement(new htmlButton('addObjectClass', _('Add SSH public key extension'))); + } return $return; } @@ -139,6 +169,23 @@ class ldapPublicKey extends baseModule { */ function process_attributes() { $messages = array(); + // add extension + if (isset($_POST['addObjectClass'])) { + $this->attributes['objectClass'][] = 'ldapPublicKey'; + return array(); + } + // remove extension + elseif (isset($_POST['remObjectClass'])) { + $this->attributes['objectClass'] = array_delete(array('ldapPublicKey'), $this->attributes['objectClass']); + if (!empty($this->attributes['sshPublicKey'])) { + unset($this->attributes['sshPublicKey']); + } + return array(); + } + // skip processing if extension is not active + if (!in_array('ldapPublicKey', $this->attributes['objectClass'])) { + return array(); + } $this->processMultiValueInputTextField('sshPublicKey', $messages); // file upload if (isset($_POST['sshPublicKeyFileSubmit'])) { @@ -175,6 +222,42 @@ class ldapPublicKey extends baseModule { return $messages; } + /** + * Returns a list of modifications which have to be made to the LDAP account. + * + * @return array list of modifications + *
This function returns an array with 3 entries: + *
array( DN1 ('add' => array($attr), 'remove' => array($attr), 'modify' => array($attr)), DN2 .... ) + *
DN is the DN to change. It may be possible to change several DNs (e.g. create a new user and add him to some groups via attribute memberUid) + *
"add" are attributes which have to be added to LDAP entry + *
"remove" are attributes which have to be removed from LDAP entry + *
"modify" are attributes which have to been modified in LDAP entry + *
"info" are values with informational value (e.g. to be used later by pre/postModify actions) + */ + function save_attributes() { + if (!in_array('ldapPublicKey', $this->attributes['objectClass']) && !in_array('ldapPublicKey', $this->orig['objectClass'])) { + // skip saving if the extension was not added/modified + return array(); + } + return parent::save_attributes(); + } + + /** + * Loads the values of an account profile into internal variables. + * + * @param array $profile hash array with profile values (identifier => value) + */ + function load_profile($profile) { + // profile mappings in meta data + parent::load_profile($profile); + // add extension + if (isset($profile['ldapPublicKey_addExt'][0]) && ($profile['ldapPublicKey_addExt'][0] == "true")) { + if (!in_array('ldapPublicKey', $this->attributes['objectClass'])) { + $this->attributes['objectClass'][] = 'ldapPublicKey'; + } + } + } + /** * In this function the LDAP account is built up. * diff --git a/lam/lib/modules/windowsUser.inc b/lam/lib/modules/windowsUser.inc index 5766f69b..be333f80 100644 --- a/lam/lib/modules/windowsUser.inc +++ b/lam/lib/modules/windowsUser.inc @@ -95,7 +95,9 @@ class windowsUser extends baseModule implements passwordService { $return['attributes'] = array('userPrincipalName', 'cn', 'sAMAccountName', 'description', 'displayName', 'givenName', 'initials', 'l', 'mail', 'otherTelephone', 'physicalDeliveryOfficeName', 'postalCode', 'postOfficeBox', 'sn', 'st', 'streetAddress', 'telephoneNumber', 'url', 'wWWHomePage', 'userAccountControl', 'profilePath', 'scriptPath', - 'pwdLastSet', 'otherMailbox', 'homeDirectory', 'homeDrive', 'msSFU30Name', 'msSFU30NisDomain'); + 'pwdLastSet', 'otherMailbox', 'homeDirectory', 'homeDrive', 'msSFU30Name', 'msSFU30NisDomain', 'pwdLastSet', + 'lastLogonTimestamp' + ); // help Entries $return['help'] = array( 'cn' => array( @@ -256,6 +258,14 @@ class windowsUser extends baseModule implements passwordService { "Headline" => _('NIS domain'), 'attr' => 'msSFU30NisDomain', "Text" => _('NIS domain name.') ), + 'pwdLastSet' => array( + "Headline" => _('Last password change'), 'attr' => 'pwdLastSet', + "Text" => _('Time of user\'s last password change.') + ), + 'lastLogonTimestamp' => array( + "Headline" => _('Last login'), 'attr' => 'lastLogonTimestamp', + "Text" => _('Time of user\'s last login.') + ), ); // upload fields $return['upload_columns'] = array( @@ -534,6 +544,12 @@ class windowsUser extends baseModule implements passwordService { if (!$this->isBooleanConfigOptionSet('windowsUser_hidemsSFU30NisDomain', true)) { $return['PDF_fields']['msSFU30NisDomain'] = _('NIS domain'); } + if (!$this->isBooleanConfigOptionSet('windowsUser_hidepwdLastSet')) { + $return['PDF_fields']['pwdLastSet'] = _('Last password change'); + } + if (!$this->isBooleanConfigOptionSet('windowsUser_hidelastLogonTimestamp')) { + $return['PDF_fields']['lastLogonTimestamp'] = _('Last login'); + } // self service search attributes $return['selfServiceSearchAttributes'] = array('sAMAccountName', 'userPrincipalName'); // self service field settings @@ -546,7 +562,8 @@ class windowsUser extends baseModule implements passwordService { 'l' => _('Location'), 'postOfficeBox' => _('Post office box'), 'postalCode' => _('Postal code'), - 'unicodePwd' => _('Password') + 'unicodePwd' => _('Password'), + 'pwdLastSet' => _('Last password change (read-only)') ); // possible self service read-only fields $return['selfServiceReadOnlyFields'] = array('physicalDeliveryOfficeName', 'telephoneNumber', @@ -565,6 +582,8 @@ class windowsUser extends baseModule implements passwordService { $configContainerOptions->addElement(new htmlTableExtendedInputCheckbox('windowsUser_hidesAMAccountName', true, _('User name (pre W2K)'), null, false)); $configContainerOptions->addElement(new htmlTableExtendedInputCheckbox('windowsUser_hidemsSFU30Name', true, _('NIS name'), null, false)); $configContainerOptions->addElement(new htmlTableExtendedInputCheckbox('windowsUser_hidemsSFU30NisDomain', true, _('NIS domain'), null, false)); + $configContainerOptions->addElement(new htmlTableExtendedInputCheckbox('windowsUser_hidepwdLastSet', false, _('Last password change'), null, false)); + $configContainerOptions->addElement(new htmlTableExtendedInputCheckbox('windowsUser_hidelastLogonTimestamp', false, _('Last login'), null, false)); $configContainer->addElement($configContainerOptions, true); $return['config_options']['all'] = $configContainer; return $return; @@ -720,7 +739,7 @@ class windowsUser extends baseModule implements passwordService { $this->addSimpleInputTextField($containerLeft, 'wWWHomePage', _('Web site')); $this->addMultiValueInputTextField($containerLeft, 'url', _('Other web sites')); - $containerLeft->addElement(new htmlSubTitle(_('Options')), true); + $containerLeft->addElement(new htmlSubTitle(_('Account')), true); // locked out $containerLeft->addElement(new htmlOutputText(_("Account is locked"))); $lockedOut = windowsUser::isLockedOut($this->attributes); @@ -748,6 +767,18 @@ class windowsUser extends baseModule implements passwordService { // require smartcard $requireCard = windowsUser::isSmartCardRequired($this->attributes); $containerLeft->addElement(new htmlTableExtendedInputCheckbox('requireCard', $requireCard, _("Require smartcard"), 'requireCard'), true); + // last password change + if (!$this->isBooleanConfigOptionSet('windowsUser_hidepwdLastSet')) { + $containerLeft->addElement(new htmlOutputText(_('Last password change'))); + $containerLeft->addElement(new htmlOutputText($this->formatPwdLastSet())); + $containerLeft->addElement(new htmlHelpLink('pwdLastSet'), true); + } + // last login + if (!$this->isBooleanConfigOptionSet('windowsUser_hidelastLogonTimestamp')) { + $containerLeft->addElement(new htmlOutputText(_('Last login'))); + $containerLeft->addElement(new htmlOutputText($this->formatLastLogonTimestamp())); + $containerLeft->addElement(new htmlHelpLink('lastLogonTimestamp'), true); + } $containerLeft->addElement(new htmlSubTitle(_('User profile')), true); // profile path @@ -1636,6 +1667,10 @@ class windowsUser extends baseModule implements passwordService { else if (isset($this->attributes['INFO.userPasswordClearText'])) { $this->addPDFKeyValue($return, 'password', _('Password'), $this->attributes['INFO.userPasswordClearText']); } + // last password change + $this->addPDFKeyValue($return, 'pwdLastSet', _('Last password change'), $this->formatPwdLastSet()); + // last login + $this->addPDFKeyValue($return, 'lastLogonTimestamp', _('Last login'), $this->formatLastLogonTimestamp()); return $return; } @@ -1729,6 +1764,11 @@ class windowsUser extends baseModule implements passwordService { $this->addSimpleSelfServiceTextField($return, 'l', _('Location'), $fields, $attributes, $readOnlyFields); $this->addSimpleSelfServiceTextField($return, 'postOfficeBox', _('Post office box'), $fields, $attributes, $readOnlyFields); $this->addSimpleSelfServiceTextField($return, 'postalCode', _('Postal code'), $fields, $attributes, $readOnlyFields); + // last password change + $row = new htmlResponsiveRow(); + $row->addLabel(new htmlOutputText($this->getSelfServiceLabel('pwdLastSet', _('Last password change')))); + $row->addField(new htmlOutputText($this->formatPwdLastSet($attributes))); + $return['pwdLastSet'] = $row; return $return; } @@ -2119,6 +2159,54 @@ class windowsUser extends baseModule implements passwordService { return array_values(array_unique($domains)); } + /** + * Returns the formatted value for last password change. + * + * @param array $attributes user attributes ($this->attributes if null) + * @return String last password change or " - " + */ + private function formatPwdLastSet($attributes = null) { + if ($attributes == null) { + $attributes = &$this->attributes; + } + if (!empty($attributes['pwdlastset'][0])) { + return $this->formatFileTime($attributes['pwdlastset'][0]); + } + elseif (empty($attributes['pwdLastSet'][0])) { + return ' - '; + } + return $this->formatFileTime($attributes['pwdLastSet'][0]); + } + + /** + * Returns the formatted value for last login. + * + * @return String last login or " - " + */ + private function formatLastLogonTimestamp() { + if (empty($this->attributes['lastLogonTimestamp'][0])) { + return ' - '; + } + return $this->formatFileTime($this->attributes['lastLogonTimestamp'][0]); + } + + /** + * Formats a value in file time (100 ns since 1601-01-01). + * + * @param integer $value time value + * @return String formatted value + */ + private function formatFileTime($value) { + if (empty($value)) { + return ''; + } + $seconds = substr($value, 0, -7); + $time = new DateTime('1601-01-01', new DateTimeZone('UTC')); + $time->add(new DateInterval('PT' . $seconds . 'S')); + $time->setTimezone(getTimeZone()); + return $time->format('Y-m-d H:i:s'); + } + } ?>