Horde_Imap_Client_Socket::_login PHP Method

_login() protected method

protected _login ( )
    protected function _login()
    {
        $secure = $this->getParam('secure');
        if (!empty($this->_temp['preauth'])) {
            unset($this->_temp['preauth']);
            /* Don't allow PREAUTH if we are requring secure access, since
             * PREAUTH cannot provide secure access. */
            if (!$this->isSecureConnection() && $secure !== false) {
                $this->logout();
                throw new Horde_Imap_Client_Exception(Horde_Imap_Client_Translation::r("Could not open secure TLS connection to the IMAP server."), Horde_Imap_Client_Exception::LOGIN_TLSFAILURE);
            }
            return $this->_loginTasks();
        }
        /* Blank passwords are not allowed, so no need to even try
         * authentication to determine this. */
        if (!strlen($this->getParam('password'))) {
            throw new Horde_Imap_Client_Exception(Horde_Imap_Client_Translation::r("No password provided."), Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED);
        }
        $this->_connect();
        $first_login = empty($this->_init['authmethod']);
        // Switch to secure channel if using TLS.
        if (!$this->isSecureConnection() && ($secure === 'tls' || $secure === true && $this->_capability('LOGINDISABLED'))) {
            if ($first_login && !$this->_capability('STARTTLS')) {
                /* We should never hit this - STARTTLS is required pursuant to
                 * RFC 3501 [6.2.1]. */
                throw new Horde_Imap_Client_Exception(Horde_Imap_Client_Translation::r("Server does not support TLS connections."), Horde_Imap_Client_Exception::LOGIN_TLSFAILURE);
            }
            // Switch over to a TLS connection.
            // STARTTLS returns no untagged response.
            $this->_sendCmd($this->_command('STARTTLS'));
            if (!$this->_connection->startTls()) {
                $this->logout();
                throw new Horde_Imap_Client_Exception(Horde_Imap_Client_Translation::r("Could not open secure TLS connection to the IMAP server."), Horde_Imap_Client_Exception::LOGIN_TLSFAILURE);
            }
            $this->_debug->info('Successfully completed TLS negotiation.');
            $this->setParam('secure', 'tls');
            $secure = 'tls';
            if ($first_login) {
                // Expire cached CAPABILITY information (RFC 3501 [6.2.1])
                $this->_setInit('capability');
                // Reset language (RFC 5255 [3.1])
                $this->_setInit('lang');
            }
            // Set language if using imapproxy
            if (!empty($this->_init['imapproxy'])) {
                $this->setLanguage();
            }
        }
        /* If we reached this point and don't have a secure connection, then
         * a secure connections is not available. */
        if ($secure === true && !$this->isSecureConnection()) {
            $this->setParam('secure', false);
            $secure = false;
        }
        if ($first_login) {
            // Add authentication methods.
            $auth_mech = array();
            $auth = array_flip($this->_capability()->getParams('AUTH'));
            // XOAUTH2
            if (isset($auth['XOAUTH2']) && $this->getParam('xoauth2_token')) {
                $auth_mech[] = 'XOAUTH2';
            }
            unset($auth['XOAUTH2']);
            /* 'AUTH=PLAIN' authentication always exists if under TLS (RFC 3501
             *  [7.2.1]; RFC 2595), even though we might get here with a
             *  non-TLS secure connection too. Use it over all other
             *  authentication methods, although we need to do sanity checking
             *  since broken IMAP servers may not support as required -
             *  fallback to LOGIN instead, if not explicitly disabled. */
            if ($secure) {
                if (isset($auth['PLAIN'])) {
                    $auth_mech[] = 'PLAIN';
                    unset($auth['PLAIN']);
                } elseif (!$this->_capability('LOGINDISABLED')) {
                    $auth_mech[] = 'LOGIN';
                }
            }
            // Check for supported SCRAM AUTH mechanisms. Preferred because it
            // provides verificaion of server authenticity.
            foreach (array_keys($auth) as $key) {
                switch ($key) {
                    case 'SCRAM-SHA-1':
                        $auth_mech[] = $key;
                        unset($auth[$key]);
                        break;
                }
            }
            // Check for supported CRAM AUTH mechanisms.
            foreach (array_keys($auth) as $key) {
                switch ($key) {
                    case 'CRAM-SHA1':
                    case 'CRAM-SHA256':
                        $auth_mech[] = $key;
                        unset($auth[$key]);
                        break;
                }
            }
            // Prefer CRAM-MD5 over DIGEST-MD5, as the latter has been
            // obsoleted (RFC 6331).
            if (isset($auth['CRAM-MD5'])) {
                $auth_mech[] = 'CRAM-MD5';
            } elseif (isset($auth['DIGEST-MD5'])) {
                $auth_mech[] = 'DIGEST-MD5';
            }
            unset($auth['CRAM-MD5'], $auth['DIGEST-MD5']);
            // Add other auth mechanisms.
            $auth_mech = array_merge($auth_mech, array_keys($auth));
            // Fall back to 'LOGIN' if available.
            if (!$secure && !$this->_capability('LOGINDISABLED')) {
                $auth_mech[] = 'LOGIN';
            }
            if (empty($auth_mech)) {
                throw new Horde_Imap_Client_Exception(Horde_Imap_Client_Translation::r("No supported IMAP authentication method could be found."), Horde_Imap_Client_Exception::LOGIN_NOAUTHMETHOD);
            }
            $auth_mech = array_unique($auth_mech);
        } else {
            $auth_mech = array($this->_init['authmethod']);
        }
        $login_err = null;
        foreach ($auth_mech as $method) {
            try {
                $resp = $this->_tryLogin($method);
                $data = $resp->data;
                $this->_setInit('authmethod', $method);
                unset($this->_temp['referralcount']);
            } catch (Horde_Imap_Client_Exception_ServerResponse $e) {
                $data = $e->resp_data;
                if (isset($data['loginerr'])) {
                    $login_err = $data['loginerr'];
                }
                $resp = false;
            } catch (Horde_Imap_Client_Exception $e) {
                $resp = false;
            }
            // Check for login referral (RFC 2221) response - can happen for
            // an OK, NO, or BYE response.
            if (isset($data['referral'])) {
                foreach (array('host', 'port', 'username') as $val) {
                    if (!is_null($data['referral']->{$val})) {
                        $this->setParam($val, $data['referral']->{$val});
                    }
                }
                if (!is_null($data['referral']->auth)) {
                    $this->_setInit('authmethod', $data['referral']->auth);
                }
                if (!isset($this->_temp['referralcount'])) {
                    $this->_temp['referralcount'] = 0;
                }
                // RFC 2221 [3] - Don't follow more than 10 levels of referral
                // without consulting the user.
                if (++$this->_temp['referralcount'] < 10) {
                    $this->logout();
                    $this->_setInit('capability');
                    $this->_setInit('namespace');
                    return $this->login();
                }
                unset($this->_temp['referralcount']);
            }
            if ($resp) {
                return $this->_loginTasks($first_login, $resp->data);
            }
        }
        /* Try again from scratch if authentication failed in an established,
         * previously-authenticated object. */
        if (!empty($this->_init['authmethod'])) {
            $this->_setInit();
            unset($this->_temp['no_cap']);
            try {
                return $this->_login();
            } catch (Horde_Imap_Client_Exception $e) {
            }
        }
        /* Default to AUTHENTICATIONFAILED error (see RFC 5530[3]). */
        if (is_null($login_err)) {
            throw new Horde_Imap_Client_Exception(Horde_Imap_Client_Translation::r("Mail server denied authentication."), Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED);
        }
        throw $login_err;
    }