Since: 2.29.0
Author: Michael Slusarz (slusarz@horde.org)
Example #1
0
 /**
  * Authenticate to the POP3 server.
  *
  * @param string $method  POP3 login method.
  *
  * @throws Horde_Imap_Client_Exception
  */
 protected function _tryLogin($method)
 {
     $username = $this->getParam('username');
     $password = $this->getParam('password');
     switch ($method) {
         case 'CRAM-MD5':
         case 'CRAM-SHA1':
         case 'CRAM-SHA256':
             // RFC 5034: CRAM-MD5
             // CRAM-SHA1 & CRAM-SHA256 supported by Courier SASL library
             $challenge = $this->_sendLine('AUTH ' . $method);
             $response = base64_encode($username . ' ' . hash_hmac(Horde_String::lower(substr($method, 5)), base64_decode(substr($challenge['resp'], 2)), $password, true));
             $this->_sendLine($response, array('debug' => sprintf('[AUTH Response (username: %s)]', $username)));
             break;
         case 'DIGEST-MD5':
             // RFC 2831; Obsoleted by RFC 6331
             $challenge = $this->_sendLine('AUTH DIGEST-MD5');
             $response = base64_encode(new Horde_Imap_Client_Auth_DigestMD5($username, $password, base64_decode(substr($challenge['resp'], 2)), $this->getParam('hostspec'), 'pop3'));
             $sresponse = $this->_sendLine($response, array('debug' => sprintf('[AUTH Response (username: %s)]', $username)));
             if (stripos(base64_decode(substr($sresponse['resp'], 2)), 'rspauth=') === false) {
                 throw new Horde_Imap_Client_Exception(Horde_Imap_Client_Translation::r("Unexpected response from server when authenticating."), Horde_Imap_Client_Exception::SERVER_CONNECT);
             }
             /* POP3 doesn't use protocol's third step. */
             $this->_sendLine('');
             break;
         case 'LOGIN':
             // RFC 4616 (AUTH=PLAIN) & 5034 (POP3 SASL)
             $this->_sendLine('AUTH LOGIN');
             $this->_sendLine(base64_encode($username));
             $this->_sendLine(base64_encode($password), array('debug' => sprintf('[AUTH Password (username: %s)]', $username)));
             break;
         case 'PLAIN':
             // RFC 5034
             $this->_sendLine('AUTH PLAIN ' . base64_encode(implode("", array($username, $username, $password))), array('debug' => sprintf('AUTH PLAIN [Auth Response (username: %s)]', $username)));
             break;
         case 'APOP':
             /* If UTF8 (+ USER) is active, and non-ASCII exists, need to apply
              * SASLprep to username/password. RFC 6856[2.2]. Reject if
              * UTF8 (+ USER) is not supported and 8-bit characters exist. */
             if (Horde_Mime::is8bit($username) || Horde_Mime::is8bit($password)) {
                 if (empty($this->_temp['utf8']) || !$this->_capability('UTF8', 'USER') || !class_exists('Horde_Stringprep')) {
                     $error = true;
                 } else {
                     Horde_Stringprep::autoload();
                     $saslprep = new Znerol\Component\Stringprep\Profile\SASLprep();
                     try {
                         $username = $saslprep->apply($username, 'UTF-8', Znerol\Compnonent\Stringprep\Profile::MODE_QUERY);
                         $password = $saslprep->apply($password, 'UTF-8', Znerol\Compnonent\Stringprep\Profile::MODE_STORE);
                         $error = false;
                     } catch (Znerol\Component\Stringprep\ProfileException $e) {
                         $error = true;
                     }
                 }
                 if ($error) {
                     throw new Horde_Imap_Client_Exception(Horde_Imap_Client_Translation::r("Authentication failed."), Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED);
                 }
             }
             // RFC 1939 [7]
             $this->_sendLine('APOP ' . $username . ' ' . hash('md5', $this->_temp['pop3timestamp'] . $password));
             break;
         case 'USER':
             /* POP3 servers without UTF8 (+ USER) does not accept non-ASCII
              * in USER/PASS. RFC 6856[2.2] */
             if ((empty($this->_temp['utf8']) || !$this->_capability('UTF8', 'USER')) && (Horde_Mime::is8bit($username) || Horde_Mime::is8bit($password))) {
                 throw new Horde_Imap_Client_Exception(Horde_Imap_Client_Translation::r("Authentication failed."), Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED);
             }
             // RFC 1939 [7]
             $this->_sendLine('USER ' . $username);
             $this->_sendLine('PASS ' . $password, array('debug' => 'PASS [Password]'));
             break;
         case 'SCRAM-SHA-1':
             $scram = new Horde_Imap_Client_Auth_Scram($username, $password, 'SHA1');
             $c1 = $this->_sendLine('AUTH ' . $method . ' ' . base64_encode($scram->getClientFirstMessage()));
             $sr1 = base64_decode(substr($c1['resp'], 2));
             if (!$scram->parseServerFirstMessage($sr1)) {
                 throw new Horde_Imap_Client_Exception(Horde_Imap_Client_Translation::r("Authentication failed."), Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED);
             }
             $c2 = $this->_sendLine(base64_encode($scram->getClientFinalMessage()));
             $sr2 = base64_decode(substr($c2['resp'], 2));
             if (!$scram->parseServerFirstMessage($sr)) {
                 throw new Horde_Imap_Client_Exception(Horde_Imap_Client_Translation::r("Authentication failed."), Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED);
                 /* This means authentication passed, according to the server,
                  * but the server signature is incorrect. This indicates that
                  * server verification has failed. Immediately disconnect from
                  * the server, since this is a possible security issue. */
                 $this->logout();
                 throw new Horde_Imap_Client_Exception(Horde_Imap_Client_Translation::r("Server failed verification check."), Horde_Imap_Client_Exception::LOGIN_SERVER_VERIFICATION_FAILED);
             }
             $this->_sendLine('');
             break;
         default:
             $e = new Horde_Imap_Client_Exception(Horde_Imap_Client_Translation::r("Unknown authentication method: %s"), Horde_Imap_Client_Exception::SERVER_CONNECT);
             $e->messagePrintf(array($method));
             throw $e;
     }
 }
