Modules¶
The library consists of 2 Modules, DataManager
and Serializer
.
Architectural diagram¶
Data manager¶
DataManager
module deals with data encryption and decryption, the creation of the AGGREGATE_KEY
and the
orchestration of the logics related to the sensitization and desensitization of events.
SensitiveDataManager¶
It is the interface for string encryption and decryption services. It asks for the implementation of the doEncrypt
and doDecrypt
methods, in which to implement your own concrete logic. The interface also provides the public
constant SensitiveDataManager::IS_SENSITIZED_INDICATOR
which is used as a prefix in encrypted strings in order to understand if a string is in the clear or not.
This check can be done with the SensitiveTool::isSensitized(string $data): bool tool. Very convenient when it is necessary to carry out validations
in the hydration phase, for example of a Value Object or an Aggregate.
The library provides an implementation of this interface that uses the AES256 algorithm: AES256SensitiveDataManager
KeyGenerator¶
It is the interface for the AGGREGATE_KEY
creation services. Asks for the implementation of the generate
method.
The library provides an implementation of this interface based on openssl: OpenSSLKeyGenerator
AggregateKeys¶
It is the interface to the repository that takes care of the persistence of the AGGREGATE_KEY
through Model
AggregateKey.
It asks for the implementation of the add
, withAggregateId
and update
methods.
A DBAL-based implementation is available by installing the Broadway Sensitive Serializer DBAL library.
Serializer¶
BroadwaySerializerDecorator¶
It is the abstract class that represents the original Broadway serializer decorator. It implements the Broadway’s serializer interface and depends on an implementation of Broadway’s serializer.
SensitiveSerializer¶
It is the concrete serializer implemented by the library. Extends BroadwaySerializerSerializer and depends on a BroadwaySerializerSerializer object (you can pass the standard Broadway serializer, SimpleInterfaceSerializer) and a SensitizerStrategy object.
Sensitization strategies¶
The library provides three different types of sensitization for the events payload, Whole
, Partial
and Custom
.
Whole strategy¶
The Whole strategy aims to encrypt all the keys of the event payload with the exception of the aggregate id and the date of issue of the event.
{
"class": "SensitiveUser\\User\\Domain\\Event\\UserRegistered",
"payload": {
"email": "#-#OFLfN9XDKtWrmCmUb6mhY0Iz2V6wtam0pcqs6vDJFRU=:bxQo+zXfjUgrD0jHuht0mQ==",
"id": "b0fce205-d816-46ac-886f-06de19236750",
"name": "#-#EXWLg\/JANMK\/M+DmlpnOyQ==:bxQo+zXfjUgrD0jHuht0mQ==",
"occurred_at": "2022-01-08T14:25:13.483+00:00",
"surname": "#-#2Iuofg4NKKPLAG2kdJrbmQ==:bxQo+zXfjUgrD0jHuht0mQ=="
}
}
The reference class for this strategy is WholePayloadSensitizer. While the client class of the strategy is
WholeStrategy.
This class depends on the WholePayloadSensitizer
and the WholePayloadSensitizerRegistry
registry which must be initialized with a class-string[]
containing the list of FQCN (Full Qualified Class Name) of the events that
you want to make subject to encryption. This therefore implies that not all events will be encrypted, but it can be
selected selectively by populating the register.
Keys exclusion
The id
key of the Aggregate can be configured during strategy creation via the
WholePayloadSensitizer::$excludedIdKey
attribute. In the same way it is possible to indicate a list of keys to be excluded from encryption using the
WholePayloadSensitizer::$excludedKeys
attribute.
Run whole strategy example example/WholeStrategy
make build-php ARG="--no-cache"
make upd
make composer ARG="install"
make enter
php example/WholeStrategy/example.php
Partial strategy¶
The partial strategy, probably the most convenient, involves the selective and parameterized encryption of a payload. It will be sufficient to pass to the PartialPayloadSensitizerRegistry register an array with the events to be encrypted and for each event, indicating the keys:
The client class of the strategy is PartialStrategy
which is dependent on the PartialPayloadSensitizerRegistry
and PartialPayloadSensitizer.
$events = [
MyEvent::class => ['email', 'surname'],
MySecondEvent::class => ['address'],
];
new PartialPayloadSensitizerRegistry($events);
Run partial strategy example example/PartialStrategy
make build-php ARG="--no-cache"
make upd
make composer ARG="install"
make enter
php example/PartialStrategy/example.php
Custom strategy¶
The Custom strategy involves the creation of specific Sensitizers
in order to sensitize only a part of the payload
according to the needs. These Sensitizers extend the abstract class PayloadSensitizer
which involves the implementation of the PayloadSensitizer::generateSensitizedPayload(): array
and PayloadSensitizer::generateDesensitizedPayload(): array
methods.
Once defined, the Sensitizers must be used to initialize the specific CustomPayloadSensitizerRegistry registry of this strategy.
The client class of the strategy is CustomStrategy
which is solely dependent on the CustomPayloadSensitizerRegistry
. An example of implementation is present in the test.
Run custom strategy example example/CustomStrategy
make build-php ARG="--no-cache"
make upd
make composer ARG="install"
make enter
php example/CustomStrategy/example.php
Strategy summary¶
With the Whole Strategy you can decide what not to encrypt if necessary, but not for a single event; you can exclude keys for all events subject to sensitization.
With the Partial Strategy you define the events you want to encrypt, and for each event you define the list of keys to be excluded, using a simple array.
With the Custom Strategy you have full control over how to intervene on the payload.
Value Serializer¶
PayloadSensitizer
uses a value serializer
respecting the ValueSerializer interface. This Serializer implements strategy pattern
to be able to chose which type
of serialization use. Broadway sensitive serializer provides a JsonValueSerializer
implementation to serialize this types: scalar
, null
, array
AggregateKey model creation¶
The PayloadSensitizer::$automaticAggregateKeyCreation parameter determines if the AggregateKey model should be created automatically at serialization, or if you want to create it manually. The existence check of the model is not carried out in the PayloadSensitizer::desensitize(array $serializedObject): array method as it would be a contradiction; the process of saving events starts with the saving and relative serialization of a first event, so when calling the desensitize method it is assumed that the AggregateKey has already been created. Otherwise an exception will be throw.
Automatic creation¶
In this mode the AggregateKey
model, if it does not exist, is created when calling method
PayloadSensitizer::sensitize(array $serializedObject): array.
The key is created if it does not exist, otherwise it uses the existing one:
$decryptedAggregateKey = $this->automaticAggregateKeyCreation ?
$this->createAggregateKeyIfDoesNotExist($aggregateId) :
$this->obtainDecryptedAggregateKeyOrError($aggregateId);
Manual creation¶
In this mode the AggregateKey
model must exist, if it doesn’t, an exception will be raised. This mode involves
creating the model in advance. The most convenient time may be during the creation of the Aggregate.
$aggregateKeyManager->createAggregateKey($userId);
$user = User::create($userId, $name, $surname, $email, $registrationDate);
$users->add($user);
Generally speaking, the correct way to handle this in both ways would be to run the domain service atomically, within a transaction. The ddd-starter-pack library provide some convenient abstractions to handle this: TransactionalApplicationServiceTest