From 2f5acd41715d175b17815bb72b93142bb88dfbe4 Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Fri, 12 Jan 2024 18:41:16 +0100 Subject: [PATCH] use env variables for admin+restricted user, jdbc-url and admin-password --- .aliases | 3 + .../office/contact/HsOfficeContactEntity.java | 4 +- src/main/resources/application.yml | 4 ++ .../db/changelog/009-environment-defaults.sql | 12 ++++ .../resources/db/changelog/050-rbac-base.sql | 10 ++-- .../resources/db/changelog/055-rbac-views.sql | 8 +-- .../db/changelog/058-rbac-generators.sql | 4 +- .../db/changelog/080-rbac-global.sql | 4 +- .../db/changelog/123-test-package-rbac.sql | 2 +- .../db/changelog/133-test-domain-rbac.sql | 2 +- .../office/migration/ImportOfficeTables.java | 60 +++++++++++++++---- .../RbacRoleControllerAcceptanceTest.java | 10 ++++ .../RbacUserControllerAcceptanceTest.java | 9 +++ src/test/resources/migration/contacts.csv | 9 +-- 14 files changed, 109 insertions(+), 32 deletions(-) create mode 100644 src/main/resources/db/changelog/009-environment-defaults.sql diff --git a/.aliases b/.aliases index 9477474d..cc2b341a 100644 --- a/.aliases +++ b/.aliases @@ -1,3 +1,6 @@ +export HSADMINNG_POSTGRES_ADMIN_USERNAME=admin +export HSADMINNG_POSTGRES_RESTRICTED_USERNAME=restricted + gradleWrapper () { if [ ! -f gradlew ]; then echo "No 'gradlew' found. Maybe you are not in the root dir of a gradle project?" diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactEntity.java index 012379b9..c3ecb6be 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactEntity.java @@ -39,10 +39,10 @@ public class HsOfficeContactEntity implements Stringifyable, HasUuid { private String postalAddress; @Column(name = "emailaddresses", columnDefinition = "json") - private String emailAddresses; + private String emailAddresses; // TODO: check if we can really add multiple. format: ["eins@...", "zwei@..."] @Column(name = "phonenumbers", columnDefinition = "json") - private String phoneNumbers; + private String phoneNumbers; // TODO: check if we can really add multiple. format: { "office": "+49 40 12345-10", "fax": "+49 40 12345-05" } @Override public String toString() { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 120e98c3..8d928aeb 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -20,3 +20,7 @@ spring: liquibase: contexts: dev + +hsadminng: + postgres: + leakproof: diff --git a/src/main/resources/db/changelog/009-environment-defaults.sql b/src/main/resources/db/changelog/009-environment-defaults.sql new file mode 100644 index 00000000..fa69a98b --- /dev/null +++ b/src/main/resources/db/changelog/009-environment-defaults.sql @@ -0,0 +1,12 @@ +--liquibase formatted sql + + +-- ============================================================================ +-- NUMERIC-HASH-FUNCTIONS +--changeset hash:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +create function postgresAdminUserName() returns text as $$ +if +$$ language sql; +--// diff --git a/src/main/resources/db/changelog/050-rbac-base.sql b/src/main/resources/db/changelog/050-rbac-base.sql index fea69fe9..3254b464 100644 --- a/src/main/resources/db/changelog/050-rbac-base.sql +++ b/src/main/resources/db/changelog/050-rbac-base.sql @@ -763,13 +763,15 @@ $$; do $$ begin - if '${ADMIN_USER}'='admin' then + if '${HSADMINNG_POSTGRES_ADMIN_USERNAME}'='admin' then create role admin; grant all privileges on all tables in schema public to admin; - - create role restricted; - grant all privileges on all tables in schema public to restricted; end if; + + if '${HSADMINNG_POSTGRES_RESTRICTED_USERNAME}'='restricted' then + create role restricted; + end if; + -- grant all privileges on all tables in schema public to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME}; end $$ --// diff --git a/src/main/resources/db/changelog/055-rbac-views.sql b/src/main/resources/db/changelog/055-rbac-views.sql index 054b6df1..d1d1d926 100644 --- a/src/main/resources/db/changelog/055-rbac-views.sql +++ b/src/main/resources/db/changelog/055-rbac-views.sql @@ -41,7 +41,7 @@ select * ) as unordered -- @formatter:on order by objectTable || '#' || objectIdName || '.' || roleType; -grant all privileges on rbacrole_rv to ${RESTRICTED_USER}; +grant all privileges on rbacrole_rv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME}; --// @@ -126,7 +126,7 @@ select o.objectTable || '#' || findIdNameByObjectUuid(o.objectTable, o.uuid) || join RbacObject as o on o.uuid = r.objectUuid order by grantedRoleIdName; -- @formatter:on -grant all privileges on rbacrole_rv to ${RESTRICTED_USER}; +grant all privileges on rbacrole_rv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME}; --// @@ -240,7 +240,7 @@ create or replace view RbacUser_rv as ) as unordered -- @formatter:on order by unordered.name; -grant all privileges on RbacUser_rv to ${RESTRICTED_USER}; +grant all privileges on RbacUser_rv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME}; --// -- ============================================================================ @@ -326,7 +326,7 @@ select r.uuid as roleuuid, p.uuid as permissionUuid, join rbacgrants g on g.ascendantuuid = r.uuid join rbacpermission p on p.uuid = g.descendantuuid join rbacobject o on o.uuid = p.objectuuid; -grant all privileges on RbacOwnGrantedPermissions_rv to ${RESTRICTED_USER}; +grant all privileges on RbacOwnGrantedPermissions_rv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME}; -- @formatter:om -- ============================================================================ diff --git a/src/main/resources/db/changelog/058-rbac-generators.sql b/src/main/resources/db/changelog/058-rbac-generators.sql index 70dfc021..fa198308 100644 --- a/src/main/resources/db/changelog/058-rbac-generators.sql +++ b/src/main/resources/db/changelog/058-rbac-generators.sql @@ -104,7 +104,7 @@ begin create or replace view %1$s_iv as select target.uuid, cleanIdentifier(%2$s) as idName from %1$s as target; - grant all privileges on %1$s_iv to ${RESTRICTED_USER}; + grant all privileges on %1$s_iv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME}; $sql$, targetTable, idNameExpression); execute sql; @@ -157,7 +157,7 @@ begin from %1$s as target where target.uuid in (select * from accessibleObjects) order by %2$s; - grant all privileges on %1$s_rv to ${RESTRICTED_USER}; + grant all privileges on %1$s_rv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME}; $sql$, targetTable, orderBy); execute sql; diff --git a/src/main/resources/db/changelog/080-rbac-global.sql b/src/main/resources/db/changelog/080-rbac-global.sql index e2141f55..034400fa 100644 --- a/src/main/resources/db/changelog/080-rbac-global.sql +++ b/src/main/resources/db/changelog/080-rbac-global.sql @@ -18,7 +18,7 @@ create table Global ); create unique index Global_Singleton on Global ((0)); -grant select on global to ${RESTRICTED_USER}; +grant select on global to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME}; --// @@ -48,7 +48,7 @@ drop view if exists global_iv; create or replace view global_iv as select target.uuid, target.name as idName from global as target; -grant all privileges on global_iv to ${RESTRICTED_USER}; +grant all privileges on global_iv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME}; /* Returns the objectUuid for a given identifying name (in this case the idName). diff --git a/src/main/resources/db/changelog/123-test-package-rbac.sql b/src/main/resources/db/changelog/123-test-package-rbac.sql index d97f6148..8a2fd857 100644 --- a/src/main/resources/db/changelog/123-test-package-rbac.sql +++ b/src/main/resources/db/changelog/123-test-package-rbac.sql @@ -93,7 +93,7 @@ call generateRbacIdentityView('test_package', 'target.name'); -- from test_package as target -- where target.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('view', 'test_package', currentSubjectsUuids())) -- order by target.name; --- grant all privileges on test_package_rv to ${RESTRICTED_USER}; +-- grant all privileges on test_package_rv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME}; call generateRbacRestrictedView('test_package', 'target.name', $updates$ diff --git a/src/main/resources/db/changelog/133-test-domain-rbac.sql b/src/main/resources/db/changelog/133-test-domain-rbac.sql index fcd5e4b7..89b63018 100644 --- a/src/main/resources/db/changelog/133-test-domain-rbac.sql +++ b/src/main/resources/db/changelog/133-test-domain-rbac.sql @@ -110,5 +110,5 @@ create or replace view test_domain_rv as select target.* from test_domain as target where target.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('view', 'domain', currentSubjectsUuids())); -grant all privileges on test_domain_rv to ${RESTRICTED_USER}; +grant all privileges on test_domain_rv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME}; --// diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/migration/ImportOfficeTables.java b/src/test/java/net/hostsharing/hsadminng/hs/office/migration/ImportOfficeTables.java index bbb1efd4..803daae3 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/migration/ImportOfficeTables.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/migration/ImportOfficeTables.java @@ -22,6 +22,7 @@ import net.hostsharing.hsadminng.hs.office.sepamandate.HsOfficeSepaMandateEntity import net.hostsharing.test.JpaAttempt; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; @@ -55,30 +56,45 @@ import static org.assertj.core.api.Assertions.assertThat; * For a real import a main method will be added later * which reads CSV files from the file system. * - * When run on a Hostsharing database, it needs the following settings (hsh99_... just examples): + * When run on a Hostsharing database, it needs the following settings (hsh99_... just examples). + * + * In a real hostsharing environment, these are created via (the old) hsadmin: * * CREATE USER hsh99_admin WITH PASSWORD 'password'; - * GRANT ALL ON SCHEMA public TO hsh99_admin; + * CREATE DATABASE hsh99_hsadminng ENCODING 'UTF8' TEMPLATE template0; + * REVOKE ALL ON DATABASE hsh99_hsadminng FROM public; -- why does hsadmin do that? + * ALTER DATABASE hsh99_hsadminng OWNER TO hsh99_admin; * * CREATE USER hsh99_restricted WITH PASSWORD 'password'; - * GRANT ALL PRIVILEGES ON ALL TALBES IN SCHEMA hsh99_hsadminng to hsh99_restricted + * GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public to hsh99_restricted; + + * Additionally we need these settings (because the Hostsharing DB-Admin has no CREATE right): * - * CREATE EXTENSION "uuid-ossp"; + * CREATE EXTENSION IF EXISTS "uuid-ossp"; * - * And the environment variables ADMIN_USER and RESTRICTED_USER have to be set to the actual users. - * TODO: password + * Then these environment variables need to be set for Liquibase: + * export HSADMIN_POSTGRES_JDBC=jdbc:postgresql://localhost:6432/hsh99_hsadminng + * export HSADMIN_POSTGRES_ADMIN_USERNAME=hsh99_admin + * export HSADMIN_POSTGRES_ADMIN_PASSWORD=password + * export HSADMIN_POSTGRES_RESTRICTED_USERNAME=hsh99_restricted + * + * Then, to run the import, uncomment the @Diabled and then run: + * + * gw test -tests ImportOfficeTables -x check */ -// @Disabled +//@Disabled @DataJpaTest(properties = { - "spring.profiles.active=migration", - "spring.datasource.url=jdbc:postgresql://localhost:5432/postgres", - "spring.datasource.username=hsh99_admin", - "spring.datasource.password=password" + "spring.datasource.url=${HSADMIN_POSTGRES_JDBC:jdbc:tc:postgresql:15.5-bookworm:///spring_boot_testcontainers}", + "spring.datasource.username=${HSADMIN_POSTGRES_ADMIN_USERNAME:admin}", + "spring.datasource.password=${HSADMIN_POSTGRES_ADMIN_PASSWORD:password}" }) @Import({ Context.class, JpaAttempt.class }) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class ImportOfficeTables extends ContextBasedTest { + @Value("${spring.datasource.url}") + private String jdbcUrl; + // TODO: use real rbacSuperuser for actual import private static final String rbacSuperuser = "superuser-alex@hostsharing.net"; @@ -115,6 +131,10 @@ public class ImportOfficeTables extends ContextBasedTest { throw new RuntimeException(e); } + if ( !"admin".equals(System.getenv("ADMIN_USER") )) { + return; + } + // no contacts yet => mostly null values assertThat(partners.toString()).isEqualToIgnoringWhitespace(""" { @@ -150,6 +170,10 @@ public class ImportOfficeTables extends ContextBasedTest { throw new RuntimeException(e); } + if ( !"admin".equals(System.getenv("ADMIN_USER") )) { + return; + } + assertThat(partners.toString()).isEqualToIgnoringWhitespace(""" { 7=partner(Mellies, Michael: Herr Michael Mellies ), @@ -199,6 +223,10 @@ public class ImportOfficeTables extends ContextBasedTest { throw new RuntimeException(e); } + if ( !"admin".equals(System.getenv("ADMIN_USER") )) { + return; + } + assertThat(bankAccounts.toString()).isEqualToIgnoringWhitespace(""" { 234234=bankAccount(holder='Michael Mellies', iban='DE37500105177419788228', bic='INGDDEFFXXX'), @@ -224,6 +252,10 @@ public class ImportOfficeTables extends ContextBasedTest { throw new RuntimeException(e); } + if ( !"admin".equals(System.getenv("ADMIN_USER") )) { + return; + } + assertThat(coopShares.toString()).isEqualToIgnoringWhitespace(""" { 33443=CoopShareTransaction(10007, 2000-12-06, SUBSCRIPTION, 20, initial share subscription), @@ -245,6 +277,10 @@ public class ImportOfficeTables extends ContextBasedTest { throw new RuntimeException(e); } + if ( !"admin".equals(System.getenv("ADMIN_USER") )) { + return; + } + assertThat(coopAssets.toString()).isEqualToIgnoringWhitespace(""" { 30000=CoopAssetsTransaction(10007, 2000-12-06, DEPOSIT, 1280.00, for subscription A), @@ -442,7 +478,7 @@ public class ImportOfficeTables extends ContextBasedTest { .debitorNumberSuffix((byte) 0) .defaultPrefix(rec.getString("member_code").replace("hsh00-", "")) .partner(partner) - .billingContact(partner.getContact()) + .billingContact(partner.getContact()) // TODO falsch .billable(rec.isEmpty("free")) .vatReverseCharge(rec.getBoolean("exempt_vat")) .vatBusiness("GROSS".equals(rec.getString("indicator_vat"))) // TODO: remove diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/RbacRoleControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/RbacRoleControllerAcceptanceTest.java index abed40ac..389b0f12 100644 --- a/src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/RbacRoleControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/RbacRoleControllerAcceptanceTest.java @@ -7,12 +7,14 @@ import net.hostsharing.hsadminng.rbac.rbacuser.RbacUserRepository; import net.hostsharing.test.Accepts; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.server.LocalServerPort; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; +import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.*; @SpringBootTest( @@ -37,6 +39,14 @@ class RbacRoleControllerAcceptanceTest { @Autowired RbacRoleRepository rbacRoleRepository; + @Value("${HSADMINNG_POSTGRES_RESTRICTED_USERNAME}") + String restrictedUser; + + @Test + void testEnv() { + assertThat(restrictedUser).isEqualTo("restricted"); + } + @Test @Accepts({ "ROL:L(List)" }) void globalAdmin_withoutAssumedRole_canViewAllRoles() { diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserControllerAcceptanceTest.java index 76d738ad..9f2fd68e 100644 --- a/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserControllerAcceptanceTest.java @@ -9,6 +9,7 @@ import net.hostsharing.test.JpaAttempt; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.transaction.annotation.Transactional; @@ -42,6 +43,14 @@ class RbacUserControllerAcceptanceTest { @Autowired RbacUserRepository rbacUserRepository; + @Value("${HSADMINNG_POSTGRES_RESTRICTED_USERNAME}") + String restrictedUser; + + @Test + void testEnv() { + assertThat(restrictedUser).isEqualTo("restricted"); + } + @Nested class CreateRbacUser { diff --git a/src/test/resources/migration/contacts.csv b/src/test/resources/migration/contacts.csv index edbd183f..1d8cc3e8 100644 --- a/src/test/resources/migration/contacts.csv +++ b/src/test/resources/migration/contacts.csv @@ -1,5 +1,6 @@ contact_id; bp_id; salut; first_name; last_name; title; firma; co; street; zipcode;city; country; phone_private; phone_office; phone_mobile; fax; email; roles -71; 7; Herr; Michael; Mellies; ; ; ; Kleine Freiheit 50; 26524; Hage; DE; ; +49 4931 123456; +49 1522 123456;; mih@example.org; billing,operation -101; 10; Frau; Jenny; Meyer; Dr.; JM e.K.;; Waldweg 5; 11001; Berlin; DE; +49 30 7777777; +49 30 8888888; ; +49 30 9999999; jm@example.org; billing -102; 10; Herr; Andrew; Meyer; ; JM e.K.;; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 5555555; ; +49 30 9999999; am@example.org; operation -121; 12; ; Petra; Schmidt; ; Test PS;; ; ; ; ; ; ; ; ; ps@example.com; billing,operation +71; 7; Herr; Michael; Mellies; ; ; ; Kleine Freiheit 50; 26524; Hage; DE; ; +49 4931 123456; +49 1522 123456;; mih@example.org; contractual,billing,operation +101; 10; Frau; Jenny; Meyer; Dr.; JM e.K.;; Waldweg 5; 11001; Berlin; DE; +49 30 7777777; +49 30 1111111; ; +49 30 2222222; jm@example.org; billing +102; 10; Herr; Andrew; Meyer; ; JM e.K.;; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 3333333; ; +49 30 4444444; am@example.org; operation +102; 10; Herr; Philip; Meyer; ; JM e.K.;; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 5555555; ; +49 30 6666666; pm@example.org; contractual +121; 12; ; Petra; Schmidt; ; Test PS;; ; ; ; ; ; ; ; ; ps@example.com; billing,contractual,operation