diff --git a/library/EngineBlock/Corto/Model/Consent.php b/library/EngineBlock/Corto/Model/Consent.php index 88cc70d26e..10ca0308a1 100644 --- a/library/EngineBlock/Corto/Model/Consent.php +++ b/library/EngineBlock/Corto/Model/Consent.php @@ -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; @@ -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); } /** @@ -160,9 +145,6 @@ 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, @@ -170,23 +152,7 @@ private function _storeConsent(ServiceProvider $serviceProvider, $consentType): $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 @@ -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); } } diff --git a/library/EngineBlock/Corto/Model/Consent/Factory.php b/library/EngineBlock/Corto/Model/Consent/Factory.php index 66f0e865c4..396abd1065 100644 --- a/library/EngineBlock/Corto/Model/Consent/Factory.php +++ b/library/EngineBlock/Corto/Model/Consent/Factory.php @@ -16,6 +16,8 @@ * limitations under the License. */ +use OpenConext\EngineBlock\Service\Consent\ConsentHashService; + /** * @todo write a test */ diff --git a/src/OpenConext/EngineBlock/Service/Consent/ConsentHashRepository.php b/src/OpenConext/EngineBlock/Service/Consent/ConsentHashRepository.php new file mode 100644 index 0000000000..8d2da7c3f7 --- /dev/null +++ b/src/OpenConext/EngineBlock/Service/Consent/ConsentHashRepository.php @@ -0,0 +1,104 @@ +_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(); + } +} diff --git a/src/OpenConext/EngineBlock/Service/Consent/ConsentHashService.php b/src/OpenConext/EngineBlock/Service/Consent/ConsentHashService.php index 298ec00d2e..4e0a0ca767 100644 --- a/src/OpenConext/EngineBlock/Service/Consent/ConsentHashService.php +++ b/src/OpenConext/EngineBlock/Service/Consent/ConsentHashService.php @@ -18,6 +18,7 @@ namespace OpenConext\EngineBlock\Service\Consent; +use PDO; use function array_filter; use function array_keys; use function array_values; @@ -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) { @@ -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); } @@ -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); } @@ -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]); } } @@ -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); } } diff --git a/src/OpenConext/EngineBlockBundle/Resources/config/services.yml b/src/OpenConext/EngineBlockBundle/Resources/config/services.yml index e658fb96f3..2b11e8a39a 100644 --- a/src/OpenConext/EngineBlockBundle/Resources/config/services.yml +++ b/src/OpenConext/EngineBlockBundle/Resources/config/services.yml @@ -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" diff --git a/tests/unit/OpenConext/EngineBlock/Service/Consent/ConsentHashServiceTest.php b/tests/unit/OpenConext/EngineBlock/Service/Consent/ConsentHashServiceTest.php index d2454e3556..c0e8f87d9f 100644 --- a/tests/unit/OpenConext/EngineBlock/Service/Consent/ConsentHashServiceTest.php +++ b/tests/unit/OpenConext/EngineBlock/Service/Consent/ConsentHashServiceTest.php @@ -18,10 +18,14 @@ 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 */ @@ -29,7 +33,8 @@ class ConsentHashServiceTest extends TestCase 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()