Changeset View
Changeset View
Standalone View
Standalone View
src/app/Backends/LDAP.php
Show All 13 Lines | class LDAP | ||||
* | * | ||||
* @return void | * @return void | ||||
*/ | */ | ||||
public static function createDomain(Domain $domain) | public static function createDomain(Domain $domain) | ||||
{ | { | ||||
$config = self::getConfig('admin'); | $config = self::getConfig('admin'); | ||||
$ldap = self::initLDAP($config); | $ldap = self::initLDAP($config); | ||||
$hosted_root_dn = \config('ldap.hosted.root_dn'); | $hostedRootDN = \config('ldap.hosted.root_dn'); | ||||
$mgmt_root_dn = \config('ldap.admin.root_dn'); | $mgmtRootDN = \config('ldap.admin.root_dn'); | ||||
$domain_base_dn = "ou={$domain->namespace},{$hosted_root_dn}"; | $domainBaseDN = "ou={$domain->namespace},{$hostedRootDN}"; | ||||
$aci = [ | $aci = [ | ||||
'(targetattr = "*")' | '(targetattr = "*")' | ||||
. '(version 3.0; acl "Deny Unauthorized"; deny (all)' | . '(version 3.0; acl "Deny Unauthorized"; deny (all)' | ||||
. '(userdn != "ldap:///uid=kolab-service,ou=Special Users,' . $mgmt_root_dn | . '(userdn != "ldap:///uid=kolab-service,ou=Special Users,' . $mgmtRootDN | ||||
. ' || ldap:///ou=People,' . $domain_base_dn . '??sub?(objectclass=inetorgperson)") ' | . ' || ldap:///ou=People,' . $domainBaseDN . '??sub?(objectclass=inetorgperson)") ' | ||||
. 'AND NOT roledn = "ldap:///cn=kolab-admin,' . $mgmt_root_dn . '";)', | . 'AND NOT roledn = "ldap:///cn=kolab-admin,' . $mgmtRootDN . '";)', | ||||
'(targetattr != "userPassword")' | '(targetattr != "userPassword")' | ||||
. '(version 3.0;acl "Search Access";allow (read,compare,search)' | . '(version 3.0;acl "Search Access";allow (read,compare,search)' | ||||
. '(userdn = "ldap:///uid=kolab-service,ou=Special Users,' . $mgmt_root_dn | . '(userdn = "ldap:///uid=kolab-service,ou=Special Users,' . $mgmtRootDN | ||||
. ' || ldap:///ou=People,' . $domain_base_dn . '??sub?(objectclass=inetorgperson)");)', | . ' || ldap:///ou=People,' . $domainBaseDN . '??sub?(objectclass=inetorgperson)");)', | ||||
'(targetattr = "*")' | '(targetattr = "*")' | ||||
. '(version 3.0;acl "Kolab Administrators";allow (all)' | . '(version 3.0;acl "Kolab Administrators";allow (all)' | ||||
. '(roledn = "ldap:///cn=kolab-admin,' . $domain_base_dn | . '(roledn = "ldap:///cn=kolab-admin,' . $domainBaseDN | ||||
. ' || ldap:///cn=kolab-admin,' . $mgmt_root_dn . '");)' | . ' || ldap:///cn=kolab-admin,' . $mgmtRootDN . '");)' | ||||
]; | ]; | ||||
$entry = [ | $entry = [ | ||||
'aci' => $aci, | 'aci' => $aci, | ||||
'associateddomain' => $domain->namespace, | 'associateddomain' => $domain->namespace, | ||||
'inetdomainbasedn' => $domain_base_dn, | 'inetdomainbasedn' => $domainBaseDN, | ||||
'objectclass' => [ | 'objectclass' => [ | ||||
'top', | 'top', | ||||
'domainrelatedobject', | 'domainrelatedobject', | ||||
'inetdomain' | 'inetdomain' | ||||
], | ], | ||||
]; | ]; | ||||
$dn = "associateddomain={$domain->namespace},{$config['domain_base_dn']}"; | $dn = "associateddomain={$domain->namespace},{$config['domain_base_dn']}"; | ||||
Show All 10 Lines | public static function createDomain(Domain $domain) | ||||
'organizationalunit' | 'organizationalunit' | ||||
], | ], | ||||
'ou' => $domain->namespace, | 'ou' => $domain->namespace, | ||||
]; | ]; | ||||
$entry['aci'] = array( | $entry['aci'] = array( | ||||
'(targetattr = "*")' | '(targetattr = "*")' | ||||
. '(version 3.0;acl "Deny Unauthorized"; deny (all)' | . '(version 3.0;acl "Deny Unauthorized"; deny (all)' | ||||
. '(userdn != "ldap:///uid=kolab-service,ou=Special Users,' . $mgmt_root_dn | . '(userdn != "ldap:///uid=kolab-service,ou=Special Users,' . $mgmtRootDN | ||||
. ' || ldap:///ou=People,' . $domain_base_dn . '??sub?(objectclass=inetorgperson)") ' | . ' || ldap:///ou=People,' . $domainBaseDN . '??sub?(objectclass=inetorgperson)") ' | ||||
. 'AND NOT roledn = "ldap:///cn=kolab-admin,' . $mgmt_root_dn . '";)', | . 'AND NOT roledn = "ldap:///cn=kolab-admin,' . $mgmtRootDN . '";)', | ||||
'(targetattr != "userPassword")' | '(targetattr != "userPassword")' | ||||
. '(version 3.0;acl "Search Access";allow (read,compare,search,write)' | . '(version 3.0;acl "Search Access";allow (read,compare,search,write)' | ||||
. '(userdn = "ldap:///uid=kolab-service,ou=Special Users,' . $mgmt_root_dn | . '(userdn = "ldap:///uid=kolab-service,ou=Special Users,' . $mgmtRootDN | ||||
. ' || ldap:///ou=People,' . $domain_base_dn . '??sub?(objectclass=inetorgperson)");)', | . ' || ldap:///ou=People,' . $domainBaseDN . '??sub?(objectclass=inetorgperson)");)', | ||||
'(targetattr = "*")' | '(targetattr = "*")' | ||||
. '(version 3.0;acl "Kolab Administrators";allow (all)' | . '(version 3.0;acl "Kolab Administrators";allow (all)' | ||||
. '(roledn = "ldap:///cn=kolab-admin,' . $domain_base_dn | . '(roledn = "ldap:///cn=kolab-admin,' . $domainBaseDN | ||||
. ' || ldap:///cn=kolab-admin,' . $mgmt_root_dn . '");)', | . ' || ldap:///cn=kolab-admin,' . $mgmtRootDN . '");)', | ||||
'(target = "ldap:///ou=*,' . $domain_base_dn . '")' | '(target = "ldap:///ou=*,' . $domainBaseDN . '")' | ||||
. '(targetattr="objectclass || aci || ou")' | . '(targetattr="objectclass || aci || ou")' | ||||
. '(version 3.0;acl "Allow Domain sub-OU Registration"; allow (add)' | . '(version 3.0;acl "Allow Domain sub-OU Registration"; allow (add)' | ||||
. '(userdn = "ldap:///uid=kolab-service,ou=Special Users,' . $mgmt_root_dn . '");)', | . '(userdn = "ldap:///uid=kolab-service,ou=Special Users,' . $mgmtRootDN . '");)', | ||||
'(target = "ldap:///uid=*,ou=People,' . $domain_base_dn . '")(targetattr="*")' | '(target = "ldap:///uid=*,ou=People,' . $domainBaseDN . '")(targetattr="*")' | ||||
. '(version 3.0;acl "Allow Domain First User Registration"; allow (add)' | . '(version 3.0;acl "Allow Domain First User Registration"; allow (add)' | ||||
. '(userdn = "ldap:///uid=kolab-service,ou=Special Users,' . $mgmt_root_dn . '");)', | . '(userdn = "ldap:///uid=kolab-service,ou=Special Users,' . $mgmtRootDN . '");)', | ||||
'(target = "ldap:///cn=*,' . $domain_base_dn . '")(targetattr="objectclass || cn")' | '(target = "ldap:///cn=*,' . $domainBaseDN . '")(targetattr="objectclass || cn")' | ||||
. '(version 3.0;acl "Allow Domain Role Registration"; allow (add)' | . '(version 3.0;acl "Allow Domain Role Registration"; allow (add)' | ||||
. '(userdn = "ldap:///uid=kolab-service,ou=Special Users,' . $mgmt_root_dn . '");)', | . '(userdn = "ldap:///uid=kolab-service,ou=Special Users,' . $mgmtRootDN . '");)', | ||||
); | ); | ||||
if (!$ldap->get_entry($domain_base_dn)) { | if (!$ldap->get_entry($domainBaseDN)) { | ||||
$ldap->add_entry($domain_base_dn, $entry); | $ldap->add_entry($domainBaseDN, $entry); | ||||
} | } | ||||
foreach (['Groups', 'People', 'Resources', 'Shared Folders'] as $item) { | foreach (['Groups', 'People', 'Resources', 'Shared Folders'] as $item) { | ||||
if (!$ldap->get_entry("ou={$item},{$domain_base_dn}")) { | if (!$ldap->get_entry("ou={$item},{$domainBaseDN}")) { | ||||
$ldap->add_entry( | $ldap->add_entry( | ||||
"ou={$item},{$domain_base_dn}", | "ou={$item},{$domainBaseDN}", | ||||
[ | [ | ||||
'ou' => $item, | 'ou' => $item, | ||||
'description' => $item, | 'description' => $item, | ||||
'objectclass' => [ | 'objectclass' => [ | ||||
'top', | 'top', | ||||
'organizationalunit' | 'organizationalunit' | ||||
] | ] | ||||
] | ] | ||||
); | ); | ||||
} | } | ||||
} | } | ||||
foreach (['kolab-admin', 'imap-user', 'activesync-user', 'billing-user'] as $item) { | foreach (['kolab-admin', 'billing-user'] as $item) { | ||||
if (!$ldap->get_entry("cn={$item},{$domain_base_dn}")) { | if (!$ldap->get_entry("cn={$item},{$domainBaseDN}")) { | ||||
$ldap->add_entry( | $ldap->add_entry( | ||||
"cn={$item},{$domain_base_dn}", | "cn={$item},{$domainBaseDN}", | ||||
[ | [ | ||||
'cn' => $item, | 'cn' => $item, | ||||
'description' => "{$item} role", | 'description' => "{$item} role", | ||||
'objectclass' => [ | 'objectclass' => [ | ||||
'top', | 'top', | ||||
'ldapsubentry', | 'ldapsubentry', | ||||
'nsmanagedroledefinition', | 'nsmanagedroledefinition', | ||||
'nsroledefinition', | 'nsroledefinition', | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | public static function createUser(User $user) | ||||
if (!$domain) { | if (!$domain) { | ||||
return false; | return false; | ||||
} | } | ||||
$entry = [ | $entry = [ | ||||
'objectclass' => [ | 'objectclass' => [ | ||||
'top', | 'top', | ||||
'inetorgperson', | 'inetorgperson', | ||||
'inetuser', | |||||
'kolabinetorgperson', | 'kolabinetorgperson', | ||||
'mailrecipient', | 'mailrecipient', | ||||
'person' | 'person' | ||||
], | ], | ||||
'mail' => $user->email, | 'mail' => $user->email, | ||||
'uid' => $user->email, | 'uid' => $user->email, | ||||
'nsroledn' => [] | |||||
]; | ]; | ||||
self::setUserAttributes($user, $entry); | self::setUserAttributes($user, $entry); | ||||
$base_dn = $ldap->domain_root_dn($_domain); | $base_dn = $ldap->domain_root_dn($_domain); | ||||
$dn = "uid={$user->email},ou=People,{$base_dn}"; | $dn = "uid={$user->email},ou=People,{$base_dn}"; | ||||
if (!$ldap->get_entry($dn)) { | if (!$ldap->get_entry($dn)) { | ||||
$ldap->add_entry($dn, $entry); | $ldap->add_entry($dn, $entry); | ||||
} | } | ||||
$ldap->close(); | $ldap->close(); | ||||
} | } | ||||
/** | /** | ||||
* Update a domain in LDAP. | * Update a domain in LDAP. | ||||
* | * | ||||
* @param \App\Domain $domain The domain to update. | * @param \App\Domain $domain The domain to update. | ||||
* | * | ||||
* @return void | * @return void | ||||
*/ | */ | ||||
public static function updateDomain($domain) | public static function updateDomain($domain) | ||||
{ | { | ||||
// | $config = self::getConfig('admin'); | ||||
$ldap = self::initLDAP($config); | |||||
$ldapDomain = $ldap->find_domain($domain->namespace); | |||||
$oldEntry = $ldap->get_entry($ldapDomain['dn']); | |||||
$newEntry = $oldEntry; | |||||
self::setDomainAttributes($domain, $newEntry); | |||||
$ldap->modify_entry($ldapDomain['dn'], $oldEntry, $newEntry); | |||||
$ldap->close(); | |||||
} | } | ||||
public static function deleteDomain($domain) | public static function deleteDomain($domain) | ||||
{ | { | ||||
$config = self::getConfig('admin'); | $config = self::getConfig('admin'); | ||||
$ldap = self::initLDAP($config); | $ldap = self::initLDAP($config); | ||||
$hosted_root_dn = \config('ldap.hosted.root_dn'); | $hostedRootDN = \config('ldap.hosted.root_dn'); | ||||
$mgmt_root_dn = \config('ldap.admin.root_dn'); | $mgmtRootDN = \config('ldap.admin.root_dn'); | ||||
$domain_base_dn = "ou={$domain->namespace},{$hosted_root_dn}"; | $domainBaseDN = "ou={$domain->namespace},{$hostedRootDN}"; | ||||
if ($ldap->get_entry($domain_base_dn)) { | if ($ldap->get_entry($domainBaseDN)) { | ||||
$ldap->delete_entry_recursive($domain_base_dn); | $ldap->delete_entry_recursive($domainBaseDN); | ||||
} | } | ||||
if ($ldap_domain = $ldap->find_domain($domain->namespace)) { | if ($ldap_domain = $ldap->find_domain($domain->namespace)) { | ||||
if ($ldap->get_entry($ldap_domain['dn'])) { | if ($ldap->get_entry($ldap_domain['dn'])) { | ||||
$ldap->delete_entry($ldap_domain['dn']); | $ldap->delete_entry($ldap_domain['dn']); | ||||
} | } | ||||
} | } | ||||
$ldap->close(); | |||||
} | } | ||||
public static function deleteUser($user) | public static function deleteUser($user) | ||||
{ | { | ||||
$config = self::getConfig('admin'); | $config = self::getConfig('admin'); | ||||
$ldap = self::initLDAP($config); | $ldap = self::initLDAP($config); | ||||
list($_local, $_domain) = explode('@', $user->email, 2); | list($_local, $_domain) = explode('@', $user->email, 2); | ||||
$domain = $ldap->find_domain($_domain); | $domain = $ldap->find_domain($_domain); | ||||
if (!$domain) { | if (!$domain) { | ||||
$ldap->close(); | |||||
return false; | return false; | ||||
} | } | ||||
$base_dn = $ldap->domain_root_dn($_domain); | $base_dn = $ldap->domain_root_dn($_domain); | ||||
$dn = "uid={$user->email},ou=People,{$base_dn}"; | $dn = "uid={$user->email},ou=People,{$base_dn}"; | ||||
if (!$ldap->get_entry($dn)) { | if (!$ldap->get_entry($dn)) { | ||||
$ldap->close(); | |||||
return false; | return false; | ||||
} | } | ||||
$ldap->delete_entry($dn); | $ldap->delete_entry($dn); | ||||
$ldap->close(); | |||||
} | } | ||||
/** | /** | ||||
* Update a user in LDAP. | * Update a user in LDAP. | ||||
* | * | ||||
* @param \App\User $user The user account to update. | * @param \App\User $user The user account to update. | ||||
* | * | ||||
* @return bool|void | * @return bool|void | ||||
*/ | */ | ||||
public static function updateUser(User $user) | public static function updateUser(User $user) | ||||
{ | { | ||||
$config = self::getConfig('admin'); | $config = self::getConfig('admin'); | ||||
$ldap = self::initLDAP($config); | $ldap = self::initLDAP($config); | ||||
list($_local, $_domain) = explode('@', $user->email, 2); | list($_local, $_domain) = explode('@', $user->email, 2); | ||||
$domain = $ldap->find_domain($_domain); | $domain = $ldap->find_domain($_domain); | ||||
if (!$domain) { | if (!$domain) { | ||||
$ldap->close(); | |||||
return false; | return false; | ||||
} | } | ||||
$base_dn = $ldap->domain_root_dn($_domain); | $base_dn = $ldap->domain_root_dn($_domain); | ||||
$dn = "uid={$user->email},ou=People,{$base_dn}"; | $dn = "uid={$user->email},ou=People,{$base_dn}"; | ||||
$old_entry = $ldap->get_entry($dn); | $oldEntry = $ldap->get_entry($dn); | ||||
$new_entry = $old_entry; | |||||
self::setUserAttributes($user, $new_entry); | if (!$oldEntry) { | ||||
$ldap->close(); | |||||
machniak: missing $ldap->close(); | |||||
return false; | |||||
} | |||||
if (!array_key_exists('nsroledn', $oldEntry)) { | |||||
$oldEntry['nsroledn'] = (array)$ldap->get_entry_attributes($dn, ['nsroledn']); | |||||
} | |||||
$ldap->modify_entry($dn, $old_entry, $new_entry); | $newEntry = $oldEntry; | ||||
self::setUserAttributes($user, $newEntry); | |||||
$ldap->modify_entry($dn, $oldEntry, $newEntry); | |||||
$ldap->close(); | $ldap->close(); | ||||
} | } | ||||
/** | /** | ||||
* Initialize connection to LDAP | * Initialize connection to LDAP | ||||
*/ | */ | ||||
private static function initLDAP(array $config, string $privilege = 'admin') | private static function initLDAP(array $config, string $privilege = 'admin') | ||||
{ | { | ||||
$ldap = new \Net_LDAP3($config); | $ldap = new \Net_LDAP3($config); | ||||
$ldap->connect(); | $ldap->connect(); | ||||
$ldap->bind(\config("ldap.{$privilege}.bind_dn"), \config("ldap.{$privilege}.bind_pw")); | $ldap->bind(\config("ldap.{$privilege}.bind_dn"), \config("ldap.{$privilege}.bind_pw")); | ||||
// TODO: error handling | // TODO: error handling | ||||
return $ldap; | return $ldap; | ||||
} | } | ||||
/** | /** | ||||
* Set domain attributes | |||||
*/ | |||||
private static function setDomainAttributes(Domain $domain, array &$entry) | |||||
{ | |||||
$entry['inetdomainstatus'] = $domain->status; | |||||
} | |||||
/** | |||||
* Set common user attributes | * Set common user attributes | ||||
*/ | */ | ||||
private static function setUserAttributes(User $user, array &$entry) | private static function setUserAttributes(User $user, array &$entry) | ||||
{ | { | ||||
$firstName = $user->getSetting('first_name'); | $firstName = $user->getSetting('first_name'); | ||||
$lastName = $user->getSetting('last_name'); | $lastName = $user->getSetting('last_name'); | ||||
$cn = "unknown"; | $cn = "unknown"; | ||||
Show All 18 Lines | private static function setUserAttributes(User $user, array &$entry) | ||||
} | } | ||||
} | } | ||||
$entry['cn'] = $cn; | $entry['cn'] = $cn; | ||||
$entry['displayname'] = $displayname; | $entry['displayname'] = $displayname; | ||||
$entry['givenname'] = $firstName; | $entry['givenname'] = $firstName; | ||||
$entry['sn'] = $lastName; | $entry['sn'] = $lastName; | ||||
$entry['userpassword'] = $user->password_ldap; | $entry['userpassword'] = $user->password_ldap; | ||||
$entry['inetuserstatus'] = $user->status; | |||||
$entry['mailquota'] = 0; | |||||
Done Inline ActionsYou could use $user->entitlements() here. machniak: You could use $user->entitlements() here. | |||||
if (!array_key_exists('nsroledn', $entry)) { | |||||
$entry['nsroledn'] = []; | |||||
} else if (!is_array($entry['nsroledn'])) { | |||||
$entry['nsroledn'] = (array)$entry['nsroledn']; | |||||
} | |||||
$roles = []; | |||||
foreach ($user->entitlements as $entitlement) { | |||||
\Log::debug("Examining {$entitlement->sku->title}"); | |||||
switch ($entitlement->sku->title) { | |||||
case "storage": | |||||
$entry['mailquota'] += 1048576; | |||||
break; | |||||
} | |||||
$roles[] = $entitlement->sku->title; | |||||
} | |||||
$hostedRootDN = \config('ldap.hosted.root_dn'); | |||||
if (in_array("2fa", $roles)) { | |||||
$entry['nsroledn'][] = "cn=2fa-user,{$hostedRootDN}"; | |||||
} else { | |||||
$key = array_search("cn=2fa-user,{$hostedRootDN}", $entry['nsroledn']); | |||||
if ($key !== false) { | |||||
unset($entry['nsroledn'][$key]); | |||||
} | |||||
} | |||||
if (in_array("activesync", $roles)) { | |||||
$entry['nsroledn'][] = "cn=activesync-user,{$hostedRootDN}"; | |||||
} else { | |||||
$key = array_search("cn=activesync-user,{$hostedRootDN}", $entry['nsroledn']); | |||||
if ($key !== false) { | |||||
unset($entry['nsroledn'][$key]); | |||||
} | |||||
} | |||||
if (!in_array("groupware", $roles)) { | |||||
$entry['nsroledn'][] = "cn=imap-user,{$hostedRootDN}"; | |||||
} else { | |||||
$key = array_search("cn=imap-user,{$hostedRootDN}", $entry['nsroledn']); | |||||
if ($key !== false) { | |||||
unset($entry['nsroledn'][$key]); | |||||
} | |||||
} | |||||
$entry['nsroledn'] = array_unique($entry['nsroledn']); | |||||
} | } | ||||
/** | /** | ||||
* Get LDAP configuration for specified access level | * Get LDAP configuration for specified access level | ||||
*/ | */ | ||||
private static function getConfig(string $privilege) | private static function getConfig(string $privilege) | ||||
{ | { | ||||
$config = [ | $config = [ | ||||
Show All 10 Lines | class LDAP | ||||
} | } | ||||
/** | /** | ||||
* Logging callback | * Logging callback | ||||
*/ | */ | ||||
public static function logHook($level, $msg): void | public static function logHook($level, $msg): void | ||||
{ | { | ||||
if ( | if ( | ||||
($level == LOG_INFO || $level == LOG_DEBUG || $level == LOG_NOTICE) | ( | ||||
$level == LOG_INFO | |||||
|| $level == LOG_DEBUG | |||||
|| $level == LOG_NOTICE | |||||
) | |||||
&& !\config('app.debug') | && !\config('app.debug') | ||||
) { | ) { | ||||
return; | return; | ||||
} | } | ||||
switch ($level) { | switch ($level) { | ||||
case LOG_CRIT: | case LOG_CRIT: | ||||
$function = 'critical'; | $function = 'critical'; | ||||
Show All 35 Lines |
missing $ldap->close();