Move SSL context options into CakeSocket.

Having all the options consolidated in one places enables all the SSL
context options to be used in the SmtpTransport instead of just allowing
self_signed as proposed in #7496
This commit is contained in:
mark_story 2015-10-12 21:56:20 -04:00
parent 5dfb780970
commit cc3531d288
4 changed files with 79 additions and 84 deletions

View file

@ -134,6 +134,7 @@ class CakeSocket {
$scheme = $this->config['protocol'] . '://';
}
$this->_setSslContext($this->config['host']);
if (!empty($this->config['context'])) {
$context = stream_context_create($this->config['context']);
} else {
@ -195,6 +196,46 @@ class CakeSocket {
return $this->connected;
}
/**
* Configure the SSL context options.
*
* @param string $host The host name being connected to.
*/
protected function _setSslContext($host)
{
foreach ($this->config as $key => $value) {
if (substr($key, 0, 4) !== 'ssl_') {
continue;
}
$contextKey = substr($key, 4);
if (empty($this->config['context']['ssl'][$contextKey])) {
$this->config['context']['ssl'][$contextKey] = $value;
}
unset($this->config[$key]);
}
if (version_compare(PHP_VERSION, '5.3.2', '>=')) {
if (!isset($this->config['context']['ssl']['SNI_enabled'])) {
$this->config['context']['ssl']['SNI_enabled'] = true;
}
if (version_compare(PHP_VERSION, '5.6.0', '>=')) {
if (empty($this->config['context']['ssl']['peer_name'])) {
$this->config['context']['ssl']['peer_name'] = $host;
}
} else {
if (empty($this->config['context']['ssl']['SNI_server_name'])) {
$this->config['context']['ssl']['SNI_server_name'] = $host;
}
}
}
if (empty($this->config['context']['ssl']['cafile'])) {
$this->config['context']['ssl']['cafile'] = CAKE . 'Config' . DS . 'cacert.pem';
}
if (!empty($this->config['context']['ssl']['verify_host'])) {
$this->config['context']['ssl']['CN_match'] = $host;
}
unset($this->config['context']['ssl']['verify_host']);
}
/**
* socket_stream_client() does not populate errNum, or $errStr when there are
* connection errors, as in the case of SSL verification failure.

View file

@ -72,7 +72,7 @@ class HttpSocket extends CakeSocket {
* Contain information about the last response (read only)
*
* @var array
*/
*/
public $response = null;
/**
@ -361,8 +361,6 @@ class HttpSocket extends CakeSocket {
return false;
}
$this->_configContext($this->request['uri']['host']);
$this->request['raw'] = '';
if ($this->request['line'] !== false) {
$this->request['raw'] = $this->request['line'];
@ -374,6 +372,8 @@ class HttpSocket extends CakeSocket {
$this->request['raw'] .= "\r\n";
$this->request['raw'] .= $this->request['body'];
// SSL context is set during the connect() method.
$this->write($this->request['raw']);
$response = null;
@ -700,47 +700,6 @@ class HttpSocket extends CakeSocket {
return true;
}
/**
* Configure the socket's context. Adds in configuration
* that can not be declared in the class definition.
*
* @param string $host The host you're connecting to.
* @return void
*/
protected function _configContext($host) {
foreach ($this->config as $key => $value) {
if (substr($key, 0, 4) !== 'ssl_') {
continue;
}
$contextKey = substr($key, 4);
if (empty($this->config['context']['ssl'][$contextKey])) {
$this->config['context']['ssl'][$contextKey] = $value;
}
unset($this->config[$key]);
}
if (version_compare(PHP_VERSION, '5.3.2', '>=')) {
if (!isset($this->config['context']['ssl']['SNI_enabled'])) {
$this->config['context']['ssl']['SNI_enabled'] = true;
}
if (version_compare(PHP_VERSION, '5.6.0', '>=')) {
if (empty($this->config['context']['ssl']['peer_name'])) {
$this->config['context']['ssl']['peer_name'] = $host;
}
} else {
if (empty($this->config['context']['ssl']['SNI_server_name'])) {
$this->config['context']['ssl']['SNI_server_name'] = $host;
}
}
}
if (empty($this->config['context']['ssl']['cafile'])) {
$this->config['context']['ssl']['cafile'] = CAKE . 'Config' . DS . 'cacert.pem';
}
if (!empty($this->config['context']['ssl']['verify_host'])) {
$this->config['context']['ssl']['CN_match'] = $host;
}
unset($this->config['context']['ssl']['verify_host']);
}
/**
* Takes a $uri array and turns it into a fully qualified URL string
*

View file

@ -379,7 +379,37 @@ class CakeSocketTest extends CakeTestCase {
$this->Socket = new CakeSocket($config);
$this->Socket->connect();
$result = $this->Socket->context();
$this->assertEquals($config['context'], $result);
$this->assertSame($config['context']['ssl']['capture_peer'], $result['ssl']['capture_peer']);
}
/**
* test configuring the context from the flat keys.
*
* @return void
*/
public function testConfigContext() {
$this->skipIf(!extension_loaded('openssl'), 'OpenSSL is not enabled cannot test SSL.');
$config = array(
'host' => 'smtp.gmail.com',
'port' => 465,
'timeout' => 5,
'ssl_verify_peer' => true,
'ssl_allow_self_signed' => false,
'ssl_verify_depth' => 5,
'ssl_verify_host' => true,
);
$this->Socket = new CakeSocket($config);
$this->Socket->connect();
$result = $this->Socket->context();
$this->assertTrue($result['ssl']['verify_peer']);
$this->assertFalse($result['ssl']['allow_self_signed']);
$this->assertEquals(5, $result['ssl']['verify_depth']);
$this->assertEquals('smtp.gmail.com', $result['ssl']['CN_match']);
$this->assertArrayNotHasKey('ssl_verify_peer', $this->Socket->config);
$this->assertArrayNotHasKey('ssl_allow_self_signed', $this->Socket->config);
$this->assertArrayNotHasKey('ssl_verify_host', $this->Socket->config);
$this->assertArrayNotHasKey('ssl_verify_depth', $this->Socket->config);
}
}

