Skip to content

Commit 2244b19

Browse files
committed
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 calls of the rfc2307bis draft. The core user_ldap app could also be changed to make this more handy, but already allows custom group filters.
1 parent d4aeba3 commit 2244b19

File tree

6 files changed

+97
-16
lines changed

6 files changed

+97
-16
lines changed

lib/AppInfo/Application.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public function registerLDAPPlugins(): void {
7777

7878
$this->ldapGroupManager = new LDAPGroupManager(
7979
$s->getGroupManager(),
80+
$s->getUserSession(),
8081
$ldapConnect,
8182
$s->getLogger(),
8283
$provider

lib/LDAPGroupManager.php

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
use OCA\User_LDAP\LDAPProvider;
3434
use OCP\AppFramework\QueryException;
3535
use OCP\IGroupManager;
36+
use OCP\IUserSession;
3637
use OCP\ILogger;
3738
use OCP\LDAP\ILDAPProvider;
3839

@@ -41,6 +42,9 @@ class LDAPGroupManager implements ILDAPGroupPlugin {
4142
/** @var ILDAPProvider */
4243
private $ldapProvider;
4344

45+
/** @var IUserSession */
46+
private $userSession;
47+
4448
/** @var IGroupManager */
4549
private $groupManager;
4650

@@ -49,8 +53,9 @@ class LDAPGroupManager implements ILDAPGroupPlugin {
4953
/** @var ILogger */
5054
private $logger;
5155

52-
public function __construct(IGroupManager $groupManager, LDAPConnect $ldapConnect, ILogger $logger, ILDAPProvider $ldapProvider) {
56+
public function __construct(IGroupManager $groupManager, IUserSession $userSession, LDAPConnect $ldapConnect, ILogger $logger, ILDAPProvider $ldapProvider) {
5357
$this->groupManager = $groupManager;
58+
$this->userSession = $userSession;
5459
$this->ldapConnect = $ldapConnect;
5560
$this->logger = $logger;
5661
$this->ldapProvider = $ldapProvider;
@@ -84,15 +89,27 @@ public function respondToActions() {
8489
* @return string|null
8590
*/
8691
public function createGroup($gid) {
92+
$adminUser = $this->userSession->getUser();
93+
$requireActorFromLDAP = $this->configuration->isLdapActorRequired();
94+
if ($requireActorFromLDAP && !$adminUser instanceof IUser) {
95+
throw new Exception('Acting user is not from LDAP');
96+
}
97+
try {
98+
$connection = $this->ldapProvider->getLDAPConnection($adminUser->getUID());
99+
// TODO: what about multiple bases?
100+
$base = $this->ldapProvider->getLDAPBaseGroups($adminUser->getUID());
101+
} catch (Exception $e) {
102+
if ($requireActorFromLDAP) {
103+
if ($this->configuration->isPreventFallback()) {
104+
throw new \Exception('Acting admin is not from LDAP', 0, $e);
105+
}
106+
return false;
107+
}
108+
$connection = $this->ldapConnect->getLDAPConnection();
109+
$base = $this->ldapConnect->getLDAPBaseGroups()[0];
110+
}
87111

88-
/**
89-
* FIXME could not create group using LDAPProvider, because its methods rely
90-
* on passing an already inserted [ug]id, which we do not have at this point.
91-
*/
92-
93-
$newGroupEntry = $this->buildNewEntry($gid);
94-
$connection = $this->ldapConnect->getLDAPConnection();
95-
$newGroupDN = "cn=$gid," . $this->ldapConnect->getLDAPBaseGroups()[0];
112+
list($newGroupDN, $newGroupEntry) = $this->buildNewEntry($gid, $base);
96113
$newGroupDN = $this->ldapProvider->sanitizeDN([$newGroupDN])[0];
97114

98115
if ($ret = ldap_add($connection, $newGroupDN, $newGroupEntry)) {
@@ -223,12 +240,30 @@ public function isLDAPGroup($gid) {
223240
}
224241
}
225242

226-
private function buildNewEntry($gid) {
227-
return [
228-
'objectClass' => ['groupOfNames', 'top'],
229-
'cn' => $gid,
230-
'member' => ['']
231-
];
243+
private function buildNewEntry($gid, $base) {
244+
$ldif = $this->configuration->getGroupTemplate();
245+
246+
$ldif = str_replace('{GID}', $gid, $ldif);
247+
$ldif = str_replace('{BASE}', $base, $ldif);
248+
249+
$entry = [];
250+
$lines = explode(PHP_EOL, $ldif);
251+
foreach ($lines as $line) {
252+
$split = explode(':', $line, 2);
253+
$key = trim($split[0]);
254+
$value = trim($split[1]);
255+
if (!isset($entry[$key])) {
256+
$entry[$key] = $value;
257+
} else if (is_array($entry[$key])) {
258+
$entry[$key][] = $value;
259+
} else {
260+
$entry[$key] = [$entry[$key], $value];
261+
}
262+
}
263+
$dn = $entry['dn'];
264+
unset($entry['dn']);
265+
266+
return [$dn, $entry];
232267
}
233268

234269
public function makeLdapBackendFirst() {

lib/LDAPUserManager.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ public function respondToActions() {
118118
* @throws ServerNotAvailableException
119119
*/
120120
public function setDisplayName($uid, $displayName) {
121+
trigger_error(__METHOD__);
122+
$this->logger->error(__METHOD__, ['app' => 'ldap_write_support']);
121123
$userDN = $this->getUserDN($uid);
122124

123125
$connection = $this->ldapProvider->getLDAPConnection($uid);
@@ -141,6 +143,10 @@ public function setDisplayName($uid, $displayName) {
141143
if (ldap_mod_replace($connection, $userDN, [$displayNameField => $displayName])) {
142144
return $displayName;
143145
}
146+
trigger_error(print_r(['conn' => $connection,
147+
'user' => $userDN,
148+
'dpyField' => $displayNameField,
149+
'dpy' => $displayName], true));
144150
throw new HintException('Failed to set display name');
145151
} catch (ConstraintViolationException $e) {
146152
throw new HintException(

lib/Service/Configuration.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ public function getUserTemplate() {
5656
);
5757
}
5858

59+
public function getGroupTemplate() {
60+
return $this->config->getAppValue(
61+
Application::APP_ID,
62+
'template.group',
63+
$this->getGroupTemplateDefault()
64+
);
65+
}
66+
5967
public function getUserTemplateDefault() {
6068
return
6169
'dn: uid={UID},{BASE}' . PHP_EOL .
@@ -67,6 +75,14 @@ public function getUserTemplateDefault() {
6775
'userPassword: {PWD}';
6876
}
6977

78+
public function getGroupTemplateDefault() {
79+
return
80+
'dn: cn={GID},{BASE}' . PHP_EOL .
81+
'objectClass: groupOfNames' . PHP_EOL .
82+
'cn: {GID}' . PHP_EOL .
83+
'member:';
84+
}
85+
7086
public function isRequireEmail(): bool {
7187
// this core settings flag is not exposed anywhere else
7288
return $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes';

lib/Settings/Admin.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ public function getForm() {
5353
'templates',
5454
[
5555
'user' => $this->config->getUserTemplate(),
56-
'userDefault' => $this->config->getUserTemplateDefault(),
56+
'userDefault' => $this->config->getGroupTemplateDefault(),
57+
'group' => $this->config->getGroupTemplate(),
58+
'groupDefault' => $this->config->getGroupTemplateDefault(),
5759
]
5860
);
5961
$this->initialStateService->provideInitialState(

src/components/AdminSettings.vue

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@
5353
<li><span class="mono">{BASE}</span> – {{ t('ldap_write_support', 'the LDAP node of the acting (sub)admin or the configured user base') }}</li>
5454
</ul>
5555
<textarea class="mono" v-on:change="setUserTemplate" v-model="templates.user">{{templates.user}}</textarea>
56+
<h3>{{ t('ldap_write_support', 'Group template') }}</h3>
57+
<p>{{ t('ldap_write_support', 'LDIF template for creating groups. Following placeholders may be used') }}</p>
58+
<ul class="disc">
59+
<li><span class="mono">{GID}</span> – {{ t('ldap_write_support', 'the group id provided by the (sub)admin') }}</li>
60+
<li><span class="mono">{BASE}</span> – {{ t('ldap_write_support', 'the LDAP node of the acting (sub)admin or the configured group base') }}</li>
61+
</ul>
62+
<textarea class="mono" v-on:change="setGroupTemplate" v-model="templates.group">{{templates.group}}</textarea>
5663
</div>
5764
</template>
5865

@@ -67,6 +74,8 @@
6774
templates: {
6875
user: Object,
6976
userDefault: Object,
77+
group: Object,
78+
groupDefault: Object,
7079
},
7180
switches: {
7281
createRequireActorFromLdap: Boolean,
@@ -92,6 +101,18 @@
92101
}
93102
OCP.AppConfig.setValue('ldap_write_support', 'template.user', this.templates.user);
94103
},
104+
setGroupTemplate() {
105+
if(this.templates.group === "") {
106+
let self = this;
107+
OCP.AppConfig.deleteKey('ldap_write_support', 'template.group', {
108+
success: function() {
109+
self.templates.group = self.templates.groupDefault;
110+
}
111+
});
112+
return;
113+
}
114+
OCP.AppConfig.setValue('ldap_write_support', 'template.group', this.templates.group);
115+
},
95116
toggleSwitch(prefKey, state, appId = 'ldap_write_support') {
96117
this.switches[prefKey] = state;
97118
let value = (state | 0).toString();

0 commit comments

Comments
 (0)