Skip to content
This repository was archived by the owner on Oct 20, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ Before make test:

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

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

# Create a debian package from the sources

add "deb http://debian.datastax.com/community stable main" in your apt sources list
Expand Down
122 changes: 116 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 PasswordCallbackTSSLSocketFactory);
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_key_passphrase = 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,47 @@ 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_key_passphrase = pdo_attr_strval(driver_options, static_cast <pdo_attribute_type>(PDO_CASSANDRA_ATTR_SSL_KEY_PASSPHRASE), 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) {
if (ssl_key_passphrase) {
H->factory->setPassword(ssl_key_passphrase);
H->factory->overrideDefaultPasswordCallback();
}
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 +356,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 +395,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 +543,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 +675,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 +700,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 +737,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 +889,37 @@ 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);
}

void PasswordCallbackTSSLSocketFactory::getPassword(std::string& password/* password */, int length/* size */) {
password = sslkeyPassphrase_;
}

/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(pdo_cassandra)
{
Expand Down Expand Up @@ -854,6 +954,16 @@ 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_KEY_PASSPHRASE", PDO_CASSANDRA_ATTR_SSL_KEY_PASSPHRASE);
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
36 changes: 34 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 All @@ -63,6 +64,8 @@ using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace org::apache::cassandra;

class PasswordCallbackTSSLSocketFactory;

enum pdo_cassandra_type {
PDO_CASSANDRA_TYPE_UTF8 = PDO_PARAM_STR,
PDO_CASSANDRA_TYPE_INTEGER = PDO_PARAM_INT,
Expand Down Expand Up @@ -103,6 +106,8 @@ typedef struct {
typedef struct {
zend_object zo;
zend_bool compression;
boost::shared_ptr<PasswordCallbackTSSLSocketFactory> 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 +119,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 +158,14 @@ 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_KEY_PASSPHRASE,
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 +193,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 +206,22 @@ 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();
};

class PasswordCallbackTSSLSocketFactory: public TSSLSocketFactory {
public:
void setPassword(const char *passphrase) {
sslkeyPassphrase_ = passphrase;
}
protected:
void getPassword(std::string& /* password */, int /* size */);
private:
std::string sslkeyPassphrase_;
};
#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
Loading