Skip to content

Commit

Permalink
FIX AWS SDK PHP DynamoDb StandardSessionConnection binary safety
Browse files Browse the repository at this point in the history
  • Loading branch information
dnsl48 committed Jul 1, 2019
1 parent 785c697 commit 59b958f
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 8 deletions.
8 changes: 4 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ env:
matrix:
fast_finish: true
include:
- php: 5.6
env: DB=MYSQL PHPUNIT_TEST=1 PHPCS_TEST=1
- php: 7.0
env: DB=MYSQL PHPUNIT_TEST=1
- php: 7.1
env: DB=MYSQL PHPUNIT_TEST=1
- php: 7.2
env: DB=MYSQL PHPUNIT_TEST=1 PHPCS_TEST=1
- php: 7.3
env: DB=MYSQL PHPUNIT_TEST=1

before_script:
- composer self-update || true
Expand Down
81 changes: 81 additions & 0 deletions code/DynamoDbClient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

namespace SilverStripe\DynamoDb;

/**
* DynamoDbClient extension that handles sessions as binary strings rather than textual content.
*
* Current AWS SDK PHP (<= 3.102.1) implementation passes session data as 'S'.
* This class overloads DynamoDbClient::updateItem method, intercepts the session table updates
* and substitutes the data type from 'S' to 'B' (from string to binary).
* PHP string is the php binary data type, so this should work seamlessly.
*
* @see https://github.com/silverstripe/silverstripe-dynamodb/issues/32
*/
class DynamoDbClient extends \Aws\DynamoDb\DynamoDbClient
{
/**
* The name of the DynamoDB table where
* sessions are stored
*
* @var string
*/
private $sessionTable;

/**
* The name of the data attribute of the session table
* where sessions are stored
*
* @var string
*/
private $dataAttribute;

/**
* Initialize the client with the session table
*
* @param string $sessionTable The session table name
*
* {@inheritdoc}
*/
public function __construct($sessionTable, ...$args)
{
$this->sessionTable = $sessionTable;
parent::__construct(...$args);
}

/**
* Initialize the client with the session data attribute (within the session table)
* This method must be used to finish the client initialization, otherwise session updates will not be
* intercepted and amended
*
* @param string $dataAttribute attribute of the session table where session data is persisted
*/
public function setSessionTableDataAttribute($dataAttribute)
{
$this->dataAttribute = $dataAttribute;
}

public function updateItem($attributes, ...$extra)
{
$this->patchSessionUpdate($attributes);
return parent::updateItem($attributes, ...$extra);
}

/**
* Update the session data type from 'S' to 'B' (from string to binary)
*
* @param mixed &$data Data to be updated in-place
*/
private function patchSessionUpdate(&$data) {
if (!isset($data['TableName']) || $data['TableName'] !== $this->sessionTable) {
return;
}

if (!isset($data['AttributeUpdates'][$this->dataAttribute]['Value']['S'])) {
return;
}

$data['AttributeUpdates'][$this->dataAttribute]['Value']['B'] = $data['AttributeUpdates'][$this->dataAttribute]['Value']['S'];
unset($data['AttributeUpdates'][$this->dataAttribute]['Value']['S']);
}
}
7 changes: 4 additions & 3 deletions code/Model/DynamoDbSession.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

namespace SilverStripe\DynamoDb\Model;

use Aws\DynamoDb\DynamoDbClient;
use Aws\DynamoDb\SessionHandler;
use SilverStripe\DynamoDb\DynamoDbClient;
use SilverStripe\DynamoDb\SessionHandler;
use Aws\DoctrineCacheAdapter;
use Doctrine\Common\Cache\ApcuCache;
use SilverStripe\Core\Config\Config;
Expand Down Expand Up @@ -78,7 +78,8 @@ public static function get()

public function __construct($options, $table)
{
$this->client = new DynamoDbClient(array_merge(['version' => '2012-08-10'], $options));
$this->client = new DynamoDbClient($table, array_merge(['version' => '2012-08-10'], $options));

$this->table = $table;
$this->handler = SessionHandler::fromClient(
$this->client,
Expand Down
36 changes: 36 additions & 0 deletions code/SessionHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace SilverStripe\DynamoDb;

use Aws\DynamoDb\SessionConnectionInterface;

/**
* The only purpose of this class is to finish our custom
* \SilverStripe\DynamoDb\DynamoDbClient initialization.
* To do so it simply needs to pass session data attribute
* from SessionConnection to DynamoDbClient::setSessionTableDataAttribute
* so the latter may intercept session table updates intelligently.
*
* @see \SilverStripe\DynamoDb\DynamoDbClient
*/
class SessionHandler extends \Aws\DynamoDb\SessionHandler
{
/**
* @var SessionConnectionInterface
*/
private $connection;

public static function fromClient(\Aws\DynamoDb\DynamoDbClient $client, array $config = [])
{
$handler = parent::fromClient($client, $config);
$client->setSessionTableDataAttribute($handler->connection->getDataAttribute());

return $handler;
}

public function __construct(SessionConnectionInterface $connection)
{
$this->connection = $connection;
parent::__construct($connection);
}
}
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"silverstripe/framework": "^4@dev"
},
"require-dev": {
"phpunit/PHPUnit": "^5.7"
"phpunit/PHPUnit": "^5.7",
"squizlabs/php_codesniffer": "^3.0",
},
"autoload": {
"psr-4": {
Expand Down

0 comments on commit 59b958f

Please sign in to comment.