Skip to content

Commit

Permalink
Merge pull request #7 from cleverage/feature/add-way-to-disable-encry…
Browse files Browse the repository at this point in the history
…ption

Add a enabler to allow values to not be decrypted or encrypted temporary
  • Loading branch information
johnkrovitch authored Dec 4, 2020
2 parents 272ca6b + f3f0ff4 commit 67bdc38
Show file tree
Hide file tree
Showing 11 changed files with 283 additions and 59 deletions.
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,35 @@ key which can prove to be tricky, especially if users already have accounts and

If each user encrypts it's own data however, you can just use the automatic encryption key generation in your
config.yml:
```
```yaml
sidus_encryption:
encryption_key:
auto_generate: false
throw_exceptions: true # Do not throw an exception when an error occurred when decrypting a value
```
This will tell the system to automatically generate a new encryption key if the user doesn't have any.
In case of password recovery, the user won't be able to retrieve any of the encrypted data because he would be the only
one able to decrypt the cipher key.
Disable Encryption
------------------
The encryption can be temporary disabled on an encrypted type (in a command for example). This can be achieved using
the `Sidus\EncryptionBundle\Encryption\Enabler\EncryptionEnablerInterface` service:
```php
// ...
$encryptionEnabler->disableEncryption();
// Starting from here, data will not be decrypted
$encryptionManager->decryptString($value); // The value will not be decrypted
$encryptionManager->encryptString($value); // The value will not be encrypted and store as is
$encryptionEnabler->enableEncryption();
// Now the encryption is re-enabled and works normally
```

Apache License
--------------
@todo
Expand Down
17 changes: 13 additions & 4 deletions src/Doctrine/Connection/Factory/ConnectionFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Type;
use Sidus\EncryptionBundle\Doctrine\Type\EncryptTypeInterface;
use Sidus\EncryptionBundle\Encryption\Enabler\EncryptionEnablerInterface;
use Sidus\EncryptionBundle\Registry\EncryptionManagerRegistry;

/**
Expand All @@ -22,20 +23,27 @@ class ConnectionFactory
private bool $initialized = false;

private EncryptionManagerRegistry $encryptionManager;

public function __construct(array $typesConfig, EncryptionManagerRegistry $encryptionManager)
{
private EncryptionEnablerInterface $encryptionEnabler;

public function __construct(
array $typesConfig,
EncryptionManagerRegistry $encryptionManager,
EncryptionEnablerInterface $encryptionEnabler
) {
$this->typesConfig = $typesConfig;
$this->encryptionManager = $encryptionManager;
$this->encryptionEnabler = $encryptionEnabler;
}

/**
* Create a connection by name.
*
* @param mixed[] $params
* @param string[]|Type[] $mappingTypes
*
* @return Connection
*
* @throws \Doctrine\DBAL\Exception
*/
public function createConnection(array $params, Configuration $config = null, EventManager $eventManager = null, array $mappingTypes = []): Connection
{
Expand Down Expand Up @@ -129,6 +137,7 @@ private function initializeTypes() : void

if ($type instanceof EncryptTypeInterface) {
$type->setEncryptionManager($this->encryptionManager->getDefaultEncryptionManager());
$type->setEncryptionEnabler($this->encryptionEnabler);
}
}
$this->initialized = true;
Expand Down
44 changes: 44 additions & 0 deletions src/Doctrine/Type/Behavior/EncryptType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

namespace Sidus\EncryptionBundle\Doctrine\Type\Behavior;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Sidus\EncryptionBundle\Encryption\Enabler\EncryptionEnablerInterface;
use Sidus\EncryptionBundle\Manager\EncryptionManagerInterface;

trait EncryptType
{
private EncryptionManagerInterface $encryptionManager;
private EncryptionEnablerInterface $encryptionEnabler;

public function convertToPHPValue($value, AbstractPlatform $platform)
{
// Allow to do not decrypt the value for the current request
if (!$this->encryptionEnabler->isEncryptionEnabled()) {
return $value;
}

return $this->encryptionManager->decryptString(base64_decode($value));
}

public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
// Allow to do not decrypt the value for the current request
if (!$this->encryptionEnabler->isEncryptionEnabled()) {
return $value;
}
$value = $this->encryptionManager->encryptString($value);

return base64_encode($value);
}

public function setEncryptionManager(EncryptionManagerInterface $encryptionManager): void
{
$this->encryptionManager = $encryptionManager;
}

public function setEncryptionEnabler(EncryptionEnablerInterface $encryptionEnabler): void
{
$this->encryptionEnabler = $encryptionEnabler;
}
}
26 changes: 3 additions & 23 deletions src/Doctrine/Type/EncryptStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,14 @@

namespace Sidus\EncryptionBundle\Doctrine\Type;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\StringType;
use Sidus\EncryptionBundle\Manager\EncryptionManagerInterface;
use Sidus\EncryptionBundle\Doctrine\Type\Behavior\EncryptType;

class EncryptStringType extends StringType implements EncryptTypeInterface
{
private EncryptionManagerInterface $encryptionManager;
use EncryptType;

public function convertToPHPValue($value, AbstractPlatform $platform)
{
$value = base64_decode($value);

return $this->encryptionManager->decryptString($value);
}

public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
$value = $this->encryptionManager->encryptString($value);

return base64_encode($value);
}

public function setEncryptionManager(EncryptionManagerInterface $encryptionManager): void
{
$this->encryptionManager = $encryptionManager;
}

public function getName()
public function getName(): string
{
return 'encrypt_string';
}
Expand Down
24 changes: 2 additions & 22 deletions src/Doctrine/Type/EncryptTextType.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,12 @@

namespace Sidus\EncryptionBundle\Doctrine\Type;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\TextType;
use Sidus\EncryptionBundle\Manager\EncryptionManagerInterface;
use Sidus\EncryptionBundle\Doctrine\Type\Behavior\EncryptType;

class EncryptTextType extends TextType implements EncryptTypeInterface
{
private EncryptionManagerInterface $encryptionManager;

public function convertToPHPValue($value, AbstractPlatform $platform)
{
$value = base64_decode($value);

return $this->encryptionManager->decryptString($value);
}

public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
$value = $this->encryptionManager->encryptString($value);

return base64_encode($value);
}

public function setEncryptionManager(EncryptionManagerInterface $encryptionManager): void
{
$this->encryptionManager = $encryptionManager;
}
use EncryptType;

public function getName()
{
Expand Down
3 changes: 3 additions & 0 deletions src/Doctrine/Type/EncryptTypeInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

namespace Sidus\EncryptionBundle\Doctrine\Type;

use Sidus\EncryptionBundle\Encryption\Enabler\EncryptionEnablerInterface;
use Sidus\EncryptionBundle\Manager\EncryptionManagerInterface;

interface EncryptTypeInterface
{
public function setEncryptionManager(EncryptionManagerInterface $encryptionManager): void;

public function setEncryptionEnabler(EncryptionEnablerInterface $encryptionEnabler): void;
}
28 changes: 28 additions & 0 deletions src/Encryption/Enabler/EncryptionEnabler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Sidus\EncryptionBundle\Encryption\Enabler;

class EncryptionEnabler implements EncryptionEnablerInterface
{
/**
* By default the encryption is enabled.
*
* @var bool
*/
private bool $enabled = true;

public function enableEncryption(): void
{
$this->enabled = true;
}

public function disableEncryption(): void
{
$this->enabled = false;
}

public function isEncryptionEnabled(): bool
{
return $this->enabled;
}
}
23 changes: 23 additions & 0 deletions src/Encryption/Enabler/EncryptionEnablerInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Sidus\EncryptionBundle\Encryption\Enabler;

interface EncryptionEnablerInterface
{
/**
* Enable the encryption for the current request.
*/
public function enableEncryption(): void;

/**
* Disable the encryption for the current request.
*/
public function disableEncryption(): void;

/**
* Return if the encryption is enabled in the current request.
*
* @return bool
*/
public function isEncryptionEnabled(): bool;
}
4 changes: 4 additions & 0 deletions src/Resources/config/services/encryption.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ services:
public: false
tags:
- { name: sidus.encryption.adapter }

Sidus\EncryptionBundle\Encryption\Enabler\EncryptionEnabler:
class: Sidus\EncryptionBundle\Encryption\Enabler\EncryptionEnabler
public: false
73 changes: 70 additions & 3 deletions tests/PHPUnit/Doctrine/Type/EncryptStringTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,23 @@
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Sidus\EncryptionBundle\Doctrine\Type\EncryptStringType;
use Sidus\EncryptionBundle\Encryption\Enabler\EncryptionEnablerInterface;
use Sidus\EncryptionBundle\Manager\EncryptionManagerInterface;

class EncryptStringTypeTest extends TestCase
{
public function testConvertToPHPValue(): void
{
[$type, $encryptionManager] = $this->createType();
[$type, $encryptionManager, $encryptionEnabler] = $this->createType();
$encryptedString = '\X666';
$platform = $this->createMock(MySqlPlatform::class);

$encryptionEnabler
->expects($this->once())
->method('isEncryptionEnabled')
->willReturn(true)
;

// The type SHOULD decrypt the encrypted string
$encryptionManager
->expects($this->once())
Expand All @@ -28,12 +35,40 @@ public function testConvertToPHPValue(): void
$this->assertEquals('my_decrypted_string', $value);
}

public function testConvertToPHPValueWithEncryptionDisabled(): void
{
[$type, $encryptionManager, $encryptionEnabler] = $this->createType();
$encryptedString = '\X666';
$platform = $this->createMock(MySqlPlatform::class);

$encryptionEnabler
->expects($this->once())
->method('isEncryptionEnabled')
->willReturn(false)
;

// The type SHOULD not encrypt the encrypted string if the encryption is disabled
$encryptionManager
->expects($this->never())
->method('decryptString')
;

$value = $type->convertToPHPValue($encryptedString, $platform);
$this->assertEquals('\X666', $value);
}

public function testConvertToDatabaseValue(): void
{
[$type, $encryptionManager] = $this->createType();
[$type, $encryptionManager, $encryptionEnabler] = $this->createType();
$string = 'my_string';
$platform = $this->createMock(MySqlPlatform::class);

$encryptionEnabler
->expects($this->once())
->method('isEncryptionEnabled')
->willReturn(true)
;

// The type SHOULD decrypt the encrypted string
$encryptionManager
->expects($this->once())
Expand All @@ -46,15 +81,47 @@ public function testConvertToDatabaseValue(): void
$this->assertEquals(base64_encode('my_encrypted_string'), $value);
}

public function testConvertToDatabaseValueWithEncryptionDisabled(): void
{
[$type, $encryptionManager, $encryptionEnabler] = $this->createType();
$string = 'my_string';
$platform = $this->createMock(MySqlPlatform::class);

$encryptionEnabler
->expects($this->once())
->method('isEncryptionEnabled')
->willReturn(false)
;

// The type SHOULD not decrypt the encrypted string if the encryption is disabled
$encryptionManager
->expects($this->never())
->method('encryptString')
;

$value = $type->convertToDatabaseValue($string, $platform);
$this->assertEquals('my_string', $value);
}

public function testGetName(): void
{
[$type] = $this->createType();

$this->assertEquals('encrypt_string', $type->getName());
}

/**
* @return EncryptStringType[]|MockObject[]
*/
private function createType(): array
{
$encryptionManager = $this->createMock(EncryptionManagerInterface::class);
$encryptionEnabler = $this->createMock(EncryptionEnablerInterface::class);

$type = new EncryptStringType();
$type->setEncryptionManager($encryptionManager);
$type->setEncryptionEnabler($encryptionEnabler);

return [$type, $encryptionManager];
return [$type, $encryptionManager, $encryptionEnabler];
}
}
Loading

0 comments on commit 67bdc38

Please sign in to comment.