From 234cee5815f8688d45146b792ebe3c8015a7dc74 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Tue, 23 Jun 2020 08:57:18 +0200 Subject: add new pendingRequestId generation-strategy that uses authenticated-encryption protect the internal pendingRequesttId --- ...tionPendingRequestIdGenerationStrategyTest.java | 484 +++++++++++++++++++++ ...dingRequestIdGenerationStrategyWithHsmTest.java | 42 ++ 2 files changed, 526 insertions(+) create mode 100644 eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest.java create mode 100644 eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyWithHsmTest.java (limited to 'eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core') diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest.java new file mode 100644 index 00000000..34f4a3b1 --- /dev/null +++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest.java @@ -0,0 +1,484 @@ +package at.gv.egiz.eaaf.core.impl.utils.test; + +import java.io.UnsupportedEncodingException; +import java.security.Provider; +import java.util.Base64; + +import javax.crypto.SecretKey; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTime; +import org.joda.time.ReadableInstant; +import org.joda.time.format.DateTimeFormat; +import org.jose4j.jwe.ContentEncryptionAlgorithmIdentifiers; +import org.jose4j.jwe.JsonWebEncryption; +import org.jose4j.jwe.KeyManagementAlgorithmIdentifiers; +import org.jose4j.lang.JoseException; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricKeyType; +import at.gv.egiz.eaaf.core.impl.data.Pair; +import at.gv.egiz.eaaf.core.impl.utils.AuthenticatedEncryptionPendingRequestIdGenerationStrategy; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("/spring/test_eaaf_pvp_not_lazy.beans.xml") +public class AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest { + + @Autowired private EaafKeyStoreFactory keyStoreFactory; + @Autowired private AuthenticatedEncryptionPendingRequestIdGenerationStrategy pendingIdStrategy; + + + @Test + public void generatePendingRequestId() throws EaafException { + String pendingId = pendingIdStrategy.generateExternalPendingRequestId(); + Assert.assertNotNull("pendingId", pendingId); + + } + + @Test + public void validatePendingRequestId() throws EaafException { + String extPendingId = pendingIdStrategy.generateExternalPendingRequestId(); + Assert.assertNotNull("external pendingId", extPendingId); + + + String pendingId = pendingIdStrategy.validateAndGetPendingRequestId(extPendingId); + Assert.assertNotNull("internal pendingId", pendingId); + + String pendingId2 = pendingIdStrategy.getPendingRequestIdWithOutChecks(extPendingId); + Assert.assertNotNull("internal pendingId", pendingId2); + + Assert.assertEquals("pendingId not match", pendingId, pendingId2); + + } + + @Test + public void nullPendingRequestId() { + try { + pendingIdStrategy.validateAndGetPendingRequestId(null); + Assert.fail("Wrong pendingId not detected"); + + } catch (PendingReqIdValidationException e) { + Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); + Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); + Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); + Assert.assertEquals("Wrong errorMsg", + "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, PendingReqId is 'null' or empty]", + e.getMessage()); + + } + } + + @Test + public void emptyPendingRequestId() { + try { + pendingIdStrategy.validateAndGetPendingRequestId(StringUtils.EMPTY); + Assert.fail("Wrong pendingId not detected"); + + } catch (PendingReqIdValidationException e) { + Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); + Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); + Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); + Assert.assertEquals("Wrong errorMsg", + "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, PendingReqId is 'null' or empty]", + e.getMessage()); + + } + } + + @Test + public void noBase64UrlPendingRequestId() { + try { + pendingIdStrategy.validateAndGetPendingRequestId(RandomStringUtils.randomAlphanumeric(25)); + Assert.fail("Wrong pendingId not detected"); + + } catch (PendingReqIdValidationException e) { + Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); + Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); + Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); + Assert.assertEquals("Wrong errorMsg", + "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, " + + "PendingReqId is NOT a valid String]", + e.getMessage()); + + } + } + + @Test + public void toLongBase64UrlPendingRequestId() { + try { + pendingIdStrategy.validateAndGetPendingRequestId(Base64.getUrlEncoder() + .encodeToString(RandomStringUtils.randomAlphanumeric(1100).getBytes())); + Assert.fail("Wrong pendingId not detected"); + + } catch (PendingReqIdValidationException e) { + Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); + Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); + Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); + Assert.assertEquals("Wrong errorMsg", + "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, " + + "pendingReqId exceeds max.size: 1024]", + e.getMessage()); + + } + } + + @Test + public void wrongFormat() throws EaafException, JoseException, UnsupportedEncodingException { + String payLoad = RandomStringUtils.randomAlphanumeric(25); + + String extPendingId = generateEncryptedPendingId(payLoad, + KeyManagementAlgorithmIdentifiers.DIRECT, + ContentEncryptionAlgorithmIdentifiers.AES_128_GCM, + "pendingReqIdSecret"); + + try { + pendingIdStrategy.validateAndGetPendingRequestId(Base64.getUrlEncoder() + .encodeToString(extPendingId.getBytes())); + Assert.fail("Wrong pendingId not detected"); + + } catch (PendingReqIdValidationException e) { + Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); + Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); + Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); + Assert.assertEquals("Wrong errorMsg", + "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, " + + "PendingReqId has an unvalid format]", + e.getMessage()); + + } + } + + @Test + public void wrongFormatToLong() throws EaafException, JoseException, UnsupportedEncodingException { + String payLoad = RandomStringUtils.randomAlphanumeric(25) + "|" + + RandomStringUtils.randomAlphanumeric(25) + "|" + "aabbcc"; + + String extPendingId = generateEncryptedPendingId(payLoad, + KeyManagementAlgorithmIdentifiers.DIRECT, + ContentEncryptionAlgorithmIdentifiers.AES_128_GCM, + "pendingReqIdSecret"); + + try { + pendingIdStrategy.validateAndGetPendingRequestId(Base64.getUrlEncoder() + .encodeToString(extPendingId.getBytes())); + Assert.fail("Wrong pendingId not detected"); + + } catch (PendingReqIdValidationException e) { + Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); + Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); + Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); + Assert.assertEquals("Wrong errorMsg", + "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, " + + "PendingReqId has an unvalid format]", + e.getMessage()); + + } + } + + @Test + public void wrongFormatNoDate() throws EaafException, JoseException, UnsupportedEncodingException { + String payLoad = RandomStringUtils.randomAlphanumeric(25) + "|" + + RandomStringUtils.randomAlphanumeric(25); + + String extPendingId = generateEncryptedPendingId(payLoad, + KeyManagementAlgorithmIdentifiers.DIRECT, + ContentEncryptionAlgorithmIdentifiers.AES_128_GCM, + "pendingReqIdSecret"); + + try { + pendingIdStrategy.validateAndGetPendingRequestId(Base64.getUrlEncoder() + .encodeToString(extPendingId.getBytes())); + Assert.fail("Wrong pendingId not detected"); + + } catch (PendingReqIdValidationException e) { + Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); + Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); + Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); + Assert.assertEquals("Wrong errorMsg", + "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, " + + "PendingReqId is NOT a valid String]", + e.getMessage()); + + } + } + + @Test + public void wrongFormatWrongDate() throws EaafException, JoseException, UnsupportedEncodingException { + String payLoad = "2020-01-01 12:01:55 111" + "|" + + RandomStringUtils.randomAlphanumeric(25); + + String extPendingId = generateEncryptedPendingId(payLoad, + KeyManagementAlgorithmIdentifiers.DIRECT, + ContentEncryptionAlgorithmIdentifiers.AES_128_GCM, + "pendingReqIdSecret"); + + try { + pendingIdStrategy.validateAndGetPendingRequestId(Base64.getUrlEncoder() + .encodeToString(extPendingId.getBytes())); + Assert.fail("Wrong pendingId not detected"); + + } catch (PendingReqIdValidationException e) { + Assert.assertNotNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); + Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); + Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); + Assert.assertTrue("Wrong errorMsg", e.getMessage().contains("PendingRequestId exceeds the valid period")); + + } + } + + @Test + public void wrongFormatNotValidation() throws EaafException, JoseException, UnsupportedEncodingException { + String payLoad = RandomStringUtils.randomAlphanumeric(25); + + String extPendingId = generateEncryptedPendingId(payLoad, + KeyManagementAlgorithmIdentifiers.DIRECT, + ContentEncryptionAlgorithmIdentifiers.AES_128_GCM, + "pendingReqIdSecret"); + + try { + pendingIdStrategy.getPendingRequestIdWithOutChecks(Base64.getUrlEncoder() + .encodeToString(extPendingId.getBytes())); + Assert.fail("Wrong pendingId not detected"); + + } catch (PendingReqIdValidationException e) { + Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); + Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); + Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); + Assert.assertEquals("Wrong errorMsg", + "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, " + + "PendingReqId has an unvalid format]", + e.getMessage()); + + } + } + + @Test + public void wrongFormatToLongNotValidation() throws EaafException, JoseException, UnsupportedEncodingException { + String payLoad = RandomStringUtils.randomAlphanumeric(25) + "|" + + RandomStringUtils.randomAlphanumeric(25) + "|" + "aabbcc"; + + String extPendingId = generateEncryptedPendingId(payLoad, + KeyManagementAlgorithmIdentifiers.DIRECT, + ContentEncryptionAlgorithmIdentifiers.AES_128_GCM, + "pendingReqIdSecret"); + + try { + pendingIdStrategy.getPendingRequestIdWithOutChecks(Base64.getUrlEncoder() + .encodeToString(extPendingId.getBytes())); + Assert.fail("Wrong pendingId not detected"); + + } catch (PendingReqIdValidationException e) { + Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); + Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); + Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); + Assert.assertEquals("Wrong errorMsg", + "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, " + + "PendingReqId has an unvalid format]", + e.getMessage()); + + } + } + + @Test + public void wrongFormatNoDateNotValidation() throws EaafException, JoseException, UnsupportedEncodingException { + String payLoad = RandomStringUtils.randomAlphanumeric(25) + "|" + + RandomStringUtils.randomAlphanumeric(25); + + String extPendingId = generateEncryptedPendingId(payLoad, + KeyManagementAlgorithmIdentifiers.DIRECT, + ContentEncryptionAlgorithmIdentifiers.AES_128_GCM, + "pendingReqIdSecret"); + + + String intPendingId = pendingIdStrategy.getPendingRequestIdWithOutChecks(Base64.getUrlEncoder() + .encodeToString(extPendingId.getBytes())); + Assert.assertNotNull("Int PendingId", intPendingId); + + } + + @Test + public void wrongFormatWrongDateNotValidation() throws EaafException, JoseException, UnsupportedEncodingException { + String payLoad = "2020-01-01 12:01:55 111" + "|" + + RandomStringUtils.randomAlphanumeric(25); + + String extPendingId = generateEncryptedPendingId(payLoad, + KeyManagementAlgorithmIdentifiers.DIRECT, + ContentEncryptionAlgorithmIdentifiers.AES_128_GCM, + "pendingReqIdSecret"); + + + String intPendingId = pendingIdStrategy.getPendingRequestIdWithOutChecks(Base64.getUrlEncoder() + .encodeToString(extPendingId.getBytes())); + Assert.assertNotNull("Int PendingId", intPendingId); + + + } + + @Test + public void validFormat() throws EaafException, JoseException, UnsupportedEncodingException { + String intId = RandomStringUtils.randomAlphanumeric(25); + ReadableInstant now = DateTime.now(); + String payLoad = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss SSS").print(now) + + "|" + intId; + + String extPendingId = generateEncryptedPendingId(payLoad, + KeyManagementAlgorithmIdentifiers.DIRECT, + ContentEncryptionAlgorithmIdentifiers.AES_128_GCM, + "pendingReqIdSecret"); + + + String intPendingId = pendingIdStrategy.getPendingRequestIdWithOutChecks(Base64.getUrlEncoder() + .encodeToString(extPendingId.getBytes())); + Assert.assertNotNull("Int PendingId", intPendingId); + Assert.assertEquals("pendingId not match", intId, intPendingId); + + } + + @Test + public void validFormatNotValidation() throws EaafException, JoseException, UnsupportedEncodingException { + String intId = RandomStringUtils.randomAlphanumeric(25); + String payLoad = "2020-01-01 12:01:55 111" + + "|" + intId; + + String extPendingId = generateEncryptedPendingId(payLoad, + KeyManagementAlgorithmIdentifiers.DIRECT, + ContentEncryptionAlgorithmIdentifiers.AES_128_GCM, + "pendingReqIdSecret"); + + String intPendingId = pendingIdStrategy.getPendingRequestIdWithOutChecks(Base64.getUrlEncoder() + .encodeToString(extPendingId.getBytes())); + Assert.assertNotNull("Int PendingId", intPendingId); + + } + + @Test + public void validFormatWrongDateNotValidation() throws EaafException, JoseException, UnsupportedEncodingException { + String intId = RandomStringUtils.randomAlphanumeric(25); + String payLoad = "2020-01-01 12:01:55 111" + "|" + + intId; + + String extPendingId = generateEncryptedPendingId(payLoad, + KeyManagementAlgorithmIdentifiers.DIRECT, + ContentEncryptionAlgorithmIdentifiers.AES_128_GCM, + "pendingReqIdSecret"); + + + String intPendingId = pendingIdStrategy.getPendingRequestIdWithOutChecks(Base64.getUrlEncoder() + .encodeToString(extPendingId.getBytes())); + Assert.assertNotNull("Int PendingId", intPendingId); + Assert.assertEquals("pendingId not match", intId, intPendingId); + + + } + + @Test + public void wrongEncrypted() throws EaafException, JoseException, UnsupportedEncodingException { + String payLoad = RandomStringUtils.randomAlphanumeric(25); + + String extPendingId = generateEncryptedPendingId(payLoad, + KeyManagementAlgorithmIdentifiers.DIRECT, + ContentEncryptionAlgorithmIdentifiers.AES_128_GCM, + "wrongPassword"); + + try { + pendingIdStrategy.validateAndGetPendingRequestId(Base64.getUrlEncoder() + .encodeToString(extPendingId.getBytes())); + Assert.fail("Wrong pendingId not detected"); + + } catch (PendingReqIdValidationException e) { + Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); + Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); + Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); + Assert.assertEquals("Wrong errorMsg", + "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, " + + "PendingReqId is NOT a valid encrypted]", + e.getMessage()); + + } + } + + @Ignore + @Test + public void wrongEncryptionAlg() throws EaafException, JoseException, UnsupportedEncodingException { + String payLoad = RandomStringUtils.randomAlphanumeric(25); + + String extPendingId = generateEncryptedPendingId(payLoad, + KeyManagementAlgorithmIdentifiers.A256KW, + ContentEncryptionAlgorithmIdentifiers.AES_128_CBC_HMAC_SHA_256, + "pendingReqIdSecret"); + + try { + pendingIdStrategy.validateAndGetPendingRequestId(Base64.getUrlEncoder() + .encodeToString(extPendingId.getBytes())); + Assert.fail("Wrong pendingId not detected"); + + } catch (PendingReqIdValidationException e) { + Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); + Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); + Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); + Assert.assertEquals("Wrong errorMsg", + "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, " + + "PendingReqId has an unvalid format]", + e.getMessage()); + + } + } + + @Ignore + @Test + public void wrongKeyEncAlg() throws EaafException, JoseException, UnsupportedEncodingException { + String payLoad = RandomStringUtils.randomAlphanumeric(25); + + String extPendingId = generateEncryptedPendingId(payLoad, + KeyManagementAlgorithmIdentifiers.A128KW, + ContentEncryptionAlgorithmIdentifiers.AES_128_CBC_HMAC_SHA_256, + "pendingReqIdSecret"); + + try { + pendingIdStrategy.validateAndGetPendingRequestId(Base64.getUrlEncoder() + .encodeToString(extPendingId.getBytes())); + Assert.fail("Wrong pendingId not detected"); + + } catch (PendingReqIdValidationException e) { + Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId()); + Assert.assertNull("internal pendingReq", e.getInvalidPendingReq()); + Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId()); + Assert.assertEquals("Wrong errorMsg", + "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, " + + "PendingReqId is NOT a valid String]", + e.getMessage()); + + } + } + + private String generateEncryptedPendingId(String payLoad, String direct, String aes128Gcm, String softKeyPassphrase) + throws EaafException, JoseException, UnsupportedEncodingException { + SymmetricKeyConfiguration config = new SymmetricKeyConfiguration(); + config.setFriendlyName("jUnit"); + config.setKeyType(SymmetricKeyType.PASSPHRASE); + config.setSoftKeySalt("notRequiredInThisScenario"); + config.setSoftKeyPassphrase(softKeyPassphrase); + Pair key = keyStoreFactory.buildNewSymmetricKey(config); + + JsonWebEncryption encToken = new JsonWebEncryption(); + encToken.setAlgorithmHeaderValue(direct); + encToken.setEncryptionMethodHeaderParameter(aes128Gcm); + encToken.setKey(key.getFirst()); + encToken.setPayload(payLoad); + + return encToken.getCompactSerialization(); + + } + +} diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyWithHsmTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyWithHsmTest.java new file mode 100644 index 00000000..95a2b7a7 --- /dev/null +++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyWithHsmTest.java @@ -0,0 +1,42 @@ +package at.gv.egiz.eaaf.core.impl.utils.test; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.utils.AuthenticatedEncryptionPendingRequestIdGenerationStrategy; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("/spring/test_eaaf_pvp_not_lazy_with_hsm.beans.xml") +public class AuthenticatedEncryptionPendingRequestIdGenerationStrategyWithHsmTest { + + @Autowired private AuthenticatedEncryptionPendingRequestIdGenerationStrategy pendingIdStrategy; + + @Test + public void generatePendingRequestId() throws EaafException { + String pendingId = pendingIdStrategy.generateExternalPendingRequestId(); + Assert.assertNotNull("pendingId", pendingId); + + } + + @Test + public void validatePendingRequestId() throws EaafException { + String extPendingId = pendingIdStrategy.generateExternalPendingRequestId(); + Assert.assertNotNull("external pendingId", extPendingId); + + + String pendingId = pendingIdStrategy.validateAndGetPendingRequestId(extPendingId); + Assert.assertNotNull("internal pendingId", pendingId); + + String pendingId2 = pendingIdStrategy.getPendingRequestIdWithOutChecks(extPendingId); + Assert.assertNotNull("internal pendingId", pendingId2); + + Assert.assertEquals("pendingId not match", pendingId, pendingId2); + + } + +} -- cgit v1.2.3