Skip to content

Commit

Permalink
Issue Orange-OpenSource#68. SSL support for client-node encrypted com…
Browse files Browse the repository at this point in the history
…munication.
  • Loading branch information
Shobhit Agarwal committed Oct 24, 2014
1 parent 57747c1 commit b140d2f
Show file tree
Hide file tree
Showing 41 changed files with 224 additions and 44 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ Before make test:
$ cp tests/config.inc-dist tests/config.inc
$ $EDITOR tests/config.inc

For running tests with SSL configuration, use $params in config.inc for setting certificate path, private/public key etc.

This is to prevent accidentally dropping keyspaces that might in use.

# Create a debian package from the sources
Expand Down
112 changes: 106 additions & 6 deletions cassandra_driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ static int pdo_cassandra_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSR
H->has_description = 0;
H->preserve_values = 0;

H->factory.reset(new TSSLSocketFactory);
H->socket.reset(new TSocketPool);
H->transport.reset(new TFramedTransport(H->socket));
H->protocol.reset(new TBinaryProtocol(H->transport));
Expand All @@ -280,6 +281,9 @@ static int pdo_cassandra_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSR

/* set possible connection timeout */
long timeout = 0;
/* set SSL propeties */
char *ssl_key = NULL, *ssl_cert = NULL, *ssl_cipher = NULL, *ssl_capath = NULL;
int ssl_validate = 0, ssl_verify_host = 1;

if (driver_options) {
timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, timeout TSRMLS_CC);
Expand All @@ -296,6 +300,42 @@ static int pdo_cassandra_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSR
if (pdo_attr_lval(driver_options, static_cast <pdo_attribute_type>(PDO_CASSANDRA_ATTR_PRESERVE_VALUES), 0 TSRMLS_CC)) {
H->preserve_values = 1;
}

ssl_key = pdo_attr_strval(driver_options, static_cast <pdo_attribute_type>(PDO_CASSANDRA_ATTR_SSL_KEY), NULL TSRMLS_CC);
ssl_cert = pdo_attr_strval(driver_options, static_cast <pdo_attribute_type>(PDO_CASSANDRA_ATTR_SSL_CERT), NULL TSRMLS_CC);
ssl_capath = pdo_attr_strval(driver_options, static_cast <pdo_attribute_type>(PDO_CASSANDRA_ATTR_SSL_CAPATH), NULL TSRMLS_CC);
ssl_cipher = pdo_attr_strval(driver_options, static_cast <pdo_attribute_type>(PDO_CASSANDRA_ATTR_SSL_CIPHER), NULL TSRMLS_CC);
ssl_validate = pdo_attr_lval(driver_options, static_cast <pdo_attribute_type>(PDO_CASSANDRA_ATTR_SSL_VALIDATE), 0 TSRMLS_CC);
ssl_verify_host = pdo_attr_lval(driver_options, static_cast <pdo_attribute_type>(PDO_CASSANDRA_ATTR_SSL_VERIFY_HOST), 1 TSRMLS_CC);

if (ssl_key || ssl_cert || ssl_cipher || ssl_capath) {
H->ssl = 1;

if (ssl_cert) {
H->factory->loadCertificate(ssl_cert);
}

if (ssl_key) {
H->factory->loadPrivateKey(ssl_key);
}

if (ssl_capath) {
H->factory->loadTrustedCertificates(ssl_capath);
}

if (ssl_validate) {
H->factory->authenticate(TRUE);
}

if (ssl_cipher) {
H->factory->ciphers(ssl_cipher);
}

if (!ssl_verify_host) {
boost::shared_ptr<AccessManager> accessManager(new NoHostVerificationAccessManager);
H->factory->access(accessManager);
}
}
}

/* Break down the values */
Expand All @@ -311,6 +351,18 @@ static int pdo_cassandra_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSR
}

