Skip to content

Commit

Permalink
Encrypt primary keys
Browse files Browse the repository at this point in the history
Add IIdCodecFlag to parametrize IdCodec-calls. The IdCodec will add a
signature to the unqualified ids during serialization and asserts the
signature's validity during deserialization.
Add annotation IdEncryption which can be used to exclude IIds from
encryption during serialization/deserialization in the IdCodec.
Pass ScoutDataObjectModuleContext to all IId-serializers/deserializers
and use it to compute the IIdCodecFlags for each call to IdCodec.
Add IIdEncryptionDataObjectMapper/JacksonIdEncryptionDataObjectMapper
that uses encrypted serializing/deserializing and use it in JSON layer.
Add rest.jersey.server-module to inject encrypted reader/writer and
IIdCodecFlags to param converters.
Move IdCrypter to scout.rt.

340299, 373060
  • Loading branch information
fschinkel committed Apr 25, 2024
1 parent f99d527 commit fb15478
Show file tree
Hide file tree
Showing 56 changed files with 2,568 additions and 202 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2023 BSI Business Systems Integration AG
* Copyright (c) 2010, 2024 BSI Business Systems Integration AG
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand All @@ -11,9 +11,12 @@

import static org.junit.Assert.*;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashSet;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;

import org.eclipse.scout.rt.dataobject.fixture.FixtureCompositeId;
Expand All @@ -22,11 +25,17 @@
import org.eclipse.scout.rt.dataobject.fixture.FixtureStringId;
import org.eclipse.scout.rt.dataobject.fixture.FixtureUuId;
import org.eclipse.scout.rt.dataobject.fixture.FixtureWrapperCompositeId;
import org.eclipse.scout.rt.dataobject.id.IdCodec.IdCodecFlag;
import org.eclipse.scout.rt.platform.BEANS;
import org.eclipse.scout.rt.platform.BeanMetaData;
import org.eclipse.scout.rt.platform.IBean;
import org.eclipse.scout.rt.platform.exception.PlatformException;
import org.eclipse.scout.rt.platform.util.Assertions.AssertionException;
import org.eclipse.scout.rt.platform.util.StringUtility;
import org.eclipse.scout.rt.platform.util.date.IDateProvider;
import org.eclipse.scout.rt.testing.platform.BeanTestingHelper;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

