Skip to content

Commit

Permalink
IdCodec: change signature delimiter and improve signature assertion
Browse files Browse the repository at this point in the history
In some projects IIds are used to transport decimal formats. As these
formats can contain multiple # the IId is considered to be signed during
deserialization which leads to exceptions because these IIds are
typically marked with @IdSignature(false).
To improve the signature assertion split the unqualified id only at the
last occurrence of the delimiter and not at every occurrence. Also check
that the unqualified id has not changed after splitting at the delimiter
if it needs to be unsigned (e.g. an unsigned id ends with the
delimiter).

406658
  • Loading branch information
fschinkel committed Jan 28, 2025
1 parent 42f0ebf commit 6118c70
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2024 BSI Business Systems Integration AG
* Copyright (c) 2010, 2025 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 @@ -730,6 +730,11 @@ protected void collectSignatureIds(Set<IId> ids) {
ids.add(FixtureCompositeWithNullValuesId.of(null, UUID.fromString("711dc5d6-0a42-4f54-b79c-50110b9e742a")));
ids.add(FixtureCompositeWithNullStringValuesId.of("foo", ""));
ids.add(FixtureCompositeWithNullStringValuesId.of("", "bar"));
ids.add(FixtureCompositeWithNullStringValuesId.of("foo", "bar"));
ids.add(FixtureCompositeWithNullStringValuesId.of("_-~SIG~-_foo", "bar"));
ids.add(FixtureCompositeWithNullStringValuesId.of("foo_-~SIG~-_", "bar"));
ids.add(FixtureCompositeWithNullStringValuesId.of("foo", "_-~SIG~-_bar"));
ids.add(FixtureCompositeWithNullStringValuesId.of("foo", "bar_-~SIG~-_"));
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));
Expand All @@ -740,8 +745,41 @@ protected void collectSignatureIds(Set<IId> ids) {

@Test
public void testEmptyIdWithSignature() {
assertThrows(IdCodecException.class, () -> getCodec().fromQualified("scout.FixtureIntegerId:###CNCgkNhEN4PEpNkWvRPY/jEIwn49f1xGLgmXyi6SdlI=", IdCodecFlag.SIGNATURE));
assertThrows(IdCodecException.class, () -> getCodec().fromUnqualified(FixtureIntegerId.class, "###CNCgkNhEN4PEpNkWvRPY/jEIwn49f1xGLgmXyi6SdlI=", IdCodecFlag.SIGNATURE));
assertThrows(IdCodecException.class, () -> getCodec().fromQualified("scout.FixtureIntegerId:_-~SIG~-_CNCgkNhEN4PEpNkWvRPY/jEIwn49f1xGLgmXyi6SdlI=", IdCodecFlag.SIGNATURE));
assertThrows(IdCodecException.class, () -> getCodec().fromUnqualified(FixtureIntegerId.class, "_-~SIG~-_CNCgkNhEN4PEpNkWvRPY/jEIwn49f1xGLgmXyi6SdlI=", IdCodecFlag.SIGNATURE));
}

@Test
public void testUnsignedIdContainingSignatureDelimiter() {
assertThrows(IdCodecException.class, () -> getCodec().fromQualified("scout.FixtureStringId:foo_-~SIG~-_bar", IdCodecFlag.SIGNATURE));
assertThrows(IdCodecException.class, () -> getCodec().fromQualified("scout.FixtureStringId:_-~SIG~-_bar", IdCodecFlag.SIGNATURE));
assertThrows(IdCodecException.class, () -> getCodec().fromQualified("scout.FixtureStringId:foo_-~SIG~-_", IdCodecFlag.SIGNATURE));
assertThrows(IdCodecException.class, () -> getCodec().fromQualified("scout.FixtureStringId:_-~SIG~-_", IdCodecFlag.SIGNATURE));
assertThrows(IdCodecException.class, () -> getCodec().fromUnqualified(FixtureStringId.class, "foo_-~SIG~-_bar", IdCodecFlag.SIGNATURE));
assertThrows(IdCodecException.class, () -> getCodec().fromUnqualified(FixtureStringId.class, "_-~SIG~-_bar", IdCodecFlag.SIGNATURE));
assertThrows(IdCodecException.class, () -> getCodec().fromUnqualified(FixtureStringId.class, "foo_-~SIG~-_", IdCodecFlag.SIGNATURE));
assertThrows(IdCodecException.class, () -> getCodec().fromUnqualified(FixtureStringId.class, "_-~SIG~-_", IdCodecFlag.SIGNATURE));

assertThrows(IdCodecException.class, () -> getCodec().fromQualified("scout.FixtureStringId:foo_-~SIG~-_bar"));
assertThrows(IdCodecException.class, () -> getCodec().fromQualified("scout.FixtureStringId:_-~SIG~-_bar"));
assertThrows(IdCodecException.class, () -> getCodec().fromQualified("scout.FixtureStringId:foo_-~SIG~-_"));
assertThrows(IdCodecException.class, () -> getCodec().fromQualified("scout.FixtureStringId:_-~SIG~-_"));
assertThrows(IdCodecException.class, () -> getCodec().fromUnqualified(FixtureStringId.class, "foo_-~SIG~-_bar"));
assertThrows(IdCodecException.class, () -> getCodec().fromUnqualified(FixtureStringId.class, "_-~SIG~-_bar"));
assertThrows(IdCodecException.class, () -> getCodec().fromUnqualified(FixtureStringId.class, "foo_-~SIG~-_"));
assertThrows(IdCodecException.class, () -> getCodec().fromUnqualified(FixtureStringId.class, "_-~SIG~-_"));
}

@Test
public void testSignedIdContainingSignatureDelimiter() {
assertThrows(IdCodecException.class, () -> getCodec().fromQualified("scout.FixtureCompositeWithNullStringValuesId:_-~SIG~-_foo;bar"));
assertThrows(IdCodecException.class, () -> getCodec().fromQualified("scout.FixtureCompositeWithNullStringValuesId:foo_-~SIG~-_;bar"));
assertThrows(IdCodecException.class, () -> getCodec().fromQualified("scout.FixtureCompositeWithNullStringValuesId:foo;_-~SIG~-_bar"));
assertThrows(IdCodecException.class, () -> getCodec().fromQualified("scout.FixtureCompositeWithNullStringValuesId:foo;bar_-~SIG~-_"));
assertThrows(IdCodecException.class, () -> getCodec().fromUnqualified(FixtureCompositeWithNullStringValuesId.class, "_-~SIG~-_foo;bar"));
assertThrows(IdCodecException.class, () -> getCodec().fromUnqualified(FixtureCompositeWithNullStringValuesId.class, "foo_-~SIG~-_;bar"));
assertThrows(IdCodecException.class, () -> getCodec().fromUnqualified(FixtureCompositeWithNullStringValuesId.class, "foo;_-~SIG~-_bar"));
assertThrows(IdCodecException.class, () -> getCodec().fromUnqualified(FixtureCompositeWithNullStringValuesId.class, "foo;bar_-~SIG~-_"));
}

@Test
Expand All @@ -757,8 +795,8 @@ public void testSignatureIdWithoutPassword() {
var integerId = FixtureIntegerId.of(42);
assertThrows(IdCodecException.class, () -> getCodec().toQualified(integerId, IdCodecFlag.SIGNATURE));
assertThrows(IdCodecException.class, () -> getCodec().toUnqualified(integerId, IdCodecFlag.SIGNATURE));
assertThrows(IdCodecException.class, () -> getCodec().fromQualified("scout.FixtureIntegerId:42###CNCgkNhEN4PEpNkWvRPY/jEIwn49f1xGLgmXyi6SdlI=", IdCodecFlag.SIGNATURE));
assertThrows(IdCodecException.class, () -> getCodec().fromUnqualified(FixtureIntegerId.class, "42###CNCgkNhEN4PEpNkWvRPY/jEIwn49f1xGLgmXyi6SdlI=", IdCodecFlag.SIGNATURE));
assertThrows(IdCodecException.class, () -> getCodec().fromQualified("scout.FixtureIntegerId:42_-~SIG~-_CNCgkNhEN4PEpNkWvRPY/jEIwn49f1xGLgmXyi6SdlI=", IdCodecFlag.SIGNATURE));
assertThrows(IdCodecException.class, () -> getCodec().fromUnqualified(FixtureIntegerId.class, "42_-~SIG~-_CNCgkNhEN4PEpNkWvRPY/jEIwn49f1xGLgmXyi6SdlI=", IdCodecFlag.SIGNATURE));
}

@IdTypeName("scout.FixtureDateId")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2024 BSI Business Systems Integration AG
* Copyright (c) 2010, 2025 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 @@ -47,7 +47,7 @@
public class IdCodec {

protected static final String ID_TYPENAME_DELIMITER = ":";
protected static final String SIGNATURE_DELIMITER = "###";
protected static final String SIGNATURE_DELIMITER = "_-~SIG~-_";

protected final LazyValue<IdFactory> m_idFactory = new LazyValue<>(IdFactory.class);
protected final LazyValue<IdInventory> m_idInventory = new LazyValue<>(IdInventory.class);
Expand Down Expand Up @@ -370,7 +370,7 @@ protected <ID extends IId> ID fromUnqualifiedUnchecked(Class<ID> idClass, String
*/
public String removeSignature(Class<? extends IId> idClass, String unqualifiedId, Set<IIdCodecFlag> flags) {
String[] unqualifiedIdSignatureParts = splitToSignatureParts(unqualifiedId);
assertSignature(idClass, unqualifiedIdSignatureParts, flags);
assertSignature(idClass, unqualifiedId, unqualifiedIdSignatureParts, flags);
return unqualifiedIdSignatureParts[0];
}

Expand All @@ -384,17 +384,19 @@ public String removeSignature(Class<? extends IId> idClass, String unqualifiedId
* This will check the presence and a signature if the id needs to be signed and the absence of such a signature if
* the id needs to be unsigned. In addition, the signature is verified for a signed id.
*/
protected void assertSignature(Class<? extends IId> idClass, String[] unqualifiedIdSignatureParts, Set<IIdCodecFlag> flags) {
protected void assertSignature(Class<? extends IId> idClass, String unqualifiedId, String[] unqualifiedIdSignatureParts, Set<IIdCodecFlag> flags) {
if (!isOneOf(IdCodecFlag.SIGNATURE, flags) || !idInventory().isIdSignature(idClass)) {
checkEquals(unqualifiedIdSignatureParts.length, 1, "Unqualified id must not be signed.");
checkEquals(unqualifiedIdSignatureParts[0], unqualifiedId, "Unqualified id must not be signed.");
return;
}
checkEquals(unqualifiedIdSignatureParts.length, 2, "Unqualified id must be signed.");
checkEquals(unqualifiedIdSignatureParts[1], createSignature(unqualifiedIdSignatureParts[0]), "Signature of unqualified id does not match.");
}

/**
* Checks if the two given {@link Object}s are equal and throws an {@link IdCodecException} with the given message if they are not equal.
* Checks if the two given {@link Object}s are equal and throws an {@link IdCodecException} with the given message if
* they are not equal.
*/
protected void checkEquals(Object o1, Object o2, String message) {
if (!Objects.equals(o1, o2)) {
Expand All @@ -406,7 +408,14 @@ protected void checkEquals(Object o1, Object o2, String message) {
* Split the given unqualifiedId into id and signature using the {@link #SIGNATURE_DELIMITER}.
*/
protected String[] splitToSignatureParts(String unqualifiedId) {
return unqualifiedId.split(SIGNATURE_DELIMITER);
int i = unqualifiedId.lastIndexOf(SIGNATURE_DELIMITER);
if (i < 0) {
return new String[]{unqualifiedId};
}
if (i + SIGNATURE_DELIMITER.length() == unqualifiedId.length()) {
return new String[]{unqualifiedId.substring(0, i)};
}
return new String[]{unqualifiedId.substring(0, i), unqualifiedId.substring(i + SIGNATURE_DELIMITER.length())};
}

/**
Expand Down

0 comments on commit 6118c70

Please sign in to comment.