From 6118c707b958a630166c3c88937360da4ba0e12a Mon Sep 17 00:00:00 2001 From: Fritz Schinkel Date: Wed, 15 Jan 2025 10:02:57 +0100 Subject: [PATCH] IdCodec: change signature delimiter and improve signature assertion 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 --- .../rt/dataobject/id/AbstractIdCodecTest.java | 48 +++++++++++++++++-- .../scout/rt/dataobject/id/IdCodec.java | 21 +++++--- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/org.eclipse.scout.rt.dataobject.test/src/main/java/org/eclipse/scout/rt/dataobject/id/AbstractIdCodecTest.java b/org.eclipse.scout.rt.dataobject.test/src/main/java/org/eclipse/scout/rt/dataobject/id/AbstractIdCodecTest.java index 40a2b76d0aa..21c618290e6 100644 --- a/org.eclipse.scout.rt.dataobject.test/src/main/java/org/eclipse/scout/rt/dataobject/id/AbstractIdCodecTest.java +++ b/org.eclipse.scout.rt.dataobject.test/src/main/java/org/eclipse/scout/rt/dataobject/id/AbstractIdCodecTest.java @@ -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 @@ -730,6 +730,11 @@ protected void collectSignatureIds(Set 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)); @@ -740,8 +745,41 @@ protected void collectSignatureIds(Set 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 @@ -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") diff --git a/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdCodec.java b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdCodec.java index 05aecef8250..9f7cf23e42c 100644 --- a/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdCodec.java +++ b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdCodec.java @@ -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 @@ -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 m_idFactory = new LazyValue<>(IdFactory.class); protected final LazyValue m_idInventory = new LazyValue<>(IdInventory.class); @@ -370,7 +370,7 @@ protected ID fromUnqualifiedUnchecked(Class idClass, String */ public String removeSignature(Class idClass, String unqualifiedId, Set flags) { String[] unqualifiedIdSignatureParts = splitToSignatureParts(unqualifiedId); - assertSignature(idClass, unqualifiedIdSignatureParts, flags); + assertSignature(idClass, unqualifiedId, unqualifiedIdSignatureParts, flags); return unqualifiedIdSignatureParts[0]; } @@ -384,9 +384,10 @@ public String removeSignature(Class 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 idClass, String[] unqualifiedIdSignatureParts, Set flags) { + protected void assertSignature(Class idClass, String unqualifiedId, String[] unqualifiedIdSignatureParts, Set 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."); @@ -394,7 +395,8 @@ protected void assertSignature(Class idClass, String[] unqualifie } /** - * 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)) { @@ -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())}; } /**