commit
8d845767ac
|
@ -52,7 +52,7 @@ class UsergroupbackendController extends Controller
|
|||
$form->setIniConfig(Config::app('groups'));
|
||||
$form->setOnSuccess(function (UserGroupBackendForm $form) {
|
||||
try {
|
||||
$form->add($form->getValues());
|
||||
$form->add(array_filter($form->getValues()));
|
||||
} catch (Exception $e) {
|
||||
$form->error($e->getMessage());
|
||||
return false;
|
||||
|
@ -85,7 +85,12 @@ class UsergroupbackendController extends Controller
|
|||
$form->setIniConfig(Config::app('groups'));
|
||||
$form->setOnSuccess(function (UserGroupBackendForm $form) use ($backendName) {
|
||||
try {
|
||||
$form->edit($backendName, $form->getValues());
|
||||
$form->edit($backendName, array_map(
|
||||
function ($v) {
|
||||
return $v !== '' ? $v : null;
|
||||
},
|
||||
$form->getValues()
|
||||
));
|
||||
} catch (Exception $e) {
|
||||
$form->error($e->getMessage());
|
||||
return false;
|
||||
|
|
|
@ -0,0 +1,305 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config\UserGroup;
|
||||
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Authentication\User\UserBackend;
|
||||
use Icinga\Authentication\UserGroup\LdapUserGroupBackend;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Protocol\Ldap\Connection;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Notification;
|
||||
|
||||
/**
|
||||
* Form for managing LDAP user group backends
|
||||
*/
|
||||
class LdapUserGroupBackendForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_ldapusergroupbackend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add elements to this form
|
||||
*
|
||||
* @param array $formData
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$resourceNames = $this->getLdapResourceNames();
|
||||
$this->addElement(
|
||||
'select',
|
||||
'resource',
|
||||
array(
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => $this->translate('LDAP Connection'),
|
||||
'description' => $this->translate('The LDAP connection to use for this backend.'),
|
||||
'multiOptions' => array_combine($resourceNames, $resourceNames)
|
||||
)
|
||||
);
|
||||
$resource = ResourceFactory::create(
|
||||
isset($formData['resource']) && in_array($formData['resource'], $resourceNames)
|
||||
? $formData['resource']
|
||||
: $resourceNames[0]
|
||||
);
|
||||
|
||||
$userBackends = array('none' => $this->translate('None', 'usergroupbackend.ldap.user_backend'));
|
||||
$userBackendNames = $this->getLdapUserBackendNames($resource);
|
||||
if (! empty($userBackendNames)) {
|
||||
$userBackends = array_merge($userBackends, array_combine($userBackendNames, $userBackendNames));
|
||||
}
|
||||
$this->addElement(
|
||||
'select',
|
||||
'user_backend',
|
||||
array(
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => $this->translate('User Backend'),
|
||||
'description' => $this->translate('The user backend to link with this user group backend.'),
|
||||
'multiOptions' => $userBackends
|
||||
)
|
||||
);
|
||||
|
||||
$groupBackend = new LdapUserGroupBackend($resource);
|
||||
if ($formData['type'] === 'ldap') {
|
||||
$defaults = $groupBackend->getOpenLdapDefaults();
|
||||
$groupConfigDisabled = $userConfigDisabled = null; // MUST BE null, do NOT change this to false!
|
||||
} else { // $formData['type'] === 'msldap'
|
||||
$defaults = $groupBackend->getActiveDirectoryDefaults();
|
||||
$groupConfigDisabled = $userConfigDisabled = true;
|
||||
}
|
||||
|
||||
$dnDisabled = null; // MUST BE null
|
||||
if (isset($formData['user_backend']) && $formData['user_backend'] !== 'none') {
|
||||
$userBackend = UserBackend::create($formData['user_backend']);
|
||||
$defaults->merge(array(
|
||||
'user_base_dn' => $userBackend->getBaseDn(),
|
||||
'user_class' => $userBackend->getUserClass(),
|
||||
'user_name_attribute' => $userBackend->getUserNameAttribute(),
|
||||
'user_filter' => $userBackend->getFilter()
|
||||
));
|
||||
$userConfigDisabled = $dnDisabled = true;
|
||||
}
|
||||
|
||||
$this->createGroupConfigElements($defaults, $groupConfigDisabled);
|
||||
$this->createUserConfigElements($defaults, $userConfigDisabled, $dnDisabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add all elements to this form required for the group configuration
|
||||
*
|
||||
* @param ConfigObject $defaults
|
||||
* @param null|bool $disabled
|
||||
*/
|
||||
protected function createGroupConfigElements(ConfigObject $defaults, $disabled)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'group_class',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'disabled' => $disabled,
|
||||
'label' => $this->translate('LDAP Group Object Class'),
|
||||
'description' => $this->translate('The object class used for storing groups on the LDAP server.'),
|
||||
'value' => $defaults->group_class
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'group_filter',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'allowEmpty' => true,
|
||||
'disabled' => $disabled,
|
||||
'label' => $this->translate('LDAP Group Filter'),
|
||||
'description' => $this->translate(
|
||||
'An additional filter to use when looking up groups using the specified connection. '
|
||||
. 'Leave empty to not to use any additional filter rules.'
|
||||
),
|
||||
'requirement' => $this->translate(
|
||||
'The filter needs to be expressed as standard LDAP expression, without'
|
||||
. ' outer parentheses. (e.g. &(foo=bar)(bar=foo) or foo=bar)'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Callback',
|
||||
false,
|
||||
array(
|
||||
'callback' => function ($v) {
|
||||
return strpos($v, '(') !== 0;
|
||||
},
|
||||
'messages' => array(
|
||||
'callbackValue' => $this->translate('The filter must not be wrapped in parantheses.')
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
'value' => $defaults->group_filter
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'group_name_attribute',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'disabled' => $disabled,
|
||||
'label' => $this->translate('LDAP Group Name Attribute'),
|
||||
'description' => $this->translate(
|
||||
'The attribute name used for storing a group\'s name on the LDAP server.'
|
||||
),
|
||||
'value' => $defaults->group_name_attribute
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'base_dn',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'label' => $this->translate('LDAP Group Base DN'),
|
||||
'description' => $this->translate(
|
||||
'The path where groups can be found on the LDAP server. Leave ' .
|
||||
'empty to select all users available using the specified connection.'
|
||||
),
|
||||
'value' => $defaults->base_dn
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add all elements to this form required for the user configuration
|
||||
*
|
||||
* @param ConfigObject $defaults
|
||||
* @param null|bool $disabled
|
||||
* @param null|bool $dnDisabled
|
||||
*/
|
||||
protected function createUserConfigElements(ConfigObject $defaults, $disabled, $dnDisabled)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'user_class',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'disabled' => $disabled,
|
||||
'label' => $this->translate('LDAP User Object Class'),
|
||||
'description' => $this->translate('The object class used for storing users on the LDAP server.'),
|
||||
'value' => $defaults->user_class
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'user_filter',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'allowEmpty' => true,
|
||||
'disabled' => $disabled,
|
||||
'label' => $this->translate('LDAP User Filter'),
|
||||
'description' => $this->translate(
|
||||
'An additional filter to use when looking up users using the specified connection. '
|
||||
. 'Leave empty to not to use any additional filter rules.'
|
||||
),
|
||||
'requirement' => $this->translate(
|
||||
'The filter needs to be expressed as standard LDAP expression, without'
|
||||
. ' outer parentheses. (e.g. &(foo=bar)(bar=foo) or foo=bar)'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Callback',
|
||||
false,
|
||||
array(
|
||||
'callback' => function ($v) {
|
||||
return strpos($v, '(') !== 0;
|
||||
},
|
||||
'messages' => array(
|
||||
'callbackValue' => $this->translate('The filter must not be wrapped in parantheses.')
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
'value' => $defaults->user_filter
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'user_name_attribute',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'disabled' => $disabled,
|
||||
'label' => $this->translate('LDAP User Name Attribute'),
|
||||
'description' => $this->translate(
|
||||
'The attribute name used for storing a user\'s name on the LDAP server.'
|
||||
),
|
||||
'value' => $defaults->user_name_attribute
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'user_base_dn',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'disabled' => $dnDisabled,
|
||||
'label' => $this->translate('LDAP User Base DN'),
|
||||
'description' => $this->translate(
|
||||
'The path where users can be found on the LDAP server. Leave ' .
|
||||
'empty to select all users available using the specified connection.'
|
||||
),
|
||||
'value' => $defaults->user_base_dn
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the names of all configured LDAP resources
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getLdapResourceNames()
|
||||
{
|
||||
$names = array();
|
||||
foreach (ResourceFactory::getResourceConfigs() as $name => $config) {
|
||||
if (in_array(strtolower($config->type), array('ldap', 'msldap'))) {
|
||||
$names[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($names)) {
|
||||
Notification::error(
|
||||
$this->translate('No LDAP resources available. Please configure an LDAP resource first.')
|
||||
);
|
||||
$this->getResponse()->redirectAndExit('config/createresource');
|
||||
}
|
||||
|
||||
return $names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the names of all configured LDAP user backends
|
||||
*
|
||||
* @param Connection $resource
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getLdapUserBackendNames(Connection $resource)
|
||||
{
|
||||
$names = array();
|
||||
foreach (Config::app('authentication') as $name => $config) {
|
||||
if (in_array(strtolower($config->backend), array('ldap', 'msldap'))) {
|
||||
$backendResource = ResourceFactory::create($config->resource);
|
||||
if (
|
||||
$backendResource->getHostname() === $resource->getHostname()
|
||||
&& $backendResource->getPort() === $resource->getPort()
|
||||
) {
|
||||
$names[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $names;
|
||||
}
|
||||
}
|
|
@ -13,6 +13,13 @@ use Icinga\Forms\ConfigForm;
|
|||
*/
|
||||
class UserGroupBackendForm extends ConfigForm
|
||||
{
|
||||
/**
|
||||
* The backend to load when displaying the form for the first time
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $backendToLoad;
|
||||
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
|
@ -31,10 +38,17 @@ class UserGroupBackendForm extends ConfigForm
|
|||
*/
|
||||
public function getBackendForm($type)
|
||||
{
|
||||
if ($type === 'db') {
|
||||
return new DbUserGroupBackendForm();
|
||||
} else {
|
||||
throw new InvalidArgumentException(sprintf($this->translate('Invalid backend type "%s" provided'), $type));
|
||||
switch ($type)
|
||||
{
|
||||
case 'db':
|
||||
return new DbUserGroupBackendForm();
|
||||
case 'ldap':
|
||||
case 'msldap':
|
||||
return new LdapUserGroupBackendForm();
|
||||
default:
|
||||
throw new InvalidArgumentException(
|
||||
sprintf($this->translate('Invalid backend type "%s" provided'), $type)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,10 +67,7 @@ class UserGroupBackendForm extends ConfigForm
|
|||
throw new NotFoundError('No user group backend called "%s" found', $name);
|
||||
}
|
||||
|
||||
$data = $this->config->getSection($name)->toArray();
|
||||
$data['type'] = $data['backend'];
|
||||
$data['name'] = $name;
|
||||
$this->populate($data);
|
||||
$this->backendToLoad = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -103,13 +114,23 @@ class UserGroupBackendForm extends ConfigForm
|
|||
}
|
||||
|
||||
$backendConfig = $this->config->getSection($name);
|
||||
if (isset($data['name']) && $data['name'] !== $name) {
|
||||
$this->config->removeSection($name);
|
||||
$name = $data['name'];
|
||||
if (isset($data['name'])) {
|
||||
if ($data['name'] !== $name) {
|
||||
$this->config->removeSection($name);
|
||||
$name = $data['name'];
|
||||
}
|
||||
|
||||
unset($data['name']);
|
||||
}
|
||||
|
||||
$this->config->setSection($name, $backendConfig->merge($data));
|
||||
$backendConfig->merge($data);
|
||||
foreach ($backendConfig->toArray() as $k => $v) {
|
||||
if ($v === null) {
|
||||
unset($backendConfig->$k);
|
||||
}
|
||||
}
|
||||
|
||||
$this->config->setSection($name, $backendConfig);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -161,7 +182,9 @@ class UserGroupBackendForm extends ConfigForm
|
|||
|
||||
// TODO(jom): We did not think about how to configure custom group backends yet!
|
||||
$backendTypes = array(
|
||||
'db' => $this->translate('Database')
|
||||
'db' => $this->translate('Database'),
|
||||
'ldap' => $this->translate('LDAP'),
|
||||
'msldap' => $this->translate('ActiveDirectory')
|
||||
);
|
||||
|
||||
$backendType = isset($formData['type']) ? $formData['type'] : null;
|
||||
|
@ -191,8 +214,34 @@ class UserGroupBackendForm extends ConfigForm
|
|||
)
|
||||
);
|
||||
|
||||
$backendForm = $this->getBackendForm($backendType);
|
||||
$backendForm->createElements($formData);
|
||||
$this->addElements($backendForm->getElements());
|
||||
$this->addSubForm($this->getBackendForm($backendType)->create($formData), 'backend_form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the configuration of the backend to load
|
||||
*/
|
||||
public function onRequest()
|
||||
{
|
||||
if ($this->backendToLoad) {
|
||||
$data = $this->config->getSection($this->backendToLoad)->toArray();
|
||||
$data['type'] = $data['backend'];
|
||||
$data['name'] = $this->backendToLoad;
|
||||
$this->populate($data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all form element values
|
||||
*
|
||||
* @param bool $suppressArrayNotation Ignored
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getValues($suppressArrayNotation = false)
|
||||
{
|
||||
$values = parent::getValues();
|
||||
$values = array_merge($values, $values['backend_form']);
|
||||
unset($values['backend_form']);
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,17 +4,16 @@
|
|||
namespace Icinga\Authentication\User;
|
||||
|
||||
use DateTime;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Exception\AuthenticationException;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Repository\Repository;
|
||||
use Icinga\Repository\LdapRepository;
|
||||
use Icinga\Repository\RepositoryQuery;
|
||||
use Icinga\Protocol\Ldap\Exception as LdapException;
|
||||
use Icinga\Protocol\Ldap\Expression;
|
||||
use Icinga\User;
|
||||
|
||||
class LdapUserBackend extends Repository implements UserBackendInterface
|
||||
class LdapUserBackend extends LdapRepository implements UserBackendInterface
|
||||
{
|
||||
/**
|
||||
* The base DN to use for a query
|
||||
|
@ -65,20 +64,6 @@ class LdapUserBackend extends Repository implements UserBackendInterface
|
|||
)
|
||||
);
|
||||
|
||||
protected $groupOptions;
|
||||
|
||||
/**
|
||||
* Normed attribute names based on known LDAP environments
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $normedAttributes = array(
|
||||
'uid' => 'uid',
|
||||
'user' => 'user',
|
||||
'inetorgperson' => 'inetOrgPerson',
|
||||
'samaccountname' => 'sAMAccountName'
|
||||
);
|
||||
|
||||
/**
|
||||
* Set the base DN to use for a query
|
||||
*
|
||||
|
@ -179,34 +164,6 @@ class LdapUserBackend extends Repository implements UserBackendInterface
|
|||
return $this->filter;
|
||||
}
|
||||
|
||||
public function setGroupOptions(array $options)
|
||||
{
|
||||
$this->groupOptions = $options;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getGroupOptions()
|
||||
{
|
||||
return $this->groupOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the given attribute name normed to known LDAP enviroments, if possible
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getNormedAttribute($name)
|
||||
{
|
||||
$loweredName = strtolower($name);
|
||||
if (array_key_exists($loweredName, $this->normedAttributes)) {
|
||||
return $this->normedAttributes[$loweredName];
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the given configuration to this backend
|
||||
*
|
||||
|
@ -325,37 +282,6 @@ class LdapUserBackend extends Repository implements UserBackendInterface
|
|||
return ((int) $value & $ADS_UF_ACCOUNTDISABLE) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given value based on the ASN.1 standard (GeneralizedTime) and return its timestamp representation
|
||||
*
|
||||
* @param string|null $value
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function retrieveGeneralizedTime($value)
|
||||
{
|
||||
if ($value === null) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (
|
||||
($dateTime = DateTime::createFromFormat('YmdHis.uO', $value)) !== false
|
||||
|| ($dateTime = DateTime::createFromFormat('YmdHis.uZ', $value)) !== false
|
||||
|| ($dateTime = DateTime::createFromFormat('YmdHis.u', $value)) !== false
|
||||
|| ($dateTime = DateTime::createFromFormat('YmdHis', $value)) !== false
|
||||
|| ($dateTime = DateTime::createFromFormat('YmdHi', $value)) !== false
|
||||
|| ($dateTime = DateTime::createFromFormat('YmdH', $value)) !== false
|
||||
) {
|
||||
return $dateTime->getTimeStamp();
|
||||
} else {
|
||||
Logger::debug(sprintf(
|
||||
'Failed to parse "%s" based on the ASN.1 standard (GeneralizedTime) for user backend "%s".',
|
||||
$value,
|
||||
$this->getName()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given shadowExpire value defines that a user is permitted to login
|
||||
*
|
||||
|
@ -413,41 +339,6 @@ class LdapUserBackend extends Repository implements UserBackendInterface
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the user groups
|
||||
*
|
||||
* @TODO: Subject to change, see #7343
|
||||
*
|
||||
* @param string $dn
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getGroups($dn)
|
||||
{
|
||||
if (empty($this->groupOptions) || ! isset($this->groupOptions['group_base_dn'])) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$result = $this->ds->select()
|
||||
->setBase($this->groupOptions['group_base_dn'])
|
||||
->from(
|
||||
$this->groupOptions['group_class'],
|
||||
array($this->groupOptions['group_attribute'])
|
||||
)
|
||||
->where(
|
||||
$this->groupOptions['group_member_attribute'],
|
||||
$dn
|
||||
)
|
||||
->fetchAll();
|
||||
|
||||
$groups = array();
|
||||
foreach ($result as $group) {
|
||||
$groups[] = $group->{$this->groupOptions['group_attribute']};
|
||||
}
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate the given user
|
||||
*
|
||||
|
@ -472,15 +363,7 @@ class LdapUserBackend extends Repository implements UserBackendInterface
|
|||
return false;
|
||||
}
|
||||
|
||||
$authenticated = $this->ds->testCredentials($userDn, $password);
|
||||
if ($authenticated) {
|
||||
$groups = $this->getGroups($userDn);
|
||||
if ($groups !== null) {
|
||||
$user->setGroups($groups);
|
||||
}
|
||||
}
|
||||
|
||||
return $authenticated;
|
||||
return $this->ds->testCredentials($userDn, $password);
|
||||
} catch (LdapException $e) {
|
||||
throw new AuthenticationException(
|
||||
'Failed to authenticate user "%s" against backend "%s". An exception was thrown:',
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
namespace Icinga\Authentication\User;
|
||||
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Data\ConfigObject;
|
||||
|
@ -106,8 +107,17 @@ class UserBackend
|
|||
*
|
||||
* @throws ConfigurationError
|
||||
*/
|
||||
public static function create($name, ConfigObject $backendConfig)
|
||||
public static function create($name, ConfigObject $backendConfig = null)
|
||||
{
|
||||
if ($backendConfig === null) {
|
||||
$authConfig = Config::app('authentication');
|
||||
if ($authConfig->hasSection($name)) {
|
||||
$backendConfig = $authConfig->getSection($name);
|
||||
} else {
|
||||
throw new ConfigurationError('User backend "%s" does not exist', $name);
|
||||
}
|
||||
}
|
||||
|
||||
if ($backendConfig->name !== null) {
|
||||
$name = $backendConfig->name;
|
||||
}
|
||||
|
@ -165,12 +175,6 @@ class UserBackend
|
|||
$backend->setUserClass($backendConfig->get('user_class', 'user'));
|
||||
$backend->setUserNameAttribute($backendConfig->get('user_name_attribute', 'sAMAccountName'));
|
||||
$backend->setFilter($backendConfig->filter);
|
||||
$backend->setGroupOptions(array(
|
||||
'group_base_dn' => $backendConfig->get('group_base_dn', $resource->getDN()),
|
||||
'group_attribute' => $backendConfig->get('group_attribute', 'sAMAccountName'),
|
||||
'group_member_attribute' => $backendConfig->get('group_member_attribute', 'member'),
|
||||
'group_class' => $backendConfig->get('group_class', 'group')
|
||||
));
|
||||
break;
|
||||
case 'ldap':
|
||||
$backend = new LdapUserBackend($resource);
|
||||
|
@ -178,12 +182,6 @@ class UserBackend
|
|||
$backend->setUserClass($backendConfig->get('user_class', 'inetOrgPerson'));
|
||||
$backend->setUserNameAttribute($backendConfig->get('user_name_attribute', 'uid'));
|
||||
$backend->setFilter($backendConfig->filter);
|
||||
$backend->setGroupOptions(array(
|
||||
'group_base_dn' => $backendConfig->group_base_dn,
|
||||
'group_attribute' => $backendConfig->group_attribute,
|
||||
'group_member_attribute' => $backendConfig->group_member_attribute,
|
||||
'group_class' => $backendConfig->group_class
|
||||
));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,627 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Authentication\UserGroup;
|
||||
|
||||
use Icinga\Authentication\User\UserBackend;
|
||||
use Icinga\Authentication\User\LdapUserBackend;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Protocol\Ldap\Expression;
|
||||
use Icinga\Repository\LdapRepository;
|
||||
use Icinga\Repository\RepositoryQuery;
|
||||
use Icinga\User;
|
||||
|
||||
class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBackendInterface
|
||||
{
|
||||
/**
|
||||
* The base DN to use for a user query
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $userBaseDn;
|
||||
|
||||
/**
|
||||
* The base DN to use for a group query
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $groupBaseDn;
|
||||
|
||||
/**
|
||||
* The objectClass where look for users
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $userClass;
|
||||
|
||||
/**
|
||||
* The objectClass where look for groups
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $groupClass;
|
||||
|
||||
/**
|
||||
* The attribute name where to find a user's name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $userNameAttribute;
|
||||
|
||||
/**
|
||||
* The attribute name where to find a group's name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $groupNameAttribute;
|
||||
|
||||
/**
|
||||
* The attribute name where to find a group's member
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $groupMemberAttribute;
|
||||
|
||||
/**
|
||||
* The custom LDAP filter to apply on a user query
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $userFilter;
|
||||
|
||||
/**
|
||||
* The custom LDAP filter to apply on a group query
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $groupFilter;
|
||||
|
||||
/**
|
||||
* The columns which are not permitted to be queried
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $filterColumns = array('group', 'user');
|
||||
|
||||
/**
|
||||
* The default sort rules to be applied on a query
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $sortRules = array(
|
||||
'group_name' => array(
|
||||
'order' => 'asc'
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Normed attribute names based on known LDAP environments
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $normedAttributes = array(
|
||||
'uid' => 'uid',
|
||||
'gid' => 'gid',
|
||||
'user' => 'user',
|
||||
'group' => 'group',
|
||||
'member' => 'member',
|
||||
'inetorgperson' => 'inetOrgPerson',
|
||||
'samaccountname' => 'sAMAccountName'
|
||||
);
|
||||
|
||||
/**
|
||||
* The name of this repository
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The datasource being used
|
||||
*
|
||||
* @var Connection
|
||||
*/
|
||||
protected $ds;
|
||||
|
||||
/**
|
||||
* Create a new LDAP repository object
|
||||
*
|
||||
* @param Connection $ds The data source to use
|
||||
*/
|
||||
public function __construct($ds)
|
||||
{
|
||||
$this->ds = $ds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the given attribute name normed to known LDAP enviroments, if possible
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getNormedAttribute($name)
|
||||
{
|
||||
$loweredName = strtolower($name);
|
||||
if (array_key_exists($loweredName, $this->normedAttributes)) {
|
||||
return $this->normedAttributes[$loweredName];
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this repository's name
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this repository's name
|
||||
*
|
||||
* In case no name has been explicitly set yet, the class name is returned.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the base DN to use for a user query
|
||||
*
|
||||
* @param string $baseDn
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setUserBaseDn($baseDn)
|
||||
{
|
||||
if (($baseDn = trim($baseDn))) {
|
||||
$this->userBaseDn = $baseDn;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base DN to use for a user query
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserBaseDn()
|
||||
{
|
||||
return $this->userBaseDn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the base DN to use for a group query
|
||||
*
|
||||
* @param string $baseDn
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setGroupBaseDn($baseDn)
|
||||
{
|
||||
if (($baseDn = trim($baseDn))) {
|
||||
$this->groupBaseDn = $baseDn;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base DN to use for a group query
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getGroupBaseDn()
|
||||
{
|
||||
return $this->groupBaseDn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the objectClass where to look for users
|
||||
*
|
||||
* @param string $userClass
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setUserClass($userClass)
|
||||
{
|
||||
$this->userClass = $this->getNormedAttribute($userClass);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the objectClass where to look for users
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserClass()
|
||||
{
|
||||
return $this->userClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the objectClass where to look for groups
|
||||
*
|
||||
* Sets also the base table name for the underlying repository.
|
||||
*
|
||||
* @param string $groupClass
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setGroupClass($groupClass)
|
||||
{
|
||||
$this->baseTable = $this->groupClass = $this->getNormedAttribute($groupClass);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the objectClass where to look for groups
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getGroupClass()
|
||||
{
|
||||
return $this->groupClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the attribute name where to find a user's name
|
||||
*
|
||||
* @param string $userNameAttribute
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setUserNameAttribute($userNameAttribute)
|
||||
{
|
||||
$this->userNameAttribute = $this->getNormedAttribute($userNameAttribute);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the attribute name where to find a user's name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserNameAttribute()
|
||||
{
|
||||
return $this->userNameAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the attribute name where to find a group's name
|
||||
*
|
||||
* @param string $groupNameAttribute
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setGroupNameAttribute($groupNameAttribute)
|
||||
{
|
||||
$this->groupNameAttribute = $this->getNormedAttribute($groupNameAttribute);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the attribute name where to find a group's name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getGroupNameAttribute()
|
||||
{
|
||||
return $this->groupNameAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the attribute name where to find a group's member
|
||||
*
|
||||
* @param string $groupMemberAttribute
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setGroupMemberAttribute($groupMemberAttribute)
|
||||
{
|
||||
$this->groupMemberAttribute = $this->getNormedAttribute($groupMemberAttribute);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the attribute name where to find a group's member
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getGroupMemberAttribute()
|
||||
{
|
||||
return $this->groupMemberAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the custom LDAP filter to apply on a user query
|
||||
*
|
||||
* @param string $filter
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setUserFilter($filter)
|
||||
{
|
||||
if (($filter = trim($filter))) {
|
||||
$this->userFilter = $filter;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the custom LDAP filter to apply on a user query
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserFilter()
|
||||
{
|
||||
return $this->userFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the custom LDAP filter to apply on a group query
|
||||
*
|
||||
* @param string $filter
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setGroupFilter($filter)
|
||||
{
|
||||
if (($filter = trim($filter))) {
|
||||
$this->groupFilter = $filter;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the custom LDAP filter to apply on a group query
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getGroupFilter()
|
||||
{
|
||||
return $this->groupFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new query for the given columns
|
||||
*
|
||||
* @param array $columns The desired columns, if null all columns will be queried
|
||||
*
|
||||
* @return RepositoryQuery
|
||||
*/
|
||||
public function select(array $columns = null)
|
||||
{
|
||||
$query = parent::select($columns);
|
||||
$query->getQuery()->setBase($this->groupBaseDn);
|
||||
if ($this->groupFilter) {
|
||||
// TODO(jom): This should differentiate between groups and their memberships
|
||||
$query->getQuery()->where(new Expression($this->groupFilter));
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this repository's query columns
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws ProgrammingError In case either $this->groupNameAttribute or $this->groupClass has not been set yet
|
||||
*/
|
||||
protected function initializeQueryColumns()
|
||||
{
|
||||
if ($this->groupClass === null) {
|
||||
throw new ProgrammingError('It is required to set the objectClass where to look for groups first');
|
||||
}
|
||||
if ($this->groupNameAttribute === null) {
|
||||
throw new ProgrammingError('It is required to set a attribute name where to find a group\'s name first');
|
||||
}
|
||||
|
||||
if ($this->ds->getCapabilities()->hasAdOid()) {
|
||||
$createdAtAttribute = 'whenCreated';
|
||||
$lastModifiedAttribute = 'whenChanged';
|
||||
} else {
|
||||
$createdAtAttribute = 'createTimestamp';
|
||||
$lastModifiedAttribute = 'modifyTimestamp';
|
||||
}
|
||||
|
||||
// TODO(jom): Fetching memberships does not work currently, we'll need some aggregate functionality!
|
||||
$columns = array(
|
||||
'group' => $this->groupNameAttribute,
|
||||
'group_name' => $this->groupNameAttribute,
|
||||
'user' => $this->groupMemberAttribute,
|
||||
'user_name' => $this->groupMemberAttribute,
|
||||
'created_at' => $createdAtAttribute,
|
||||
'last_modified' => $lastModifiedAttribute
|
||||
);
|
||||
return array('group' => $columns, 'group_membership' => $columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this repository's conversion rules
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws ProgrammingError In case $this->groupClass has not been set yet
|
||||
*/
|
||||
protected function initializeConversionRules()
|
||||
{
|
||||
if ($this->groupClass === null) {
|
||||
throw new ProgrammingError('It is required to set the objectClass where to look for groups first');
|
||||
}
|
||||
|
||||
return array(
|
||||
$this->groupClass => array(
|
||||
'created_at' => 'generalized_time',
|
||||
'last_modified' => 'generalized_time'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the requested table exists
|
||||
*
|
||||
* This will return $this->groupClass in case $table equals "group" or "group_membership".
|
||||
*
|
||||
* @param string $table The table to validate
|
||||
* @param RepositoryQuery $query An optional query to pass as context
|
||||
* (unused by the base implementation)
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws ProgrammingError In case the given table does not exist
|
||||
*/
|
||||
public function requireTable($table, RepositoryQuery $query = null)
|
||||
{
|
||||
$table = parent::requireTable($table, $query);
|
||||
if ($table === 'group' || $table === 'group_membership') {
|
||||
$table = $this->groupClass;
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the groups the given user is a member of
|
||||
*
|
||||
* @param User $user
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMemberships(User $user)
|
||||
{
|
||||
$userQuery = $this->ds
|
||||
->select()
|
||||
->from($this->userClass)
|
||||
->where($this->userNameAttribute, $user->getUsername())
|
||||
->setBase($this->userBaseDn)
|
||||
->setUsePagedResults(false);
|
||||
if ($this->userFilter) {
|
||||
$userQuery->where(new Expression($this->userFilter));
|
||||
}
|
||||
|
||||
if (($userDn = $userQuery->fetchDn()) === null) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$groupQuery = $this->ds
|
||||
->select()
|
||||
->from($this->groupClass, array($this->groupNameAttribute))
|
||||
->where($this->groupMemberAttribute, $userDn)
|
||||
->setBase($this->groupBaseDn);
|
||||
if ($this->groupFilter) {
|
||||
$groupQuery->where(new Expression($this->groupFilter));
|
||||
}
|
||||
|
||||
$groups = array();
|
||||
foreach ($groupQuery as $row) {
|
||||
$groups[] = $row->{$this->groupNameAttribute};
|
||||
}
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the given configuration on this backend
|
||||
*
|
||||
* @param ConfigObject $config
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws ConfigurationError In case a linked user backend does not exist or is invalid
|
||||
*/
|
||||
public function setConfig(ConfigObject $config)
|
||||
{
|
||||
if ($config->backend === 'ldap') {
|
||||
$defaults = $this->getOpenLdapDefaults();
|
||||
} elseif ($config->backend === 'msldap') {
|
||||
$defaults = $this->getActiveDirectoryDefaults();
|
||||
} else {
|
||||
$defaults = new ConfigObject();
|
||||
}
|
||||
|
||||
if ($config->user_backend && $config->user_backend !== 'none') {
|
||||
$userBackend = UserBackend::create($config->user_backend);
|
||||
if (! $userBackend instanceof LdapUserBackend) {
|
||||
throw new ConfigurationError('User backend "%s" is not of type LDAP', $config->user_backend);
|
||||
}
|
||||
|
||||
if (
|
||||
$this->ds->getHostname() !== $userBackend->getDataSource()->getHostname()
|
||||
|| $this->ds->getPort() !== $userBackend->getDataSource()->getPort()
|
||||
) {
|
||||
// TODO(jom): Elaborate whether it makes sense to link directories on different hosts
|
||||
throw new ConfigurationError(
|
||||
'It is required that a linked user backend refers to the '
|
||||
. 'same directory as it\'s user group backend counterpart'
|
||||
);
|
||||
}
|
||||
|
||||
$defaults->merge(array(
|
||||
'user_base_dn' => $userBackend->getBaseDn(),
|
||||
'user_class' => $userBackend->getUserClass(),
|
||||
'user_name_attribute' => $userBackend->getUserNameAttribute(),
|
||||
'user_filter' => $userBackend->getFilter()
|
||||
));
|
||||
}
|
||||
|
||||
return $this
|
||||
->setGroupBaseDn($config->base_dn)
|
||||
->setUserBaseDn($config->get('user_base_dn', $this->getGroupBaseDn()))
|
||||
->setGroupClass($config->get('group_class', $defaults->group_class))
|
||||
->setUserClass($config->get('user_class', $defaults->user_class))
|
||||
->setGroupNameAttribute($config->get('group_name_attribute', $defaults->group_name_attribute))
|
||||
->setUserNameAttribute($config->get('user_name_attribute', $defaults->user_name_attribute))
|
||||
->setGroupMemberAttribute($config->get('group_member_attribute', $defaults->group_member_attribute))
|
||||
->setGroupFilter($config->filter)
|
||||
->setUserFilter($config->user_filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configuration defaults for an OpenLDAP environment
|
||||
*
|
||||
* @return ConfigObject
|
||||
*/
|
||||
public function getOpenLdapDefaults()
|
||||
{
|
||||
return new ConfigObject(array(
|
||||
'group_class' => 'group',
|
||||
'user_class' => 'inetOrgPerson',
|
||||
'group_name_attribute' => 'gid',
|
||||
'user_name_attribute' => 'uid',
|
||||
'group_member_attribute' => 'member'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configuration defaults for an ActiveDirectory environment
|
||||
*
|
||||
* @return ConfigObject
|
||||
*/
|
||||
public function getActiveDirectoryDefaults()
|
||||
{
|
||||
return new ConfigObject(array(
|
||||
'group_class' => 'group',
|
||||
'user_class' => 'user',
|
||||
'group_name_attribute' => 'sAMAccountName',
|
||||
'user_name_attribute' => 'sAMAccountName',
|
||||
'group_member_attribute' => 'member'
|
||||
));
|
||||
}
|
||||
}
|
|
@ -21,6 +21,8 @@ class UserGroupBackend
|
|||
*/
|
||||
protected static $defaultBackends = array(
|
||||
'db',
|
||||
'ldap',
|
||||
'msldap',
|
||||
//'ini'
|
||||
);
|
||||
|
||||
|
@ -156,6 +158,11 @@ class UserGroupBackend
|
|||
case 'ini':
|
||||
$backend = new IniUserGroupBackend($resource);
|
||||
break;
|
||||
case 'ldap':
|
||||
case 'msldap':
|
||||
$backend = new LdapUserGroupBackend($resource);
|
||||
$backend->setConfig($backendConfig);
|
||||
break;
|
||||
}
|
||||
|
||||
$backend->setName($name);
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Repository;
|
||||
|
||||
use Icinga\Protocol\Ldap\Connection;
|
||||
|
||||
/**
|
||||
* Abstract base class for concrete LDAP repository implementations
|
||||
*
|
||||
* Additionally provided features:
|
||||
* <ul>
|
||||
* <li>Attribute name normalization</li>
|
||||
* </ul>
|
||||
*/
|
||||
abstract class LdapRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* The datasource being used
|
||||
*
|
||||
* @var Connection
|
||||
*/
|
||||
protected $ds;
|
||||
|
||||
/**
|
||||
* Normed attribute names based on known LDAP environments
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $normedAttributes = array(
|
||||
'uid' => 'uid',
|
||||
'gid' => 'gid',
|
||||
'user' => 'user',
|
||||
'group' => 'group',
|
||||
'member' => 'member',
|
||||
'inetorgperson' => 'inetOrgPerson',
|
||||
'samaccountname' => 'sAMAccountName'
|
||||
);
|
||||
|
||||
/**
|
||||
* Create a new LDAP repository object
|
||||
*
|
||||
* @param Connection $ds The data source to use
|
||||
*/
|
||||
public function __construct(Connection $ds)
|
||||
{
|
||||
parent::__construct($ds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the given attribute name normed to known LDAP enviroments, if possible
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getNormedAttribute($name)
|
||||
{
|
||||
$loweredName = strtolower($name);
|
||||
if (array_key_exists($loweredName, $this->normedAttributes)) {
|
||||
return $this->normedAttributes[$loweredName];
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
}
|
|
@ -599,6 +599,37 @@ abstract class Repository implements Selectable
|
|||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given value based on the ASN.1 standard (GeneralizedTime) and return its timestamp representation
|
||||
*
|
||||
* @param string|null $value
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function retrieveGeneralizedTime($value)
|
||||
{
|
||||
if ($value === null) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (
|
||||
($dateTime = DateTime::createFromFormat('YmdHis.uO', $value)) !== false
|
||||
|| ($dateTime = DateTime::createFromFormat('YmdHis.uZ', $value)) !== false
|
||||
|| ($dateTime = DateTime::createFromFormat('YmdHis.u', $value)) !== false
|
||||
|| ($dateTime = DateTime::createFromFormat('YmdHis', $value)) !== false
|
||||
|| ($dateTime = DateTime::createFromFormat('YmdHi', $value)) !== false
|
||||
|| ($dateTime = DateTime::createFromFormat('YmdH', $value)) !== false
|
||||
) {
|
||||
return $dateTime->getTimeStamp();
|
||||
} else {
|
||||
Logger::debug(sprintf(
|
||||
'Failed to parse "%s" based on the ASN.1 standard (GeneralizedTime) in repository "%s".',
|
||||
$value,
|
||||
$this->getName()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the requested table exists
|
||||
*
|
||||
|
|
|
@ -855,8 +855,19 @@ class Form extends Zend_Form
|
|||
public function populate(array $defaults)
|
||||
{
|
||||
$this->create($defaults);
|
||||
$this->preserveDefaults($this, $defaults);
|
||||
return parent::populate($defaults);
|
||||
}
|
||||
|
||||
foreach ($this->getElements() as $name => $_) {
|
||||
/**
|
||||
* Recurse the given form and unset all unchanged default values
|
||||
*
|
||||
* @param Zend_Form $form
|
||||
* @param array $defaults
|
||||
*/
|
||||
protected function preserveDefaults(Zend_Form $form, array & $defaults)
|
||||
{
|
||||
foreach ($form->getElements() as $name => $_) {
|
||||
if (
|
||||
array_key_exists($name, $defaults)
|
||||
&& array_key_exists($name . static::DEFAULT_SUFFIX, $defaults)
|
||||
|
@ -866,7 +877,9 @@ class Form extends Zend_Form
|
|||
}
|
||||
}
|
||||
|
||||
return parent::populate($defaults);
|
||||
foreach ($form->getSubForms() as $_ => $subForm) {
|
||||
$this->preserveDefaults($subForm, $defaults);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue