Skip to content

Commit 43b41b3

Browse files
authored
data protection follow up (#626)
* adapt defuse/php-ancryption as internal package adapting Ecotone coding standards * emphasize on message protection
1 parent fb35463 commit 43b41b3

File tree

67 files changed

+4819
-176
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+4819
-176
lines changed

.github/workflows/test-monorepo.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ jobs:
123123
- name: Test PHPStan
124124
run: vendor/bin/phpstan
125125

126+
- name: Create random file for encryption tests
127+
run: (cd packages/DataProtection && tests/before-tests.sh)
128+
126129
- name: Test PHPUnit on Postgres
127130
run: vendor/bin/phpunit --no-coverage
128131
env:

composer.json

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,17 +117,19 @@
117117
},
118118
"require": {
119119
"php": "^8.2",
120+
"ext-amqp": "*",
121+
"ext-openssl": "*",
120122
"doctrine/dbal": "^3.9|^4.0",
121123
"doctrine/persistence": "^2.5|^3.4",
122124
"defuse/php-encryption": "^2.4",
123125
"enqueue/amqp-lib": "^0.10.25",
124126
"enqueue/redis": "^0.10.9",
125127
"enqueue/sqs": "^0.10.15",
126128
"enqueue/enqueue": "^0.10.0",
127-
"ext-amqp": "*",
128129
"laminas/laminas-code": "^4",
129130
"jms/serializer": "^3.32",
130131
"laravel/framework": "^9.5.2|^10.0|^11.0|^12.0|^13.0",
132+
"paragonie/random_compat": "^2.0",
131133
"prooph/pdo-event-store": "^1.16.3",
132134
"psr/log": "^2.0|^3.0",
133135
"queue-interop/queue-interop": "^0.8",
@@ -172,7 +174,8 @@
172174
"symfony/monolog-bundle": "^3.10",
173175
"kwn/php-rdkafka-stubs": "^2.2",
174176
"symfony/var-exporter": "^6.4|^7.0|^8.0",
175-
"enqueue/dsn": "^0.10.27"
177+
"enqueue/dsn": "^0.10.27",
178+
"yoast/phpunit-polyfills": "^4.0.0"
176179
},
177180
"conflict": {
178181
"symfony/doctrine-messenger": ">7.0.5 < 7.1.0",
@@ -212,7 +215,10 @@
212215
},
213216
"scripts": {
214217
"tests:phpstan": "vendor/bin/phpstan",
215-
"tests:phpunit": "vendor/bin/phpunit --no-coverage",
218+
"tests:phpunit": [
219+
"(cd packages/DataProtection && tests/before-tests.sh)",
220+
"vendor/bin/phpunit --no-coverage"
221+
],
216222
"tests:behat": "vendor/bin/behat -vvv",
217223
"tests:ci": [
218224
"@tests:phpstan",

packages/DataProtection/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ file
77
.phpunit.result.cache
88
composer.lock
99
phpunit.xml
10+
11+
tests/Fixture/files/big-generated-file

packages/DataProtection/composer.json

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@
1919
"ecotone",
2020
"Encryption",
2121
"OpenSSL",
22-
"Data Protection",
23-
"Data Obfuscation"
22+
"Sensitive Data Protection",
23+
"Secure Messages"
2424
],
25-
"description": "Extends Ecotone with Data Protection features allowing to obfuscate messages with sensitive data.",
25+
"description": "Extends Ecotone with Data Protection features allowing to secure sensitive data.",
2626
"autoload": {
2727
"psr-4": {
2828
"Ecotone\\DataProtection\\": "src"
@@ -36,20 +36,23 @@
3636
}
3737
},
3838
"require": {
39+
"php": "^8.2",
3940
"ext-openssl": "*",
4041
"ecotone/ecotone": "~1.299.2",
4142
"ecotone/jms-converter": "~1.299.2",
42-
"defuse/php-encryption": "^2.4"
43+
"paragonie/random_compat": "^2.0"
4344
},
4445
"require-dev": {
45-
"phpunit/phpunit": "^9.5|^10.5|^11.0",
46-
"phpstan/phpstan": "^1.8",
47-
"psr/container": "^2.0",
46+
"phpunit/phpunit": "^11.0",
47+
"phpstan/phpstan": "^2.1",
4848
"wikimedia/composer-merge-plugin": "^2.1"
4949
},
5050
"scripts": {
5151
"tests:phpstan": "vendor/bin/phpstan",
52-
"tests:phpunit": "vendor/bin/phpunit --no-coverage --testdox",
52+
"tests:phpunit": [
53+
"tests/before-tests.sh",
54+
"vendor/bin/phpunit --no-coverage"
55+
],
5356
"tests:ci": [
5457
"@tests:phpstan",
5558
"@tests:phpunit"

packages/DataProtection/phpunit.xml.dist

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<phpunit
33
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4-
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
4+
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
55
backupGlobals="true"
66
>
7-
<coverage processUncoveredFiles="true">
7+
<source>
88
<include>
9-
<directory suffix=".php">./src</directory>
9+
<directory>./src</directory>
1010
</include>
11+
</source>
12+
<coverage>
1113
<report>
1214
<text outputFile="php://stdout" showOnlySummary="true" />
1315
</report>

packages/DataProtection/src/Configuration/ChannelProtectionConfiguration.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ public function channelName(): string
2525
return $this->channelName;
2626
}
2727

28-
public function obfuscatorConfig(): ObfuscatorConfig
28+
public function messageEncryptionConfig(): MessageEncryptionConfig
2929
{
30-
return new ObfuscatorConfig($this->encryptionKey, $this->isPayloadSensitive, $this->sensitiveHeaders);
30+
return new MessageEncryptionConfig($this->encryptionKey, $this->isPayloadSensitive, $this->sensitiveHeaders);
3131
}
3232

3333
public function withSensitivePayload(bool $isPayloadSensitive): self

packages/DataProtection/src/Configuration/DataProtectionConfiguration.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
namespace Ecotone\DataProtection\Configuration;
88

9-
use Defuse\Crypto\Key;
9+
use Ecotone\DataProtection\Encryption\Key;
1010
use Ecotone\Messaging\Support\Assert;
1111

1212
class DataProtectionConfiguration

packages/DataProtection/src/Configuration/DataProtectionModule.php

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77

88
namespace Ecotone\DataProtection\Configuration;
99

10-
use Defuse\Crypto\Key;
1110
use Ecotone\AnnotationFinder\AnnotatedMethod;
1211
use Ecotone\AnnotationFinder\AnnotationFinder;
1312
use Ecotone\DataProtection\Attribute\Sensitive;
1413
use Ecotone\DataProtection\Attribute\WithEncryptionKey;
1514
use Ecotone\DataProtection\Attribute\WithSensitiveHeader;
16-
use Ecotone\DataProtection\Obfuscator\Obfuscator;
15+
use Ecotone\DataProtection\Encryption\Key;
16+
use Ecotone\DataProtection\MessageEncryption\MessageEncryptor;
1717
use Ecotone\DataProtection\OutboundDecryptionChannelBuilder;
1818
use Ecotone\DataProtection\OutboundEncryptionChannelBuilder;
1919
use Ecotone\JMSConverter\JMSConverterConfiguration;
@@ -39,20 +39,23 @@
3939
#[ModuleAnnotation]
4040
final class DataProtectionModule extends NoExternalConfigurationModule
4141
{
42+
final public const ENCRYPTOR_SERVICE_ID_FORMAT = 'ecotone.data-protection.encryptor.%s';
43+
final public const KEY_SERVICE_ID_FORMAT = 'ecotone.encryption.key.%s';
44+
4245
/**
43-
* @param array<ObfuscatorConfig> $obfuscatorConfigs
46+
* @param array<MessageEncryptionConfig> $encryptionConfigs
4447
*/
45-
public function __construct(private array $obfuscatorConfigs)
48+
public function __construct(private array $encryptionConfigs)
4649
{
4750
}
4851

4952
public static function create(AnnotationFinder $annotationRegistrationService, InterfaceToCallRegistry $interfaceToCallRegistry): static
5053
{
51-
$obfuscatorConfigs = self::resolveObfuscatorConfigsFromAnnotatedClasses($annotationRegistrationService->findAnnotatedClasses(Sensitive::class), [], $interfaceToCallRegistry);
52-
$obfuscatorConfigs = self::resolveObfuscatorConfigsFromAnnotatedMethods($annotationRegistrationService->findAnnotatedMethods(CommandHandler::class), $obfuscatorConfigs, $interfaceToCallRegistry);
53-
$obfuscatorConfigs = self::resolveObfuscatorConfigsFromAnnotatedMethods($annotationRegistrationService->findAnnotatedMethods(EventHandler::class), $obfuscatorConfigs, $interfaceToCallRegistry);
54+
$encryptionConfigs = self::resolveEncryptionConfigsFromAnnotatedClasses($annotationRegistrationService->findAnnotatedClasses(Sensitive::class), $interfaceToCallRegistry);
55+
$encryptionConfigs = self::resolveEncryptionConfigsFromAnnotatedMethods($annotationRegistrationService->findAnnotatedMethods(CommandHandler::class), $encryptionConfigs, $interfaceToCallRegistry);
56+
$encryptionConfigs = self::resolveEncryptionConfigsFromAnnotatedMethods($annotationRegistrationService->findAnnotatedMethods(EventHandler::class), $encryptionConfigs, $interfaceToCallRegistry);
5457

55-
return new self($obfuscatorConfigs);
58+
return new self($encryptionConfigs);
5659
}
5760

5861
public function prepare(Configuration $messagingConfiguration, array $extensionObjects, ModuleReferenceSearchService $moduleReferenceSearchService, InterfaceToCallRegistry $interfaceToCallRegistry): void
@@ -70,7 +73,7 @@ public function prepare(Configuration $messagingConfiguration, array $extensionO
7073

7174
foreach ($dataProtectionConfiguration->keys() as $encryptionKeyName => $key) {
7275
$messagingConfiguration->registerServiceDefinition(
73-
id: sprintf('ecotone.encryption.key.%s', $encryptionKeyName),
76+
id: sprintf(self::KEY_SERVICE_ID_FORMAT, $encryptionKeyName),
7477
definition: new Definition(
7578
Key::class,
7679
[$key->saveToAsciiSafeString()],
@@ -79,39 +82,39 @@ public function prepare(Configuration $messagingConfiguration, array $extensionO
7982
);
8083
}
8184

82-
$channelObfuscatorReferences = $messageObfuscatorReferences = [];
85+
$channelEncryptorReferences = $messageEncryptorReferences = [];
8386
foreach ($channelProtectionConfigurations as $channelProtectionConfiguration) {
8487
Assert::isTrue($messagingConfiguration->isPollableChannel($channelProtectionConfiguration->channelName()), sprintf('`%s` channel must be pollable channel to use Data Protection.', $channelProtectionConfiguration->channelName()));
8588

86-
$obfuscatorConfig = $channelProtectionConfiguration->obfuscatorConfig();
89+
$encryptionConfig = $channelProtectionConfiguration->messageEncryptionConfig();
8790
$messagingConfiguration->registerServiceDefinition(
88-
id: $id = sprintf('ecotone.encryption.obfuscator.%s', $channelProtectionConfiguration->channelName()),
91+
id: $id = sprintf(self::ENCRYPTOR_SERVICE_ID_FORMAT, $channelProtectionConfiguration->channelName()),
8992
definition: new Definition(
90-
Obfuscator::class,
93+
MessageEncryptor::class,
9194
[
92-
Reference::to(sprintf('ecotone.encryption.key.%s', $obfuscatorConfig->encryptionKeyName($dataProtectionConfiguration))),
93-
$obfuscatorConfig->isPayloadSensitive,
94-
$obfuscatorConfig->sensitiveHeaders,
95+
Reference::to(sprintf(self::KEY_SERVICE_ID_FORMAT, $encryptionConfig->encryptionKeyName($dataProtectionConfiguration))),
96+
$encryptionConfig->isPayloadSensitive,
97+
$encryptionConfig->sensitiveHeaders,
9598
],
9699
)
97100
);
98101

99-
$channelObfuscatorReferences[$channelProtectionConfiguration->channelName()] = Reference::to($id);
102+
$channelEncryptorReferences[$channelProtectionConfiguration->channelName()] = Reference::to($id);
100103
}
101104

102-
foreach ($this->obfuscatorConfigs as $messageClass => $obfuscatorConfig) {
105+
foreach ($this->encryptionConfigs as $messageClass => $encryptionConfig) {
103106
$messagingConfiguration->registerServiceDefinition(
104-
id: $id = sprintf('ecotone.encryption.obfuscator.%s', $messageClass),
107+
id: $id = sprintf(self::ENCRYPTOR_SERVICE_ID_FORMAT, $messageClass),
105108
definition: new Definition(
106-
Obfuscator::class,
109+
MessageEncryptor::class,
107110
[
108-
Reference::to(sprintf('ecotone.encryption.key.%s', $obfuscatorConfig->encryptionKeyName($dataProtectionConfiguration))),
109-
$obfuscatorConfig->isPayloadSensitive,
110-
$obfuscatorConfig->sensitiveHeaders,
111+
Reference::to(sprintf(self::KEY_SERVICE_ID_FORMAT, $encryptionConfig->encryptionKeyName($dataProtectionConfiguration))),
112+
$encryptionConfig->isPayloadSensitive,
113+
$encryptionConfig->sensitiveHeaders,
111114
],
112115
)
113116
);
114-
$messageObfuscatorReferences[$messageClass] = Reference::to($id);
117+
$messageEncryptorReferences[$messageClass] = Reference::to($id);
115118
}
116119

117120
foreach (ExtensionObjectResolver::resolve(MessageChannelWithSerializationBuilder::class, $extensionObjects) as $pollableMessageChannel) {
@@ -122,15 +125,15 @@ public function prepare(Configuration $messagingConfiguration, array $extensionO
122125
$messagingConfiguration->registerChannelInterceptor(
123126
new OutboundEncryptionChannelBuilder(
124127
relatedChannel: $pollableMessageChannel->getMessageChannelName(),
125-
channelObfuscatorReference: $channelObfuscatorReferences[$pollableMessageChannel->getMessageChannelName()] ?? null,
126-
messageObfuscatorReferences: $messageObfuscatorReferences,
128+
channelEncryptorReference: $channelEncryptorReferences[$pollableMessageChannel->getMessageChannelName()] ?? null,
129+
messageEncryptorReferences: $messageEncryptorReferences,
127130
)
128131
);
129132
$messagingConfiguration->registerChannelInterceptor(
130133
new OutboundDecryptionChannelBuilder(
131134
relatedChannel: $pollableMessageChannel->getMessageChannelName(),
132-
channelObfuscatorReference: $channelObfuscatorReferences[$pollableMessageChannel->getMessageChannelName()] ?? null,
133-
messageObfuscatorReferences: $messageObfuscatorReferences,
135+
channelEncryptionReference: $channelEncryptorReferences[$pollableMessageChannel->getMessageChannelName()] ?? null,
136+
messageEncryptionReferences: $messageEncryptorReferences,
134137
)
135138
);
136139
}
@@ -151,20 +154,21 @@ public function getModulePackageName(): string
151154
return ModulePackageList::DATA_PROTECTION_PACKAGE;
152155
}
153156

154-
private static function resolveObfuscatorConfigsFromAnnotatedClasses(array $sensitiveMessages, array $obfuscatorConfigs, InterfaceToCallRegistry $interfaceToCallRegistry): array
157+
private static function resolveEncryptionConfigsFromAnnotatedClasses(array $sensitiveMessages, InterfaceToCallRegistry $interfaceToCallRegistry): array
155158
{
159+
$encryptionConfigs = [];
156160
foreach ($sensitiveMessages as $message) {
157161
$classDefinition = $interfaceToCallRegistry->getClassDefinitionFor(Type::create($message));
158162
$encryptionKey = $classDefinition->findSingleClassAnnotation(Type::create(WithEncryptionKey::class))?->encryptionKey();
159163
$sensitiveHeaders = array_map(static fn (WithSensitiveHeader $annotation) => $annotation->header, $classDefinition->getClassAnnotations(Type::create(WithSensitiveHeader::class)) ?? []);
160164

161-
$obfuscatorConfigs[$message] = new ObfuscatorConfig(encryptionKey: $encryptionKey, isPayloadSensitive: true, sensitiveHeaders: $sensitiveHeaders);
165+
$encryptionConfigs[$message] = new MessageEncryptionConfig(encryptionKey: $encryptionKey, isPayloadSensitive: true, sensitiveHeaders: $sensitiveHeaders);
162166
}
163167

164-
return $obfuscatorConfigs;
168+
return $encryptionConfigs;
165169
}
166170

167-
private static function resolveObfuscatorConfigsFromAnnotatedMethods(array $annotatedMethods, array $obfuscatorConfigs, InterfaceToCallRegistry $interfaceToCallRegistry): array
171+
private static function resolveEncryptionConfigsFromAnnotatedMethods(array $annotatedMethods, array $encryptionConfigs, InterfaceToCallRegistry $interfaceToCallRegistry): array
168172
{
169173
/** @var AnnotatedMethod $method */
170174
foreach ($annotatedMethods as $method) {
@@ -175,7 +179,7 @@ private static function resolveObfuscatorConfigsFromAnnotatedMethods(array $anno
175179
$payload->hasAnnotation(Header::class)
176180
|| $payload->hasAnnotation(Headers::class)
177181
|| $payload->hasAnnotation(Reference::class)
178-
|| array_key_exists($payload->getTypeHint(), $obfuscatorConfigs)
182+
|| array_key_exists($payload->getTypeHint(), $encryptionConfigs)
179183
) {
180184
continue;
181185
}
@@ -193,10 +197,10 @@ private static function resolveObfuscatorConfigsFromAnnotatedMethods(array $anno
193197
}
194198
}
195199

196-
$obfuscatorConfigs[$payload->getTypeHint()] = new ObfuscatorConfig(encryptionKey: $encryptionKey, isPayloadSensitive: true, sensitiveHeaders: $sensitiveHeaders);
200+
$encryptionConfigs[$payload->getTypeHint()] = new MessageEncryptionConfig(encryptionKey: $encryptionKey, isPayloadSensitive: true, sensitiveHeaders: $sensitiveHeaders);
197201
}
198202

199-
return $obfuscatorConfigs;
203+
return $encryptionConfigs;
200204
}
201205

202206
private function verifyLicense(Configuration $messagingConfiguration): void

packages/DataProtection/src/Configuration/ObfuscatorConfig.php renamed to packages/DataProtection/src/Configuration/MessageEncryptionConfig.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
use Ecotone\Messaging\Support\Assert;
1010

11-
final readonly class ObfuscatorConfig
11+
final readonly class MessageEncryptionConfig
1212
{
1313
/**
1414
* @param array<string> $sensitiveHeaders

0 commit comments

Comments
 (0)