/**
Expand All @@ -40,6 +49,18 @@ public abstract class AbstractIdCodecTest {
protected static final String TEST_STRING_2 = "bazäöl";
protected static final Date TEST_DATE = new Date(123456789);

protected static IBean<?> s_bean;

@BeforeClass
public static void beforeClass() {
s_bean = BeanTestingHelper.get().registerBean(new BeanMetaData(P_IdCodec.class).withReplace(true));
}

@AfterClass
public static void afterClass() {
BeanTestingHelper.get().unregisterBean(s_bean);
}

/**
* @return IdCodec instance used for tests
*/
Expand Down Expand Up @@ -571,13 +592,13 @@ public void testFromQualified_UnsupportedWrappedType() {
@Test
public void testFromQualifiedLenient_Default() {
FixtureUuId id = FixtureUuId.of(TEST_UUID);
IId id2 = getCodec().fromQualifiedLenient("scout.FixtureUuId:" + TEST_UUID);
IId id2 = getCodec().fromQualified("scout.FixtureUuId:" + TEST_UUID, IdCodecFlag.LENIENT);
assertEquals(id, id2);
}

@Test
public void testFromQualifiedLenient_UnknownType() {
IId id = getCodec().fromQualifiedLenient("DoesNotExist:" + TEST_UUID);
IId id = getCodec().fromQualified("DoesNotExist:" + TEST_UUID, IdCodecFlag.LENIENT);
assertTrue(id instanceof UnknownId);
UnknownId uid = (UnknownId) id;
assertEquals("DoesNotExist", uid.getIdTypeName());
Expand All @@ -589,7 +610,7 @@ public void testFromQualifiedLenient_UnknownType() {

@Test
public void testFromQualifiedLenient_CompositeUnknownType() {
IId id = getCodec().fromQualifiedLenient("DoesNotExist:abc;123");
IId id = getCodec().fromQualified("DoesNotExist:abc;123", IdCodecFlag.LENIENT);
assertTrue(id instanceof UnknownId);
UnknownId uid = (UnknownId) id;
assertEquals("DoesNotExist", uid.getIdTypeName());
Expand All @@ -601,7 +622,7 @@ public void testFromQualifiedLenient_CompositeUnknownType() {

@Test
public void testFromQualifiedLenient_WrongFormat() {
IId id = getCodec().fromQualifiedLenient("Does:Not:Exist:" + TEST_UUID);
IId id = getCodec().fromQualified("Does:Not:Exist:" + TEST_UUID, IdCodecFlag.LENIENT);
assertTrue(id instanceof UnknownId);
UnknownId uid = (UnknownId) id;
assertEquals("Does", uid.getIdTypeName());
Expand All @@ -613,7 +634,7 @@ public void testFromQualifiedLenient_WrongFormat() {

@Test
public void testFromQualifiedLenient_NoIdTypeName() {
IId id = getCodec().fromQualifiedLenient("Foo" + TEST_UUID);
IId id = getCodec().fromQualified("Foo" + TEST_UUID, IdCodecFlag.LENIENT);
assertTrue(id instanceof UnknownId);
UnknownId uid = (UnknownId) id;
assertNull(uid.getIdTypeName());
Expand All @@ -625,7 +646,7 @@ public void testFromQualifiedLenient_NoIdTypeName() {

@Test
public void testFromQualifiedLenient_CompositeWrongCardinalityToSmall() {
IId id = getCodec().fromQualifiedLenient("scout.FixtureCompositeId:" + TEST_UUID);
IId id = getCodec().fromQualified("scout.FixtureCompositeId:" + TEST_UUID, IdCodecFlag.LENIENT);
assertTrue(id instanceof UnknownId);
UnknownId uid = (UnknownId) id;
assertEquals("scout.FixtureCompositeId", uid.getIdTypeName());
Expand All @@ -637,7 +658,7 @@ public void testFromQualifiedLenient_CompositeWrongCardinalityToSmall() {

@Test
public void testFromQualifiedLenient_CompositeWrongCardinalityToHigh() {
IId id = getCodec().fromQualifiedLenient("scout.FixtureCompositeId:" + "a;b;c");
IId id = getCodec().fromQualified("scout.FixtureCompositeId:" + "a;b;c", IdCodecFlag.LENIENT);
assertTrue(id instanceof UnknownId);
UnknownId uid = (UnknownId) id;
assertEquals("scout.FixtureCompositeId", uid.getIdTypeName());
Expand All @@ -654,6 +675,66 @@ public void testRegisterTypeMapper() {
assertThrows(AssertionException.class, () -> getCodec().registerRawTypeMapper(String.class, x -> x, null));
}

@Test
public void testQualifiedEncryption() {
var ids = new HashSet<IId>();
collectEncryptionIds(ids);
ids.forEach(id -> {
String encrypted = getCodec().toQualified(id, IdCodecFlag.ENCRYPTION);
IId decrypted = getCodec().fromQualified(encrypted, IdCodecFlag.ENCRYPTION);
assertQualifiedEncryption(id, encrypted, decrypted);

encrypted = getCodec().toQualified(id, Set.of(IdCodecFlag.ENCRYPTION));
decrypted = getCodec().fromQualified(encrypted, Set.of(IdCodecFlag.ENCRYPTION));
assertQualifiedEncryption(id, encrypted, decrypted);
});
}

@Test
public void testUnqualifiedEncryption() {
var ids = new HashSet<IId>();
collectEncryptionIds(ids);
ids.forEach(id -> {
String encrypted = getCodec().toUnqualified(id, IdCodecFlag.ENCRYPTION);
IId decrypted = getCodec().fromUnqualified(id.getClass(), encrypted, IdCodecFlag.ENCRYPTION);
assertUnqualifiedEncryption(id, encrypted, decrypted);

encrypted = getCodec().toUnqualified(id, Set.of(IdCodecFlag.ENCRYPTION));
decrypted = getCodec().fromUnqualified(id.getClass(), encrypted, Set.of(IdCodecFlag.ENCRYPTION));
assertUnqualifiedEncryption(id, encrypted, decrypted);
});
}

protected void assertQualifiedEncryption(IId id, String encrypted, IId decrypted) {
assertEncryption(id, encrypted, decrypted);
}

protected void assertUnqualifiedEncryption(IId id, String encrypted, IId decrypted) {
assertEncryption(id, encrypted, decrypted);
}

protected void assertEncryption(IId id, String encrypted, IId decrypted) {
assertEquals(id, decrypted);
}

protected void collectEncryptionIds(Set<IId> ids) {
ids.add(FixtureUuId.of(TEST_UUID));
ids.add(FixtureStringId.of(TEST_STRING));
ids.add(FixtureDateId.of(TEST_DATE));
ids.add(FixtureLocaleId.of(Locale.ITALY));
ids.add(FixtureCompositeId.of(TEST_STRING, TEST_UUID));
ids.add(FixtureWrapperCompositeId.of(TEST_STRING, TEST_UUID, TEST_STRING_2));
ids.add(FixtureCompositeWithNullValuesId.of(null, UUID.fromString("711dc5d6-0a42-4f54-b79c-50110b9e742a")));
ids.add(FixtureCompositeWithNullStringValuesId.of("foo", ""));
ids.add(FixtureCompositeWithNullStringValuesId.of("", "bar"));
ids.add(FixtureCompositeWithAllTypesId.of("foo", null, null, null, null, null));
ids.add(FixtureCompositeWithAllTypesId.of(null, TEST_UUID, null, null, null, null));
ids.add(FixtureCompositeWithAllTypesId.of(null, null, 42L, null, null, null));
ids.add(FixtureCompositeWithAllTypesId.of(null, null, null, 43, null, null));
ids.add(FixtureCompositeWithAllTypesId.of(null, null, null, null, TEST_DATE, null));
ids.add(FixtureCompositeWithAllTypesId.of(null, null, null, null, null, Locale.GERMANY));
}

@IdTypeName("scout.FixtureDateId")
protected static final class FixtureDateId extends AbstractRootId<Date> {
private static final long serialVersionUID = 1L;
Expand Down Expand Up @@ -812,4 +893,12 @@ public static FixtureCustomComparableRawDataId of(CustomComparableRawDataType da
return new FixtureCustomComparableRawDataId(date);
}
}

protected static class P_IdCodec extends IdCodec {

@Override
protected byte[] getEncryptionPrivateKey() {
return "42".getBytes(StandardCharsets.UTF_8);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2023 BSI Business Systems Integration AG
* Copyright (c) 2010, 2024 BSI Business Systems Integration AG
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -59,6 +59,19 @@ public void testRegisterIdTypeName() {
assertThrows(AssertionException.class, () -> m_inventory.registerIdTypeName("scout.FixtureMockId", FixtureMockId.class));
}

@Test
public void testIdEncryption() {
assertTrue(m_inventory.isIdEncryption(ExplicitlyOverriddenEncryptedId.class));
assertTrue(m_inventory.isIdEncryption(ImplicitlyOverriddenEncryptedId.class));
assertTrue(m_inventory.isIdEncryption(ExplicitlyEncryptedId.class));
assertTrue(m_inventory.isIdEncryption(ImplicitlyEncryptedId.class));

assertFalse(m_inventory.isIdEncryption(ImplicitlyUnencryptedId.class));
assertFalse(m_inventory.isIdEncryption(ExplicitlyUnencryptedId.class));
assertFalse(m_inventory.isIdEncryption(ImplicitlyOverriddenUnencryptedId.class));
assertFalse(m_inventory.isIdEncryption(ExplicitlyOverriddenUnencryptedId.class));
}

@IgnoreBean
protected static final class FixtureMockId extends AbstractStringId {
private static final long serialVersionUID = 1L;
Expand All @@ -67,4 +80,116 @@ private FixtureMockId(String id) {
super(id);
}
}

@IdEncryption
protected abstract static class AbstractImplicitlyEncryptedId extends AbstractStringId {
private static final long serialVersionUID = 1L;

protected AbstractImplicitlyEncryptedId(String id) {
super(id);
}
}

@IgnoreBean
protected static class ImplicitlyEncryptedId extends AbstractImplicitlyEncryptedId {
private static final long serialVersionUID = 1L;

protected ImplicitlyEncryptedId(String id) {
super(id);
}
}

@IgnoreBean
@IdEncryption
protected static class ExplicitlyEncryptedId extends AbstractStringId {
private static final long serialVersionUID = 1L;

protected ExplicitlyEncryptedId(String id) {
super(id);
}
}

@IdEncryption(false)
protected abstract static class AbstractImplicitlyUnencryptedId extends AbstractStringId {
private static final long serialVersionUID = 1L;

protected AbstractImplicitlyUnencryptedId(String id) {
super(id);
}
}

@IgnoreBean
protected static class ImplicitlyUnencryptedId extends AbstractImplicitlyUnencryptedId {
private static final long serialVersionUID = 1L;

protected ImplicitlyUnencryptedId(String id) {
super(id);
}
}

@IgnoreBean
@IdEncryption(false)
protected static class ExplicitlyUnencryptedId extends AbstractStringId {
private static final long serialVersionUID = 1L;

protected ExplicitlyUnencryptedId(String id) {
super(id);
}
}

@IdEncryption
protected abstract static class AbstractImplicitlyOverriddenEncryptedId extends AbstractImplicitlyUnencryptedId {
private static final long serialVersionUID = 1L;

protected AbstractImplicitlyOverriddenEncryptedId(String id) {
super(id);
}
}

@IgnoreBean
protected static class ImplicitlyOverriddenEncryptedId extends AbstractImplicitlyOverriddenEncryptedId {
private static final long serialVersionUID = 1L;

protected ImplicitlyOverriddenEncryptedId(String id) {
super(id);
}
}

@IgnoreBean
@IdEncryption
protected static class ExplicitlyOverriddenEncryptedId extends AbstractImplicitlyUnencryptedId {
private static final long serialVersionUID = 1L;

protected ExplicitlyOverriddenEncryptedId(String id) {
super(id);
}
}

@IdEncryption(false)
protected abstract static class AbstractImplicitlyOverriddenUnencryptedId extends AbstractImplicitlyEncryptedId {
private static final long serialVersionUID = 1L;

protected AbstractImplicitlyOverriddenUnencryptedId(String id) {
super(id);
}
}

@IgnoreBean
protected static class ImplicitlyOverriddenUnencryptedId extends AbstractImplicitlyOverriddenUnencryptedId {
private static final long serialVersionUID = 1L;

protected ImplicitlyOverriddenUnencryptedId(String id) {
super(id);
}
}

@IgnoreBean
@IdEncryption(false)
protected static class ExplicitlyOverriddenUnencryptedId extends AbstractImplicitlyEncryptedId {
private static final long serialVersionUID = 1L;

protected ExplicitlyOverriddenUnencryptedId(String id) {
super(id);
}
}
}

0 comments on commit fb15478

Please sign in to comment.