-- #740 HMM MCP VPD execution boundary
-- Run as ADMIN with SQLcl. The password is prompted without echo and is used
-- only when CB_ORDS does not already exist.
set define on verify off echo off feedback on serveroutput on
whenever sqlerror exit sql.sqlcode rollback

accept hmm_cb_ords_password char prompt 'CB_ORDS initial password: ' hide

declare
  v_user_count number;
  v_password varchar2(4000) := q'~&hmm_cb_ords_password~';
begin
  select count(*)
    into v_user_count
    from dba_users
   where username = 'CB_ORDS';

  if v_user_count = 0 then
    if length(v_password) < 16
       or instr(v_password, '"') > 0
       or instr(v_password, chr(10)) > 0
       or instr(v_password, chr(13)) > 0
       or not regexp_like(v_password, '[A-Z]')
       or not regexp_like(v_password, '[a-z]')
       or not regexp_like(v_password, '[0-9]')
       or not regexp_like(v_password, '[^A-Za-z0-9]') then
      raise_application_error(
          -20001,
          'CB_ORDS password must be 16+ chars with upper/lower/digit/special and no quote/newline.');
    end if;
    execute immediate
        'create user CB_ORDS identified by "' || v_password || '" '
        || 'default tablespace DATA temporary tablespace TEMP quota 0 on DATA';
    dbms_output.put_line('Created CB_ORDS.');
  else
    dbms_output.put_line('CB_ORDS already exists; password was not changed.');
  end if;
end;
/

alter user CB_ORDS account unlock;
grant create session to CB_ORDS;

create or replace package CB_ORDS_HANDLER_PKG
authid definer
as
  procedure SET_VPD_CONTEXT(p_authorization in varchar2);
  procedure CLEAR_VPD_CONTEXT;
end CB_ORDS_HANDLER_PKG;
/

create or replace package body CB_ORDS_HANDLER_PKG
as
  c_bearer_prefix constant varchar2(7) := 'Bearer ';

  procedure CLEAR_VPD_CONTEXT
  is
  begin
    HMM_ACCESS_CTX_PKG.CLEAR_USER;
    dbms_session.clear_identifier;
  end CLEAR_VPD_CONTEXT;

  procedure SET_VPD_CONTEXT(p_authorization in varchar2)
  is
    v_authorization varchar2(2048) := trim(p_authorization);
    v_token varchar2(512);
  begin
    CLEAR_VPD_CONTEXT;
    if v_authorization is null
       or length(v_authorization) > 2048
       or upper(substr(v_authorization, 1, length(c_bearer_prefix)))
          <> upper(c_bearer_prefix) then
      raise_application_error(-20002, 'A valid Bearer authorization header is required.');
    end if;

    v_token := trim(substr(v_authorization, length(c_bearer_prefix) + 1));
    if v_token is null or length(v_token) > 512 then
      raise_application_error(-20003, 'A valid Bearer token is required.');
    end if;

    HMM_ACCESS_CTX_PKG.SET_USER_BY_BEARER(v_token);
    dbms_session.set_identifier(
        sys_context('HMM_ACCESS_CTX', 'EMPLOYEE_CODE'));
  exception
    when others then
      CLEAR_VPD_CONTEXT;
      raise;
  end SET_VPD_CONTEXT;
end CB_ORDS_HANDLER_PKG;
/

grant execute on CB_ORDS_HANDLER_PKG to CB_ORDS;

grant select on HMM_ORG_TEAMS to CB_ORDS;
grant select on HMM_HR_EMPLOYEES to CB_ORDS;
grant select on HMM_LEAVE_BALANCES to CB_ORDS;
grant select on HMM_LEAVE_REQUESTS to CB_ORDS;
grant select on HMM_ATTENDANCE_DAILY to CB_ORDS;
grant select on HMM_HR_TERMS to CB_ORDS;

create or replace synonym CB_ORDS.CB_ORDS_HANDLER_PKG
  for ADMIN.CB_ORDS_HANDLER_PKG;
create or replace synonym CB_ORDS.HMM_ORG_TEAMS
  for ADMIN.HMM_ORG_TEAMS;
create or replace synonym CB_ORDS.HMM_HR_EMPLOYEES
  for ADMIN.HMM_HR_EMPLOYEES;
create or replace synonym CB_ORDS.HMM_LEAVE_BALANCES
  for ADMIN.HMM_LEAVE_BALANCES;
create or replace synonym CB_ORDS.HMM_LEAVE_REQUESTS
  for ADMIN.HMM_LEAVE_REQUESTS;
create or replace synonym CB_ORDS.HMM_ATTENDANCE_DAILY
  for ADMIN.HMM_ATTENDANCE_DAILY;
create or replace synonym CB_ORDS.HMM_HR_TERMS
  for ADMIN.HMM_HR_TERMS;

declare
  v_exempt_count number;
  v_policy_count number;
begin
  select count(*)
    into v_exempt_count
    from dba_sys_privs
   where grantee = 'CB_ORDS'
     and privilege = 'EXEMPT ACCESS POLICY';
  if v_exempt_count <> 0 then
    raise_application_error(-20004, 'CB_ORDS must not have EXEMPT ACCESS POLICY.');
  end if;

  select count(*)
    into v_policy_count
    from dba_policies
   where object_owner = 'ADMIN'
     and object_name in ('HMM_LEAVE_BALANCES', 'HMM_LEAVE_REQUESTS')
     and policy_name = 'HMM_LEAVE_SCOPE_POLICY'
     and enable = 'YES'
     and sel = 'YES';
  if v_policy_count <> 2 then
    raise_application_error(-20005, 'Both HMM leave VPD policies must be enabled.');
  end if;
end;
/

select username, account_status
  from dba_users
 where username = 'CB_ORDS';

select privilege
  from dba_sys_privs
 where grantee = 'CB_ORDS'
 order by privilege;

select object_name, object_type, status
  from dba_objects
 where owner = 'ADMIN'
   and object_name = 'CB_ORDS_HANDLER_PKG'
 order by object_type;

undefine hmm_cb_ords_password
prompt HMM MCP VPD runtime boundary is ready.
