diff --git a/doc/getting-started-with-rackspace.rst b/doc/getting-started-with-rackspace.rst index 35317a3e6..73aa3a8d4 100644 --- a/doc/getting-started-with-rackspace.rst +++ b/doc/getting-started-with-rackspace.rst @@ -138,7 +138,7 @@ Okay, you're ready to spin up a server: .. code-block:: php -use Guzzle\Http\Exception\BadResponseException; + use Guzzle\Http\Exception\BadResponseException; $server = $compute->server(); diff --git a/lib/OpenCloud/Database/Service.php b/lib/OpenCloud/Database/Service.php index dd63a60f1..de20872b6 100644 --- a/lib/OpenCloud/Database/Service.php +++ b/lib/OpenCloud/Database/Service.php @@ -17,6 +17,7 @@ namespace OpenCloud\Database; +use Guzzle\Http\ClientInterface; use OpenCloud\Common\Service\NovaService; use OpenCloud\Database\Resource\Instance; use OpenCloud\Database\Resource\Configuration; @@ -104,4 +105,39 @@ public function datastoreList($params = array()) return $this->resourceList('Datastore', $url); } + + /** + * {@inheritDoc} + */ + public function setClient(ClientInterface $client) + { + // The Rackspace Cloud Databases service only supports the + // RC4 SSL cipher which is not supported by modern OpenSSL clients. + // Until the service can support additional, more modern and secure + // ciphers, this SDK has to ask curl to allow using the weaker + // cipher. For more information, see https://github.com/rackspace/php-opencloud/issues/560 + + $curlOptions = $client->getConfig()->get('curl.options'); + $curlOptions['CURLOPT_SSL_CIPHER_LIST'] = static::getSslCipherList(); + $client->getConfig()->set('curl.options', $curlOptions); + + $logMessage = 'The SDK is using a custom cipher suite when connecting ' + . 'to the Rackspace Cloud Databases service. This suite contains ' + . 'a weak cipher (RC4) so please use at your own risk. See ' + . 'https://github.com/rackspace/php-opencloud/issues/560 for details.'; + $client->getLogger()->critical($logMessage); + + $this->client = $client; + } + + /** + * @see https://github.com/rackspace/php-opencloud/issues/560#issuecomment-81790778 + */ + public static function getSslCipherList() + { + return 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:' + . 'ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:ECDH+3DES:' + . 'DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:' + . 'ECDH+RC4:DH+RC4:RSA+RC4:!aNULL:!eNULL:!MD5'; + } } diff --git a/tests/OpenCloud/Smoke/Unit/Networking.php b/tests/OpenCloud/Smoke/Unit/Networking.php index 8ccd30a94..02ed838bb 100644 --- a/tests/OpenCloud/Smoke/Unit/Networking.php +++ b/tests/OpenCloud/Smoke/Unit/Networking.php @@ -272,6 +272,30 @@ protected function testSecurityGroupOperations() $securityGroup = $this->getService()->getSecurityGroup($securityGroup->getId()); $this->stepInfo('Security Group ID: ' . $securityGroup->getId()); $this->stepInfo('Security Group Name: ' . $securityGroup->getName()); + + $network1 = $this->getService()->createNetwork(array( + 'name' => 'test_network_for_test_port_sg' + )); + $this->cleanupNetworkIds[] = $network1->getId(); + + $subnet1 = $this->getService()->createSubnet(array( + 'cidr' => '192.165.66.0/25', + 'networkId' => $network1->getId(), + 'ipVersion' => 4, + 'name' => 'test_subnet_for_test_port_sg' + )); + $this->cleanupSubnetIds[] = $subnet1->getId(); + + $port1 = $this->getService()->createPort(array( + 'networkId' => $network1->getId(), + 'name' => 'test_port_for_test_port_sg' + )); + $this->cleanupPortIds[] = $port1->getId(); + + $this->step('Apply security group to port'); + $port1->update(array( + 'securityGroups' => array($securityGroup->getId()) + )); } protected function testSecurityGroupRuleOperations() diff --git a/tests/OpenCloud/Tests/Database/DatabaseTestCase.php b/tests/OpenCloud/Tests/Database/DatabaseTestCase.php index 0e8ad75cb..403f6955f 100644 --- a/tests/OpenCloud/Tests/Database/DatabaseTestCase.php +++ b/tests/OpenCloud/Tests/Database/DatabaseTestCase.php @@ -18,6 +18,7 @@ namespace OpenCloud\Tests\Database; use OpenCloud\Tests\OpenCloudTestCase; +use OpenCloud\Tests\MockLogger; class DatabaseTestCase extends OpenCloudTestCase { @@ -28,7 +29,9 @@ class DatabaseTestCase extends OpenCloudTestCase public function setupObjects() { - $this->service = $this->getClient()->databaseService(); + $client = $this->getClient(); + $client->setLogger(new MockLogger()); + $this->service = $client->databaseService(); $this->addMockSubscriber($this->getTestFilePath('Instance')); $this->instance = $this->service->instance('foo'); @@ -37,4 +40,9 @@ public function setupObjects() $this->datastore = $this->service->datastore('10000000-0000-0000-0000-000000000001'); $this->datastoreVersion = $this->datastore->version('b00000b0-00b0-0b00-00b0-000b000000bb'); } + + protected function assertCriticalMessageWasLogged() + { + $this->assertNotEmpty($this->getClient()->getLogger()->getCriticalLogMessage()); + } } diff --git a/tests/OpenCloud/Tests/Database/ServiceTest.php b/tests/OpenCloud/Tests/Database/ServiceTest.php index 8212fb61a..96a6be1c6 100644 --- a/tests/OpenCloud/Tests/Database/ServiceTest.php +++ b/tests/OpenCloud/Tests/Database/ServiceTest.php @@ -27,6 +27,8 @@ namespace OpenCloud\Tests\Database; +use OpenCloud\Database\Service; + class ServiceTest extends DatabaseTestCase { public function test__construct() @@ -71,4 +73,12 @@ public function testDatastoreList() { $this->assertInstanceOf(self::COLLECTION_CLASS, $this->service->datastoreList()); } + + public function testClientUsesCustomCipherSuite() + { + $client = $this->service->getClient(); + $curlOptions = $client->getConfig('curl.options'); + $this->assertEquals(Service::getSslCipherList(), $curlOptions['CURLOPT_SSL_CIPHER_LIST']); + $this->assertCriticalMessageWasLogged(); + } } diff --git a/tests/OpenCloud/Tests/MockLogger.php b/tests/OpenCloud/Tests/MockLogger.php new file mode 100644 index 000000000..9aca3dd68 --- /dev/null +++ b/tests/OpenCloud/Tests/MockLogger.php @@ -0,0 +1,35 @@ +criticalLogMessage; + } + + public function getCriticalLogMessage() + { + return $this->criticalLogMessage; + } +} diff --git a/tests/OpenCloud/Tests/RackspaceTest.php b/tests/OpenCloud/Tests/RackspaceTest.php index 790d54645..7cf37f183 100644 --- a/tests/OpenCloud/Tests/RackspaceTest.php +++ b/tests/OpenCloud/Tests/RackspaceTest.php @@ -17,6 +17,8 @@ namespace OpenCloud\Tests; +use OpenCloud\Tests\MockLogger; + class RackspaceTest extends OpenCloudTestCase { const CREDENTIALS = <<getClient()->getLogger(); + $this->getClient()->setLogger(new MockLogger()); + $this->assertInstanceOf( 'OpenCloud\Database\Service', $this->getClient()->databaseService('cloudDatabases', 'DFW') ); + + // Re-inject old logger + $this->getClient()->setLogger($oldLogger); + $this->assertInstanceOf( 'OpenCloud\LoadBalancer\Service', $this->getClient()->loadBalancerService('cloudLoadBalancers', 'DFW')