diff --git a/dds-backoffice/README.md b/dds-backoffice/README.md index 3286201..27ebab2 100644 --- a/dds-backoffice/README.md +++ b/dds-backoffice/README.md @@ -5,6 +5,7 @@ - 기본 포트: `8083` - 기본 화면: `/` 또는 `/dds` - 기본 보호 객체: `ADMIN.V_DDS_CUSTOMERS_PG`, `ADMIN.V_DDS_CUSTOMERS_MY` +- DDS 전용 사용자: `dds_demo_my`, `dds_demo_pg`, `dds_demo_both`, `dds_demo_none` - 조회 방식: 선택한 DDS `END USER` 자격으로 직접 Oracle JDBC 연결 ## 두 데모의 관계 @@ -28,10 +29,10 @@ ORDS Handler가 Bearer 값을 `cb_dds_hr` 같은 문자열로 매핑하는 것 ## 실행 -먼저 기존 DDS SQL을 적용합니다. +먼저 DDS 데모 전용 로컬 데이터셋과 권한 객체를 적용합니다. 이 스크립트는 VPD VIEW나 외부 RDS DB Link를 사용하지 않습니다. ```bash -./run.sh dds-setup +sqlplus "$ADB_USER/$ADB_PASSWORD@$ADB_TNS" @sql/adb/31_dds_standalone_demo_setup.sql ``` 그 다음 DDS 인스턴스를 실행합니다. diff --git a/dds-backoffice/src/main/java/com/cloudhandson/ddsbackoffice/service/DdsQueryService.java b/dds-backoffice/src/main/java/com/cloudhandson/ddsbackoffice/service/DdsQueryService.java index ff56a69..869dabf 100644 --- a/dds-backoffice/src/main/java/com/cloudhandson/ddsbackoffice/service/DdsQueryService.java +++ b/dds-backoffice/src/main/java/com/cloudhandson/ddsbackoffice/service/DdsQueryService.java @@ -47,12 +47,12 @@ public class DdsQueryService { public List sources() { return List.of( new DdsSourceOption( - "PG", "PostgreSQL 원본", properties.pgObject(), - "DDS DATA GRANT가 허용한 PostgreSQL 데이터만 반환합니다." + "PG", "PG 데이터셋", properties.pgObject(), + "DDS 전용 로컬 PG 데이터셋에서 허용된 행만 반환합니다." ), new DdsSourceOption( - "MY", "MySQL 원본", properties.myObject(), - "DDS DATA GRANT가 허용한 MySQL 데이터만 반환합니다." + "MY", "MY 데이터셋", properties.myObject(), + "DDS 전용 로컬 MY 데이터셋에서 허용된 행만 반환합니다." ) ); } diff --git a/dds-backoffice/src/main/resources/application.yml b/dds-backoffice/src/main/resources/application.yml index 5a11050..942da7c 100644 --- a/dds-backoffice/src/main/resources/application.yml +++ b/dds-backoffice/src/main/resources/application.yml @@ -31,20 +31,20 @@ dds: my: label: MY 전용 사용자 description: MySQL 원본만 허용하는 DATA ROLE - username: ${DDS_BACKOFFICE_MY_USERNAME:ddsuser_my} + username: ${DDS_BACKOFFICE_MY_USERNAME:dds_demo_my} password: ${DDS_BACKOFFICE_MY_PASSWORD:${DDSUSER_MY_PASSWORD:}} pg: label: PG 전용 사용자 description: PostgreSQL 원본만 허용하는 DATA ROLE - username: ${DDS_BACKOFFICE_PG_USERNAME:ddsuser_pg} + username: ${DDS_BACKOFFICE_PG_USERNAME:dds_demo_pg} password: ${DDS_BACKOFFICE_PG_PASSWORD:${DDSUSER_PG_PASSWORD:}} both: label: 통합 사용자 description: 두 원본을 모두 허용하는 DATA ROLE - username: ${DDS_BACKOFFICE_BOTH_USERNAME:ddsuser_both} + username: ${DDS_BACKOFFICE_BOTH_USERNAME:dds_demo_both} password: ${DDS_BACKOFFICE_BOTH_PASSWORD:${DDSUSER_BOTH_PASSWORD:}} none: label: 차단 사용자 description: 접속만 가능하고 DATA GRANT가 없는 사용자 - username: ${DDS_BACKOFFICE_NONE_USERNAME:ddsuser_none} + username: ${DDS_BACKOFFICE_NONE_USERNAME:dds_demo_none} password: ${DDS_BACKOFFICE_NONE_PASSWORD:${DDSUSER_NONE_PASSWORD:}} diff --git a/dds-backoffice/src/main/resources/templates/dds.html b/dds-backoffice/src/main/resources/templates/dds.html index baddc02..9e14931 100644 --- a/dds-backoffice/src/main/resources/templates/dds.html +++ b/dds-backoffice/src/main/resources/templates/dds.html @@ -98,10 +98,10 @@
-
ddsuser_myMY 원본 허용PG 객체는 ORA-00942
-
ddsuser_pgPG 원본 허용MY 객체는 ORA-00942
-
ddsuser_bothPG + MY 허용두 DATA GRANT 모두 적용
-
ddsuser_none접속만 허용데이터 권한 없음 · default deny
+
dds_demo_myMY 데이터셋 허용PG 객체는 ORA-00942
+
dds_demo_pgPG 데이터셋 허용MY 객체는 ORA-00942
+
dds_demo_bothPG + MY 허용두 DATA GRANT 모두 적용
+
dds_demo_none접속만 허용데이터 권한 없음 · default deny
diff --git a/sql/adb/31_dds_standalone_demo_setup.sql b/sql/adb/31_dds_standalone_demo_setup.sql new file mode 100644 index 0000000..5a515fb --- /dev/null +++ b/sql/adb/31_dds_standalone_demo_setup.sql @@ -0,0 +1,119 @@ +-- ============================================================ +-- 31_dds_standalone_demo_setup.sql +-- Independent local Deep Data Security demo. +-- +-- This script deliberately does not use VPD views, application +-- permission tables, or external database links. It creates a +-- local PG/MY-shaped matrix so the DDS demo can run independently +-- when the VPD demo's RDS links are unavailable. +-- ============================================================ +WHENEVER SQLERROR EXIT SQL.SQLCODE +SET ECHO OFF +SET FEEDBACK ON +SET DEFINE ON +SET VERIFY OFF + +PROMPT === 1. Creating DDS-only local source tables === +BEGIN + EXECUTE IMMEDIATE 'DROP VIEW v_dds_customers_pg'; +EXCEPTION WHEN OTHERS THEN NULL; +END; +/ +BEGIN + EXECUTE IMMEDIATE 'DROP VIEW v_dds_customers_my'; +EXCEPTION WHEN OTHERS THEN NULL; +END; +/ +BEGIN + EXECUTE IMMEDIATE 'DROP TABLE cb_dds_demo_customers_pg PURGE'; +EXCEPTION WHEN OTHERS THEN NULL; +END; +/ +BEGIN + EXECUTE IMMEDIATE 'DROP TABLE cb_dds_demo_customers_my PURGE'; +EXCEPTION WHEN OTHERS THEN NULL; +END; +/ + +CREATE TABLE cb_dds_demo_customers_pg ( + customer_id NUMBER PRIMARY KEY, + full_name VARCHAR2(100) NOT NULL, + email VARCHAR2(200), + signup_date DATE DEFAULT SYSDATE NOT NULL, + region VARCHAR2(30) NOT NULL +); + +CREATE TABLE cb_dds_demo_customers_my ( + customer_id NUMBER PRIMARY KEY, + full_name VARCHAR2(100) NOT NULL, + email VARCHAR2(200), + signup_date DATE DEFAULT SYSDATE NOT NULL, + region VARCHAR2(30) NOT NULL +); + +INSERT INTO cb_dds_demo_customers_pg VALUES (101, 'PG Alice', 'pg.alice@example.test', DATE '2026-01-10', 'APAC'); +INSERT INTO cb_dds_demo_customers_pg VALUES (102, 'PG Bob', 'pg.bob@example.test', DATE '2026-01-11', 'EMEA'); +INSERT INTO cb_dds_demo_customers_pg VALUES (103, 'PG Carol', 'pg.carol@example.test', DATE '2026-01-12', 'AMER'); + +INSERT INTO cb_dds_demo_customers_my VALUES (201, 'MY Alice', 'my.alice@example.test', DATE '2026-02-10', 'APAC'); +INSERT INTO cb_dds_demo_customers_my VALUES (202, 'MY Bob', 'my.bob@example.test', DATE '2026-02-11', 'EMEA'); +INSERT INTO cb_dds_demo_customers_my VALUES (203, 'MY Carol', 'my.carol@example.test', DATE '2026-02-12', 'AMER'); + +CREATE OR REPLACE VIEW v_dds_customers_pg AS +SELECT customer_id, full_name, email, signup_date, region +FROM cb_dds_demo_customers_pg; + +CREATE OR REPLACE VIEW v_dds_customers_my AS +SELECT customer_id, full_name, email, signup_date, region +FROM cb_dds_demo_customers_my; + +COMMIT; + +PROMPT === 2. Creating independent DDS END USERs === +CREATE END USER "dds_demo_my" IDENTIFIED BY "&DDSUSER_MY_PASSWORD"; +CREATE END USER "dds_demo_pg" IDENTIFIED BY "&DDSUSER_PG_PASSWORD"; +CREATE END USER "dds_demo_both" IDENTIFIED BY "&DDSUSER_BOTH_PASSWORD"; +CREATE END USER "dds_demo_none" IDENTIFIED BY "&DDSUSER_NONE_PASSWORD"; + +PROMPT === 3. Creating independent DATA ROLEs === +CREATE ROLE dds_demo_connect_role; +GRANT CREATE SESSION TO dds_demo_connect_role; + +CREATE DATA ROLE dds_demo_my_role; +CREATE DATA ROLE dds_demo_pg_role; +CREATE DATA ROLE dds_demo_both_role; +CREATE DATA ROLE dds_demo_none_role; + +GRANT dds_demo_connect_role TO dds_demo_my_role; +GRANT dds_demo_connect_role TO dds_demo_pg_role; +GRANT dds_demo_connect_role TO dds_demo_both_role; +GRANT dds_demo_connect_role TO dds_demo_none_role; + +GRANT DATA ROLE dds_demo_my_role TO "dds_demo_my"; +GRANT DATA ROLE dds_demo_pg_role TO "dds_demo_pg"; +GRANT DATA ROLE dds_demo_both_role TO "dds_demo_both"; +GRANT DATA ROLE dds_demo_none_role TO "dds_demo_none"; + +PROMPT === 4. Creating independent DATA GRANTs === +CREATE DATA GRANT admin.dds_demo_my_grant + AS SELECT + ON admin.v_dds_customers_my + TO dds_demo_my_role; + +CREATE DATA GRANT admin.dds_demo_pg_grant + AS SELECT + ON admin.v_dds_customers_pg + TO dds_demo_pg_role; + +CREATE DATA GRANT admin.dds_demo_both_pg_grant + AS SELECT + ON admin.v_dds_customers_pg + TO dds_demo_both_role; + +CREATE DATA GRANT admin.dds_demo_both_my_grant + AS SELECT + ON admin.v_dds_customers_my + TO dds_demo_both_role; + +PROMPT === Independent DDS demo setup complete === +EXIT;