From a625cd8f1f5796f42b08472cbce337be8ea135b7 Mon Sep 17 00:00:00 2001 From: Claus-Justus Heine Date: Tue, 13 Oct 2020 21:59:39 +0200 Subject: [PATCH 1/2] Add a new group template just as it is already there for adding users. Rationale: this allows to support "custom" group LDAP classes, like the groupOfMembers class of the rfc2307bis draft. The core user_ldap app could also be changed to make this more handy, but already allows custom group filters. Signed-off-by: Claus-Justus Heine --- lib/AppInfo/Application.php | 1 + lib/LDAPGroupManager.php | 65 ++++++++++++++++++++++++-------- lib/LDAPUserManager.php | 6 +++ lib/Service/Configuration.php | 16 ++++++++ lib/Settings/Admin.php | 4 +- src/components/AdminSettings.vue | 21 +++++++++++ 6 files changed, 97 insertions(+), 16 deletions(-) diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 80c53c05..9d75ccda 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -77,6 +77,7 @@ public function registerLDAPPlugins(): void { $this->ldapGroupManager = new LDAPGroupManager( $s->getGroupManager(), + $s->getUserSession(), $ldapConnect, $s->getLogger(), $provider diff --git a/lib/LDAPGroupManager.php b/lib/LDAPGroupManager.php index ae587883..c13e1eba 100644 --- a/lib/LDAPGroupManager.php +++ b/lib/LDAPGroupManager.php @@ -33,6 +33,7 @@ use OCA\User_LDAP\LDAPProvider; use OCP\AppFramework\QueryException; use OCP\IGroupManager; +use OCP\IUserSession; use OCP\ILogger; use OCP\LDAP\ILDAPProvider; @@ -41,6 +42,9 @@ class LDAPGroupManager implements ILDAPGroupPlugin { /** @var ILDAPProvider */ private $ldapProvider; + /** @var IUserSession */ + private $userSession; + /** @var IGroupManager */ private $groupManager; @@ -49,8 +53,9 @@ class LDAPGroupManager implements ILDAPGroupPlugin { /** @var ILogger */ private $logger; - public function __construct(IGroupManager $groupManager, LDAPConnect $ldapConnect, ILogger $logger, ILDAPProvider $ldapProvider) { + public function __construct(IGroupManager $groupManager, IUserSession $userSession, LDAPConnect $ldapConnect, ILogger $logger, ILDAPProvider $ldapProvider) { $this->groupManager = $groupManager; + $this->userSession = $userSession; $this->ldapConnect = $ldapConnect; $this->logger = $logger; $this->ldapProvider = $ldapProvider; @@ -84,15 +89,27 @@ public function respondToActions() { * @return string|null */ public function createGroup($gid) { + $adminUser = $this->userSession->getUser(); + $requireActorFromLDAP = $this->configuration->isLdapActorRequired(); + if ($requireActorFromLDAP && !$adminUser instanceof IUser) { + throw new Exception('Acting user is not from LDAP'); + } + try { + $connection = $this->ldapProvider->getLDAPConnection($adminUser->getUID()); + // TODO: what about multiple bases? + $base = $this->ldapProvider->getLDAPBaseGroups($adminUser->getUID()); + } catch (Exception $e) { + if ($requireActorFromLDAP) { + if ($this->configuration->isPreventFallback()) { + throw new \Exception('Acting admin is not from LDAP', 0, $e); + } + return false; + } + $connection = $this->ldapConnect->getLDAPConnection(); + $base = $this->ldapConnect->getLDAPBaseGroups()[0]; + } - /** - * FIXME could not create group using LDAPProvider, because its methods rely - * on passing an already inserted [ug]id, which we do not have at this point. - */ - - $newGroupEntry = $this->buildNewEntry($gid); - $connection = $this->ldapConnect->getLDAPConnection(); - $newGroupDN = "cn=$gid," . $this->ldapConnect->getLDAPBaseGroups()[0]; + list($newGroupDN, $newGroupEntry) = $this->buildNewEntry($gid, $base); $newGroupDN = $this->ldapProvider->sanitizeDN([$newGroupDN])[0]; if ($ret = ldap_add($connection, $newGroupDN, $newGroupEntry)) { @@ -223,12 +240,30 @@ public function isLDAPGroup($gid) { } } - private function buildNewEntry($gid) { - return [ - 'objectClass' => ['groupOfNames', 'top'], - 'cn' => $gid, - 'member' => [''] - ]; + private function buildNewEntry($gid, $base) { + $ldif = $this->configuration->getGroupTemplate(); + + $ldif = str_replace('{GID}', $gid, $ldif); + $ldif = str_replace('{BASE}', $base, $ldif); + + $entry = []; + $lines = explode(PHP_EOL, $ldif); + foreach ($lines as $line) { + $split = explode(':', $line, 2); + $key = trim($split[0]); + $value = trim($split[1]); + if (!isset($entry[$key])) { + $entry[$key] = $value; + } else if (is_array($entry[$key])) { + $entry[$key][] = $value; + } else { + $entry[$key] = [$entry[$key], $value]; + } + } + $dn = $entry['dn']; + unset($entry['dn']); + + return [$dn, $entry]; } public function makeLdapBackendFirst() { diff --git a/lib/LDAPUserManager.php b/lib/LDAPUserManager.php index 4215b7dd..47dd9d88 100644 --- a/lib/LDAPUserManager.php +++ b/lib/LDAPUserManager.php @@ -118,6 +118,8 @@ public function respondToActions() { * @throws ServerNotAvailableException */ public function setDisplayName($uid, $displayName) { + trigger_error(__METHOD__); + $this->logger->error(__METHOD__, ['app' => 'ldap_write_support']); $userDN = $this->getUserDN($uid); $connection = $this->ldapProvider->getLDAPConnection($uid); @@ -141,6 +143,10 @@ public function setDisplayName($uid, $displayName) { if (ldap_mod_replace($connection, $userDN, [$displayNameField => $displayName])) { return $displayName; } + trigger_error(print_r(['conn' => $connection, + 'user' => $userDN, + 'dpyField' => $displayNameField, + 'dpy' => $displayName], true)); throw new HintException('Failed to set display name'); } catch (ConstraintViolationException $e) { throw new HintException( diff --git a/lib/Service/Configuration.php b/lib/Service/Configuration.php index 95c830b8..59b88320 100644 --- a/lib/Service/Configuration.php +++ b/lib/Service/Configuration.php @@ -56,6 +56,14 @@ public function getUserTemplate() { ); } + public function getGroupTemplate() { + return $this->config->getAppValue( + Application::APP_ID, + 'template.group', + $this->getGroupTemplateDefault() + ); + } + public function getUserTemplateDefault() { return 'dn: uid={UID},{BASE}' . PHP_EOL . @@ -67,6 +75,14 @@ public function getUserTemplateDefault() { 'userPassword: {PWD}'; } + public function getGroupTemplateDefault() { + return + 'dn: cn={GID},{BASE}' . PHP_EOL . + 'objectClass: groupOfNames' . PHP_EOL . + 'cn: {GID}' . PHP_EOL . + 'member:'; + } + public function isRequireEmail(): bool { // this core settings flag is not exposed anywhere else return $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes'; diff --git a/lib/Settings/Admin.php b/lib/Settings/Admin.php index bacd1e6a..9e6d2093 100644 --- a/lib/Settings/Admin.php +++ b/lib/Settings/Admin.php @@ -53,7 +53,9 @@ public function getForm() { 'templates', [ 'user' => $this->config->getUserTemplate(), - 'userDefault' => $this->config->getUserTemplateDefault(), + 'userDefault' => $this->config->getGroupTemplateDefault(), + 'group' => $this->config->getGroupTemplate(), + 'groupDefault' => $this->config->getGroupTemplateDefault(), ] ); $this->initialStateService->provideInitialState( diff --git a/src/components/AdminSettings.vue b/src/components/AdminSettings.vue index 6d73e693..c5a8f052 100644 --- a/src/components/AdminSettings.vue +++ b/src/components/AdminSettings.vue @@ -53,6 +53,13 @@
  • {BASE} – {{ t('ldap_write_support', 'the LDAP node of the acting (sub)admin or the configured user base') }}
  • +

    {{ t('ldap_write_support', 'Group template') }}

    +

    {{ t('ldap_write_support', 'LDIF template for creating groups. Following placeholders may be used') }}

    + + @@ -67,6 +74,8 @@ templates: { user: Object, userDefault: Object, + group: Object, + groupDefault: Object, }, switches: { createRequireActorFromLdap: Boolean, @@ -92,6 +101,18 @@ } OCP.AppConfig.setValue('ldap_write_support', 'template.user', this.templates.user); }, + setGroupTemplate() { + if(this.templates.group === "") { + let self = this; + OCP.AppConfig.deleteKey('ldap_write_support', 'template.group', { + success: function() { + self.templates.group = self.templates.groupDefault; + } + }); + return; + } + OCP.AppConfig.setValue('ldap_write_support', 'template.group', this.templates.group); + }, toggleSwitch(prefKey, state, appId = 'ldap_write_support') { this.switches[prefKey] = state; let value = (state | 0).toString(); From bce41caf32ade9e4e7317cc3c3620e37fcf964dd Mon Sep 17 00:00:00 2001 From: Claus-Justus Heine Date: Wed, 14 Oct 2020 03:48:07 +0200 Subject: [PATCH 2/2] Fix silly erros. --- lib/AppInfo/Application.php | 6 ++++-- lib/LDAPGroupManager.php | 11 ++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 9d75ccda..2fb2c62d 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -79,8 +79,10 @@ public function registerLDAPPlugins(): void { $s->getGroupManager(), $s->getUserSession(), $ldapConnect, - $s->getLogger(), - $provider + $provider, + $c->query(Configuration::class), + $s->getL10N(self::APP_ID), + $s->getLogger() ); /** @var UserPluginManager $userPluginManager */ diff --git a/lib/LDAPGroupManager.php b/lib/LDAPGroupManager.php index c13e1eba..d6c93b71 100644 --- a/lib/LDAPGroupManager.php +++ b/lib/LDAPGroupManager.php @@ -28,13 +28,16 @@ use Exception; use OC\Group\Backend; use OCA\LdapWriteSupport\AppInfo\Application; +use OCA\LdapWriteSupport\Service\Configuration; use OCA\User_LDAP\Group_Proxy; use OCA\User_LDAP\ILDAPGroupPlugin; use OCA\User_LDAP\LDAPProvider; use OCP\AppFramework\QueryException; use OCP\IGroupManager; -use OCP\IUserSession; +use OCP\IL10N; use OCP\ILogger; +use OCP\IUser; +use OCP\IUserSession; use OCP\LDAP\ILDAPProvider; class LDAPGroupManager implements ILDAPGroupPlugin { @@ -53,12 +56,14 @@ class LDAPGroupManager implements ILDAPGroupPlugin { /** @var ILogger */ private $logger; - public function __construct(IGroupManager $groupManager, IUserSession $userSession, LDAPConnect $ldapConnect, ILogger $logger, ILDAPProvider $ldapProvider) { + public function __construct(IGroupManager $groupManager, IUserSession $userSession, LDAPConnect $ldapConnect, ILDAPProvider $ldapProvider, Configuration $configuration, IL10N $l10n, ILogger $logger) { $this->groupManager = $groupManager; $this->userSession = $userSession; $this->ldapConnect = $ldapConnect; - $this->logger = $logger; $this->ldapProvider = $ldapProvider; + $this->configuration = $configuration; + $this->l10n = $l10n; + $this->logger = $logger; if($this->ldapConnect->groupsEnabled()) { $this->makeLdapBackendFirst();