Fix für IMAP Login für Nextcloud

Das user_external Backend der Nextcloud wird seit NextCloud 29 nicht mehr unterstützt und offensichtlich auch nicht mehr aktiv weiterentwickelt. Wir verwenden dieses Plugin um uns gegen IMAP4 Protokoll zu Authentizieren (gegen unseren Mailenable Server). Leider wirft das Plugin Error 500 wenn man ein falsches Passwort eingibt, und bei jedem Versuch etwas zu loggen (weil sich das Log facility von Nextcloud in Version 30 geändert hat). Hier ein gefixetes IMAP.php (/var/www/html/nextcloud/apps/user_external/lib) dass diese Probleme behebt: Getestet mit NextCloud Version 31.0.9

<?php
namespace OCA\UserExternal;

use OCP\ILogger;

class IMAP extends Base {
    private string $mailbox;
    private int $port;
    private ?string $sslmode;
    private string $domain;
    private bool $stripeDomain;
    private bool $groupDomain;

    public function __construct(
        string $mailbox,
        ?int $port = null,
        ?string $sslmode = null,
        ?string $domain = null,
        bool $stripeDomain = true,
        bool $groupDomain = false
    ) {
        parent::__construct($mailbox);
        $this->mailbox = $mailbox;
        $this->port = $port ?? 143;
        $this->sslmode = $sslmode;
        $this->domain = $domain ?? '';
        $this->stripeDomain = $stripeDomain;
        $this->groupDomain = $groupDomain;
    }

    /**
     * Safe logger helper – follows NC 31+ ILogger interface
     */
    private function log(string $level, string $message, array $context = []): void {
        try {
            /** @var ILogger $logger */
            $logger = \OC::$server->get(ILogger::class);
            $logger->$level($message, array_merge(['app' => 'user_external'], $context));
        } catch (\Throwable $e) {
            // Fallback to PHP error log if Nextcloud context missing
            error_log("[user_external][$level] " . $message);
        }
    }

    public function checkPassword($uid, $password) {
        if (empty($uid) || empty($password)) {
            $this->log('warning', 'IMAP login attempt with empty credentials');
            return false;
        }

        if (!str_contains($uid, '@') && str_contains($uid, '%40')) {
            $uid = str_replace('%40', '@', $uid);
        }

        $pieces = explode('@', $uid);
        if ($this->domain !== '') {
            if (count($pieces) === 1) {
                $username = $uid . '@' . $this->domain;
            } elseif (count($pieces) === 2 && $pieces[1] === $this->domain) {
                $username = $uid;
                if ($this->stripeDomain) {
                    $uid = $pieces[0];
                }
            } else {
                $this->log('warning', 'IMAP login rejected – invalid domain', ['expected' => $this->domain, 'user' => $uid]);
                return false;
            }
        } else {
            $username = $uid;
        }

        $groups = [];
        if (count($pieces) > 1 && $this->groupDomain && $pieces[1]) {
            $groups[] = $pieces[1];
        }

        $protocol = ($this->sslmode === 'ssl') ? 'imaps' : 'imap';
        $url = "{$protocol}://{$this->mailbox}:{$this->port}";

        $ch = curl_init();
        if ($this->sslmode === 'tls') {
            curl_setopt($ch, CURLOPT_USE_SSL, CURLUSESSL_ALL);
        }

        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_USERPWD => "{$username}:{$password}",
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_CUSTOMREQUEST => 'CAPABILITY',
            CURLOPT_FAILONERROR => false,
        ]);

        try {
            @curl_exec($ch);
            $errorcode = curl_errno($ch);
        } catch (\Throwable $e) {
            $this->log('error', 'IMAP curl_exec exception: ' . $e->getMessage());
            curl_close($ch);
            return false;
        }

        switch ($errorcode) {
            case 0:
                curl_close($ch);
                $uid = mb_strtolower($uid);
                $this->storeUser($uid, $groups);
                $this->log('info', "IMAP login successful for user $uid");
                return $uid;

            case CURLE_COULDNT_CONNECT:
            case CURLE_SSL_CONNECT_ERROR:
            case 28: // Timeout
                $this->log('warning', 'IMAP connection issue: ' . curl_strerror($errorcode));
                break;

            case 9:
            case 67:
            case 94:
                $this->log('info', "IMAP login failed for user $uid (invalid credentials)");
                break;

            default:
                $this->log('error', "IMAP error $errorcode: " . curl_strerror($errorcode));
                break;
        }

        curl_close($ch);
        return false;
    }
}

2 „Gefällt mir“