Skip to content

Commit

Permalink
Move DB logic to ConsentHashRepository
Browse files Browse the repository at this point in the history
  • Loading branch information
Koen Cornelis committed May 20, 2021
1 parent 074c009 commit dff4b53
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 85 deletions.
103 changes: 25 additions & 78 deletions library/EngineBlock/Corto/Model/Consent.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,22 +59,16 @@ class EngineBlock_Corto_Model_Consent
private $_hashService;

/**
* @param string $tableName
* @param bool $mustStoreValues
* @param EngineBlock_Saml2_ResponseAnnotationDecorator $response
* @param array $responseAttributes
* @param EngineBlock_Database_ConnectionFactory $databaseConnectionFactory
* @param bool $amPriorToConsentEnabled Is the run_all_manipulations_prior_to_consent feature enabled or not
* @param ConsentHashService $hashService
*/
public function __construct(
$tableName,
$mustStoreValues,
string $tableName,
bool $mustStoreValues,
EngineBlock_Saml2_ResponseAnnotationDecorator $response,
array $responseAttributes,
EngineBlock_Database_ConnectionFactory $databaseConnectionFactory,
$amPriorToConsentEnabled,
$hashService
bool $amPriorToConsentEnabled,
ConsentHashService $hashService
)
{
$this->_tableName = $tableName;
Expand Down Expand Up @@ -106,24 +100,15 @@ public function giveImplicitConsentFor(ServiceProvider $serviceProvider): bool
return $this->_storeConsent($serviceProvider, ConsentType::TYPE_IMPLICIT);
}

/**
* @throws EngineBlock_Exception
*/
public function countTotalConsent(): int
{
$dbh = $this->_getConsentDatabaseConnection();
$hashedUserId = sha1($this->_getConsentUid());
$query = "SELECT COUNT(*) FROM consent where hashed_user_id = ?";
$parameters = array($hashedUserId);
$statement = $dbh->prepare($query);
if (!$statement) {
throw new EngineBlock_Exception(
"Unable to create a prepared statement to count consent?!", EngineBlock_Exception::CODE_ALERT
);
if (!$dbh) {
return 0;
}
/** @var $statement PDOStatement */
$statement->execute($parameters);
return (int)$statement->fetchColumn();

$consentUid = $this->_getConsentUid();
return $this->_hashService->countTotalConsent($dbh, $consentUid);
}

/**
Expand Down Expand Up @@ -160,33 +145,14 @@ private function _storeConsent(ServiceProvider $serviceProvider, $consentType):
return false;
}

$query = "INSERT INTO consent (hashed_user_id, service_id, attribute, consent_type, consent_date)
VALUES (?, ?, ?, ?, NOW())
ON DUPLICATE KEY UPDATE attribute=VALUES(attribute), consent_type=VALUES(consent_type), consent_date=NOW()";
$parameters = array(
sha1($this->_getConsentUid()),
$serviceProvider->entityId,
$this->_getStableAttributesHash($this->_responseAttributes),
$consentType,
);

$statement = $dbh->prepare($query);
if (!$statement) {
throw new EngineBlock_Exception(
"Unable to create a prepared statement to insert consent?!",
EngineBlock_Exception::CODE_CRITICAL
);
}

/** @var $statement PDOStatement */
if (!$statement->execute($parameters)) {
throw new EngineBlock_Corto_Module_Services_Exception(
sprintf('Error storing consent: "%s"', var_export($statement->errorInfo(), true)),
EngineBlock_Exception::CODE_CRITICAL
);
}

return true;
return $this->_hashService->storeConsentHashInDb($dbh, $parameters);
}

private function _hasStoredConsent(ServiceProvider $serviceProvider, $consentType): bool
Expand All @@ -196,45 +162,26 @@ private function _hasStoredConsent(ServiceProvider $serviceProvider, $consentTyp
return false;
}

$unstableConsentHash = $this->_getAttributesHash($this->_responseAttributes);
$hasUnstableConsentHash = $this->retrieveConsentHashFromDb($dbh, $serviceProvider, $consentType, $unstableConsentHash);
$parameters = array(
sha1($this->_getConsentUid()),
$serviceProvider->entityId,
$this->_getAttributesHash($this->_responseAttributes),
$consentType,
);

$hasUnstableConsentHash = $this->_hashService->retrieveConsentHashFromDb($dbh, $parameters);

