Verified Commit ccee0ead authored by dockx thibault's avatar dockx thibault
Browse files

:ambulance: Fix(Snapshots) - Snapshots are now taken before modifications

Automatic snapshots are well taken before modifications and take all user info.
Showing with 71 additions and 39 deletions
+71 -39
......@@ -2,7 +2,7 @@
## core-fd.schema - Needed by FusionDirectory for its basic functionalities
##
# Last OID used for attributes : 1.3.6.1.4.1.38414.62.1.67 05/02/24 #
# Last OID used for attributes : 1.3.6.1.4.1.38414.62.1.68 12/03/24 #
# Last OID used for objectClass : 1.3.6.1.4.1.38414.62.2.11 29/01/24 #
##### Attributes from gosa ######
......@@ -73,6 +73,12 @@ attributetype ( 1.3.6.1.4.1.38414.62.1.51 NAME 'fdSnapshotDataSource'
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.38414.62.1.68 NAME 'fdSnapshotHash'
DESC 'FusionDirectory - hash of the current snapShot allowing diff verification with MD5'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
##### Subscriptions Attributes ######
attributetype ( 1.3.6.1.4.1.38414.62.11.1 NAME 'fdSubscriptionStartDate'
......@@ -504,7 +510,7 @@ objectclass ( 1.3.6.1.4.1.10098.1.2.1.19.19 NAME 'gosaSnapshotObject'
DESC 'GOsa - Container object for undo and snapshot data'
SUP top STRUCTURAL
MUST ( gosaSnapshotTimestamp $ gosaSnapshotDN $ gosaSnapshotData $ fdSnapshotDataSource )
MAY ( fdSnapshotObjectType $ description ) )
MAY ( fdSnapshotObjectType $ description $ fdSnapshotHash) )
### New FusionDirectory Objectclass ###
......
......@@ -254,6 +254,7 @@ class SnapshotHandler
$target['description'] = $description;
$target['fdSnapshotObjectType'] = $objectType;
$target['fdSnapshotDataSource'] = $snapshotSource;
$target['fdSnapshotHash'] = md5($data);
/* Insert the new snapshot
But we have to check first, if the given gosaSnapshotTimestamp
......@@ -380,7 +381,7 @@ class SnapshotHandler
$ldap->cd($new_base);
$ldap->search(
'(&(objectClass=gosaSnapshotObject)(gosaSnapshotDN='.ldap_escape_f($dn).'))',
['gosaSnapshotTimestamp','gosaSnapshotDN','description','fdSnapshotObjectType'],
['gosaSnapshotTimestamp','gosaSnapshotDN','description','fdSnapshotObjectType','fdSnapshotHash'],
'one'
);
......@@ -416,7 +417,7 @@ class SnapshotHandler
$ldap->cd($new_base);
$ldap->search(
'(objectClass=gosaSnapshotObject)',
['gosaSnapshotTimestamp','gosaSnapshotDN','description','fdSnapshotObjectType'],
['gosaSnapshotTimestamp','gosaSnapshotDN','description','fdSnapshotObjectType', 'fdSnapshotHash'],
'one'
);
while ($entry = $ldap->fetch(TRUE)) {
......
......@@ -23,8 +23,8 @@ class PostalAddressAttribute extends TextAreaAttribute
function inputValue ($ldapValue)
{
return str_replace(
['$', '\24','\5C'],
["\n", '$', '\\'],
['$', '\24', '\5C'],
["\n", '$', '\\'],
$ldapValue
);
}
......@@ -36,7 +36,7 @@ class PostalAddressAttribute extends TextAreaAttribute
'$',
str_replace(
['\\', '$'],
['\5C','\24'],
['\5C', '\24'],
$this->getValue()
)
);
......@@ -55,7 +55,7 @@ class user extends simplePlugin
'plIcon' => 'geticon.php?context=applications&icon=user-info&size=48',
'plSmallIcon' => 'geticon.php?context=applications&icon=user-info&size=16',
'plSelfModify' => TRUE,
'plObjectClass' => ['inetOrgPerson','organizationalPerson','person'],
'plObjectClass' => ['inetOrgPerson', 'organizationalPerson', 'person'],
'plFilter' => '(objectClass=inetOrgPerson)',
'plObjectType' => ['user' => [
'name' => _('User'),
......@@ -65,10 +65,10 @@ class user extends simplePlugin
'icon' => 'geticon.php?context=types&icon=user&size=16',
'ou' => get_ou('userRDN'),
]],
'plForeignKeys' => [
'manager' => ['user','dn','manager=%oldvalue%','*']
'plForeignKeys' => [
'manager' => ['user', 'dn', 'manager=%oldvalue%', '*']
],
'plSearchAttrs' => ['uid','description'],
'plSearchAttrs' => ['uid', 'description'],
'plProvidedAcls' => array_merge(
parent::generatePlProvidedAcls(static::getAttributesInfo()),
......@@ -82,9 +82,9 @@ class user extends simplePlugin
global $config;
$languages = Language::getList(TRUE);
asort($languages);
$languages = array_merge(['' => ''], $languages);
$languages = array_merge(['' => ''], $languages);
$attributesInfo = [
'perso' => [
'perso' => [
'name' => _('Personal information'),
'icon' => 'geticon.php?context=types&icon=user&size=16',
'attrs' => [
......@@ -115,7 +115,7 @@ class user extends simplePlugin
),
]
],
'contact' => [
'contact' => [
'name' => _('Organizational contact information'),
'icon' => 'geticon.php?context=types&icon=contact&size=16',
'attrs' => [
......@@ -161,7 +161,7 @@ class user extends simplePlugin
),
]
],
'account' => [
'account' => [
'name' => _('Account information'),
'icon' => 'geticon.php?context=applications&icon=ldap&size=16',
'attrs' => [
......@@ -181,7 +181,7 @@ class user extends simplePlugin
),
]
],
'homecontact' => [
'homecontact' => [
'name' => _('Personal contact information'),
'icon' => 'geticon.php?context=types&icon=contact&size=16',
'attrs' => [
......@@ -259,6 +259,7 @@ class user extends simplePlugin
function __construct ($dn = NULL, $object = NULL, $parent = NULL, $mainTab = FALSE)
{
global $config;
parent::__construct($dn, $object, $parent, $mainTab);
if ($this->is_template && !$this->initially_was_account) {
......@@ -274,6 +275,14 @@ class user extends simplePlugin
$this->attributesAccess['jpegPhoto']->setPlaceholder(fread($fd, filesize($filename)));
$this->was_locked = $this->attributesAccess['userPassword']->isLocked();
// Verification is snapshot is enabled and automatic.
// Note : string values are stored in that array.
if (isset($config->current['ENABLEAUTOMATICSNAPSHOTS']) && isset($config->current['ENABLESNAPSHOTS'])) {
if (strtolower($config->current['ENABLEAUTOMATICSNAPSHOTS']) === 'true' && strtolower($config->current['ENABLESNAPSHOTS']) === 'true') {
$this->generateAutomaticSnapshot();
}
}
}
function resetCopyInfos ()
......@@ -285,14 +294,14 @@ class user extends simplePlugin
private function update_cn ()
{
global $config;
$pattern = $config->get_cfg_value('CnPattern', '%givenName% %sn%');
$pattern = $config->get_cfg_value('CnPattern', '%givenName% %sn%');
$this->attributesAccess['cn']->setValue($this->applyPattern($pattern));
}
private function applyPattern ($pattern)
{
$fields = templateHandling::listFields($pattern);
$attrs = [];
$fields = templateHandling::listFields($pattern);
$attrs = [];
foreach ($fields as $field) {
if (in_array($field, $this->attributes)) {
$attrs[$field] = $this->$field;
......@@ -307,7 +316,7 @@ class user extends simplePlugin
}
}
}
trigger_error('Could not find field '.$field.' in any tab!');
trigger_error('Could not find field ' . $field . ' in any tab!');
}
return templateHandling::parseString($pattern, $attrs);
......@@ -318,13 +327,13 @@ class user extends simplePlugin
global $config;
if ($this->is_template) {
return 'cn='.ldap_escape_dn($this->_template_cn).',ou=templates,'.get_ou('userRDN').$this->base;
return 'cn=' . ldap_escape_dn($this->_template_cn) . ',ou=templates,' . get_ou('userRDN') . $this->base;
}
$this->update_cn();
$attribute = $config->get_cfg_value('accountPrimaryAttribute', 'uid');
return $this->create_unique_dn($attribute, get_ou('userRDN').$this->base);
return $this->create_unique_dn($attribute, get_ou('userRDN') . $this->base);
}
public function render (): string
......@@ -365,8 +374,8 @@ class user extends simplePlugin
}
if (!$this->is_template && $this->was_locked && $this->attributesAccess['userPassword']->hasChanged()) {
$methods = passwordMethod::get_available_methods();
$pmethod = new $methods[$this->attributesAccess['userPassword']->getMethod()]($this->dn);
$methods = passwordMethod::get_available_methods();
$pmethod = new $methods[$this->attributesAccess['userPassword']->getMethod()]($this->dn);
$pmethod->lock_account($this->dn);
}
......@@ -383,24 +392,40 @@ class user extends simplePlugin
session::set('ui', $ui);
session::set('Last_init_lang', 'update');
}
// Verification is snapshot is enabled and automatic.
// Note : string values are stored in that array.
if (isset($config->current['ENABLEAUTOMATICSNAPSHOTS']) && isset($config->current['ENABLESNAPSHOTS'])) {
if (strtolower($config->current['ENABLEAUTOMATICSNAPSHOTS']) === 'true' && strtolower($config->current['ENABLESNAPSHOTS']) === 'true' ) {
$this->generateAutomaticSnapshot();
}
}
return parent::post_save();
}
/*
* Create the snapshot object in case of automated snapshot.
// public function verifyLastSnapshotMD5 () : BOOL
// {
//
// }
/**
* @return void
* Note : Create a snapshot of current data before save, verifying if data have changed before taking a snap.
*/
public function generateAutomaticSnapshot ()
{
$snapshotHandler = new SnapshotHandler();
$snapshotHandler->createSnapshot($this->dn, 'automatic snapshot', 'USER', 'FD');
$snapshotHandler->verifySnapshotRetention($this->dn);
// Get the hash of current data before modifications.
global $config;
$ldap = $config->get_ldap_link();
$currentSnapHash = md5($ldap->generateLdif($this->dn, '(!(objectClass=gosaDepartment))', 'sub'));
// Verify if current snap hash already exist in the list of existing snapshots - not taking a snap if it exists.
$snapshotHandler = new SnapshotHandler();
$existingSnapshots = $snapshotHandler->getAvailableSnapsShots($this->dn);
$sameHashExist = FALSE;
foreach ($existingSnapshots as $snap) {
if (!empty($snap['fdSnapshotHash'][0]) && $snap['fdSnapshotHash'][0] === $currentSnapHash) {
$sameHashExist = TRUE;
}
}
// Create the snapshot
if ($sameHashExist === FALSE) {
$snapshotHandler->createSnapshot($this->dn, 'automatic snapshot', 'USER', 'FD');
$snapshotHandler->verifySnapshotRetention($this->dn);
}
}
function adapt_from_template (array $attrs, array $skip = [])
......@@ -430,7 +455,7 @@ class user extends simplePlugin
$ldap = $config->get_ldap_link();
$ldap->cat($userdn, ['pwdPolicySubentry', 'pwdHistory', 'pwdChangedTime', 'userPassword']);
$attrs = $ldap->fetch(TRUE);
$attrs = $ldap->fetch(TRUE);
$ppolicydn = '';
if (isset($attrs['pwdPolicySubentry'][0])) {
$ppolicydn = $attrs['pwdPolicySubentry'][0];
......@@ -482,7 +507,7 @@ class user extends simplePlugin
if (isset($policy['pwdMinAge'][0]) && isset($attrs['pwdChangedTime'][0])) {
$date = LdapGeneralizedTime::fromString($attrs['pwdChangedTime'][0]);
$date->setTimezone(timezone::utc());
$now = new DateTime('now', timezone::utc());
$now = new DateTime('now', timezone::utc());
if ($now->getTimeStamp() < $date->getTimeStamp() + $policy['pwdMinAge'][0]) {
return sprintf(_('You must wait %d seconds before changing your password again'), $policy['pwdMinAge'][0] - ($now->getTimeStamp() - $date->getTimeStamp()));
}
......@@ -494,7 +519,7 @@ class user extends simplePlugin
unset($attrs['pwdHistory']['count']);
foreach ($attrs['pwdHistory'] as $pwdHistory) {
$pwdHistory = explode('#', $pwdHistory, 4);
$method = passwordMethod::get_method($pwdHistory[3], $user);
$method = passwordMethod::get_method($pwdHistory[3], $user);
if (($method !== NULL) && $method->checkPassword($new_password, $pwdHistory[3])) {
return _('Password is in history of old passwords');
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment