Commit 8aa65e79 authored by Côme Chilliet's avatar Côme Chilliet

Merge branch '5531-give-acl-based-on-an-ldap-filter' into '1.4-dev'

Resolve "Give ACL based on an LDAP filter"

See merge request fusiondirectory/fd!679
parents 954351c7 4067bf36
......@@ -74,20 +74,29 @@ class acl
static function explodeACL ($acl)
{
$list = explode(':', $acl);
if (count($list) == 5) {
list($index, $type, $role, $members, $filter) = $list;
$filter = base64_decode($filter);
if (count($list) == 6) {
list($index, $type, $role, $members, $userfilter, $targetfilter) = $list;
$userfilter = base64_decode($userfilter);
$targetfilter = base64_decode($targetfilter);
} elseif (count($list) == 5) {
list($index, $type, $role, $members, $userfilter) = $list;
$userfilter = base64_decode($userfilter);
$targetfilter = '';
} else {
$filter = "";
list($index, $type, $role, $members) = $list;
$userfilter = '';
$targetfilter = '';
}
$a = [ $index => [
'type' => $type,
'filter' => $filter,
'members' => acl::extractMembers($members),
'acl' => base64_decode($role),
]];
$a = [
$index => [
'type' => $type,
'userfilter' => $userfilter,
'targetfilter' => $targetfilter,
'members' => acl::extractMembers($members),
'acl' => base64_decode($role),
]
];
/* Handle unknown types */
if (!in_array($type, ['subtree', 'base'])) {
......@@ -104,7 +113,7 @@ class acl
*
* \return an array with members
*/
static function extractMembers ($ms)
static function extractMembers (string $ms)
{
global $config;
$a = [];
......@@ -158,7 +167,7 @@ class acl
*
* \param string $acl The acl to be extracted
*/
static function extractACL ($acl)
static function extractACL (string $acl)
{
/* Rip acl off the string, seperate by ',' and place it in an array */
$as = preg_replace('/^[^:]+:[^:]+:[^:]*:([^:]*).*$/', '\1', $acl);
......
This diff is collapsed.
<?php
/*
This code is part of FusionDirectory (http://www.fusiondirectory.org/)
Copyright (C) 2013-2019 FusionDirectory
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
class ACLsAssignmentAttribute extends DialogOrderedArrayAttribute
{
protected $order = TRUE;
protected $dialogClass = 'ACLsAssignmentDialog';
protected $height = 300;
protected function getAttributeArrayValue ($key, $value)
{
/* Convert text value to displayable array value */
sort($value['members']);
static $nbShown = 4;
$members = join(', ', array_slice($value['members'], 0, $nbShown));
if (count($value['members']) > $nbShown) {
$members .= sprintf(_(', and %d others'), (count($value['members']) - $nbShown));
}
$value['members'] = $members;
return $value;
}
function readValue ($value)
{
$acl = explode(':', $value);
return [$acl[0], [
'scope' => $acl[1],
'role' => base64_decode($acl[2]),
'members' => array_map('base64_decode', explode(',', $acl[3])),
'userfilter' => (isset($acl[4]) ? base64_decode($acl[4]) : ''),
'targetfilter' => (isset($acl[5]) ? base64_decode($acl[5]) : ''),
]];
}
function writeValue ($key, $value)
{
return $key.
':'.$value['scope'].
':'.base64_encode($value['role']).
':'.join(',', array_map('base64_encode', $value['members'])).
':'.base64_encode($value['userfilter']).
':'.base64_encode($value['targetfilter']);
}
function foreignKeyUpdate ($oldvalue, $newvalue, array $source)
{
foreach ($this->value as $key => &$value) {
if ($source['FIELD'] == 'dn') {
if ($newvalue === NULL) {
if (preg_match('/'.preg_quote($oldvalue, '/').'$/', $value['role'])) {
unset($this->value[$key]);
}
foreach ($value['members'] as $member_key => $member) {
if (preg_match('/'.preg_quote($oldvalue, '/').'$/', $member)) {
unset($value['members'][$member_key]);
}
}
unset($member);
} elseif ($source['MODE'] == 'move') {
$value['role'] = preg_replace('/'.preg_quote($oldvalue, '/').'$/', $newvalue, $value['role']);
foreach ($value['members'] as &$member) {
$member = preg_replace('/'.preg_quote($oldvalue, '/').'$/', $newvalue, $member);
}
unset($member);
} elseif ($source['MODE'] == 'copy') {
/* Copied members are added */
foreach ($value['members'] as $member) {
if (preg_match('/'.preg_quote($oldvalue, '/').'$/', $member)) {
$value['members'][] = preg_replace('/'.preg_quote($oldvalue, '/').'$/', $newvalue, $member);
}
}
}
} else {
trigger_error('unknown source "'.$source['CLASS'].'" with field "'.$source['FIELD'].'"');
}
}
unset($value);
}
function foreignKeyCheck ($oldvalue, array $source): bool
{
foreach ($this->value as $value) {
if (
(($source['CLASS'] == 'aclRole') && ($value['role'] == $oldvalue)) ||
(in_array($source['CLASS'], ['user','posixGroup','roleGeneric']) && in_array($oldvalue, $value['members']))
) {
return TRUE;
} elseif (!in_array($source['CLASS'], ['aclRole','user','posixGroup','roleGeneric'])) {
trigger_error('unknown source '.$source['CLASS']);
}
}
return FALSE;
}
}
<?php
/*
This code is part of FusionDirectory (http://www.fusiondirectory.org/)
Copyright (C) 2013-2019 FusionDirectory
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
class ACLsAssignmentDialog extends GenericDialog
{
protected $initialAclValue;
protected $post_cancel = 'add_acl_cancel';
protected $post_finish = 'add_acl_finish';
protected $dialogClass = 'aclAssignmentDialogWindow';
function __construct ($simplePlugin, $attribute, $acl = NULL)
{
$isContainer = FALSE;
if (isset($simplePlugin->attrs['objectClass'])) {
if (count(array_intersect(
$simplePlugin->attrs['objectClass'],
['organizationalUnit', 'organization', 'domain', 'country', 'locality'])
)) {
$isContainer = TRUE;
}
} else {
$isContainer = TRUE;
}
$this->attribute = $attribute;
$this->dialog = new $this->dialogClass($acl, $isContainer);
$this->dialog->dn = $simplePlugin->dn;
$this->initialAclValue = $acl;
}
function dialog_execute ()
{
$this->dialog->save_object();
return $this->dialog->execute();
}
function handle_finish ()
{
$this->dialog->save_object();
$messages = $this->dialog->check();
if (!empty($messages)) {
msg_dialog::displayChecks($messages);
return $this->dialog->execute();
}
$this->attribute->addValue($this->dialog->getAclEntry());
return FALSE;
}
function handle_cancel ()
{
if ($this->initialAclValue !== NULL) {
$this->attribute->addValue($this->initialAclValue);
}
return FALSE;
}
}
<?php
/*
This code is part of FusionDirectory (http://www.fusiondirectory.org/)
Copyright (C) 2013-2016 FusionDirectory
Copyright (C) 2013-2019 FusionDirectory
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
......@@ -18,247 +18,6 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
class aclAssignmentDialogWindow extends simplePlugin
{
static function plInfo (): array
{
return [
'plShortName' => _('ACL Assignment Dialog'),
'plDescription' => _('Access control roles assignment dialog'),
'plCategory' => ['acl'],
'plProvidedAcls' => parent::generatePlProvidedAcls(static::getAttributesInfo())
];
}
static function getAttributesInfo (): array
{
return [
'properties' => [
'name' => _('Properties'),
'attrs' => [
new SelectAttribute(
_('Mode'), _('Is this applying on complete subtree or only the base?'),
'aclMode', TRUE,
['subtree', 'base'], 'base',
[_('Subtree'), _('Base only')]
),
new SelectAttribute(
_('Role'), _('Role to apply'),
'aclRole', TRUE,
[]
),
new BooleanAttribute(
_('For all users'), _('Apply this ACL for all LDAP users'),
'allUsers', FALSE
),
new UsersGroupsRolesAttribute(
_('Members'), _('Users or groups to assign this role to.'),
'aclMembers', TRUE
)
]
],
];
}
function __construct ($value, $isContainer = FALSE)
{
parent::__construct(NULL, NULL, NULL, TRUE);
if ($isContainer) {
$this->attributesAccess['aclMode']->setDefaultValue('subtree');
} else {
$this->attributesAccess['aclMode']->setDefaultValue('base');
}
$this->attributesAccess['aclMode']->resetToDefault();
$roles = objects::ls('aclRole', 'cn');
$this->attributesAccess['aclRole']->setChoices(array_keys($roles), array_values($roles));
$this->attributesAccess['allUsers']->setInLdap(FALSE);
$this->attributesAccess['allUsers']->setManagedAttributes(
[
'disable' => [
TRUE => ['aclMembers']
]
]
);
if ($value !== NULL) {
$this->aclMode = $value['scope'];
$this->aclRole = $value['role'];
$this->aclMembers = $value['members'];
if ($value['members'][0] == '*') {
$this->allUsers = TRUE;
}
}
}
function execute (): string
{
$smarty = get_smarty();
$display = parent::execute();
if (!is_object($this->dialog)) {
$display .= $smarty->fetch('string:'.
'<p class="plugbottom">'.
' <input type="submit" name="add_acl_finish" value="{msgPool type=addButton}"/>'.
' &nbsp;'.
' <input type="submit" formnovalidate="formnovalidate" name="add_acl_cancel" value="{msgPool type=cancelButton}"/>'.
'</p>');
}
return $display;
}
function getAclEntry ()
{
$entry = [
'scope' => $this->aclMode,
'role' => $this->aclRole,
'members' => $this->aclMembers,
];
if ($this->allUsers) {
$entry['members'] = ['*'];
}
return $entry;
}
}
class ACLsAssignmentDialog extends GenericDialog
{
protected $initialAclValue;
protected $post_cancel = 'add_acl_cancel';
protected $post_finish = 'add_acl_finish';
protected $dialogClass = 'aclAssignmentDialogWindow';
function __construct ($simplePlugin, $attribute, $acl = NULL)
{
$isContainer = FALSE;
if (isset($simplePlugin->attrs['objectClass'])) {
if (count(array_intersect(
$simplePlugin->attrs['objectClass'],
['organizationalUnit', 'organization', 'domain', 'country', 'locality'])
)) {
$isContainer = TRUE;
}
} else {
$isContainer = TRUE;
}
$this->attribute = $attribute;
$this->dialog = new $this->dialogClass($acl, $isContainer);
$this->dialog->dn = $simplePlugin->dn;
$this->initialAclValue = $acl;
}
function dialog_execute ()
{
$this->dialog->save_object();
return $this->dialog->execute();
}
function handle_finish ()
{
$this->dialog->save_object();
$messages = $this->dialog->check();
if (!empty($messages)) {
msg_dialog::displayChecks($messages);
return $this->dialog->execute();
}
$this->attribute->addValue($this->dialog->getAclEntry());
return FALSE;
}
function handle_cancel ()
{
if ($this->initialAclValue !== NULL) {
$this->attribute->addValue($this->initialAclValue);
}
return FALSE;
}
}
class ACLsAssignmentAttribute extends DialogOrderedArrayAttribute
{
protected $order = TRUE;
protected $dialogClass = 'ACLsAssignmentDialog';
protected $height = 300;
protected function getAttributeArrayValue ($key, $value)
{
/* Convert text value to displayable array value */
sort($value['members']);
static $nbShown = 4;
$members = join(', ', array_slice($value['members'], 0, $nbShown));
if (count($value['members']) > $nbShown) {
$members .= sprintf(_(', and %d others'), (count($value['members']) - $nbShown));
}
$value['members'] = $members;
return $value;
}
function readValue ($value)
{
$acl = explode(':', $value);
return [$acl[0], [
'scope' => $acl[1],
'role' => base64_decode($acl[2]),
'members' => array_map('base64_decode', explode(',', $acl[3])),
]];
}
function writeValue ($key, $value)
{
return $key.':'.$value['scope'].':'.base64_encode($value['role']).':'.join(',', array_map('base64_encode', $value['members']));
}
function foreignKeyUpdate ($oldvalue, $newvalue, array $source)
{
foreach ($this->value as $key => &$value) {
if ($source['FIELD'] == 'dn') {
if ($newvalue === NULL) {
if (preg_match('/'.preg_quote($oldvalue, '/').'$/', $value['role'])) {
unset($this->value[$key]);
}
foreach ($value['members'] as $member_key => $member) {
if (preg_match('/'.preg_quote($oldvalue, '/').'$/', $member)) {
unset($value['members'][$member_key]);
}
}
unset($member);
} elseif ($source['MODE'] == 'move') {
$value['role'] = preg_replace('/'.preg_quote($oldvalue, '/').'$/', $newvalue, $value['role']);
foreach ($value['members'] as &$member) {
$member = preg_replace('/'.preg_quote($oldvalue, '/').'$/', $newvalue, $member);
}
unset($member);
} elseif ($source['MODE'] == 'copy') {
/* Copied members are added */
foreach ($value['members'] as $member) {
if (preg_match('/'.preg_quote($oldvalue, '/').'$/', $member)) {
$value['members'][] = preg_replace('/'.preg_quote($oldvalue, '/').'$/', $newvalue, $member);
}
}
}
} else {
trigger_error('unknown source "'.$source['CLASS'].'" with field "'.$source['FIELD'].'"');
}
}
unset($value);
}
function foreignKeyCheck ($oldvalue, array $source): bool
{
foreach ($this->value as $value) {
if (
(($source['CLASS'] == 'aclRole') && ($value['role'] == $oldvalue)) ||
(in_array($source['CLASS'], ['user','posixGroup','roleGeneric']) && in_array($oldvalue, $value['members']))
) {
return TRUE;
} elseif (!in_array($source['CLASS'], ['aclRole','user','posixGroup','roleGeneric'])) {
trigger_error('unknown source '.$source['CLASS']);
}
}
return FALSE;
}
}
class aclAssignment extends simplePlugin
{
static function plInfo (): array
......
<?php
/*
This code is part of FusionDirectory (http://www.fusiondirectory.org/)
Copyright (C) 2013-2019 FusionDirectory
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
class aclAssignmentDialogWindow extends simplePlugin
{
static function plInfo (): array
{
return [
'plShortName' => _('ACL Assignment Dialog'),
'plDescription' => _('Access control roles assignment dialog'),
'plCategory' => ['acl'],
'plProvidedAcls' => parent::generatePlProvidedAcls(static::getAttributesInfo())
];
}
static function getAttributesInfo (): array
{
return [
'properties' => [
'name' => _('Properties'),
'attrs' => [
new SelectAttribute(
_('Mode'), _('Is this applying on complete subtree or only the base?'),
'aclMode', TRUE,
['subtree', 'base'], 'base',
[_('Subtree'), _('Base only')]
),
new SelectAttribute(
_('Role'), _('Role to apply'),
'aclRole', TRUE,
[]
),
new BooleanAttribute(
_('For all users'), _('Apply this ACL for all LDAP users'),
'allUsers', FALSE
),
new UsersGroupsRolesAttribute(
_('Members'), _('Users or groups to assign this role to.'),
'aclMembers', TRUE
),
]
],
'advanced' => [
'name' => _('Advanced'),
'attrs' => [
new StringAttribute(
_('Restrict users with filter'), _('LDAP filter which a member must match to actually get the rights'),
'aclUserFilter', FALSE
),
new StringAttribute(
_('Restrict targets with filter'), _('LDAP filter which a dn must match to actually be concerned. May use %dn% mask for user dn. Example: (manager=%dn%).'),
'aclTargetFilter', FALSE
),
]
],
];
}
function __construct ($value, $isContainer = FALSE)
{
parent::__construct(NULL, NULL, NULL, TRUE);
if ($isContainer) {
$this->attributesAccess['aclMode']->setDefaultValue('subtree');
} else {
$this->attributesAccess['aclMode']->setDefaultValue('base');
}
$this->attributesAccess['aclMode']->resetToDefault();
$roles = objects::ls('aclRole', 'cn');
$this->attributesAccess['aclRole']->setChoices(array_keys($roles), array_values($roles));
$this->attributesAccess['allUsers']->setInLdap(FALSE);
$this->attributesAccess['allUsers']->setManagedAttributes(
[
'disable' => [
TRUE => ['aclMembers']
]
]
);
if ($value !== NULL) {
$this->aclMode = $value['scope'];
$this->aclRole = $value['role'];
$this->aclMembers = $value['members'];
if ($value['members'][0] == '*') {
$this->allUsers = TRUE;
}
$this->aclUserFilter = $value['userfilter'];
$this->aclTargetFilter = $value['targetfilter'];
}
}
function execute (): string
{
$smarty = get_smarty();
$display = parent::execute();
if (!is_object($this->dialog)) {
$display .= $smarty->fetch('string:'.
'<p class="plugbottom">'.
' <input type="submit" name="add_acl_finish" value="{msgPool type=addButton}"/>'.
' &nbsp;'.
' <input type="submit" formnovalidate="formnovalidate" name="add_acl_cancel" value="{msgPool type=cancelButton}"/>'.
'</p>');
}
return $display;
}
function getAclEntry ()
{
$entry = [
'scope' => $this->aclMode,
'role' => $this->aclRole,
'members' => $this->aclMembers,
'userfilter' => $this->aclUserFilter,
'targetfilter' => $this->aclTargetFilter,
];
if ($this->allUsers) {
$entry['members'] = ['*'];
}
return $entry;
}
}
Markdown is supported
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