Skip to content

Commit

Permalink
eventuate-clients#9: Enhancing the Eventuate Java Client According GD…
Browse files Browse the repository at this point in the history
…PR. Added encryption to the eventuate jdbc access.
  • Loading branch information
dartartem committed Apr 17, 2018
1 parent 29e57c1 commit 4d335a0
Show file tree
Hide file tree
Showing 10 changed files with 275 additions and 38 deletions.
1 change: 1 addition & 0 deletions eventuate-client-java-common-impl/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ apply plugin: PrivateModulePlugin
dependencies {
compile project(":eventuate-client-java")

compile "org.springframework.security:spring-security-core:5.0.4.RELEASE"
compile "com.fasterxml.jackson.core:jackson-databind:2.8.8"
compile "com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.8.8"
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,37 @@
package io.eventuate.javaclient.commonimpl;

import io.eventuate.EventContext;
import io.eventuate.javaclient.commonimpl.encryption.EncryptionKeyStore;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

import java.util.Optional;

public class AggregateCrudFindOptions {

private Optional<EventContext> triggeringEvent = Optional.empty();
private Optional<EventContext> triggeringEvent;
private Optional<EncryptionKeyStore> encryptionKeyStore;

public AggregateCrudFindOptions() {
triggeringEvent = Optional.empty();
encryptionKeyStore = Optional.empty();
}

public AggregateCrudFindOptions(Optional<EventContext> triggeringEvent) {
this(triggeringEvent, Optional.empty());
}

public AggregateCrudFindOptions(Optional<EventContext> triggeringEvent, Optional<EncryptionKeyStore> encryptionKeyStore) {
this.triggeringEvent = triggeringEvent;
this.encryptionKeyStore = encryptionKeyStore;
}

public Optional<EventContext> getTriggeringEvent() {
return triggeringEvent;
}

@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}

@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
public Optional<EncryptionKeyStore> getEncryptionKeyStore() {
return encryptionKeyStore;
}

public AggregateCrudFindOptions withTriggeringEvent(EventContext eventContext) {
Expand All @@ -40,4 +43,14 @@ public AggregateCrudFindOptions withTriggeringEvent(Optional<EventContext> event
this.triggeringEvent = eventContext;
return this;
}

@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}

@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
package io.eventuate.javaclient.commonimpl;

import io.eventuate.EventContext;
import io.eventuate.javaclient.commonimpl.encryption.EncryptionKey;

import java.util.Optional;

public class AggregateCrudSaveOptions {

private final Optional<String> entityId;
private final Optional<EventContext> triggeringEvent;
private final Optional<EncryptionKey> encryptionKey;

public AggregateCrudSaveOptions() {
this.entityId = Optional.empty();
this.triggeringEvent = Optional.empty();
entityId = Optional.empty();
triggeringEvent = Optional.empty();
encryptionKey = Optional.empty();
}

public AggregateCrudSaveOptions(Optional<EventContext> triggeringEvent, Optional<String> entityId) {
this(triggeringEvent, entityId, Optional.empty());
}

public AggregateCrudSaveOptions(Optional<EventContext> triggeringEvent, Optional<String> entityId, Optional<EncryptionKey> encryptionKey) {
this.triggeringEvent = triggeringEvent;
this.entityId = entityId;
this.encryptionKey = encryptionKey;
}

public Optional<String> getEntityId() {
Expand All @@ -27,14 +35,15 @@ public Optional<EventContext> getTriggeringEvent() {
return triggeringEvent;
}

public Optional<EncryptionKey> getEncryptionKey() {
return encryptionKey;
}

public AggregateCrudSaveOptions withEventContext(EventContext ectx) {
return new AggregateCrudSaveOptions(Optional.of(ectx), this.entityId);

public AggregateCrudSaveOptions withEventContext(EventContext eventContext) {
return new AggregateCrudSaveOptions(Optional.of(eventContext), entityId, encryptionKey);
}

public AggregateCrudSaveOptions withId(String entityId) {
return new AggregateCrudSaveOptions(this.triggeringEvent, Optional.of(entityId));
return new AggregateCrudSaveOptions(triggeringEvent, Optional.of(entityId), encryptionKey);
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.eventuate.javaclient.commonimpl;

import io.eventuate.EventContext;
import io.eventuate.javaclient.commonimpl.encryption.EncryptionKey;
import org.apache.commons.lang.builder.ToStringBuilder;

import java.util.Optional;
Expand All @@ -9,15 +10,34 @@ public class AggregateCrudUpdateOptions {

private final Optional<EventContext> triggeringEvent;
private final Optional<SerializedSnapshot> snapshot;
private final Optional<EncryptionKey> encryptionKey;

public AggregateCrudUpdateOptions() {
this.triggeringEvent = Optional.empty();
this.snapshot = Optional.empty();
triggeringEvent = Optional.empty();
snapshot = Optional.empty();
encryptionKey = Optional.empty();
}

public AggregateCrudUpdateOptions(Optional<EventContext> triggeringEvent, Optional<SerializedSnapshot> snapshot) {
this(triggeringEvent, snapshot, Optional.empty());
}

public AggregateCrudUpdateOptions(Optional<EventContext> triggeringEvent, Optional<SerializedSnapshot> snapshot, Optional<EncryptionKey> encryptionKey) {
this.triggeringEvent = triggeringEvent;
this.snapshot = snapshot;
this.encryptionKey = encryptionKey;
}

public Optional<EventContext> getTriggeringEvent() {
return triggeringEvent;
}

public Optional<SerializedSnapshot> getSnapshot() {
return snapshot;
}

public Optional<EncryptionKey> getEncryptionKey() {
return encryptionKey;
}

public AggregateCrudUpdateOptions withSnapshot(SerializedSnapshot serializedSnapshot) {
Expand All @@ -29,16 +49,8 @@ public String toString() {
return ToStringBuilder.reflectionToString(this);
}

public Optional<EventContext> getTriggeringEvent() {
return triggeringEvent;
}

public Optional<SerializedSnapshot> getSnapshot() {
return snapshot;
}

public AggregateCrudUpdateOptions withTriggeringEvent(EventContext eventContext) {
return new AggregateCrudUpdateOptions(Optional.of(eventContext), this.snapshot);
return new AggregateCrudUpdateOptions(Optional.of(eventContext), snapshot);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package io.eventuate.javaclient.commonimpl.encryption;

import io.eventuate.javaclient.commonimpl.JSonMapper;

public class EncryptedEventData {
public static String ENCRYPTED_EVENT_DATA_STRING_PREFIX = "__ENCRYPTED__";

private String encryptionKeyId;
private String data;

public EncryptedEventData() {
}

public EncryptedEventData(String encryptionKeyId, String data) {
this.encryptionKeyId = encryptionKeyId;
this.data = data;
}

public static boolean checkIfEventDataStringIsEncrypted(String eventData) {
return eventData.startsWith(ENCRYPTED_EVENT_DATA_STRING_PREFIX);
}

public static EncryptedEventData fromEventDataString(String eventData) {
String json = eventData.substring(ENCRYPTED_EVENT_DATA_STRING_PREFIX.length());
return JSonMapper.fromJson(json, EncryptedEventData.class);
}

public String getEncryptionKeyId() {
return encryptionKeyId;
}

public void setEncryptionKeyId(String encryptionKeyId) {
this.encryptionKeyId = encryptionKeyId;
}

public String getData() {
return data;
}

public void setData(String data) {
this.data = data;
}

public String asString() {
return ENCRYPTED_EVENT_DATA_STRING_PREFIX + JSonMapper.toJson(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.eventuate.javaclient.commonimpl.encryption;

public class EncryptionKey {
private String id;
private String key;
private String salt;

public EncryptionKey(String id, String key, String salt) {
this.id = id;
this.key = key;
this.salt = salt;
}

public String getId() {
return id;
}

public String getKey() {
return key;
}

public void setKey(String key) {
this.key = key;
}

public String getSalt() {
return salt;
}

public void setSalt(String salt) {
this.salt = salt;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.eventuate.javaclient.commonimpl.encryption;

public interface EncryptionKeyStore {
EncryptionKey findEncryptionKeyById(String keyId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.eventuate.javaclient.commonimpl.encryption;

import org.springframework.security.crypto.encrypt.Encryptors;

public class EventDataEncryptor {
public static String encrypt(EncryptionKey encryptionKey, String eventData) {
return Encryptors.text(encryptionKey.getKey(), encryptionKey.getSalt()).encrypt(eventData);
}

public static String decrypt(EncryptionKey encryptionKey, String eventData) {
return Encryptors.text(encryptionKey.getKey(), encryptionKey.getSalt()).decrypt(eventData);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
import io.eventuate.javaclient.commonimpl.LoadedEvents;
import io.eventuate.javaclient.commonimpl.SerializedSnapshot;
import io.eventuate.javaclient.commonimpl.SerializedSnapshotWithVersion;
import io.eventuate.javaclient.commonimpl.encryption.EncryptedEventData;
import io.eventuate.javaclient.commonimpl.encryption.EncryptionKey;
import io.eventuate.javaclient.commonimpl.encryption.EncryptionKeyStore;
import io.eventuate.javaclient.commonimpl.encryption.EventDataEncryptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
Expand All @@ -31,8 +35,6 @@

public class EventuateJdbcAccessImpl implements EventuateJdbcAccess {

public static final String DEFAULT_DATABASE_SCHEMA = "eventuate";

protected Logger logger = LoggerFactory.getLogger(getClass());

private JdbcTemplate jdbcTemplate;
Expand Down Expand Up @@ -69,13 +71,15 @@ public SaveUpdateResult save(String aggregateType, List<EventTypeAndData> events
throw new EntityAlreadyExistsException();
}


for (EventIdTypeAndData event : eventsWithIds)
jdbcTemplate.update(String.format("INSERT INTO %s (event_id, event_type, event_data, entity_type, entity_id, triggering_event, metadata) VALUES (?, ?, ?, ?, ?, ?, ?)", eventTable),
event.getId().asString(), event.getEventType(), event.getEventData(), aggregateType, entityId,
event.getId().asString(),
event.getEventType(),
encryptEventDataIfNeeded(event.getEventData(), saveOptions.flatMap(AggregateCrudSaveOptions::getEncryptionKey)),
aggregateType,
entityId,
saveOptions.flatMap(AggregateCrudSaveOptions::getTriggeringEvent).map(EventContext::getEventToken).orElse(null),
event.getMetadata().orElse(null)
);
event.getMetadata().orElse(null));

return new SaveUpdateResult(new EntityIdVersionAndEventIds(entityId, entityVersion, eventsWithIds.stream().map(EventIdTypeAndData::getId).collect(Collectors.toList())),
new PublishableEvents(aggregateType, entityId, eventsWithIds));
Expand Down Expand Up @@ -140,6 +144,9 @@ public <T extends Aggregate<T>> LoadedEvents find(String aggregateType, String e
);
}

events.forEach(eventAndTrigger ->
eventAndTrigger.event.setEventData(decryptEventDataIfNeeded(eventAndTrigger.event.getEventData(), findOptions.flatMap(AggregateCrudFindOptions::getEncryptionKeyStore))));

logger.debug("Loaded {} events", events);
Optional<EventAndTrigger> matching = findOptions.
flatMap(AggregateCrudFindOptions::getTriggeringEvent).
Expand Down Expand Up @@ -229,7 +236,7 @@ public SaveUpdateResult update(EntityIdAndType entityIdAndType, Int128 entityVer
jdbcTemplate.update(String.format("INSERT INTO %s (event_id, event_type, event_data, entity_type, entity_id, triggering_event, metadata) VALUES (?, ?, ?, ?, ?, ?, ?)", eventTable),
event.getId().asString(),
event.getEventType(),
event.getEventData(),
encryptEventDataIfNeeded(event.getEventData(), updateOptions.flatMap(AggregateCrudUpdateOptions::getEncryptionKey)),
entityType,
entityId,
updateOptions.flatMap(AggregateCrudUpdateOptions::getTriggeringEvent).map(EventContext::getEventToken).orElse(null),
Expand All @@ -253,6 +260,25 @@ protected String snapshotTriggeringEvents(Optional<LoadedSnapshot> previousSnaps
return null;
}

private String encryptEventDataIfNeeded(String eventData, Optional<EncryptionKey> encryptionKey) {
return encryptionKey
.map(key -> new EncryptedEventData(key.getId(), EventDataEncryptor.encrypt(key, eventData)).asString())
.orElse(eventData);
}

private String decryptEventDataIfNeeded(String eventData, Optional<EncryptionKeyStore> encryptionKeyStore) {
if (EncryptedEventData.checkIfEventDataStringIsEncrypted(eventData)) {
EncryptedEventData encryptedEventData = EncryptedEventData.fromEventDataString(eventData);
String data = encryptedEventData.getData();
String keyId = encryptedEventData.getEncryptionKeyId();

EncryptionKey key = encryptionKeyStore
.map(store -> store.findEncryptionKeyById(keyId))
.orElseThrow(() -> new IllegalArgumentException("EncryptionKeyStore is not specified"));

return EventDataEncryptor.decrypt(key, data);
}

return eventData;
}
}
Loading

0 comments on commit 4d335a0

Please sign in to comment.