Example #2
0
 /**
  * Authenticate to the IMAP server.
  *
  * @param string $method  IMAP login method.
  *
  * @return Horde_Imap_Client_Interaction_Pipeline  Pipeline object.
  *
  * @throws Horde_Imap_Client_Exception
  */
 protected function _tryLogin($method)
 {
     $username = $this->getParam('username');
     $password = $this->getParam('password');
     switch ($method) {
         case 'CRAM-MD5':
         case 'CRAM-SHA1':
         case 'CRAM-SHA256':
             // RFC 2195: CRAM-MD5
             // CRAM-SHA1 & CRAM-SHA256 supported by Courier SASL library
             $args = array($username, Horde_String::lower(substr($method, 5)), $password);
             $cmd = $this->_command('AUTHENTICATE')->add(array($method, new Horde_Imap_Client_Interaction_Command_Continuation(function ($ob) use($args) {
                 return new Horde_Imap_Client_Data_Format_List(base64_encode($args[0] . ' ' . hash_hmac($args[1], base64_decode($ob->token->current()), $args[2], false)));
             })));
             $cmd->debug = array(null, sprintf('[AUTHENTICATE response (username: %s)]', $username));
             break;
         case 'DIGEST-MD5':
             // RFC 2831/4422; obsoleted by RFC 6331
             // Need $args because PHP 5.3 doesn't allow access to $this in
             // anonymous functions.
             $args = array($username, $password, $this->getParam('hostspec'));
             $cmd = $this->_command('AUTHENTICATE')->add(array($method, new Horde_Imap_Client_Interaction_Command_Continuation(function ($ob) use($args) {
                 return new Horde_Imap_Client_Data_Format_List(base64_encode(new Horde_Imap_Client_Auth_DigestMD5($args[0], $args[1], base64_decode($ob->token->current()), $args[2], 'imap')));
             }), new Horde_Imap_Client_Interaction_Command_Continuation(function ($ob) {
                 if (strpos(base64_decode($ob->token->current()), 'rspauth=') === false) {
                     throw new Horde_Imap_Client_Exception(Horde_Imap_Client_Translation::r("Unexpected response from server when authenticating."), Horde_Imap_Client_Exception::SERVER_CONNECT);
                 }
                 return new Horde_Imap_Client_Data_Format_List();
             })));
             $cmd->debug = array(null, sprintf('[AUTHENTICATE Response (username: %s)]', $username), null);
             break;
         case 'LOGIN':
             /* See, e.g., RFC 6855 [5] - LOGIN command does not support
              * non-ASCII characters. If we reach this point, treat as an
              * authentication failure. */
             try {
                 $username = new Horde_Imap_Client_Data_Format_Astring($username);
                 $password = new Horde_Imap_Client_Data_Format_Astring($password);
             } catch (Horde_Imap_Client_Data_Format_Exception $e) {
                 throw new Horde_Imap_Client_Exception(Horde_Imap_Client_Translation::r("Authentication failed."), Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED);
             }
             $cmd = $this->_command('LOGIN')->add(array($username, $password));
             $cmd->debug = array(sprintf('LOGIN %s [PASSWORD]', $username));
             break;
         case 'PLAIN':
             // RFC 2595/4616 - PLAIN SASL mechanism
             $cmd = $this->_authInitialResponse($method, base64_encode(implode("", array($username, $username, $password))), $username);
             break;
         case 'SCRAM-SHA-1':
             $scram = new Horde_Imap_Client_Auth_Scram($username, $password, 'SHA1');
             $cmd = $this->_authInitialResponse($method, base64_encode($scram->getClientFirstMessage()));
             $cmd->add(new Horde_Imap_Client_Interaction_Command_Continuation(function ($ob) use($scram) {
                 $sr1 = base64_decode($ob->token->current());
                 return new Horde_Imap_Client_Data_Format_List($scram->parseServerFirstMessage($sr1) ? base64_encode($scram->getClientFinalMessage()) : '*');
             }));
             $self = $this;
             $cmd->add(new Horde_Imap_Client_Interaction_Command_Continuation(function ($ob) use($scram, $self) {
                 $sr2 = base64_decode($ob->token->current());
                 if (!$scram->parseServerFinalMessage($sr2)) {
                     /* This means authentication passed, according to the
                      * server, but the server signature is incorrect.
                      * This indicates that server verification has failed.
                      * Immediately disconnect from the server, since this
                      * is a possible security issue. */
                     $self->logout();
                     throw new Horde_Imap_Client_Exception(Horde_Imap_Client_Translation::r("Server failed verification check."), Horde_Imap_Client_Exception::LOGIN_SERVER_VERIFICATION_FAILED);
                 }
                 return new Horde_Imap_Client_Data_Format_List();
             }));
             break;
         case 'XOAUTH2':
             // Google XOAUTH2
             $cmd = $this->_authInitialResponse($method, $this->getParam('xoauth2_token'));
             /* This is an optional command continuation. XOAUTH2 will return
              * error information in continuation response. */
             $error_continuation = new Horde_Imap_Client_Interaction_Command_Continuation(function ($ob) {
                 return new Horde_Imap_Client_Data_Format_List();
             });
             $error_continuation->optional = true;
             $cmd->add($error_continuation);
             break;
         default:
             $e = new Horde_Imap_Client_Exception(Horde_Imap_Client_Translation::r("Unknown authentication method: %s"), Horde_Imap_Client_Exception::SERVER_CONNECT);
             $e->messagePrintf(array($method));
             throw $e;
     }
     return $this->_sendCmd($this->_pipeline($cmd));
 }