if ($hasUnstableConsentHash) {
return true;
}

$stableConsentHash = $this->_getStableAttributesHash($this->_responseAttributes);
return $this->retrieveConsentHashFromDb($dbh, $serviceProvider, $consentType, $stableConsentHash);
}

private function retrieveConsentHashFromDb(PDO $dbh, ServiceProvider $serviceProvider, $consentType, $attributesHash): bool
{
try {
$query = "SELECT * FROM {$this->_tableName} WHERE hashed_user_id = ? AND service_id = ? AND attribute = ? AND consent_type = ?";
$hashedUserId = sha1($this->_getConsentUid());
$parameters = array(
$hashedUserId,
$serviceProvider->entityId,
$attributesHash,
$consentType,
);

/** @var $statement PDOStatement */
$statement = $dbh->prepare($query);
$statement->execute($parameters);
$rows = $statement->fetchAll();

if (count($rows) < 1) {
// No stored consent found
return false;
}
$parameters[2] = array(
sha1($this->_getConsentUid()),
$serviceProvider->entityId,
$this->_getStableAttributesHash($this->_responseAttributes),
$consentType,
);

return true;
} catch (PDOException $e) {
throw new EngineBlock_Corto_ProxyServer_Exception(
sprintf('Consent retrieval failed! Error: "%s"', $e->getMessage()),
EngineBlock_Exception::CODE_ALERT
);
}
return $this->_hashService->retrieveConsentHashFromDb($dbh, $parameters);
}
}
2 changes: 2 additions & 0 deletions library/EngineBlock/Corto/Model/Consent/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
* limitations under the License.
*/

use OpenConext\EngineBlock\Service\Consent\ConsentHashService;

/**
* @todo write a test
*/
Expand Down
104 changes: 104 additions & 0 deletions src/OpenConext/EngineBlock/Service/Consent/ConsentHashRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

/**
* Copyright 2010 SURFnet B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace OpenConext\EngineBlock\Service\Consent;

use EngineBlock_Corto_Module_Services_Exception;
use EngineBlock_Corto_ProxyServer_Exception;
use EngineBlock_Exception;
use PDO;
use PDOException;
use PDOStatement;

class ConsentHashRepository
{
/**
* @throws EngineBlock_Corto_ProxyServer_Exception
*/
public function retrieveConsentHashFromDb(PDO $dbh, array $parameters): bool
{
try {
$query = "SELECT * FROM {$this->_tableName} WHERE hashed_user_id = ? AND service_id = ? AND attribute = ? AND consent_type = ?";

/** @var $statement PDOStatement */
$statement = $dbh->prepare($query);
$statement->execute($parameters);
$rows = $statement->fetchAll();

if (count($rows) < 1) {
// No stored consent found
return false;
}

return true;
} catch (PDOException $e) {
throw new EngineBlock_Corto_ProxyServer_Exception(
sprintf('Consent retrieval failed! Error: "%s"', $e->getMessage()),
EngineBlock_Exception::CODE_ALERT
);
}
}

/**
* @throws EngineBlock_Corto_Module_Services_Exception
* @throws EngineBlock_Exception
*/
public function storeConsentHashInDb(PDO $dbh, array $parameters): bool
{
$query = "INSERT INTO consent (hashed_user_id, service_id, attribute, consent_type, consent_date)
VALUES (?, ?, ?, ?, NOW())
ON DUPLICATE KEY UPDATE attribute=VALUES(attribute), consent_type=VALUES(consent_type), consent_date=NOW()";

$statement = $dbh->prepare($query);
if (!$statement) {
throw new EngineBlock_Exception(
"Unable to create a prepared statement to insert consent?!",
EngineBlock_Exception::CODE_CRITICAL
);
}

/** @var $statement PDOStatement */
if (!$statement->execute($parameters)) {
throw new EngineBlock_Corto_Module_Services_Exception(
sprintf('Error storing consent: "%s"', var_export($statement->errorInfo(), true)),
EngineBlock_Exception::CODE_CRITICAL
);
}

return true;
}

