From f7809af6e4b969ccc85ec689dca86bb37fc43e59 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 19 May 2017 10:50:51 +0200 Subject: [PATCH] Support AUTHENTICATE LOGIN for IMAP connections (#5563) Add imap_auth_type=IMAP to force use of LOGIN instead of AUTHENTICATE LOGIN. In imap_auth_type=CHECK mode prefer LOGIN over AUTHENTICATE LOGIN (for performance reasons). --- CHANGELOG | 1 + config/defaults.inc.php | 5 +- program/lib/Roundcube/rcube_imap_generic.php | 66 ++++++++++++-------- 3 files changed, 43 insertions(+), 29 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9ad457f0b..ec9a0c662 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Support AUTHENTICATE LOGIN for IMAP connections (#5563) - Support LDAP GSSAPI authentication (#5703) - Allow contacts without an email address (#5079) - Localized timezone selector (#4983) diff --git a/config/defaults.inc.php b/config/defaults.inc.php index bd6937c15..363cf69df 100644 --- a/config/defaults.inc.php +++ b/config/defaults.inc.php @@ -137,8 +137,9 @@ $config['default_host'] = 'localhost'; // TCP port used for IMAP connections $config['default_port'] = 143; -// IMAP AUTH type (DIGEST-MD5, CRAM-MD5, LOGIN, PLAIN or null to use -// best server supported one) +// IMAP authentication method (DIGEST-MD5, CRAM-MD5, LOGIN, PLAIN or null). +// Use 'IMAP' to authenticate with IMAP LOGIN command. +// By default the most secure method (from supported) will be selected. $config['imap_auth_type'] = null; // IMAP socket context options diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index 3dac8a55c..bcbbabe48 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -667,7 +667,7 @@ class rcube_imap_generic $line = $this->readReply(); $result = $this->parseResult($line); } - else { // PLAIN + else if ($type == 'PLAIN') { // proxy authorization if (!empty($this->prefs['auth_cid'])) { $authc = $this->prefs['auth_cid']; @@ -699,8 +699,29 @@ class rcube_imap_generic $result = $this->parseResult($line); } } + else if ($type == 'LOGIN') { + $this->putLine($this->nextTag() . " AUTHENTICATE LOGIN"); - if ($result == self::ERROR_OK) { + $line = trim($this->readReply()); + if ($line[0] != '+') { + return $this->parseResult($line); + } + + $this->putLine(base64_encode($user), true, true); + + $line = trim($this->readReply()); + if ($line[0] != '+') { + return $this->parseResult($line); + } + + // send result, get reply and process it + $this->putLine(base64_encode($pass), true, true); + + $line = $this->readReply(); + $result = $this->parseResult($line); + } + + if ($result === self::ERROR_OK) { // optional CAPABILITY response if ($line && preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) { $this->parseCapability($matches[1], true); @@ -724,6 +745,12 @@ class rcube_imap_generic */ protected function login($user, $password) { + // Prevent from sending credentials in plain text when connection is not secure + if ($this->getCapability('LOGINDISABLED')) { + $this->setError(self::ERROR_BAD, "Login disabled by IMAP server"); + return false; + } + list($code, $response) = $this->execute('LOGIN', array( $this->escape($user), $this->escape($password)), self::COMMAND_CAPABILITY | self::COMMAND_ANONYMIZED); @@ -850,22 +877,11 @@ class rcube_imap_generic $result = null; // check for supported auth methods - if ($auth_method == 'CHECK') { + if (!$auth_method || $auth_method == 'CHECK') { if ($auth_caps = $this->getCapability('AUTH')) { $auth_methods = $auth_caps; } - // RFC 2595 (LOGINDISABLED) LOGIN disabled when connection is not secure - $login_disabled = $this->getCapability('LOGINDISABLED'); - if (($key = array_search('LOGIN', $auth_methods)) !== false) { - if ($login_disabled) { - unset($auth_methods[$key]); - } - } - else if (!$login_disabled) { - $auth_methods[] = 'LOGIN'; - } - // Use best (for security) supported authentication method $all_methods = array('DIGEST-MD5', 'CRAM-MD5', 'CRAM_MD5', 'PLAIN', 'LOGIN'); @@ -878,17 +894,10 @@ class rcube_imap_generic break; } } - } - else { - // Prevent from sending credentials in plain text when connection is not secure - if ($auth_method == 'LOGIN' && $this->getCapability('LOGINDISABLED')) { - $this->setError(self::ERROR_BAD, "Login disabled by IMAP server"); - $this->closeConnection(); - return false; - } - // replace AUTH with CRAM-MD5 for backward compat. - if ($auth_method == 'AUTH') { - $auth_method = 'CRAM-MD5'; + + // Prefer LOGIN over AUTHENTICATE LOGIN for performance reasons + if ($auth_method == 'LOGIN' && !$this->getCapability('LOGINDISABLED')) { + $auth_method = 'IMAP'; } } @@ -901,13 +910,16 @@ class rcube_imap_generic $auth_method = 'CRAM-MD5'; case 'CRAM-MD5': case 'DIGEST-MD5': - case 'PLAIN': case 'GSSAPI': + case 'PLAIN': + case 'LOGIN': $result = $this->authenticate($user, $password, $auth_method); break; - case 'LOGIN': + + case 'IMAP': $result = $this->login($user, $password); break; + default: $this->setError(self::ERROR_BAD, "Configuration error. Unknown auth method: $auth_method"); }