feat(backoffice): add Smilegate identity administration
This commit is contained in:
35
docs/design/smilegate-identity-administration/README.md
Normal file
35
docs/design/smilegate-identity-administration/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Smilegate Backoffice Identity Administration
|
||||
|
||||
## Goal
|
||||
|
||||
Keep `admin` as the backoffice control-plane login. Provide an administrator-facing
|
||||
model for managing Smilegate PoC tool users, groups, roles, and their assignments.
|
||||
These users are tool operators (for example a Data & AI TF lead or member), not
|
||||
game-service players.
|
||||
|
||||
## Scope
|
||||
|
||||
* `SG_APP_USER`, `SG_APP_GROUP`, and `SG_APP_ROLE` are the application masters.
|
||||
* `SG_USER_ROLE`, `SG_USER_GROUP`, and `SG_GROUP_ROLE` express normalized
|
||||
user/group/role assignments.
|
||||
* Every change is recorded in `SG_AUDIT_EVENT` by the backoffice audit service.
|
||||
* Existing `/users`, `/groups`, and `/roles` pages use only the `SG_*` identity
|
||||
model. They must not require the legacy VPD/permission objects to render.
|
||||
|
||||
## Seed data
|
||||
|
||||
| Type | Code | Purpose |
|
||||
| --- | --- | --- |
|
||||
| User | `sg-teamlead` | Data & AI TF team lead demo operator |
|
||||
| User | `sg-member` | Data & AI TF member demo operator |
|
||||
| Group | `DATA_AI_TF` | Smilegate Data & AI TF |
|
||||
| Role | `DATA_AI_TEAM_LEAD` | Team lead operational role |
|
||||
| Role | `DATA_AI_TEAM_MEMBER` | Team member operational role |
|
||||
|
||||
## Acceptance checks
|
||||
|
||||
1. An authenticated `admin` can open `/users`, `/groups`, and `/roles`.
|
||||
2. The seed users, group, and roles appear; assignments can be added and removed.
|
||||
3. Create, activation, role, and group changes are committed atomically and leave
|
||||
an `SG_AUDIT_EVENT` row.
|
||||
4. The pages do not call the legacy effective VPD permission matrix.
|
||||
119
sql/adb/71_sg_identity_administration.sql
Normal file
119
sql/adb/71_sg_identity_administration.sql
Normal file
@@ -0,0 +1,119 @@
|
||||
-- Smilegate PoC backoffice identity administration model.
|
||||
-- Tool operators are distinct from game-service users and from the admin login.
|
||||
|
||||
set define off
|
||||
|
||||
declare
|
||||
procedure create_if_missing(p_sql varchar2) is
|
||||
begin
|
||||
execute immediate p_sql;
|
||||
exception
|
||||
when others then
|
||||
if sqlcode != -955 then raise; end if;
|
||||
end;
|
||||
begin
|
||||
create_if_missing('create table sg_app_user (
|
||||
user_id number primary key,
|
||||
login_id varchar2(100) not null unique,
|
||||
user_name varchar2(200) not null,
|
||||
employee_no varchar2(100),
|
||||
dept_code varchar2(100),
|
||||
can_read_contents char(1) default ''N'' not null,
|
||||
active char(1) default ''Y'' not null,
|
||||
created_at timestamp default systimestamp not null,
|
||||
updated_at timestamp default systimestamp not null,
|
||||
constraint sg_app_user_active_ck check (active in (''Y'', ''N''))
|
||||
)');
|
||||
create_if_missing('create table sg_app_group (
|
||||
group_id number primary key,
|
||||
group_code varchar2(100) not null unique,
|
||||
group_name varchar2(200) not null,
|
||||
description varchar2(500),
|
||||
active_yn char(1) default ''Y'' not null,
|
||||
created_at timestamp default systimestamp not null,
|
||||
updated_at timestamp default systimestamp not null,
|
||||
constraint sg_app_group_active_ck check (active_yn in (''Y'', ''N''))
|
||||
)');
|
||||
create_if_missing('create table sg_app_role (
|
||||
role_id number primary key,
|
||||
role_name varchar2(100) not null unique,
|
||||
description varchar2(500),
|
||||
max_sensitivity_level varchar2(30) default ''INTERNAL'' not null,
|
||||
created_at timestamp default systimestamp not null,
|
||||
updated_at timestamp default systimestamp not null,
|
||||
constraint sg_app_role_sensitivity_ck check (max_sensitivity_level in (''PUBLIC'', ''INTERNAL'', ''CONFIDENTIAL'', ''RESTRICTED''))
|
||||
)');
|
||||
create_if_missing('create table sg_user_role (
|
||||
user_id number not null,
|
||||
role_id number not null,
|
||||
created_at timestamp default systimestamp not null,
|
||||
constraint sg_user_role_pk primary key (user_id, role_id),
|
||||
constraint sg_user_role_user_fk foreign key (user_id) references sg_app_user(user_id),
|
||||
constraint sg_user_role_role_fk foreign key (role_id) references sg_app_role(role_id)
|
||||
)');
|
||||
create_if_missing('create table sg_user_group (
|
||||
group_id number not null,
|
||||
user_id number not null,
|
||||
created_at timestamp default systimestamp not null,
|
||||
constraint sg_user_group_pk primary key (group_id, user_id),
|
||||
constraint sg_user_group_group_fk foreign key (group_id) references sg_app_group(group_id),
|
||||
constraint sg_user_group_user_fk foreign key (user_id) references sg_app_user(user_id)
|
||||
)');
|
||||
create_if_missing('create table sg_group_role (
|
||||
group_id number not null,
|
||||
role_id number not null,
|
||||
created_at timestamp default systimestamp not null,
|
||||
constraint sg_group_role_pk primary key (group_id, role_id),
|
||||
constraint sg_group_role_group_fk foreign key (group_id) references sg_app_group(group_id),
|
||||
constraint sg_group_role_role_fk foreign key (role_id) references sg_app_role(role_id)
|
||||
)');
|
||||
create_if_missing('create table sg_audit_event (
|
||||
audit_id number primary key,
|
||||
event_type varchar2(100) not null,
|
||||
key_id number,
|
||||
object_id number,
|
||||
status varchar2(30) not null,
|
||||
row_count number,
|
||||
error_code varchar2(100),
|
||||
message varchar2(2000),
|
||||
created_at timestamp default systimestamp not null
|
||||
)');
|
||||
create_if_missing('create sequence sg_audit_event_seq start with 1 increment by 1 nocache');
|
||||
end;
|
||||
/
|
||||
|
||||
merge into sg_app_user t
|
||||
using (
|
||||
select 1001 user_id, 'sg-teamlead' login_id, 'SG Demo Team Lead' user_name, 'SG-001' employee_no, 'DATA_AI' dept_code from dual
|
||||
union all
|
||||
select 1002, 'sg-member', 'SG Demo Team Member', 'SG-002', 'DATA_AI' from dual
|
||||
) s on (t.user_id = s.user_id)
|
||||
when matched then update set t.login_id=s.login_id, t.user_name=s.user_name, t.employee_no=s.employee_no, t.dept_code=s.dept_code, t.active='Y', t.updated_at=systimestamp
|
||||
when not matched then insert (user_id, login_id, user_name, employee_no, dept_code, can_read_contents, active)
|
||||
values (s.user_id, s.login_id, s.user_name, s.employee_no, s.dept_code, 'N', 'Y');
|
||||
|
||||
merge into sg_app_group t
|
||||
using (select 2001 group_id, 'DATA_AI_TF' group_code, 'Data & AI TF' group_name, 'Smilegate Data and AI proof-of-concept operators' description from dual) s
|
||||
on (t.group_id = s.group_id)
|
||||
when matched then update set t.group_code=s.group_code, t.group_name=s.group_name, t.description=s.description, t.active_yn='Y', t.updated_at=systimestamp
|
||||
when not matched then insert (group_id, group_code, group_name, description, active_yn) values (s.group_id, s.group_code, s.group_name, s.description, 'Y');
|
||||
|
||||
merge into sg_app_role t
|
||||
using (
|
||||
select 3001 role_id, 'DATA_AI_TEAM_LEAD' role_name, 'Data and AI TF lead' description, 'CONFIDENTIAL' max_sensitivity_level from dual
|
||||
union all
|
||||
select 3002, 'DATA_AI_TEAM_MEMBER', 'Data and AI TF member', 'INTERNAL' from dual
|
||||
) s on (t.role_id=s.role_id)
|
||||
when matched then update set t.role_name=s.role_name, t.description=s.description, t.max_sensitivity_level=s.max_sensitivity_level, t.updated_at=systimestamp
|
||||
when not matched then insert (role_id, role_name, description, max_sensitivity_level) values (s.role_id, s.role_name, s.description, s.max_sensitivity_level);
|
||||
|
||||
merge into sg_user_group t using (select 2001 group_id, 1001 user_id from dual union all select 2001, 1002 from dual) s
|
||||
on (t.group_id=s.group_id and t.user_id=s.user_id) when not matched then insert (group_id, user_id) values (s.group_id, s.user_id);
|
||||
|
||||
merge into sg_user_role t using (select 1001 user_id, 3001 role_id from dual union all select 1002, 3002 from dual) s
|
||||
on (t.user_id=s.user_id and t.role_id=s.role_id) when not matched then insert (user_id, role_id) values (s.user_id, s.role_id);
|
||||
|
||||
merge into sg_group_role t using (select 2001 group_id, 3002 role_id from dual) s
|
||||
on (t.group_id=s.group_id and t.role_id=s.role_id) when not matched then insert (group_id, role_id) values (s.group_id, s.role_id);
|
||||
|
||||
commit;
|
||||
@@ -3,10 +3,10 @@
|
||||
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.cloudhandson.vpdbackoffice.mapper.AuditMapper">
|
||||
<insert id="insert" parameterType="com.cloudhandson.vpdbackoffice.domain.audit.AuditEvent">
|
||||
INSERT INTO cb_ords_probe_audit (
|
||||
INSERT INTO sg_audit_event (
|
||||
audit_id, event_type, key_id, object_id, status, row_count, error_code, message, created_at
|
||||
) VALUES (
|
||||
cb_ords_probe_audit_seq.NEXTVAL,
|
||||
sg_audit_event_seq.NEXTVAL,
|
||||
#{eventType,jdbcType=VARCHAR},
|
||||
#{keyId,jdbcType=NUMERIC},
|
||||
#{objectId,jdbcType=NUMERIC},
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
group_name,
|
||||
description,
|
||||
active_yn
|
||||
FROM cb_app_group
|
||||
FROM sg_app_group
|
||||
ORDER BY group_code
|
||||
</select>
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
g.group_name,
|
||||
u.user_id,
|
||||
u.user_name AS username
|
||||
FROM cb_user_group ug
|
||||
JOIN cb_app_group g ON g.group_id = ug.group_id
|
||||
JOIN cb_app_user u ON u.user_id = ug.user_id
|
||||
FROM sg_user_group ug
|
||||
JOIN sg_app_group g ON g.group_id = ug.group_id
|
||||
JOIN sg_app_user u ON u.user_id = ug.user_id
|
||||
ORDER BY g.group_code, u.user_name
|
||||
</select>
|
||||
|
||||
@@ -30,18 +30,18 @@
|
||||
g.group_name,
|
||||
r.role_id,
|
||||
r.role_name
|
||||
FROM cb_group_role gr
|
||||
JOIN cb_app_group g ON g.group_id = gr.group_id
|
||||
JOIN cb_app_role r ON r.role_id = gr.role_id
|
||||
FROM sg_group_role gr
|
||||
JOIN sg_app_group g ON g.group_id = gr.group_id
|
||||
JOIN sg_app_role r ON r.role_id = gr.role_id
|
||||
ORDER BY g.group_code, r.role_name
|
||||
</select>
|
||||
|
||||
<select id="nextGroupId" resultType="long">
|
||||
SELECT NVL(MAX(group_id), 0) + 1 FROM cb_app_group
|
||||
SELECT NVL(MAX(group_id), 0) + 1 FROM sg_app_group
|
||||
</select>
|
||||
|
||||
<insert id="insertGroup">
|
||||
INSERT INTO cb_app_group (
|
||||
INSERT INTO sg_app_group (
|
||||
group_id, group_code, group_name, description, active_yn
|
||||
) VALUES (
|
||||
#{groupId,jdbcType=NUMERIC},
|
||||
@@ -53,29 +53,29 @@
|
||||
</insert>
|
||||
|
||||
<update id="updateActive">
|
||||
UPDATE cb_app_group
|
||||
UPDATE sg_app_group
|
||||
SET active_yn = #{activeYn,jdbcType=VARCHAR}
|
||||
WHERE group_id = #{groupId,jdbcType=NUMERIC}
|
||||
</update>
|
||||
|
||||
<insert id="insertGroupUser">
|
||||
INSERT INTO cb_user_group (group_id, user_id)
|
||||
INSERT INTO sg_user_group (group_id, user_id)
|
||||
VALUES (#{groupId,jdbcType=NUMERIC}, #{userId,jdbcType=NUMERIC})
|
||||
</insert>
|
||||
|
||||
<delete id="deleteGroupUser">
|
||||
DELETE FROM cb_user_group
|
||||
DELETE FROM sg_user_group
|
||||
WHERE group_id = #{groupId,jdbcType=NUMERIC}
|
||||
AND user_id = #{userId,jdbcType=NUMERIC}
|
||||
</delete>
|
||||
|
||||
<insert id="insertGroupRole">
|
||||
INSERT INTO cb_group_role (group_id, role_id)
|
||||
INSERT INTO sg_group_role (group_id, role_id)
|
||||
VALUES (#{groupId,jdbcType=NUMERIC}, #{roleId,jdbcType=NUMERIC})
|
||||
</insert>
|
||||
|
||||
<delete id="deleteGroupRole">
|
||||
DELETE FROM cb_group_role
|
||||
DELETE FROM sg_group_role
|
||||
WHERE group_id = #{groupId,jdbcType=NUMERIC}
|
||||
AND role_id = #{roleId,jdbcType=NUMERIC}
|
||||
</delete>
|
||||
|
||||
@@ -5,132 +5,77 @@
|
||||
<select id="findRoles" resultType="com.cloudhandson.vpdbackoffice.domain.permission.AppRole">
|
||||
SELECT role_id,
|
||||
role_name,
|
||||
CAST(NULL AS VARCHAR2(200)) AS description,
|
||||
description,
|
||||
NVL(max_sensitivity_level, 'PUBLIC') AS max_sensitivity_level
|
||||
FROM cb_app_role
|
||||
FROM sg_app_role
|
||||
ORDER BY role_name
|
||||
</select>
|
||||
|
||||
<select id="findRole" resultType="com.cloudhandson.vpdbackoffice.domain.permission.AppRole">
|
||||
SELECT role_id,
|
||||
role_name,
|
||||
CAST(NULL AS VARCHAR2(200)) AS description,
|
||||
description,
|
||||
NVL(max_sensitivity_level, 'PUBLIC') AS max_sensitivity_level
|
||||
FROM cb_app_role
|
||||
FROM sg_app_role
|
||||
WHERE role_id = #{roleId}
|
||||
</select>
|
||||
|
||||
<select id="nextRoleId" resultType="long">
|
||||
SELECT NVL(MAX(role_id), 0) + 1 FROM cb_app_role
|
||||
SELECT NVL(MAX(role_id), 0) + 1 FROM sg_app_role
|
||||
</select>
|
||||
|
||||
<insert id="insertRole">
|
||||
INSERT INTO cb_app_role (role_id, role_name, max_sensitivity_level)
|
||||
INSERT INTO sg_app_role (role_id, role_name, description, max_sensitivity_level)
|
||||
VALUES (
|
||||
#{roleId,jdbcType=NUMERIC},
|
||||
UPPER(#{roleName,jdbcType=VARCHAR}),
|
||||
#{description,jdbcType=VARCHAR},
|
||||
#{maxSensitivityLevel,jdbcType=VARCHAR}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<update id="updateRoleMaxSensitivity">
|
||||
UPDATE cb_app_role
|
||||
UPDATE sg_app_role
|
||||
SET max_sensitivity_level = #{maxSensitivityLevel,jdbcType=VARCHAR}
|
||||
WHERE role_id = #{roleId,jdbcType=NUMERIC}
|
||||
</update>
|
||||
|
||||
<delete id="deleteRole">
|
||||
DELETE FROM cb_app_role
|
||||
DELETE FROM sg_app_role
|
||||
WHERE role_id = #{roleId,jdbcType=NUMERIC}
|
||||
</delete>
|
||||
|
||||
<select id="countUserRolesByRoleId" resultType="int">
|
||||
SELECT COUNT(*)
|
||||
FROM cb_user_role
|
||||
FROM sg_user_role
|
||||
WHERE role_id = #{roleId,jdbcType=NUMERIC}
|
||||
</select>
|
||||
|
||||
<select id="countGroupRolesByRoleId" resultType="int">
|
||||
SELECT COUNT(*)
|
||||
FROM cb_group_role
|
||||
FROM sg_group_role
|
||||
WHERE role_id = #{roleId,jdbcType=NUMERIC}
|
||||
</select>
|
||||
|
||||
<select id="countPermissionsByRoleId" resultType="int">
|
||||
SELECT COUNT(*)
|
||||
FROM cb_permission
|
||||
WHERE role_id = #{roleId,jdbcType=NUMERIC}
|
||||
FROM dual
|
||||
WHERE 1 = 0
|
||||
</select>
|
||||
|
||||
<select id="findPermissionViews" resultType="com.cloudhandson.vpdbackoffice.domain.permission.PermissionView">
|
||||
SELECT p.perm_id AS permission_id,
|
||||
r.role_id,
|
||||
r.role_name,
|
||||
NVL(o.object_id, -1) AS object_id,
|
||||
p.target_name AS object_name,
|
||||
p.action_name AS action,
|
||||
NVL(p.permission_effect, 'ALLOW') AS permission_effect,
|
||||
LISTAGG(
|
||||
NVL2(pr.rule_column, pr.rule_column || ' ', '') ||
|
||||
pr.rule_type ||
|
||||
NVL2(pr.rule_value, ' ' || pr.rule_value, ''),
|
||||
', '
|
||||
)
|
||||
WITHIN GROUP (ORDER BY pr.rule_id) AS rules,
|
||||
(
|
||||
SELECT LISTAGG(pc.column_name, ', ') WITHIN GROUP (ORDER BY pc.column_name)
|
||||
FROM cb_permission_column pc
|
||||
WHERE pc.permission_id = p.perm_id
|
||||
) AS visible_columns,
|
||||
(
|
||||
SELECT LISTAGG(
|
||||
CASE
|
||||
WHEN pr2.rule_type = 'ALL' THEN 'ALL ROWS'
|
||||
WHEN pr2.rule_type = 'MY_DEPT' THEN NVL(pr2.rule_column, 'DEPT_CODE') || ' = SYS_CONTEXT(CB_AGENT_CTX.DEPT_CODE)'
|
||||
WHEN pr2.rule_type = 'SELF' THEN NVL(pr2.rule_column, 'OWNER_EMP_NO') || ' = SYS_CONTEXT(CB_AGENT_CTX.EMP_NO)'
|
||||
WHEN pr2.rule_type = 'DEPT' THEN NVL(pr2.rule_column, 'DEPT_CODE') || ' = ' || pr2.rule_value
|
||||
WHEN pr2.rule_type = 'EMP_NO' THEN NVL(pr2.rule_column, 'OWNER_EMP_NO') || ' = ' || pr2.rule_value
|
||||
WHEN pr2.rule_type = 'TAG' THEN 'REGEXP_LIKE(UPPER('
|
||||
|| NVL(pr2.rule_column, 'TECH_TAG')
|
||||
|| '), ''(^|,)' || REPLACE(UPPER(pr2.rule_value), '''', '''''') || '(,|$)'')'
|
||||
WHEN pr2.rule_type = 'TOKEN_SUBJECT' THEN
|
||||
pr2.rule_column || ' = SYS_CONTEXT(''CB_AGENT_CTX'', ''STAKEHOLDER_USER_ID'')'
|
||||
WHEN pr2.rule_type = 'OWN_CONTRACT' THEN
|
||||
pr2.rule_column || ' = SYS_CONTEXT(''CB_AGENT_CTX'', ''STAKEHOLDER_USER_ID'')'
|
||||
WHEN pr2.rule_type = 'CHANNEL_CONTRACT' THEN
|
||||
pr2.rule_column || ' = SYS_CONTEXT(''CB_AGENT_CTX'', ''STAKEHOLDER_CHANNEL'')'
|
||||
WHEN pr2.rule_type = 'OWN_CUSTOMER' THEN
|
||||
'EXISTS (SELECT 1 FROM (SELECT c.' || pr2.rule_column || ' AS access_key '
|
||||
|| 'FROM POC_2.KB_CONTRACTS c '
|
||||
|| 'WHERE c.FC_ID = SYS_CONTEXT(''CB_AGENT_CTX'', ''STAKEHOLDER_USER_ID'')) allowed_contract '
|
||||
|| 'WHERE allowed_contract.access_key = ' || pr2.rule_column || ')'
|
||||
WHEN pr2.rule_type = 'CHANNEL_CUSTOMER' THEN
|
||||
'EXISTS (SELECT 1 FROM (SELECT c.' || pr2.rule_column || ' AS access_key '
|
||||
|| 'FROM POC_2.KB_CONTRACTS c '
|
||||
|| 'WHERE c.FC_CHANNEL = SYS_CONTEXT(''CB_AGENT_CTX'', ''STAKEHOLDER_CHANNEL'')) allowed_contract '
|
||||
|| 'WHERE allowed_contract.access_key = ' || pr2.rule_column || ')'
|
||||
WHEN pr2.rule_type = 'STATIC_SQL' THEN pr2.rule_value
|
||||
ELSE pr2.rule_column || ' ' || pr2.rule_type || ' ' || pr2.rule_value
|
||||
END,
|
||||
CHR(10) || 'AND '
|
||||
) WITHIN GROUP (ORDER BY pr2.rule_id)
|
||||
FROM cb_permission_rule pr2
|
||||
WHERE pr2.perm_id = p.perm_id
|
||||
) AS filter_preview,
|
||||
(
|
||||
SELECT CASE
|
||||
WHEN COUNT(*) = 0 THEN '컬럼 마스킹은 ASO에서 관리'
|
||||
ELSE '레거시 권한별 컬럼 예외: ' || LISTAGG(pc2.column_name, ', ') WITHIN GROUP (ORDER BY pc2.column_name)
|
||||
END
|
||||
FROM cb_permission_column pc2
|
||||
WHERE pc2.permission_id = p.perm_id
|
||||
) AS null_policy_preview
|
||||
FROM cb_permission p
|
||||
JOIN cb_app_role r ON r.role_id = p.role_id
|
||||
LEFT JOIN cb_protected_object o ON o.object_name = p.target_name
|
||||
LEFT JOIN cb_permission_rule pr ON pr.perm_id = p.perm_id
|
||||
GROUP BY p.perm_id, r.role_id, r.role_name, o.object_id, p.target_name, p.action_name, p.permission_effect
|
||||
ORDER BY r.role_name, p.target_name
|
||||
SELECT CAST(NULL AS NUMBER) AS permission_id,
|
||||
CAST(NULL AS NUMBER) AS role_id,
|
||||
CAST(NULL AS VARCHAR2(100)) AS role_name,
|
||||
CAST(NULL AS NUMBER) AS object_id,
|
||||
CAST(NULL AS VARCHAR2(200)) AS object_name,
|
||||
CAST(NULL AS VARCHAR2(30)) AS action,
|
||||
CAST(NULL AS VARCHAR2(30)) AS permission_effect,
|
||||
CAST(NULL AS VARCHAR2(4000)) AS rules,
|
||||
CAST(NULL AS VARCHAR2(4000)) AS visible_columns,
|
||||
CAST(NULL AS VARCHAR2(4000)) AS filter_preview,
|
||||
CAST(NULL AS VARCHAR2(4000)) AS null_policy_preview
|
||||
FROM dual WHERE 1 = 0
|
||||
</select>
|
||||
|
||||
<select id="findPermissionId" resultType="long">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
dept_code,
|
||||
can_read_contents,
|
||||
active AS active_yn
|
||||
FROM cb_app_user
|
||||
FROM sg_app_user
|
||||
ORDER BY username
|
||||
</select>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
dept_code,
|
||||
can_read_contents,
|
||||
active AS active_yn
|
||||
FROM cb_app_user
|
||||
FROM sg_app_user
|
||||
WHERE user_id = #{userId}
|
||||
</select>
|
||||
|
||||
@@ -29,18 +29,18 @@
|
||||
u.user_name AS username,
|
||||
r.role_id,
|
||||
r.role_name
|
||||
FROM cb_user_role ur
|
||||
JOIN cb_app_user u ON u.user_id = ur.user_id
|
||||
JOIN cb_app_role r ON r.role_id = ur.role_id
|
||||
FROM sg_user_role ur
|
||||
JOIN sg_app_user u ON u.user_id = ur.user_id
|
||||
JOIN sg_app_role r ON r.role_id = ur.role_id
|
||||
ORDER BY u.user_name, r.role_name
|
||||
</select>
|
||||
|
||||
<select id="nextUserId" resultType="long">
|
||||
SELECT NVL(MAX(user_id), 0) + 1 FROM cb_app_user
|
||||
SELECT NVL(MAX(user_id), 0) + 1 FROM sg_app_user
|
||||
</select>
|
||||
|
||||
<insert id="insertUser">
|
||||
INSERT INTO cb_app_user (
|
||||
INSERT INTO sg_app_user (
|
||||
user_id, user_name, employee_no, dept_code, can_read_contents, active
|
||||
) VALUES (
|
||||
#{userId},
|
||||
@@ -53,18 +53,18 @@
|
||||
</insert>
|
||||
|
||||
<update id="updateActive">
|
||||
UPDATE cb_app_user
|
||||
UPDATE sg_app_user
|
||||
SET active = #{activeYn}
|
||||
WHERE user_id = #{userId}
|
||||
</update>
|
||||
|
||||
<insert id="insertUserRole">
|
||||
INSERT INTO cb_user_role (user_id, role_id)
|
||||
INSERT INTO sg_user_role (user_id, role_id)
|
||||
VALUES (#{userId}, #{roleId})
|
||||
</insert>
|
||||
|
||||
<delete id="deleteUserRole">
|
||||
DELETE FROM cb_user_role
|
||||
DELETE FROM sg_user_role
|
||||
WHERE user_id = #{userId}
|
||||
AND role_id = #{roleId}
|
||||
</delete>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="backoffice-can-mutate" th:content="${canMutate}">
|
||||
<meta name="backoffice-read-only" th:content="${readOnlyMode}">
|
||||
<title th:text="${title == '데이터 접근 제어' ? title : title + ' · 데이터 접근 제어'}">데이터 접근 제어</title>
|
||||
<title th:text="${title == 'SMILEGATE DATA & AI POC' ? title : title + ' · SMILEGATE DATA & AI POC'}">SMILEGATE DATA & AI POC</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="/css/app.css" rel="stylesheet">
|
||||
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
|
||||
@@ -15,9 +15,9 @@
|
||||
<body>
|
||||
<nav th:fragment="nav" class="navbar rw-nav navbar-expand-lg" data-product-nav>
|
||||
<div class="container rw-nav-top">
|
||||
<a class="navbar-brand" href="/">데이터 접근 제어</a>
|
||||
<a class="navbar-brand" href="/">SMILEGATE DATA & AI POC</a>
|
||||
<div class="rw-menu" aria-label="주요 메뉴">
|
||||
<button class="rw-menu-trigger" type="button" data-submenu-trigger="access" aria-controls="submenu-access" aria-expanded="false">접근 제어</button>
|
||||
<button class="rw-menu-trigger" type="button" data-submenu-trigger="access" aria-controls="submenu-access" aria-expanded="false">운영 사용자 관리</button>
|
||||
<button class="rw-menu-trigger" type="button" data-submenu-trigger="protection" aria-controls="submenu-protection" aria-expanded="false">보호·검증</button>
|
||||
<button class="rw-menu-trigger" type="button" data-submenu-trigger="integration" aria-controls="submenu-integration" aria-expanded="false">연동 도구</button>
|
||||
<button class="rw-menu-trigger" type="button" data-submenu-trigger="operations" aria-controls="submenu-operations" aria-expanded="false">운영</button>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<h1>그룹</h1>
|
||||
<details class="explanation-details">
|
||||
<summary>도움말</summary>
|
||||
<p>사용자 그룹을 만들고 그룹에 사용자와 역할을 부여합니다. 권한은 역할에 연결되고, 사용자는 직접 역할과 그룹 역할을 함께 상속합니다.</p>
|
||||
<p>PoC 운영 그룹을 만들고 그룹에 사용자와 역할을 부여합니다. 사용자는 직접 부여된 역할과 그룹 역할을 함께 사용합니다.</p>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<h1>역할</h1>
|
||||
<details class="explanation-details">
|
||||
<summary>도움말</summary>
|
||||
<p>사용자에게 부여할 역할을 관리합니다. 표시 보호 등급 상한은 허용된 행에서 원문으로 볼 수 있는 컬럼 등급의 참고값이며, 행 접근 권한은 행 접근 규칙과 Oracle VPD 정책에서 결정합니다.</p>
|
||||
<p>스마일게이트 Data & AI PoC 운영 역할을 관리합니다. 역할은 사용자에게 직접 부여하거나 그룹을 통해 부여할 수 있습니다.</p>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
@@ -28,14 +28,14 @@
|
||||
<input class="form-control" name="description" maxlength="200">
|
||||
</label>
|
||||
<label>
|
||||
표시 보호 등급 상한 (참고)
|
||||
데이터 취급 등급
|
||||
<select class="form-select" name="maxSensitivityLevel">
|
||||
<option value="PUBLIC">PUBLIC</option>
|
||||
<option value="INTERNAL">INTERNAL</option>
|
||||
<option value="CONFIDENTIAL">CONFIDENTIAL</option>
|
||||
<option value="RESTRICTED">RESTRICTED</option>
|
||||
</select>
|
||||
<span class="form-hint">이 역할이 허용된 행에서 원문으로 볼 수 있는 컬럼 등급의 참고 상한입니다. 행을 볼 수 있는지는 행 접근 규칙과 Oracle VPD 정책이 결정하며, 이 값은 행 권한을 부여하지 않습니다.</span>
|
||||
<span class="form-hint">PoC 운영 시 역할별 데이터 취급 기준을 표현하는 분류값입니다.</span>
|
||||
</label>
|
||||
<button class="btn rw-btn-primary" type="submit">추가</button>
|
||||
</form>
|
||||
@@ -49,7 +49,7 @@
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>역할명</th>
|
||||
<th>표시 보호 등급 상한</th>
|
||||
<th>데이터 취급 등급</th>
|
||||
<th>삭제 영향</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
@@ -61,7 +61,7 @@
|
||||
<td th:text="${role.roleId()}">10</td>
|
||||
<td th:text="${role.roleName()}">HR_DEPT_ROLE</td>
|
||||
<td>
|
||||
<span class="badge text-bg-light" th:title="${'허용된 행의 컬럼 표시 상한: ' + role.maxSensitivityLevel()}"
|
||||
<span class="badge text-bg-light" th:title="${'역할 데이터 취급 등급: ' + role.maxSensitivityLevel()}"
|
||||
th:text="${role.maxSensitivityLevel()}">PUBLIC</span>
|
||||
<form method="post" action="/roles/max-sensitivity" class="inline-form">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
|
||||
@@ -74,7 +74,7 @@
|
||||
</select>
|
||||
<button class="btn btn-sm btn-outline-primary" type="submit">저장</button>
|
||||
</form>
|
||||
<small class="text-muted d-block mt-1">행 접근 권한과 별개인 표시 보호 상한</small>
|
||||
<small class="text-muted d-block mt-1">PoC 운영 기준 분류값</small>
|
||||
</td>
|
||||
<td class="delete-impact">
|
||||
<div>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<h1>사용자</h1>
|
||||
<details class="explanation-details">
|
||||
<summary>도움말</summary>
|
||||
<p>Bearer Token과 권한 매핑에 사용할 내부 사용자를 관리합니다. 여기의 사용자는 Oracle DB schema 계정이 아니라 권한체계에서 식별하는 application user입니다.</p>
|
||||
<p>스마일게이트 Data & AI PoC 도구를 사용할 운영 사용자를 관리합니다. 게임 서비스 이용자나 Oracle DB 계정과는 별개의 백오피스 관리 대상입니다.</p>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user