mirror of
https://github.com/kamilwylegala/cakephp2-php8.git
synced 2025-01-19 02:56:15 +00:00
Merge pull request #734 from steinkel/feature/smtp-tls
Adding TLS support to SmtpTransport
This commit is contained in:
commit
596f2c0d91
4 changed files with 238 additions and 3 deletions
|
@ -76,6 +76,27 @@ class CakeSocket {
|
|||
*/
|
||||
public $lastError = array();
|
||||
|
||||
/**
|
||||
* True if the socket stream is encrypted after a CakeSocket::enableCrypto() call
|
||||
* @var type
|
||||
*/
|
||||
public $encrypted = false;
|
||||
|
||||
/**
|
||||
* Contains all the encryption methods available
|
||||
* @var array
|
||||
*/
|
||||
protected $_encryptMethods = array(
|
||||
'sslv2_client' => STREAM_CRYPTO_METHOD_SSLv2_CLIENT,
|
||||
'sslv3_client' => STREAM_CRYPTO_METHOD_SSLv3_CLIENT,
|
||||
'sslv23_client' => STREAM_CRYPTO_METHOD_SSLv23_CLIENT,
|
||||
'tls_client' => STREAM_CRYPTO_METHOD_TLS_CLIENT,
|
||||
'sslv2_server' => STREAM_CRYPTO_METHOD_SSLv2_SERVER,
|
||||
'sslv3_server' => STREAM_CRYPTO_METHOD_SSLv3_SERVER,
|
||||
'sslv23_server' => STREAM_CRYPTO_METHOD_SSLv23_SERVER,
|
||||
'tls_server' => STREAM_CRYPTO_METHOD_TLS_SERVER
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
|
@ -277,4 +298,34 @@ class CakeSocket {
|
|||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Encrypts current stream socket, using one of the defined encryption methods
|
||||
*
|
||||
* @param string $type can be one of 'ssl2', 'ssl3', 'ssl23' or 'tls'
|
||||
* @param string $clientOrServer can be one of 'client', 'server'. Default is 'client'
|
||||
* @param boolean $enable enable or disable encryption. Default is true (enable)
|
||||
* @return boolean True on success
|
||||
* @throws SocketException
|
||||
* @see stream_socket_enable_crypto
|
||||
*/
|
||||
public function enableCrypto($type, $clientOrServer = 'client', $enable = true) {
|
||||
if (!array_key_exists($type . '_' . $clientOrServer, $this->_encryptMethods)) {
|
||||
throw new InvalidArgumentException(__d('cake_dev', 'Invalid encryption scheme chosen'));
|
||||
}
|
||||
$enableCryptoResult = false;
|
||||
try {
|
||||
$enableCryptoResult = stream_socket_enable_crypto($this->connection, $enable, $this->_encryptMethods[$type . '_' . $clientOrServer]);
|
||||
} catch (Exception $e) {
|
||||
$this->setLastError(null, $e->getMessage());
|
||||
throw new SocketException($e->getMessage());
|
||||
}
|
||||
if ($enableCryptoResult === true) {
|
||||
$this->encrypted = $enable;
|
||||
return true;
|
||||
} else {
|
||||
$errorMessage = __d('cake_dev', 'Unable to perform enableCrypto operation on CakeSocket');
|
||||
$this->setLastError(null, $errorMessage);
|
||||
throw new SocketException($errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -79,7 +79,8 @@ class SmtpTransport extends AbstractTransport {
|
|||
'timeout' => 30,
|
||||
'username' => null,
|
||||
'password' => null,
|
||||
'client' => null
|
||||
'client' => null,
|
||||
'tls' => false
|
||||
);
|
||||
$this->_config = $config + $default;
|
||||
}
|
||||
|
@ -107,7 +108,15 @@ class SmtpTransport extends AbstractTransport {
|
|||
|
||||
try {
|
||||
$this->_smtpSend("EHLO {$host}", '250');
|
||||
if ($this->_config['tls']) {
|
||||
$this->_smtpSend("STARTTLS", '220');
|
||||
$this->_socket->enableCrypto('tls');
|
||||
$this->_smtpSend("EHLO {$host}", '250');
|
||||
}
|
||||
} catch (SocketException $e) {
|
||||
if ($this->_config['tls']) {
|
||||
throw new SocketException(__d('cake_dev', 'SMTP server did not accept the connection or trying to connect to non TLS SMTP server using TLS.'));
|
||||
}
|
||||
try {
|
||||
$this->_smtpSend("HELO {$host}", '250');
|
||||
} catch (SocketException $e2) {
|
||||
|
@ -132,6 +141,8 @@ class SmtpTransport extends AbstractTransport {
|
|||
if (!$this->_smtpSend(base64_encode($this->_config['password']), '235')) {
|
||||
throw new SocketException(__d('cake_dev', 'SMTP server did not accept the password.'));
|
||||
}
|
||||
} elseif ($authRequired == '504') {
|
||||
throw new SocketException(__d('cake_dev', 'SMTP authentication method not allowed, check if SMTP server requires TLS'));
|
||||
} elseif ($authRequired != '503') {
|
||||
throw new SocketException(__d('cake_dev', 'SMTP does not require authentication.'));
|
||||
}
|
||||
|
|
|
@ -214,4 +214,113 @@ class CakeSocketTest extends CakeTestCase {
|
|||
$anotherSocket->reset();
|
||||
$this->assertEquals(array(), $anotherSocket->config);
|
||||
}
|
||||
|
||||
/**
|
||||
* testEncrypt
|
||||
*
|
||||
* @expectedException SocketException
|
||||
* @return void
|
||||
*/
|
||||
public function testEnableCryptoSocketExceptionNoSsl() {
|
||||
$configNoSslOrTls = array('host' => 'localhost', 'port' => 80, 'timeout' => 0.1);
|
||||
|
||||
// testing exception on no ssl socket server for ssl and tls methods
|
||||
$this->Socket = new CakeSocket($configNoSslOrTls);
|
||||
$this->Socket->connect();
|
||||
$this->Socket->enableCrypto('sslv3', 'client');
|
||||
}
|
||||
|
||||
/**
|
||||
* testEnableCryptoSocketExceptionNoTls
|
||||
*
|
||||
* @expectedException SocketException
|
||||
* @return void
|
||||
*/
|
||||
public function testEnableCryptoSocketExceptionNoTls() {
|
||||
$configNoSslOrTls = array('host' => 'localhost', 'port' => 80, 'timeout' => 0.1);
|
||||
|
||||
// testing exception on no ssl socket server for ssl and tls methods
|
||||
$this->Socket = new CakeSocket($configNoSslOrTls);
|
||||
$this->Socket->connect();
|
||||
$this->Socket->enableCrypto('tls', 'client');
|
||||
}
|
||||
|
||||
/**
|
||||
* _connectSocketToSslTls
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _connectSocketToSslTls() {
|
||||
$configSslTls = array('host' => 'smtp.gmail.com', 'port' => 465, 'timeout' => 5);
|
||||
$this->Socket = new CakeSocket($configSslTls);
|
||||
$this->Socket->connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* testEnableCryptoBadMode
|
||||
*
|
||||
* @expectedException InvalidArgumentException
|
||||
* @return void
|
||||
*/
|
||||
public function testEnableCryptoBadMode() {
|
||||
// testing wrong encryption mode
|
||||
$this->_connectSocketToSslTls();
|
||||
$this->Socket->enableCrypto('doesntExistMode', 'server');
|
||||
$this->Socket->disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* testEnableCrypto
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testEnableCrypto() {
|
||||
// testing on ssl server
|
||||
$this->_connectSocketToSslTls();
|
||||
$this->assertTrue($this->Socket->enableCrypto('sslv3', 'client'));
|
||||
$this->Socket->disconnect();
|
||||
|
||||
// testing on tls server
|
||||
$this->_connectSocketToSslTls();
|
||||
$this->assertTrue($this->Socket->enableCrypto('tls', 'client'));
|
||||
$this->Socket->disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* testEnableCryptoExceptionEnableTwice
|
||||
*
|
||||
* @expectedException SocketException
|
||||
* @return void
|
||||
*/
|
||||
public function testEnableCryptoExceptionEnableTwice() {
|
||||
// testing on tls server
|
||||
$this->_connectSocketToSslTls();
|
||||
$this->Socket->enableCrypto('tls', 'client');
|
||||
$this->Socket->enableCrypto('tls', 'client');
|
||||
}
|
||||
|
||||
/**
|
||||
* testEnableCryptoExceptionDisableTwice
|
||||
*
|
||||
* @expectedException SocketException
|
||||
* @return void
|
||||
*/
|
||||
public function testEnableCryptoExceptionDisableTwice() {
|
||||
// testing on tls server
|
||||
$this->_connectSocketToSslTls();
|
||||
$this->Socket->enableCrypto('tls', 'client', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* testEnableCryptoEnableStatus
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testEnableCryptoEnableStatus() {
|
||||
// testing on tls server
|
||||
$this->_connectSocketToSslTls();
|
||||
$this->assertFalse($this->Socket->encrypted);
|
||||
$this->Socket->enableCrypto('tls', 'client', true);
|
||||
$this->assertTrue($this->Socket->encrypted);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ class SmtpTransportTest extends CakeTestCase {
|
|||
*/
|
||||
public function setUp() {
|
||||
if (!class_exists('MockSocket')) {
|
||||
$this->getMock('CakeSocket', array('read', 'write', 'connect'), array(), 'MockSocket');
|
||||
$this->getMock('CakeSocket', array('read', 'write', 'connect', 'enableCrypto'), array(), 'MockSocket');
|
||||
}
|
||||
$this->socket = new MockSocket();
|
||||
|
||||
|
@ -105,6 +105,70 @@ class SmtpTransportTest extends CakeTestCase {
|
|||
$this->SmtpTransport->connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* testConnectEhloTls method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testConnectEhloTls() {
|
||||
$this->SmtpTransport->config(array('tls' => true));
|
||||
$this->socket->expects($this->any())->method('connect')->will($this->returnValue(true));
|
||||
$this->socket->expects($this->at(0))->method('read')->will($this->returnValue(false));
|
||||
$this->socket->expects($this->at(1))->method('read')->will($this->returnValue("220 Welcome message\r\n"));
|
||||
$this->socket->expects($this->at(2))->method('write')->with("EHLO localhost\r\n");
|
||||
$this->socket->expects($this->at(3))->method('read')->will($this->returnValue(false));
|
||||
$this->socket->expects($this->at(4))->method('read')->will($this->returnValue("250 Accepted\r\n"));
|
||||
$this->socket->expects($this->at(5))->method('write')->with("STARTTLS\r\n");
|
||||
$this->socket->expects($this->at(6))->method('read')->will($this->returnValue(false));
|
||||
$this->socket->expects($this->at(7))->method('read')->will($this->returnValue("220 Server ready\r\n"));
|
||||
$this->socket->expects($this->at(8))->method('other')->with('tls')->will($this->returnValue(true));
|
||||
$this->socket->expects($this->at(9))->method('write')->with("EHLO localhost\r\n");
|
||||
$this->socket->expects($this->at(10))->method('read')->will($this->returnValue(false));
|
||||
$this->socket->expects($this->at(11))->method('read')->will($this->returnValue("250 Accepted\r\n"));
|
||||
$this->SmtpTransport->connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* testConnectEhloTlsOnNonTlsServer method
|
||||
*
|
||||
* @expectedException SocketException
|
||||
* @return void
|
||||
*/
|
||||
public function testConnectEhloTlsOnNonTlsServer() {
|
||||
$this->SmtpTransport->config(array('tls' => true));
|
||||
$this->socket->expects($this->any())->method('connect')->will($this->returnValue(true));
|
||||
$this->socket->expects($this->at(0))->method('read')->will($this->returnValue(false));
|
||||
$this->socket->expects($this->at(1))->method('read')->will($this->returnValue("220 Welcome message\r\n"));
|
||||
$this->socket->expects($this->at(2))->method('write')->with("EHLO localhost\r\n");
|
||||
$this->socket->expects($this->at(3))->method('read')->will($this->returnValue(false));
|
||||
$this->socket->expects($this->at(4))->method('read')->will($this->returnValue("250 Accepted\r\n"));
|
||||
$this->socket->expects($this->at(5))->method('write')->with("STARTTLS\r\n");
|
||||
$this->socket->expects($this->at(6))->method('read')->will($this->returnValue(false));
|
||||
$this->socket->expects($this->at(7))->method('read')->will($this->returnValue("500 5.3.3 Unrecognized command\r\n"));
|
||||
$this->SmtpTransport->connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* testConnectEhloNoTlsOnRequiredTlsServer method
|
||||
*
|
||||
* @expectedException SocketException
|
||||
* @return void
|
||||
*/
|
||||
public function testConnectEhloNoTlsOnRequiredTlsServer() {
|
||||
$this->SmtpTransport->config(array('tls' => false, 'username' => 'user', 'password' => 'pass'));
|
||||
$this->socket->expects($this->any())->method('connect')->will($this->returnValue(true));
|
||||
$this->socket->expects($this->at(0))->method('read')->will($this->returnValue(false));
|
||||
$this->socket->expects($this->at(1))->method('read')->will($this->returnValue("220 Welcome message\r\n"));
|
||||
$this->socket->expects($this->at(2))->method('write')->with("EHLO localhost\r\n");
|
||||
$this->socket->expects($this->at(3))->method('read')->will($this->returnValue(false));
|
||||
$this->socket->expects($this->at(4))->method('read')->will($this->returnValue("250 Accepted\r\n"));
|
||||
$this->socket->expects($this->at(5))->method('read')->with("AUTH LOGIN\r\n");
|
||||
$this->socket->expects($this->at(6))->method('read')->will($this->returnValue(false));
|
||||
$this->socket->expects($this->at(7))->method('read')->will($this->returnValue("504 5.7.4 Unrecognized authentication type\r\n"));
|
||||
$this->SmtpTransport->connect();
|
||||
$this->SmtpTransport->auth();
|
||||
}
|
||||
|
||||
/**
|
||||
* testConnectHelo method
|
||||
*
|
||||
|
|
Loading…
Add table
Reference in a new issue