View file

@ -314,23 +314,6 @@ class HttpSocketTest extends CakeTestCase {
$response = $this->Socket->request(true);
$this->assertFalse($response);
$context = array(
'ssl' => array(
'verify_peer' => true,
'allow_self_signed' => false,
'verify_depth' => 5,
'SNI_enabled' => true,
'CN_match' => 'www.cakephp.org',
'cafile' => CAKE . 'Config' . DS . 'cacert.pem'
)
);
if (version_compare(PHP_VERSION, '5.6.0', '>=')) {
$context['ssl']['peer_name'] = 'www.cakephp.org';
} else {
$context['ssl']['SNI_server_name'] = 'www.cakephp.org';
}
$tests = array(
array(
'request' => 'http://www.cakephp.org/?foo=bar',
@ -341,7 +324,10 @@ class HttpSocketTest extends CakeTestCase {
'protocol' => 'tcp',
'port' => 80,
'timeout' => 30,
'context' => $context,
'ssl_verify_peer' => true,
'ssl_allow_self_signed' => false,
'ssl_verify_depth' => 5,
'ssl_verify_host' => true,
'request' => array(
'uri' => array(
'scheme' => 'http',
@ -1843,27 +1829,6 @@ class HttpSocketTest extends CakeTestCase {
$this->assertEquals(true, $return);
}
/**
* test configuring the context from the flat keys.
*
* @return void
*/
public function testConfigContext() {
$this->Socket->expects($this->any())
->method('read')->will($this->returnValue(false));
$this->Socket->reset();
$this->Socket->request('http://example.com');
$this->assertTrue($this->Socket->config['context']['ssl']['verify_peer']);
$this->assertFalse($this->Socket->config['context']['ssl']['allow_self_signed']);
$this->assertEquals(5, $this->Socket->config['context']['ssl']['verify_depth']);
$this->assertEquals('example.com', $this->Socket->config['context']['ssl']['CN_match']);
$this->assertArrayNotHasKey('ssl_verify_peer', $this->Socket->config);
$this->assertArrayNotHasKey('ssl_allow_self_signed', $this->Socket->config);
$this->assertArrayNotHasKey('ssl_verify_host', $this->Socket->config);
$this->assertArrayNotHasKey('ssl_verify_depth', $this->Socket->config);
}
/**
* Test that requests fail when peer verification fails.
*