Skip to content

Commit d168db1

Browse files
rotdropsusnux
authored andcommitted
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 <[email protected]>
1 parent e7f6954 commit d168db1

File tree

5 files changed

+102
-18
lines changed

5 files changed

+102
-18
lines changed

lib/LDAPGroupManager.php

+56-17
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,25 @@
2828
use Exception;
2929
use OC\Group\Backend;
3030
use OCA\LdapWriteSupport\AppInfo\Application;
31+
use OCA\LdapWriteSupport\Service\Configuration;
3132
use OCA\User_LDAP\Group_Proxy;
3233
use OCA\User_LDAP\ILDAPGroupPlugin;
3334
use OCP\IGroupManager;
35+
use OCP\IUser;
36+
use OCP\IUserSession;
3437
use OCP\LDAP\ILDAPProvider;
3538
use Psr\Log\LoggerInterface;
3639

3740
class LDAPGroupManager implements ILDAPGroupPlugin {
41+
/** @var Configuration */
42+
protected $configuration;
3843

3944
/** @var ILDAPProvider */
4045
private $ldapProvider;
4146

47+
/** @var IUserSession */
48+
private $userSession;
49+
4250
/** @var IGroupManager */
4351
private $groupManager;
4452

@@ -47,11 +55,13 @@ class LDAPGroupManager implements ILDAPGroupPlugin {
4755
/** @var LoggerInterface */
4856
private $logger;
4957

50-
public function __construct(IGroupManager $groupManager, LDAPConnect $ldapConnect, LoggerInterface $logger, ILDAPProvider $LDAPProvider) {
58+
public function __construct(IGroupManager $groupManager, IUserSession $userSession, LDAPConnect $ldapConnect, LoggerInterface $logger, ILDAPProvider $LDAPProvider) {
5159
$this->groupManager = $groupManager;
60+
$this->userSession = $userSession;
5261
$this->ldapConnect = $ldapConnect;
62+
$this->ldapProvider = $ldapProvider;
63+
$this->configuration = $configuration;
5364
$this->logger = $logger;
54-
$this->ldapProvider = $LDAPProvider;
5565

5666
if($this->ldapConnect->groupsEnabled()) {
5767
$this->makeLdapBackendFirst();
@@ -82,15 +92,27 @@ public function respondToActions() {
8292
* @return string|null
8393
*/
8494
public function createGroup($gid) {
95+
$adminUser = $this->userSession->getUser();
96+
$requireActorFromLDAP = $this->configuration->isLdapActorRequired();
97+
if ($requireActorFromLDAP && !$adminUser instanceof IUser) {
98+
throw new Exception('Acting user is not from LDAP');
99+
}
100+
try {
101+
$connection = $this->ldapProvider->getLDAPConnection($adminUser->getUID());
102+
// TODO: what about multiple bases?
103+
$base = $this->ldapProvider->getLDAPBaseGroups($adminUser->getUID());
104+
} catch (Exception $e) {
105+
if ($requireActorFromLDAP) {
106+
if ($this->configuration->isPreventFallback()) {
107+
throw new \Exception('Acting admin is not from LDAP', 0, $e);
108+
}
109+
return false;
110+
}
111+
$connection = $this->ldapConnect->getLDAPConnection();
112+
$base = $this->ldapConnect->getLDAPBaseGroups()[0];
113+
}
85114

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

96118
if ($ret = ldap_add($connection, $newGroupDN, $newGroupEntry)) {
@@ -151,7 +173,6 @@ public function addToGroup($uid, $gid) {
151173
break;
152174
case 'gidNumber':
153175
throw new Exception('Cannot add to group when gidNumber is used as relation');
154-
break;
155176
}
156177

157178
if (!$ret = ldap_mod_add($connection, $groupDN, $entry)) {
@@ -220,12 +241,30 @@ public function isLDAPGroup($gid): bool {
220241
}
221242
}
222243

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

231270
public function makeLdapBackendFirst(): void {

lib/LDAPUserManager.php

+6
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ public function respondToActions() {
107107
* @throws ServerNotAvailableException
108108
*/
109109
public function setDisplayName($uid, $displayName) {
110+
trigger_error(__METHOD__);
111+
$this->logger->error(__METHOD__, ['app' => 'ldap_write_support']);
110112
$userDN = $this->getUserDN($uid);
111113

112114
$connection = $this->ldapProvider->getLDAPConnection($uid);
@@ -130,6 +132,10 @@ public function setDisplayName($uid, $displayName) {
130132
if (ldap_mod_replace($connection, $userDN, [$displayNameField => $displayName])) {
131133
return $displayName;
132134
}
135+
trigger_error(print_r(['conn' => $connection,
136+
'user' => $userDN,
137+
'dpyField' => $displayNameField,
138+
'dpy' => $displayName], true));
133139
throw new HintException('Failed to set display name');
134140
} catch (ConstraintViolationException $e) {
135141
throw new HintException(

lib/Service/Configuration.php

+16
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 .
@@ -66,6 +74,14 @@ public function getUserTemplateDefault() {
6674
'sn: {UID}';
6775
}
6876

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

lib/Settings/Admin.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ public function getForm() {
5151
'templates',
5252
[
5353
'user' => $this->config->getUserTemplate(),
54-
'userDefault' => $this->config->getUserTemplateDefault(),
54+
'userDefault' => $this->config->getGroupTemplateDefault(),
55+
'group' => $this->config->getGroupTemplate(),
56+
'groupDefault' => $this->config->getGroupTemplateDefault(),
5557
]
5658
);
5759
$this->initialStateService->provideInitialState(

src/components/AdminSettings.vue

+21
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)