try {
H->socket->open();

if (H->ssl) {
/* Remeber at this point the socket is already open */
H->sslSocket = H->factory->createSocket(H->socket->getSocketFD());
H->sslSocket->setHost(H->socket->getHost());
H->sslSocket->setPort(H->socket->getPort());
H->transport.reset(new TFramedTransport(H->sslSocket));
H->protocol.reset(new TBinaryProtocol(H->transport));
H->client.reset(new CassandraClient(H->protocol));
}

H->transport->open();

php_cassandra_handle_auth (dbh, H);
Expand Down Expand Up @@ -338,6 +390,8 @@ static int pdo_cassandra_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSR
pdo_cassandra_error_exception(dbh, PDO_CASSANDRA_AUTHORIZATION_ERROR, "%s", e.why.c_str());
} catch (SchemaDisagreementException &e) {
pdo_cassandra_error_exception(dbh, PDO_CASSANDRA_SCHEMA_DISAGREEMENT, "%s", e.what());
} catch (TSSLException &e) {
pdo_cassandra_error_exception(dbh, PDO_CASSANDRA_SSL_ERROR, "%s", e.what());
} catch (TTransportException &e) {
pdo_cassandra_error_exception(dbh, PDO_CASSANDRA_TRANSPORT_ERROR, "%s", e.what());
} catch (TException &e) {
Expand Down Expand Up @@ -484,6 +538,8 @@ static long pdo_cassandra_handle_execute(pdo_dbh_t *dbh, const char *sql, long s
pdo_cassandra_error(dbh, PDO_CASSANDRA_AUTHORIZATION_ERROR, "%s", e.why.c_str());
} catch (SchemaDisagreementException &e) {
pdo_cassandra_error(dbh, PDO_CASSANDRA_SCHEMA_DISAGREEMENT, "%s", e.what());
} catch (TSSLException &e) {
pdo_cassandra_error(dbh, PDO_CASSANDRA_SSL_ERROR, "%s", e.what());
} catch (TTransportException &e) {
pdo_cassandra_error(dbh, PDO_CASSANDRA_TRANSPORT_ERROR, "%s", e.what());
} catch (TException &e) {
Expand Down Expand Up @@ -614,6 +670,9 @@ static int pdo_cassandra_handle_close(pdo_dbh_t *dbh TSRMLS_DC)
pdo_cassandra_einfo *einfo = &H->einfo;

H->transport->close();
if (H->ssl) {
H->sslSocket.reset();
}
H->socket.reset();
H->transport.reset();
H->protocol.reset();
Expand All @@ -636,6 +695,11 @@ static int pdo_cassandra_handle_set_attribute(pdo_dbh_t *dbh, long attr, zval *v
{
pdo_cassandra_db_handle *H = static_cast <pdo_cassandra_db_handle *>(dbh->driver_data);
pdo_cassandra_constant attribute = static_cast <pdo_cassandra_constant>(attr);
boost::shared_ptr<TSocket> sock = H->socket;

if (H->ssl) {
sock = H->sslSocket;
}

switch (attribute) {

Expand Down Expand Up @@ -668,30 +732,30 @@ static int pdo_cassandra_handle_set_attribute(pdo_dbh_t *dbh, long attr, zval *v
convert_to_long(val);

if (Z_LVAL_P(val) == 0) {
H->socket->setLinger(false, 0);
sock->setLinger(false, 0);
} else {
H->socket->setLinger(true, Z_LVAL_P(val));
sock->setLinger(true, Z_LVAL_P(val));
}
break;

case PDO_CASSANDRA_ATTR_NO_DELAY:
convert_to_boolean(val);
H->socket->setNoDelay(Z_BVAL_P(val));
sock->setNoDelay(Z_BVAL_P(val));
break;

case PDO_CASSANDRA_ATTR_CONN_TIMEOUT:
convert_to_long(val);
H->socket->setConnTimeout(Z_LVAL_P(val));
sock->setConnTimeout(Z_LVAL_P(val));
break;

case PDO_CASSANDRA_ATTR_RECV_TIMEOUT:
convert_to_long(val);
H->socket->setRecvTimeout(Z_LVAL_P(val));
sock->setRecvTimeout(Z_LVAL_P(val));
break;

case PDO_CASSANDRA_ATTR_SEND_TIMEOUT:
convert_to_long(val);
H->socket->setSendTimeout(Z_LVAL_P(val));
sock->setSendTimeout(Z_LVAL_P(val));
break;

case PDO_CASSANDRA_ATTR_COMPRESSION:
Expand Down Expand Up @@ -820,6 +884,33 @@ pdo_driver_t pdo_cassandra_driver = {
pdo_cassandra_handle_factory
};

/**
* Default implementation of AccessManager
*/
Decision NoHostVerificationAccessManager::verify(const sockaddr_storage& sa)
throw() {
(void) sa;
return SKIP;
}

Decision NoHostVerificationAccessManager::verify(const std::string& host,
const char* name,
int size) throw() {
return ALLOW;;
}

Decision NoHostVerificationAccessManager::verify(const sockaddr_storage& sa,
const char* data,
int size) throw() {
bool match = false;
if (sa.ss_family == AF_INET && size == sizeof(in_addr)) {
match = (memcmp(&((sockaddr_in*)&sa)->sin_addr, data, size) == 0);
} else if (sa.ss_family == AF_INET6 && size == sizeof(in6_addr)) {
match = (memcmp(&((sockaddr_in6*)&sa)->sin6_addr, data, size) == 0);
}
return (match ? ALLOW : SKIP);
}

/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(pdo_cassandra)
{
Expand Down Expand Up @@ -854,6 +945,15 @@ PHP_MINIT_FUNCTION(pdo_cassandra)
PHP_PDO_CASSANDRA_REGISTER_CONST_LONG("CASSANDRA_CONSISTENCYLEVEL_THREE", PDO_CASSANDRA_CONSISTENCYLEVEL_THREE);
PHP_PDO_CASSANDRA_REGISTER_CONST_LONG("CASSANDRA_CONSISTENCYLEVEL_LOCAL_ONE", PDO_CASSANDRA_CONSISTENCYLEVEL_LOCAL_ONE);

// SSL properties
PHP_PDO_CASSANDRA_REGISTER_CONST_LONG("CASSANDRA_ATTR_SSL_KEY", PDO_CASSANDRA_ATTR_SSL_KEY);
PHP_PDO_CASSANDRA_REGISTER_CONST_LONG("CASSANDRA_ATTR_SSL_CERT", PDO_CASSANDRA_ATTR_SSL_CERT);
PHP_PDO_CASSANDRA_REGISTER_CONST_LONG("CASSANDRA_ATTR_SSL_CAPATH", PDO_CASSANDRA_ATTR_SSL_CAPATH);
PHP_PDO_CASSANDRA_REGISTER_CONST_LONG("CASSANDRA_ATTR_SSL_VALIDATE", PDO_CASSANDRA_ATTR_SSL_VALIDATE);
PHP_PDO_CASSANDRA_REGISTER_CONST_LONG("CASSANDRA_ATTR_SSL_VERIFY_HOST", PDO_CASSANDRA_ATTR_SSL_VERIFY_HOST);
PHP_PDO_CASSANDRA_REGISTER_CONST_LONG("CASSANDRA_ATTR_SSL_CIPHER", PDO_CASSANDRA_ATTR_SSL_CIPHER);


// Type exports
PHP_PDO_CASSANDRA_REGISTER_CONST_LONG("CASSANDRA_INT", PDO_CASSANDRA_TYPE_INTEGER);
PHP_PDO_CASSANDRA_REGISTER_CONST_LONG("CASSANDRA_FLOAT", PDO_CASSANDRA_TYPE_FLOAT);
Expand Down
4 changes: 4 additions & 0 deletions cassandra_statement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ static zend_bool pdo_cassandra_describe_keyspace(pdo_stmt_t *stmt TSRMLS_DC)
pdo_cassandra_error(stmt->dbh, PDO_CASSANDRA_AUTHORIZATION_ERROR, "%s", e.why.c_str());
} catch (SchemaDisagreementException &e) {
pdo_cassandra_error(stmt->dbh, PDO_CASSANDRA_SCHEMA_DISAGREEMENT, "%s", e.what());
} catch (TSSLException &e) {
pdo_cassandra_error_exception(stmt->dbh, PDO_CASSANDRA_SSL_ERROR, "%s", e.what());
} catch (TTransportException &e) {
pdo_cassandra_error(stmt->dbh, PDO_CASSANDRA_TRANSPORT_ERROR, "%s", e.what());
} catch (TException &e) {
Expand Down Expand Up @@ -123,6 +125,8 @@ static int pdo_cassandra_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
pdo_cassandra_error(stmt->dbh, PDO_CASSANDRA_AUTHORIZATION_ERROR, "%s", e.why.c_str());
} catch (SchemaDisagreementException &e) {
pdo_cassandra_error(stmt->dbh, PDO_CASSANDRA_SCHEMA_DISAGREEMENT, "%s", e.what());
} catch (TSSLException &e) {
pdo_cassandra_error_exception(stmt->dbh, PDO_CASSANDRA_SSL_ERROR, "%s", e.what());
} catch (TTransportException &e) {
pdo_cassandra_error(stmt->dbh, PDO_CASSANDRA_TRANSPORT_ERROR, "%s", e.what());
} catch (TException &e) {
Expand Down
22 changes: 20 additions & 2 deletions php_pdo_cassandra_int.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

#ifndef _PHP_PDO_CASSANDRA_PRIVATE_H_
# define _PHP_PDO_CASSANDRA_PRIVATE_H_
#define _PHP_PDO_CASSANDRA_PRIVATE_H_

#ifndef CASSANDRA_CQL_VERSION
#define CASSANDRA_CQL_VERSION "3.0.0"
Expand Down Expand Up @@ -50,6 +50,7 @@ extern "C" {
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/transport/TSocketPool.h>
#include <thrift/transport/TTransportUtils.h>
#include <thrift/transport/TSSLSocket.h>

#undef HAVE_ZLIB
#define HAVE_ZLIB HAVE_ZLIB_CP
Expand Down Expand Up @@ -103,6 +104,8 @@ typedef struct {
typedef struct {
zend_object zo;
zend_bool compression;
boost::shared_ptr<TSSLSocketFactory> factory;
boost::shared_ptr<TSSLSocket> sslSocket;
boost::shared_ptr<TSocketPool> socket;
boost::shared_ptr<TFramedTransport> transport;
boost::shared_ptr<TProtocol> protocol;
Expand All @@ -114,6 +117,7 @@ typedef struct {
KsDef description;
zend_bool has_description;
zend_bool preserve_values;
zend_bool ssl;
ConsistencyLevel::type consistency;
ConsistencyLevel::type tmpConsistency;
} pdo_cassandra_db_handle;
Expand Down Expand Up @@ -152,7 +156,13 @@ enum pdo_cassandra_constant {
PDO_CASSANDRA_ATTR_THRIFT_DEBUG,
PDO_CASSANDRA_ATTR_PRESERVE_VALUES,
PDO_CASSANDRA_ATTR_MAX,
PDO_CASSANDRA_ATTR_CONSISTENCYLEVEL
PDO_CASSANDRA_ATTR_CONSISTENCYLEVEL,
PDO_CASSANDRA_ATTR_SSL_KEY,
PDO_CASSANDRA_ATTR_SSL_CERT,
PDO_CASSANDRA_ATTR_SSL_CAPATH,
PDO_CASSANDRA_ATTR_SSL_VALIDATE,
PDO_CASSANDRA_ATTR_SSL_VERIFY_HOST,
PDO_CASSANDRA_ATTR_SSL_CIPHER

};
/* }}} */
Expand Down Expand Up @@ -180,6 +190,7 @@ enum pdo_cassandra_error {
PDO_CASSANDRA_AUTHORIZATION_ERROR,
PDO_CASSANDRA_SCHEMA_DISAGREEMENT,
PDO_CASSANDRA_TRANSPORT_ERROR,
PDO_CASSANDRA_SSL_ERROR,
PDO_CASSANDRA_INVALID_CONNECTION_STRING,
PDO_CASSANDRA_INTEGER_CONVERSION_ERROR
};
Expand All @@ -192,4 +203,11 @@ void pdo_cassandra_set_active_keyspace(pdo_cassandra_db_handle *H, const std::st
void pdo_cassandra_set_active_columnfamily(pdo_cassandra_db_handle *H, const std::string &query TSRMLS_DC);
std::string pdo_cassandra_get_first_sub_pattern(const std::string &subject, const std::string &pattern TSRMLS_DC);

class NoHostVerificationAccessManager: public AccessManager {
public:
// AccessManager interface
Decision verify(const sockaddr_storage& sa) throw();
Decision verify(const std::string& host, const char* name, int size) throw();
Decision verify(const sockaddr_storage& sa, const char* data, int size) throw();
};
#endif /* _PHP_PDO_CASSANDRA_PRIVATE_H_ */
2 changes: 1 addition & 1 deletion tests/001-construct.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Test pdo cassandra construction

require_once(dirname(__FILE__) . '/config.inc');

$db = new PDO($dsn, $username, $password);
$db = new PDO($dsn, $username, $password, $params);

echo "OK";

Expand Down
2 changes: 1 addition & 1 deletion tests/002-select.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Test prepared statement emulation
<?php
require_once(dirname(__FILE__) . '/config.inc');

$db = new PDO($dsn, $username, $password);
$db = new PDO($dsn, $username, $password, $params);

pdo_cassandra_init ($db, $keyspace);

Expand Down
2 changes: 1 addition & 1 deletion tests/003-transaction.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Test transaction
<?php
require_once(dirname(__FILE__) . '/config.inc');

$db = new PDO($dsn, $username, $password);
$db = new PDO($dsn, $username, $password, $params);

try {
$db->beginTransaction();
Expand Down
2 changes: 1 addition & 1 deletion tests/004-columnmeta.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Test column metadata
<?php
require_once(dirname(__FILE__) . '/config.inc');

$db = new PDO($dsn, $username, $password);
$db = new PDO($dsn, $username, $password, $params);

$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Expand Down
2 changes: 1 addition & 1 deletion tests/005-attributes.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Test setting/getting attributes
--FILE--
<?php
require_once(dirname(__FILE__) . '/config.inc');
$db = new PDO($dsn, $username, $password);
$db = new PDO($dsn, $username, $password, $params);

var_dump ($db->getAttribute (PDO::ATTR_SERVER_VERSION));
var_dump ($db->setAttribute (PDO::CASSANDRA_ATTR_NUM_RETRIES, 10));
Expand Down
2 changes: 1 addition & 1 deletion tests/006-iterate.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Test iterating prepared statement
<?php
require_once(dirname(__FILE__) . '/config.inc');

$db = new PDO($dsn, $username, $password);
$db = new PDO($dsn, $username, $password, $params);

pdo_cassandra_init ($db, $keyspace);

Expand Down
2 changes: 1 addition & 1 deletion tests/007-fetchgrouped.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Test fetching grouped columns
<?php
require_once(dirname(__FILE__) . '/config.inc');

$db = new PDO($dsn, $username, $password);
$db = new PDO($dsn, $username, $password, $params);

pdo_cassandra_init ($db, $keyspace);

Expand Down
2 changes: 1 addition & 1 deletion tests/008-executemultiple.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Test execute prepared statement multiple times

require_once(dirname(__FILE__) . '/config.inc');

$db = new PDO($dsn, $username, $password);
$db = new PDO($dsn, $username, $password, $params);

pdo_cassandra_init ($db, $keyspace);

Expand Down
2 changes: 1 addition & 1 deletion tests/010-auth.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Test authentication
<?php
require_once(dirname(__FILE__) . '/config.inc');

$db = new PDO($dsn, $username, $password);
$db = new PDO($dsn, $username, $password, $params);
echo "OK";

?>
Expand Down
4 changes: 2 additions & 2 deletions tests/011-persistentconnection.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ Test initialization of persistent connections

require_once(dirname(__FILE__) . '/config.inc');

$db = new PDO($dsn, $username, $password, array (
$db = new PDO($dsn, $username, $password, array_merge($params, array (
PDO::ATTR_PERSISTENT => true
));
)));

echo "OK";

Expand Down
Loading

0 comments on commit b140d2f

Please sign in to comment.