From 560cd9cf9fd615b7a436220b00f65cf9e0f8e5ba Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Thu, 13 Oct 2022 10:36:20 +0200 Subject: [PATCH] audit log with context per task instead of just transaction --- .../changelog/006-numeric-hash-functions.sql | 12 ++++++++++ .../resources/db/changelog/020-audit-log.sql | 22 ++++++++++++------- .../208-hs-office-contact-test-data.sql | 2 +- .../218-hs-office-person-test-data.sql | 2 +- .../228-hs-office-partner-test-data.sql | 2 +- .../238-hs-office-relationship-test-data.sql | 2 +- .../248-hs-office-bankaccount-test-data.sql | 2 +- .../278-hs-office-debitor-test-data.sql | 2 +- .../db/changelog/db.changelog-master.yaml | 2 ++ ...eBankAccountRepositoryIntegrationTest.java | 8 +++---- ...fficeContactRepositoryIntegrationTest.java | 7 +++--- ...fficeDebitorRepositoryIntegrationTest.java | 7 +++--- ...fficePartnerRepositoryIntegrationTest.java | 7 +++--- ...OfficePersonRepositoryIntegrationTest.java | 9 ++++---- ...RelationshipRepositoryIntegrationTest.java | 8 +++---- 15 files changed, 58 insertions(+), 36 deletions(-) create mode 100644 src/main/resources/db/changelog/006-numeric-hash-functions.sql diff --git a/src/main/resources/db/changelog/006-numeric-hash-functions.sql b/src/main/resources/db/changelog/006-numeric-hash-functions.sql new file mode 100644 index 00000000..5e2e2814 --- /dev/null +++ b/src/main/resources/db/changelog/006-numeric-hash-functions.sql @@ -0,0 +1,12 @@ +--liquibase formatted sql + + +-- ============================================================================ +-- NUMERIC-HASH-FUNCTIONS +--changeset hash:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +create function bigIntHash(text) returns bigint as $$ +select ('x'||substr(md5($1),1,16))::bit(64)::bigint; +$$ language sql; +--// diff --git a/src/main/resources/db/changelog/020-audit-log.sql b/src/main/resources/db/changelog/020-audit-log.sql index 5965e807..e9a6b413 100644 --- a/src/main/resources/db/changelog/020-audit-log.sql +++ b/src/main/resources/db/changelog/020-audit-log.sql @@ -23,7 +23,8 @@ do $$ */ create table tx_context ( - txId bigint primary key not null, + contextId bigint primary key not null, + txId bigint not null, txTimestamp timestamp not null, currentUser varchar(63) not null, -- not the uuid, because users can be deleted assumedRoles varchar not null, -- not the uuids, because roles can be deleted @@ -42,7 +43,7 @@ create index on tx_context using brin (txTimestamp); */ create table tx_journal ( - txId bigint not null references tx_context (txId), + contextId bigint not null references tx_context (contextId), targetTable text not null, targetUuid uuid not null, -- Assumes that all audited tables have a uuid column. targetOp operation not null, @@ -61,28 +62,33 @@ create index on tx_journal (targetTable, targetUuid); create or replace function tx_journal_trigger() returns trigger language plpgsql as $$ +declare + curTask text; + curContextId bigint; begin + curTask := currentTask(); + curContextId := txid_current()+bigIntHash(curTask); insert - into tx_context - values (txid_current(), now(), - currentUser(), assumedRoles(), currentTask(), currentRequest()) + into tx_context (contextId, txId, txTimestamp, currentUser, assumedRoles, currentTask, currentRequest) + values (curContextId, txid_current(), now(), + currentUser(), assumedRoles(), curTask, currentRequest()) on conflict do nothing; case tg_op when 'INSERT' then insert into tx_journal - values (txid_current(), + values (curContextId, tg_table_name, new.uuid, tg_op::operation, to_jsonb(new)); when 'UPDATE' then insert into tx_journal - values (txid_current(), + values (curContextId, tg_table_name, old.uuid, tg_op::operation, jsonb_changes_delta(to_jsonb(old), to_jsonb(new))); when 'DELETE' then insert into tx_journal - values (txid_current(), + values (curContextId, tg_table_name, old.uuid, 'DELETE'::operation, null::jsonb); else raise exception 'Trigger op % not supported for %.', tg_op, tg_table_name; diff --git a/src/main/resources/db/changelog/208-hs-office-contact-test-data.sql b/src/main/resources/db/changelog/208-hs-office-contact-test-data.sql index 1d651a69..af1fc304 100644 --- a/src/main/resources/db/changelog/208-hs-office-contact-test-data.sql +++ b/src/main/resources/db/changelog/208-hs-office-contact-test-data.sql @@ -14,7 +14,7 @@ declare currentTask varchar; emailAddr varchar; begin - currentTask = 'creating RBAC test contact ' || contLabel; + currentTask = 'creating contact test-data ' || contLabel; execute format('set local hsadminng.currentTask to %L', currentTask); emailAddr = 'contact-admin@' || cleanIdentifier(contLabel) || '.example.com'; diff --git a/src/main/resources/db/changelog/218-hs-office-person-test-data.sql b/src/main/resources/db/changelog/218-hs-office-person-test-data.sql index d6567483..35946088 100644 --- a/src/main/resources/db/changelog/218-hs-office-person-test-data.sql +++ b/src/main/resources/db/changelog/218-hs-office-person-test-data.sql @@ -21,7 +21,7 @@ declare emailAddr varchar; begin fullName := concat_ws(', ', newTradeName, newFamilyName, newGivenName); - currentTask = 'creating RBAC test person ' || fullName; + currentTask = 'creating person test-data ' || fullName; emailAddr = 'person-' || left(cleanIdentifier(fullName), 32) || '@example.com'; call defineContext(currentTask); perform createRbacUser(emailAddr); diff --git a/src/main/resources/db/changelog/228-hs-office-partner-test-data.sql b/src/main/resources/db/changelog/228-hs-office-partner-test-data.sql index d2e15861..7e4f5505 100644 --- a/src/main/resources/db/changelog/228-hs-office-partner-test-data.sql +++ b/src/main/resources/db/changelog/228-hs-office-partner-test-data.sql @@ -17,7 +17,7 @@ declare relatedContact hs_office_contact; begin idName := cleanIdentifier( personTradeName|| '-' || contactLabel); - currentTask := 'creating RBAC test partner ' || idName; + currentTask := 'creating partner test-data ' || idName; call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global.admin'); execute format('set local hsadminng.currentTask to %L', currentTask); diff --git a/src/main/resources/db/changelog/238-hs-office-relationship-test-data.sql b/src/main/resources/db/changelog/238-hs-office-relationship-test-data.sql index 628c377a..1e8e40c0 100644 --- a/src/main/resources/db/changelog/238-hs-office-relationship-test-data.sql +++ b/src/main/resources/db/changelog/238-hs-office-relationship-test-data.sql @@ -23,7 +23,7 @@ declare begin idName := cleanIdentifier( anchorPersonTradeName || '-' || holderPersonFamilyName); - currentTask := 'creating RBAC test relationship ' || idName; + currentTask := 'creating relationship test-data ' || idName; call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global.admin'); execute format('set local hsadminng.currentTask to %L', currentTask); diff --git a/src/main/resources/db/changelog/248-hs-office-bankaccount-test-data.sql b/src/main/resources/db/changelog/248-hs-office-bankaccount-test-data.sql index 16560864..88deb9fe 100644 --- a/src/main/resources/db/changelog/248-hs-office-bankaccount-test-data.sql +++ b/src/main/resources/db/changelog/248-hs-office-bankaccount-test-data.sql @@ -14,7 +14,7 @@ declare currentTask varchar; emailAddr varchar; begin - currentTask = 'creating RBAC test bankaccount ' || givenHolder; + currentTask = 'creating bankaccount test-data ' || givenHolder; execute format('set local hsadminng.currentTask to %L', currentTask); emailAddr = 'bankaccount-admin@' || cleanIdentifier(givenHolder) || '.example.com'; diff --git a/src/main/resources/db/changelog/278-hs-office-debitor-test-data.sql b/src/main/resources/db/changelog/278-hs-office-debitor-test-data.sql index 208f6823..1435a86d 100644 --- a/src/main/resources/db/changelog/278-hs-office-debitor-test-data.sql +++ b/src/main/resources/db/changelog/278-hs-office-debitor-test-data.sql @@ -19,7 +19,7 @@ declare newDebitorNumber numeric(6); begin idName := cleanIdentifier( partnerTradeName|| '-' || billingContactLabel); - currentTask := 'creating RBAC test debitor ' || idName; + currentTask := 'creating debitor test-data ' || idName; call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global.admin'); execute format('set local hsadminng.currentTask to %L', currentTask); diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index 17fdafa2..376c4609 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -9,6 +9,8 @@ databaseChangeLog: file: db/changelog/004-jsonb-changes-delta.sql - include: file: db/changelog/005-uuid-ossp-extension.sql + - include: + file: db/changelog/006-numeric-hash-functions.sql - include: file: db/changelog/010-context.sql - include: diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountRepositoryIntegrationTest.java index b3680965..feb3c887 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountRepositoryIntegrationTest.java @@ -293,14 +293,13 @@ class HsOfficeBankAccountRepositoryIntegrationTest extends ContextBasedTest { }).assertSuccessful().returnedValue(); } - @Test public void auditJournalLogIsAvailable() { // given final var query = em.createNativeQuery(""" select c.currenttask, j.targettable, j.targetop from tx_journal j - join tx_context c on j.txid = c.txid + join tx_context c on j.contextId = c.contextId where targettable = 'hs_office_bankaccount'; """); @@ -308,8 +307,9 @@ class HsOfficeBankAccountRepositoryIntegrationTest extends ContextBasedTest { @SuppressWarnings("unchecked") final List customerLogEntries = query.getResultList(); // then - assertThat(customerLogEntries).map(Arrays::toString) - .contains("[creating RBAC test bankaccount First GmbH, hs_office_bankaccount, INSERT]"); + assertThat(customerLogEntries).map(Arrays::toString).contains( + "[creating bankaccount test-data First GmbH, hs_office_bankaccount, INSERT]", + "[creating bankaccount test-data Second e.K., hs_office_bankaccount, INSERT]"); } @BeforeEach diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepositoryIntegrationTest.java index 40cd8628..bb950436 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepositoryIntegrationTest.java @@ -271,7 +271,7 @@ class HsOfficeContactRepositoryIntegrationTest extends ContextBasedTest { final var query = em.createNativeQuery(""" select c.currenttask, j.targettable, j.targetop from tx_journal j - join tx_context c on j.txid = c.txid + join tx_context c on j.contextId = c.contextId where targettable = 'hs_office_contact'; """); @@ -279,8 +279,9 @@ class HsOfficeContactRepositoryIntegrationTest extends ContextBasedTest { @SuppressWarnings("unchecked") final List customerLogEntries = query.getResultList(); // then - assertThat(customerLogEntries).map(Arrays::toString) - .contains("[creating RBAC test contact first contact, hs_office_contact, INSERT]"); + assertThat(customerLogEntries).map(Arrays::toString).contains( + "[creating contact test-data first contact, hs_office_contact, INSERT]", + "[creating contact test-data second contact, hs_office_contact, INSERT]"); } private HsOfficeContactEntity givenSomeTemporaryContact( diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java index 3294a216..598ffc4d 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java @@ -438,7 +438,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest { final var query = em.createNativeQuery(""" select c.currenttask, j.targettable, j.targetop from tx_journal j - join tx_context c on j.txid = c.txid + join tx_context c on j.contextId = c.contextId where targettable = 'hs_office_debitor'; """); @@ -446,8 +446,9 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest { @SuppressWarnings("unchecked") final List customerLogEntries = query.getResultList(); // then - assertThat(customerLogEntries).map(Arrays::toString) - .contains("[creating RBAC test debitor FirstGmbH-firstcontact, hs_office_debitor, INSERT]"); + assertThat(customerLogEntries).map(Arrays::toString).contains( + "[creating debitor test-data FirstGmbH-firstcontact, hs_office_debitor, INSERT]", + "[creating debitor test-data Seconde.K.-secondcontact, hs_office_debitor, INSERT]"); } private HsOfficePartnerEntity rawReference(final HsOfficePartnerEntity givenPartner) { diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java index 0417f548..3dce4b26 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java @@ -393,7 +393,7 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest { final var query = em.createNativeQuery(""" select c.currenttask, j.targettable, j.targetop from tx_journal j - join tx_context c on j.txid = c.txid + join tx_context c on j.contextId = c.contextId where targettable = 'hs_office_partner'; """); @@ -401,8 +401,9 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest { @SuppressWarnings("unchecked") final List customerLogEntries = query.getResultList(); // then - assertThat(customerLogEntries).map(Arrays::toString) - .contains("[creating RBAC test partner FirstGmbH-firstcontact, hs_office_partner, INSERT]"); + assertThat(customerLogEntries).map(Arrays::toString).contains( + "[creating partner test-data FirstGmbH-firstcontact, hs_office_partner, INSERT]", + "[creating partner test-data Seconde.K.-secondcontact, hs_office_partner, INSERT]"); } @AfterEach diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java index aef0afb9..f6627551 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java @@ -3,9 +3,7 @@ package net.hostsharing.hsadminng.hs.office.person; import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.context.ContextBasedTest; import net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantRepository; -import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantRepository; import net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleRepository; -import net.hostsharing.hsadminng.rbac.rbacrole.RbacRoleRepository; import net.hostsharing.test.Array; import net.hostsharing.test.JpaAttempt; import org.junit.jupiter.api.AfterEach; @@ -272,7 +270,7 @@ class HsOfficePersonRepositoryIntegrationTest extends ContextBasedTest { final var query = em.createNativeQuery(""" select c.currenttask, j.targettable, j.targetop from tx_journal j - join tx_context c on j.txid = c.txid + join tx_context c on j.contextId = c.contextId where targettable = 'hs_office_person'; """); @@ -280,8 +278,9 @@ class HsOfficePersonRepositoryIntegrationTest extends ContextBasedTest { @SuppressWarnings("unchecked") final List customerLogEntries = query.getResultList(); // then - assertThat(customerLogEntries).map(Arrays::toString) - .contains("[creating RBAC test person First GmbH, hs_office_person, INSERT]"); + assertThat(customerLogEntries).map(Arrays::toString).contains( + "[creating person test-data First GmbH, hs_office_person, INSERT]", + "[creating person test-data Second e.K., Sandra, Miller, hs_office_person, INSERT]"); } @AfterEach diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipRepositoryIntegrationTest.java index aeb2c36b..1efcd216 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipRepositoryIntegrationTest.java @@ -26,7 +26,6 @@ import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.grantD import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.roleNamesOf; import static net.hostsharing.test.JpaAttempt.attempt; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assumptions.assumeThat; @DataJpaTest @ComponentScan(basePackageClasses = { HsOfficeRelationshipRepository.class, Context.class, JpaAttempt.class }) @@ -373,7 +372,7 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTest { final var query = em.createNativeQuery(""" select c.currenttask, j.targettable, j.targetop from tx_journal j - join tx_context c on j.txid = c.txid + join tx_context c on j.contextId = c.contextId where targettable = 'hs_office_relationship'; """); @@ -381,8 +380,9 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTest { @SuppressWarnings("unchecked") final List customerLogEntries = query.getResultList(); // then - assertThat(customerLogEntries).map(Arrays::toString) - .contains("[creating RBAC test relationship FirstGmbH-Smith, hs_office_relationship, INSERT]"); + assertThat(customerLogEntries).map(Arrays::toString).contains( + "[creating relationship test-data FirstGmbH-Smith, hs_office_relationship, INSERT]", + "[creating relationship test-data Seconde.K.-Smith, hs_office_relationship, INSERT]"); } private HsOfficeRelationshipEntity givenSomeTemporaryRelationshipBessler(final String holderPerson, final String contact) {