Browse Source

Add SSL context options to Socket.

This ports #7496 to 3.x adding the ability to set ssl context options on
any socket. This is most helpful with the SmtpTransport.
Mark Story 10 years ago
parent
commit
5dc186bbb9
2 changed files with 72 additions and 1 deletions
  1. 40 0
      src/Network/Socket.php
  2. 32 1
      tests/TestCase/Network/SocketTest.php

+ 40 - 0
src/Network/Socket.php

@@ -133,6 +133,7 @@ class Socket
             $scheme = $this->_config['protocol'] . '://';
         }
 
+        $this->_setSslContext($this->_config['host']);
         if (!empty($this->_config['context'])) {
             $context = stream_context_create($this->_config['context']);
         } else {
@@ -173,6 +174,45 @@ class Socket
     }
 
     /**
+     * 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 (!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'])) {
+            $dir = dirname(__DIR__);
+            $this->_config['context']['ssl']['cafile'] = $dir . DIRECTORY_SEPARATOR .
+                'config' . DIRECTORY_SEPARATOR . '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.
      *

+ 32 - 1
tests/TestCase/Network/SocketTest.php

@@ -411,6 +411,37 @@ class SocketTest extends TestCase
             $this->markTestSkipped('No network, skipping test.');
         }
         $result = $this->Socket->context();
-        $this->assertEquals($config['context'], $result);
+        $this->assertTrue($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,
+       );
+       $socket = new Socket($config);
+
+       $socket->connect();
+       $result = $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', $socket->config());
+       $this->assertArrayNotHasKey('ssl_allow_self_signed', $socket->config());
+       $this->assertArrayNotHasKey('ssl_verify_host', $socket->config());
+       $this->assertArrayNotHasKey('ssl_verify_depth', $socket->config());
     }
 }