IT 03.Moduli - matiux/broadway-sensitive-serializer Wiki

Moduli della libreria

La libreria è composta da 2 Moduli, DataManager e Serializer

Data Manager

Il modulo DataManager si occupa della criptazione e decriptazione dei dati, della creazione delle AGGREGATE_KEY e dell'orchestrazione delle logiche inerenti la sensibilizzazione e desensibilizzazione degli eventi.

SensitiveDataManager

È l'interfaccia per i servizi di criptazione e decriptazione di stringhe. Chiede l'implementazione dei metodi encrypt e decrypt, nei quali implementare la propria logica concreta. L'interfaccia mette anche a disposizione la costante pubblica SensitiveDataManager::IS_SENSITIZED_INDICATOR che viene utilizzata come prefisso nelle stringhe criptate al fine di capire se una stringa è in chiaro o no. Questa verifica la si può fare con il tool SensitiveTool::isSensitized(string $data): bool.

La libreria mette a disposizione un'implementazione di questa interfaccia che strutta l'algoritmo AES256: AES256SensitiveDataManager

KeyGenerator

È l'interfaccia per i servizi di creazione delle AGGREGATE_KEY. Chiede l'implementazione del metodo generate.

La libreria mette a disposizione un'implementazione di questa interfaccia basta su openssl: OpenSSLKeyGenerator

AggregateKeys

È l'interfaccia per il repository che si occupa della persistenza della AGGREGATE_KEY attraverso il Modello AggregateKey. Chiede l'implementazione dei metodi add, withAggregateId e update.

È disponibile un'implementazione basata su DBAL installando la libreria Broadway Sensitive Serializer DBAL.

Serializer

BroadwaySerializerDecorator

È la classe astratta che rappresenta il decoratore del serializzatore originale di Broadway. Implementa l'interfaccia Broadway\Serializer\Serializer e dipende da un oggetto Broadway\Serializer\Serializer.

SensitiveSerializer

È il serializzatore concreto implementato dalla libreria. Estende BroadwaySerializerDecorator e dipende da un oggetto Broadway\Serializer\Serializer (si può passare il serializzatore Broadway standard, SimpleInterfaceSerializer) e da un oggetto SensitizerStrategy.

Strategie di sensibilizzazione

La libreria mette a disposizioni tre diverse tipologie di sensibilizzazione dei payload degli aventi, Whole, Partial e Custom.

Whole Strategy

La strategia Whole ha come scopo quello di criptare tutte le chiavi del payload dell'evento ad eccezione dell id dell'aggregato e la data di emissione dell'evento.

{
    "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=="
    }
}

La classe di riferimento per questa strategia è WholePayloadSensitizer. Mentre la classe client della strategia è WholePayloadSensitizer. Questa classe dipende da WholePayloadSensitizer e dal registro WholePayloadSensitizerRegistry che deve essere inizializzato con un class-string[] contenete la lista dei FQCN (Full Qualified Class Name) degli eventi che si vogliono rendere soggetti alla criptazione. Questo implica quindi che non tutti gli eventi saranno criptati, ma lo si potrà scegliere in modo selettivo popolando il registro.

Esclusione delle chiavi

La chiave id può essere configurata in fase di creazione della strategia tramite l'attributo WholePayloadSensitizer::$excludedIdKey. Allo Stesso modo è possibile indicare una lista di chiavi che si vogliono escludere dalla criptazione tramite l'attributo WholePayloadSensitizer::$excludedKeys

Run Whole Strategy example example/WholeStrategy

./dc up -d
./dc enter
php example/WholeStrategy/example.php

Partial Strategy

La strategia Partial, probabilmente la più conveniente, prevede la criptazione selettiva e parametrizzata di un payload. Sarà sufficiente passare al registro PartialPayloadSensitizerRegistry un array con gli eventi che si vogliono mettere sotto criptazione e per ogni evento, indicare le chiavi:

$events = [
   MyEvent::class => ['email', 'surname'],
   MySecondEvent::class => ['address'],
];

new PartialPayloadSensitizerRegistry($events);

Run Partial Strategy example example/PartialStrategy

./dc up -d
./dc enter
php example/PartialStrategy/example.php

Custom Strategy

La strategia Custom prevede la creazione di specifici Sensitizer al fine di sensibilizzare solo una parte del payload in base alle esigenze. Questi Sensitizers estendono la classe astratta PayloadSensitizer che implica l'implementazione dei metodi PayloadSensitizer::generateSensitizedPayload(string $decryptedAggregateKey): array e PayloadSensitizer::generateDesensitizedPayload(string $decryptedAggregateKey): array.

Una volta definiti i Sensitizers vanno usati per inizializzare il registro CustomPayloadSensitizerRegistry specifico di questa strategia.

La classe client della strategia è WholePayloadSensitizerStrategy che dipende unicamente dal WholePayloadSensitizerStrategy. Un esempio di implementazione è presente nel test.

Run Custom Strategy example example/CustomStrategy

./dc up -d
./dc enter
php example/CustomStrategy/example.php

Riepilogo strategie

Creazione automatica del modello AggregateKey

Il parametro PayloadSensitizer::$automaticAggregateKeyCreation determina se il modello AggregateKey deve essere creato automaticamente in fase di serializzazione, oppure se lo si vuole creare manualmente. Il controllo di esistenza del modello non viene effettuato nel metodo PayloadSensitizer::desensitize(array $serializedObject): array in quanto sarebbe un controsenso; il processo di salvataggio degli eventi parte con il salvataggio e la relativa serializzazione di un primo evento, quindi quando si chiama il metodo desensitize si da per scontato che l'AggregateKey sia già stato creato. Diversamente verrà sollevata un'eccezione.

Creazione automatica

In questa modalità il modello AggregateKey, se non esistente viene creato durante la chiamata al metodo PayloadSensitizer::sensitize(array $serializedObject): array. La chiave viene creata se non esiste, diversamente usa quella esistente:

$decryptedAggregateKey = $this->automaticAggregateKeyCreation ?
   $this->createAggregateKeyIfDoesNotExist($aggregateId) :
   $this->obtainDecryptedAggregateKeyOrError($aggregateId);

Creazione manuale

In questa modalità il modello AggregateKey deve esistere, se non c'è verrà sollevata un'eccezione. Questa modalità implica la creazione anticipata del modello. Il momento più conveniente potrebbe essere durante la creazione dell'Aggregato.

$aggregateKeyManager->createAggregateKey($userId);

$user = User::create($userId, $name, $surname, $email, $registrationDate);

$users->add($user);

In linea generale il modo corretto per gestire la cosa in entrambe le modalità, sarebbe di eseguire il servizio di dominio in modo atomico, all'interno di una transazione. La libreria ddd-starter-pack fornire alcune astrazioni convenienti per gestire la cosa: TransactionalApplicationServiceTest

Diagramma architetturale

Architecture diagram