diff --git a/lib/LDAPGroupManager.php b/lib/LDAPGroupManager.php index bccd6f74..ded38080 100644 --- a/lib/LDAPGroupManager.php +++ b/lib/LDAPGroupManager.php @@ -28,17 +28,25 @@ 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 OCP\IGroupManager; +use OCP\IUser; +use OCP\IUserSession; use OCP\LDAP\ILDAPProvider; use Psr\Log\LoggerInterface; class LDAPGroupManager implements ILDAPGroupPlugin { + /** @var Configuration */ + protected $configuration; /** @var ILDAPProvider */ private $ldapProvider; + /** @var IUserSession */ + private $userSession; + /** @var IGroupManager */ private $groupManager; @@ -47,11 +55,13 @@ class LDAPGroupManager implements ILDAPGroupPlugin { /** @var LoggerInterface */ private $logger; - public function __construct(IGroupManager $groupManager, LDAPConnect $ldapConnect, LoggerInterface $logger, ILDAPProvider $LDAPProvider) { + public function __construct(IGroupManager $groupManager, IUserSession $userSession, LDAPConnect $ldapConnect, LoggerInterface $logger, ILDAPProvider $ldapProvider, Configuration $configuration) { $this->groupManager = $groupManager; + $this->userSession = $userSession; $this->ldapConnect = $ldapConnect; + $this->ldapProvider = $ldapProvider; + $this->configuration = $configuration; $this->logger = $logger; - $this->ldapProvider = $LDAPProvider; if($this->ldapConnect->groupsEnabled()) { $this->makeLdapBackendFirst(); @@ -82,15 +92,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)) { @@ -151,7 +173,6 @@ public function addToGroup($uid, $gid) { break; case 'gidNumber': throw new Exception('Cannot add to group when gidNumber is used as relation'); - break; } if (!$ret = ldap_mod_add($connection, $groupDN, $entry)) { @@ -220,12 +241,30 @@ public function isLDAPGroup($gid): bool { } } - private function buildNewEntry($gid): array { - return [ - 'objectClass' => ['groupOfNames', 'top'], - 'cn' => $gid, - 'member' => [''] - ]; + private function buildNewEntry($gid, $base): array { + $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(): void { diff --git a/lib/LDAPUserManager.php b/lib/LDAPUserManager.php index f8735e96..5204780e 100644 --- a/lib/LDAPUserManager.php +++ b/lib/LDAPUserManager.php @@ -107,6 +107,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); @@ -130,6 +132,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 3c2ebaaa..c51dc010 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 . @@ -66,6 +74,14 @@ public function getUserTemplateDefault() { 'sn: {UID}'; } + 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 bae106fa..8597d8ff 100644 --- a/lib/Settings/Admin.php +++ b/lib/Settings/Admin.php @@ -51,7 +51,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 505e9cd4..1f057ea1 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') }}
  • @@ -71,6 +78,8 @@ export default { templates: { required: true, type: Object, + group: Object, + groupDefault: Object, }, switches: { required: true, @@ -95,6 +104,18 @@ export default { return } OCP.AppConfig.setValue('ldap_write_support', 'template.user', this.userTemplate) + }, + 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') {