/**
* @throws EngineBlock_Exception
*/
public function countTotalConsent(PDO $dbh, $consentUid): int
{
$query = "SELECT COUNT(*) FROM consent where hashed_user_id = ?";
$parameters = array(sha1($consentUid));
$statement = $dbh->prepare($query);
if (!$statement) {
throw new EngineBlock_Exception(
"Unable to create a prepared statement to count consent?!",
EngineBlock_Exception::CODE_ALERT
);
}
/** @var $statement PDOStatement */
$statement->execute($parameters);
return (int)$statement->fetchColumn();
}
}
39 changes: 34 additions & 5 deletions src/OpenConext/EngineBlock/Service/Consent/ConsentHashService.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

namespace OpenConext\EngineBlock\Service\Consent;

use PDO;
use function array_filter;
use function array_keys;
use function array_values;
Expand All @@ -34,7 +35,32 @@

final class ConsentHashService
{
public function getUnstableAttributesHash(array $attributes,bool $mustStoreValues): string
/**
* @var ConsentHashRepository
*/
private $consentHashRepository;

public function __construct(ConsentHashRepository $consentHashRepository)
{
$this->consentHashRepository = $consentHashRepository;
}

public function retrieveConsentHashFromDb(PDO $dbh, array $parameters): bool
{
return $this->consentHashRepository->retrieveConsentHashFromDb($dbh, $parameters);
}

public function storeConsentHashInDb(PDO $dbh, array $parameters): bool
{
return $this->consentHashRepository->storeConsentHashInDb($dbh, $parameters);
}

public function countTotalConsent(PDO $dbh, $consentUid): int
{
return $this->consentHashRepository->countTotalConsent($dbh, $consentUid);
}

public function getUnstableAttributesHash(array $attributes, bool $mustStoreValues): string
{
$hashBase = null;
if ($mustStoreValues) {
Expand All @@ -51,7 +77,9 @@ public function getUnstableAttributesHash(array $attributes,bool $mustStoreValue
public function getStableAttributesHash(array $attributes, bool $mustStoreValues) : string
{
$lowerCasedAttributes = $this->caseNormalizeStringArray($attributes);
$hashBase = $mustStoreValues ? $this->createHashBaseWithValues($lowerCasedAttributes) : $this->createHashBaseWithoutValues($lowerCasedAttributes);
$hashBase = $mustStoreValues
? $this->createHashBaseWithValues($lowerCasedAttributes)
: $this->createHashBaseWithoutValues($lowerCasedAttributes);

return sha1($hashBase);
}
Expand Down Expand Up @@ -86,7 +114,7 @@ private function sortArray(array $sortMe): array
$sortFunction = 'ksort';
$copy = $this->removeEmptyAttributes($copy);

if($this->isSequentialArray($copy)){
if ($this->isSequentialArray($copy)) {
$sortFunction = 'sort';
$copy = $this->renumberIndices($copy);
}
Expand Down Expand Up @@ -126,7 +154,7 @@ private function removeEmptyAttributes(array $array): array
$copy = unserialize(serialize($array));

foreach ($copy as $key => $value) {
if ($this->is_blank($value)) {
if ($this->isBlank($value)) {
unset($copy[$key]);
}
}
Expand All @@ -141,7 +169,8 @@ private function removeEmptyAttributes(array $array): array
* - "0"
* @param $value array|string|integer|float
*/
private function is_blank($value): bool {
private function isBlank($value): bool
{
return empty($value) && !is_numeric($value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,10 @@ services:
tags:
- { name: 'twig.extension' }

engineblock.service.consent.ConsentHashRepository:
class: OpenConext\EngineBlock\Service\Consent\ConsentHashRepository

engineblock.service.consent.ConsentHashService:
class: OpenConext\EngineBlock\Service\Consent\ConsentHashService
public: false
arguments:
- "engineblock.service.consent.ConsentHashRepository"
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,23 @@

namespace OpenConext\EngineBlock\Service\Consent;

use Mockery as m;
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
use PHPUnit\Framework\TestCase;

class ConsentHashServiceTest extends TestCase
{
use MockeryPHPUnitIntegration;

/**
* @var ConsentHashService
*/
private $chs;

public function setUp()
{
$this->chs = new ConsentHashService();
$mockConsentHashRepository = m::mock('OpenConext\EngineBlock\Service\Consent\ConsentHashRepository');
$this->chs = new ConsentHashService($mockConsentHashRepository);
}

public function test_stable_attribute_hash_switched_order_associative_array()
Expand Down

0 comments on commit dff4b53

Please sign in to comment.