Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/mail.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Kesselberg <mail@danielkesselberg.de>2021-06-16 15:39:03 +0300
committerDaniel Kesselberg <mail@danielkesselberg.de>2021-07-06 23:04:31 +0300
commit8fb14b5ffa3450b2c2201ff9bb42c589e4a4afb7 (patch)
treea5b84701a79eca0784c96a87b37bb20127c4ba86 /lib/Service
parent70ef1726ad78b25db571e4b8096eaaf2fa2d84c2 (diff)
Add provisioning for aliases
Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
Diffstat (limited to 'lib/Service')
-rw-r--r--lib/Service/AliasesService.php44
-rw-r--r--lib/Service/Provisioning/Manager.php167
2 files changed, 161 insertions, 50 deletions
diff --git a/lib/Service/AliasesService.php b/lib/Service/AliasesService.php
index db21e1388..7d308b97c 100644
--- a/lib/Service/AliasesService.php
+++ b/lib/Service/AliasesService.php
@@ -26,6 +26,7 @@ namespace OCA\Mail\Service;
use OCA\Mail\Db\Alias;
use OCA\Mail\Db\AliasMapper;
use OCA\Mail\Db\MailAccountMapper;
+use OCA\Mail\Exception\ClientException;
use OCP\AppFramework\Db\DoesNotExistException;
class AliasesService {
@@ -81,15 +82,17 @@ class AliasesService {
}
/**
- * @param int $aliasId
- * @param String $currentUserId
- * @return Alias
+ * @throws ClientException
* @throws DoesNotExistException
*/
- public function delete(int $aliasId, string $currentUserId): Alias {
- $alias = $this->aliasMapper->find($aliasId, $currentUserId);
- $this->aliasMapper->delete($alias);
- return $alias;
+ public function delete(string $userId, int $aliasId): Alias {
+ $entity = $this->aliasMapper->find($aliasId, $userId);
+
+ if ($entity->isProvisioned()) {
+ throw new ClientException('Deleting a provisioned alias is not allowed.');
+ }
+
+ return $this->aliasMapper->delete($entity);
}
/**
@@ -105,16 +108,29 @@ class AliasesService {
}
/**
+ * Update alias and name
+ *
+ * @throws DoesNotExistException
+ */
+ public function update(string $userId, int $aliasId, string $alias, string $aliasName): Alias {
+ $entity = $this->aliasMapper->find($aliasId, $userId);
+
+ if (!$entity->isProvisioned()) {
+ $entity->setAlias($alias);
+ }
+ $entity->setName($aliasName);
+
+ return $this->aliasMapper->update($entity);
+ }
+
+ /**
* Update signature for alias
*
- * @param string $userId
- * @param int $aliasId
- * @param string|null $signature
* @throws DoesNotExistException
*/
- public function updateSignature(string $userId, int $aliasId, string $signature = null): void {
- $alias = $this->find($aliasId, $userId);
- $alias->setSignature($signature);
- $this->aliasMapper->update($alias);
+ public function updateSignature(string $userId, int $aliasId, string $signature = null): Alias {
+ $entity = $this->find($aliasId, $userId);
+ $entity->setSignature($signature);
+ return $this->aliasMapper->update($entity);
}
}
diff --git a/lib/Service/Provisioning/Manager.php b/lib/Service/Provisioning/Manager.php
index 8cc9c2e06..6f06c330e 100644
--- a/lib/Service/Provisioning/Manager.php
+++ b/lib/Service/Provisioning/Manager.php
@@ -24,6 +24,8 @@ declare(strict_types=1);
namespace OCA\Mail\Service\Provisioning;
use Horde_Mail_Rfc822_Address;
+use OCA\Mail\Db\Alias;
+use OCA\Mail\Db\AliasMapper;
use OCA\Mail\Db\MailAccount;
use OCA\Mail\Db\MailAccountMapper;
use OCA\Mail\Db\Provisioning;
@@ -33,6 +35,8 @@ use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\IUser;
use OCP\IUserManager;
+use OCP\LDAP\ILDAPProvider;
+use OCP\LDAP\ILDAPProviderFactory;
use OCP\Security\ICrypto;
use Psr\Log\LoggerInterface;
@@ -50,6 +54,12 @@ class Manager {
/** @var ICrypto */
private $crypto;
+ /** @var ILDAPProviderFactory */
+ private $ldapProviderFactory;
+
+ /** @var AliasMapper */
+ private $aliasMapper;
+
/** @var LoggerInterface */
private $logger;
@@ -57,11 +67,15 @@ class Manager {
ProvisioningMapper $provisioningMapper,
MailAccountMapper $mailAccountMapper,
ICrypto $crypto,
+ ILDAPProviderFactory $ldapProviderFactory,
+ AliasMapper $aliasMapper,
LoggerInterface $logger) {
$this->userManager = $userManager;
$this->provisioningMapper = $provisioningMapper;
$this->mailAccountMapper = $mailAccountMapper;
$this->crypto = $crypto;
+ $this->ldapProviderFactory = $ldapProviderFactory;
+ $this->aliasMapper = $aliasMapper;
$this->logger = $logger;
}
@@ -85,6 +99,75 @@ class Manager {
}
/**
+ * Delete orphaned aliases for the given account.
+ *
+ * A alias is orphaned if not listed in newAliases anymore
+ * (=> the provisioning configuration does contain it anymore)
+ *
+ * Exception for Nextcloud 20: \Doctrine\DBAL\DBALException
+ * Exception for Nextcloud 21 and newer: \OCP\DB\Exception
+ *
+ * @TODO: Change throws to \OCP\DB\Exception once Mail requires Nextcloud 21 or above
+ *
+ * @throws \Exception
+ */
+ private function deleteOrphanedAliases(string $userId, int $accountId, array $newAliases): void {
+ $existingAliases = $this->aliasMapper->findAll($accountId, $userId);
+ foreach ($existingAliases as $existingAlias) {
+ if (!in_array($existingAlias->getAlias(), $newAliases, true)) {
+ $this->aliasMapper->delete($existingAlias);
+ }
+ }
+ }
+
+ /**
+ * Create new aliases for the given account.
+ *
+ * Exception for Nextcloud 20: \Doctrine\DBAL\DBALException
+ * Exception for Nextcloud 21 and newer: \OCP\DB\Exception
+ *
+ * @TODO: Change throws to \OCP\DB\Exception once Mail requires Nextcloud 21 or above
+ *
+ * @throws \Exception
+ */
+ private function createNewAliases(string $userId, int $accountId, array $newAliases, string $displayName): void {
+ foreach ($newAliases as $newAlias) {
+ try {
+ $this->aliasMapper->findByAlias($newAlias, $userId);
+ } catch (DoesNotExistException $e) {
+ $alias = new Alias();
+ $alias->setAccountId($accountId);
+ $alias->setName($displayName);
+ $alias->setAlias($newAlias);
+ $this->aliasMapper->insert($alias);
+ }
+ }
+ }
+
+ /**
+ * @throws \Exception if user id was not found in LDAP
+ *
+ * @TODO: Remove psalm-suppress once Mail requires Nextcloud 22 or above
+ */
+ public function ldapAliasesIntegration(Provisioning $provisioning, IUser $user): Provisioning {
+ if ($user->getBackendClassName() !== 'LDAP' || $provisioning->getLdapAliasesProvisioning() === false || empty($provisioning->getLdapAliasesAttribute())) {
+ return $provisioning;
+ }
+
+ /** @psalm-suppress UndefinedInterfaceMethod */
+ if ($this->ldapProviderFactory->isAvailable() === false) {
+ $this->logger->debug('Request to provision mail aliases but ldap not available');
+ return $provisioning;
+ }
+
+ $ldapProvider = $this->ldapProviderFactory->getLDAPProvider();
+ /** @psalm-suppress UndefinedInterfaceMethod */
+ $provisioning->setAliases($ldapProvider->getMultiValueUserAttribute($user->getUID(), $provisioning->getLdapAliasesAttribute()));
+
+ return $provisioning;
+ }
+
+ /**
* @param Provisioning[] $provisionings
*/
public function provisionSingleUser(array $provisionings, IUser $user): bool {
@@ -96,57 +179,69 @@ class Manager {
try {
// TODO: match by UID only, catch multiple objects returned below and delete all those accounts
- $existing = $this->mailAccountMapper->findProvisionedAccount($user);
+ $mailAccount = $this->mailAccountMapper->findProvisionedAccount($user);
- $this->mailAccountMapper->update(
- $this->updateAccount($user, $existing, $provisioning)
+ $mailAccount = $this->mailAccountMapper->update(
+ $this->updateAccount($user, $mailAccount, $provisioning)
);
- return true;
- } catch (DoesNotExistException $e) {
+ } catch (DoesNotExistException | MultipleObjectsReturnedException $e) {
+ if ($e instanceof MultipleObjectsReturnedException) {
+ // This is unlikely to happen but not impossible.
+ // Let's wipe any existing accounts and start fresh
+ $this->aliasMapper->deleteProvisionedAliasesByUid($user->getUID());
+ $this->mailAccountMapper->deleteProvisionedAccountsByUid($user->getUID());
+ }
+
// Fine, then we create a new one
- $new = new MailAccount();
- $new->setUserId($user->getUID());
+ $mailAccount = new MailAccount();
+ $mailAccount->setUserId($user->getUID());
- $this->mailAccountMapper->insert(
- $this->updateAccount($user, $new, $provisioning)
+ $mailAccount = $this->mailAccountMapper->insert(
+ $this->updateAccount($user, $mailAccount, $provisioning)
);
- return true;
- } catch (MultipleObjectsReturnedException $e) {
- // This is unlikely to happen but not impossible.
- // Let's wipe any existing accounts and start fresh
- $this->mailAccountMapper->deleteProvisionedAccountsByUid($user->getUID());
+ }
- $new = new MailAccount();
- $new->setUserId($user->getUID());
+ // @TODO: Remove method_exists once Mail requires Nextcloud 22 or above
+ if (method_exists(ILDAPProvider::class, 'getMultiValueUserAttribute')) {
+ try {
+ $provisioning = $this->ldapAliasesIntegration($provisioning, $user);
+ } catch (\Throwable $e) {
+ $this->logger->warning('Request to provision mail aliases failed', ['exception' => $e]);
+ // return here to avoid provisioning of aliases.
+ return true;
+ }
- $this->mailAccountMapper->insert(
- $this->updateAccount($user, $new, $provisioning)
- );
- return true;
+ try {
+ $this->deleteOrphanedAliases($user->getUID(), $mailAccount->getId(), $provisioning->getAliases());
+ } catch (\Throwable $e) {
+ $this->logger->warning('Deleting orphaned aliases failed', ['exception' => $e]);
+ }
+
+ try {
+ $this->createNewAliases($user->getUID(), $mailAccount->getId(), $provisioning->getAliases(), $user->getDisplayName());
+ } catch (\Throwable $e) {
+ $this->logger->warning('Creating new aliases failed', ['exception' => $e]);
+ }
}
- return false;
+
+ return true;
}
+ /**
+ * @throws ValidationException
+ * @throws \Exception
+ */
public function newProvisioning(array $data): void {
- try {
- $provisioning = $this->provisioningMapper->validate(
- $data
- );
- } catch (ValidationException $e) {
- throw $e;
- }
+ $provisioning = $this->provisioningMapper->validate($data);
$this->provisioningMapper->insert($provisioning);
}
+ /**
+ * @throws ValidationException
+ * @throws \Exception
+ */
public function updateProvisioning(array $data): void {
- try {
- $provisioning = $this->provisioningMapper->validate(
- $data
- );
- } catch (ValidationException $e) {
- throw $e;
- }
-
+ $provisioning = $this->provisioningMapper->validate($data);
$this->provisioningMapper->update($provisioning);
}