Template for creating data owners and application users

How many times haven’t I seen applications logging onto the Oracle database as the schema owner. This is definitely not good practice. And usually by the time the DBA discovers this, it’s “to late” to change. I’ve heard managers say: “It will be to expensive and to much of a risk changing this now”. (Note! The same manager actually argued the same when I asked them to – at least – change the password to something else than the username.)

The best way to actually change this is to talk to and educate your developers. In my company I created a script the developers could use when creating new schema users. The script is meant as a template, and should of course be changed if needed.

In the top of the script the developer chooses a application name, and some other settings:

-- -------------------------------------------------------------------
-- Set the following parameters
-- -------------------------------------------------------------------

-- ORA_VERSION:      The Oracle version (default 12)
-- PBD_NAME:         The name of the plugable database (only if version 12 and above)
-- CREATE_SCRIPT:    (Y/N) where
--                       N - Everything is ran towards the database,
--                       Y - Only script is created)
-- APP_NAME          The application name
-- OWNER_SUFFIX      Suffix for data owner name: <APP_NAME><OWNER_SUFFIX>
-- SUPPORT_SUFFIX    Suffix for support user:    <APP_NAME><SUPPORT_SUFFIX>
-- OWNER_GRANTS      Priveleges granted to data owner
-- TBS_LOBS          (Y/N) Y if tablespace for LOBS is to be created, else N.
-- TBS_AUTOEXTEND    (Y/N) Y if tbs should use AUTOEXTEND feature
-- TBS_OMF_USE       (Y/N) Y if Oracle Managed Files is to be used
--                   Note! Parameter DB_CREATE_FILE_DEST needs to be set
-- TBS_DIR           Path to files in tablespaces
-- TBS_ASM_USE       (Y/N) Y if ASM is to be used, else N
--                   Note! Will not work if TBS_OMF_USE set to "Y"
-- TBS_ASM_DGRP      Spesify name of disk group if ASM enabled
-- TBS_SIZE          Size for data tablespace
-- TBS_IDX_SIZE      Size for index tablespace
-- TBS_LOB_SIZE      Size for lob tablepace
-- TRG_PREFIX        Prefix for login triggers
--
-- ATOMIKOS_ENABLE   (Y/N) Y to enable XA (Atomikos), N to disable
--                   "Y" will grant necessary rights to read-write role to enable use of atomikos.

DEFINE ORA_VERSION=12
DEFINE PBD_NAME=ORCL

DEFINE CREATE_SCRIPT=N
DEFINE APP_NAME=DEMO
DEFINE OWNER_SUFFIX=DATA
DEFINE SUPPORT_SUFFIX=SUPP
DEFINE OWNER_GRANTS='create table, create view, create sequence, create procedure, create type, create trigger, create synonym'

DEFINE TBS_LOBS=Y
DEFINE TBS_AUTOEXTEND=Y
DEFINE TBS_OMF_USE=N
DEFINE TBS_DIR="/home/oracle/app/oracle/oradata/orcl"
DEFINE TBS_ASM_USE=N
DEFINE TBS_ASM_DGRP="+disk_group"
DEFINE TBS_SIZE="100M"
DEFINE TBS_IDX_SIZE="50M"
DEFINE TBS_LOB_SIZE="50M"
DEFINE TRG_PREFIX=SET_DEF_SCHEMA_

DEFINE ATOMIKOS_ENABLE=Y

The script then creates the following in your database or your choosen PBD (if ORA_VERSION >= 12):

– Tablespaces <APP_NAME>_DATA, <APP_NAME>_IDX, <APP_NAME>_LOBS (optional)
– Users <APP_NAME><OWNER_SUFFIX>,<APP_NAME>,<APP_NAME><SUPPORT_SUFFIX>
– Roles <APP_NAME>_RW, <APP_NAME>_RO
– Triggers <APP_NAME>.AFTER_LOGON_TRG, <APP_NAME><SUPPORT_SUFFIX>.AFTER_LOGON_TRG
– Package <APP_NAME>_GRANT in owner schema: To grant access rights to roles after object creation

For example if APP_NAME is set to HR, then you’ll get the following:
TABLESPACES: HR_DATA, HR_IDX, HR_LOBS (optionally)
ROLES: HR_RO, HR_RW
USERS: HRDATA, HR, HRSUPP (default password is the same as lower case APP_NAME – in this case “hr” – of course to be changed)
PACKAGE: HR_GRANT with the GRANTTOROLES procedure (in HRDATA schema)
TRIGGERS: HR.AFTER_LOGON_TRG, HRSUPP.AFTER_LOGON_TRG

The HR user is granted the HR_RW role, and the HRSUPP user is granted the HR_RO role.

After you login to the HRDATA user and create objects, you run the HR_GRANT.GRANTTOROLES procedure to give access to the new objects.
When you login as the HR user the HR.AFTER_LOGON_TRG set HRDATA as the CURRENT_SCHEMA.

#> sqlplus hrdata/hr
HR> create table department (deptid number, department_name varchar2(50), leader_id number);

Table created.

HRDATA> exec pwh_grant.granttoroles;

PL/SQL procedure successfully completed.

HRDATA> conn hr/hr

HR> select * from department;

No rows selected.

Feel free to use the script (at own risk) – create_dev_users.sql:

-- -------------------------------------------------------------------
--
-- Title: create_dev_users.sql
--
-- Description: 
-- This script creates:
--      - Tablespaces <APP_NAME>_DATA, <APP_NAME>_IDX, <APP_NAME>_LOBS(optional)
--      - Users <APP_NAME><OWNER_GSUFFIX>,<APP_NAME>,<APP_NAME><SUPPORT_SUFFIX>
--      - Roles <APP_NAME>_RW, <APP_NAME>_RO
--      - Triggers <APP_NAME>.AFTER_LOGON_TRG, <APP_NAME><SUPPORT_SUFFIX>.AFTER_LOGON_TRG 
--      - Package <APP_NAME>_GRANT in owner schema: To grant access rights to roles after object creation
--
-- Usage:
--      - Run as SYSTEM (or other user with DBA role) or SYSDBA
--      - Note! If ATOMIKOS_ENABLE is Y, then run as SYSDBA
--
-- Notes:
--      - Set variables in head of script (below these comments) 
--
-- Author: Lasse Jenssen, lasse.jenssen@gmail.com
-- Date:  20 Nov 2013
--
-- Version: 1.3
--
-- History
--    01.feb 2013 - v1.0: Initial script (for testing)
--    12.jan 2014 - v1.1: First official release
--    24.apr 2014 - v1.2: Added Atomikos support
--    21.may 2015 - v1.3: Support for Oracle versions
-- -------------------------------------------------------------------

-- -------------------------------------------------------------------
-- Set the following parameters
-- -------------------------------------------------------------------

-- ORA_VERSION:      The Oracle version (default 12)
-- PBD_NAME:         The name of the plugable database (only if version 12 and above)
-- CREATE_SCRIPT:    (Y/N) where 
--                       N - Everything is ran towards the database, 
--                       Y - Only script is created)
-- APP_NAME          The application name
-- OWNER_SUFFIX      Suffix for data owner name: <APP_NAME><OWNER_SUFFIX>
-- SUPPORT_SUFFIX    Suffix for support user:    <APP_NAME><SUPPORT_SUFFIX>
-- OWNER_GRANTS      Priveleges granted to data owner
-- TBS_LOBS          (Y/N) Y if tablespace for LOBS is to be created, else N.
-- TBS_AUTOEXTEND    (Y/N) Y if tbs should use AUTOEXTEND feature
-- TBS_OMF_USE       (Y/N) Y if Oracle Managed Files is to be used
--                   Note! Parameter DB_CREATE_FILE_DEST needs to be set
-- TBS_DIR           Path to files in tablespaces
-- TBS_ASM_USE       (Y/N) Y if ASM is to be used, else N
--                   Note! Will not work if TBS_OMF_USE set to "Y"
-- TBS_ASM_DGRP      Spesify name of disk group if ASM enabled
-- TBS_SIZE          Size for data tablespace
-- TBS_IDX_SIZE      Size for index tablespace
-- TBS_LOB_SIZE      Size for lob tablepace
-- TRG_PREFIX        Prefix for login triggers 
--
-- ATOMIKOS_ENABLE   (Y/N) Y to enable XA (Atomikos), N to disable
--                   "Y" will grant necessary rights to read-write role to enable use of atomikos.

DEFINE ORA_VERSION=12
DEFINE PBD_NAME=ORCL

DEFINE CREATE_SCRIPT=N
DEFINE APP_NAME=DEMO
DEFINE OWNER_SUFFIX=DATA
DEFINE SUPPORT_SUFFIX=SUPP
DEFINE OWNER_GRANTS='create table, create view, create sequence, create procedure, create type, create trigger, create synonym'

DEFINE TBS_LOBS=Y
DEFINE TBS_AUTOEXTEND=Y
DEFINE TBS_OMF_USE=N
DEFINE TBS_DIR="/home/oracle/app/oracle/oradata/orcl"
DEFINE TBS_ASM_USE=N
DEFINE TBS_ASM_DGRP="+disk_group"
DEFINE TBS_SIZE="100M"
DEFINE TBS_IDX_SIZE="50M"
DEFINE TBS_LOB_SIZE="50M"
DEFINE TRG_PREFIX=SET_DEF_SCHEMA_

DEFINE ATOMIKOS_ENABLE=Y

-- ------ DO NOT EDIT BELOW THIS LINE --------------------------------
WHENEVER SQLERROR EXIT SQL.SQLCODE

set serveroutput on size 1000000
set verify off
set feedback off

-- -------------------------------------------------------------------
-- Oracle version related settings
-- -------------------------------------------------------------------
DECLARE
   l_ora_version  number    		:=&ORA_VERSION;
   l_pbd_name     varchar2(50)		:='&PBD_NAME';
   procedure log(txt_i IN varchar2) as
   begin
     dbms_output.put_line('-- * '||rpad(txt_i,76,' ')||' * --');
   end;
BEGIN
    log(rpad('-',76,'-'));
	log('Your settings:');
	log('    Oracle version:' || l_ora_version);
	
	
	if l_ora_version >= 12 then
	    log('    Plugable Name:' || l_pbd_name);
	    execute immediate 'alter session set container=' || l_pbd_name ;
	end if;
	log(rpad('-',76,'-'));
END;
/

-- Need to be set again because of possible change of plugable database
set serveroutput on size 1000000
set verify off
set feedback off

set lines 120

prompt

-- Check if script ran as appropriate user rights
-- Generally needs to be ran as SYSTEM
-- If ATOMIKOS_ENABLE=Y then need to be ran as SYSDBA
DECLARE
   l_xa_enable     boolean         := case when '&ATOMIKOS_ENABLE'='N' then false else true end;
BEGIN
   if (USER not in ('SYS','SYSTEM')) then
      raise_application_error(-20001, 'Script must be ran as SYSTEM or SYSDBA');
   end if;
   if (l_xa_enable AND USER!='SYS') then
     raise_application_error(-20001, 'Enabling Atomikas has to be ran as SYSDBA');
   end if;
END;
/

-- Startup message
DECLARE
   l_cre_scr       boolean         := case when '&CREATE_SCRIPT'='N' then false else true end;
   
   procedure log(txt_i IN varchar2) as
   begin
     dbms_output.put_line('-- * '||rpad(txt_i,76,' ')||' * --');
   end;
BEGIN
   log(rpad('-',76,'-'));
   log(chr(8));

   if l_cre_scr then
      log('Script: Save as "create_app_users_env.sql" ');
      log(chr(8));
      log('Description:');
      log('  Script to generate an application environment in Oracle');
      log('Use:');
      log('  Run as SYSTEM (or SYSDBA if ATOMIKOS_ENABLE=Y)');
   else
      log('Script: create_dev_users.sql');
      log(chr(8));
      log('Use:');
      log('  Run as SYSTEM (or SYSDBA if ATOMIKOS_ENABLE=Y)');
      log(chr(8));
      log('Description: This script is potensially creating');
      log('             users, roles, tablespaces and login triggers');
      log('             for an test or development environment.');
      log(chr(8));
      log('Author: Lasse Jenssen, CoE - Database mailto: lasse.jenssen@evry.com');
      log(chr(8));
      log('Note! Before running please set the required parameters ');
      log('      in the top of the script.');
   end if;
   
   log(chr(8));
   log(rpad('-',76,'-'));
END;
/

prompt *** --------------------------------------------- ***
prompt ***      Creating TABLESPACES ... (waiting)       ***
prompt *** --------------------------------------------- ***

DECLARE
   l_cre_scr       boolean         := case when '&CREATE_SCRIPT'='N' then false else true end;
   l_app_name      varchar2(10)    :='&APP_NAME';
   l_own_suff      varchar2(10)    :='&OWNER_SUFFIX';
   l_sup_suff      varchar2(10)    :='&SUPPORT_SUFFIX';

   l_tbs_size      varchar2(10)    :='&TBS_SIZE';
   l_tbs_idx_size  varchar2(10)    :='&TBS_IDX_SIZE';
   l_tbs_lob_size  varchar2(10)    :='&TBS_LOB_SIZE';
   
   l_tbs_lobs      char(1)         :='&TBS_LOBS';
   l_tbs_auto      char(1)         :='&TBS_AUTOEXTEND';
   l_tbs_omf_use   char(1)         :='&TBS_OMF_USE';
   l_tbs_asm_use   char(1)         :='&TBS_ASM_USE';
   l_tbs_asm_dgrp  varchar2(30)    :='&TBS_ASM_DGRP';
   l_tbs_dir       varchar2(100)   :='&TBS_DIR';

   l_filename      varchar2(100);
   l_tbs           varchar2(30);
   l_cnt           number;

   l_sql           varchar2(4000);
   
   procedure log(txt_i varchar2) as
   begin
      dbms_output.put_line(txt_i);
   end;

BEGIN
   
   -- Creating DATA tbs
   l_tbs   := lower(l_app_name || '_DATA');
   
   l_filename := case 
                      when l_tbs_asm_use='Y' then l_tbs_asm_dgrp
                                             else l_tbs_dir || '/' || l_tbs || '01.dbf'
                    end;

   l_sql := 'CREATE TABLESPACE ' || l_tbs || 
                  ' datafile ' ||
                  case when l_tbs_omf_use!='Y' then '''' || l_filename || '''' else '' end ||
                  ' SIZE ' || l_tbs_size ||
                  case when l_tbs_auto='Y' then ' autoextend on maxsize unlimited' else '' end;   
   
   if l_cre_scr then
       log(l_sql || ';');
   else
      select count(*) into l_cnt from dba_tablespaces where upper(tablespace_name)=upper(l_tbs);
   
      if l_cnt=0 then
         begin
            execute immediate l_sql;
            log('Creating tablespace ' || l_tbs ||' succeeded.');
         exception when others then
         log('ERROR: Creating tablespace ' || l_tbs ||' failed.');
         end;  
      else
        log('Tablespace ' || l_tbs || ' exists.');
      end if;
   end if;
   
   -- Creating IDX tbs
   l_tbs := lower(l_app_name || '_IDX');
   
   l_filename := case 
                      when l_tbs_asm_use='Y' then l_tbs_asm_dgrp
                      else l_tbs_dir || '/' || l_tbs || '01.dbf'
                    end;
   
   l_sql := 'CREATE TABLESPACE ' || l_tbs || 
                  ' datafile ' ||
                  case when l_tbs_omf_use!='Y' then '''' || l_filename || '''' else '' end ||
                  ' SIZE ' || l_tbs_idx_size ||
                  case when l_tbs_auto='Y' then ' autoextend on maxsize unlimited' else '' end;
   
   if l_cre_scr then
      log(l_sql || ';');
   else                                            
      select count(*) into l_cnt from dba_tablespaces where upper(tablespace_name)=upper(l_tbs);
   
      if l_cnt=0 then
         begin
            execute immediate l_sql;
            log('Creating tablespace ' || l_tbs ||' succeeded.');
         exception when others then
            log('ERROR: Creating tablespace ' || l_tbs ||' failed:' || SQLERRM);
         end;
      else
         log('Tablespace ' || l_tbs || ' exists.');
      end if;
   end if;
   
   -- Creating LOB tbs
   if l_tbs_lobs='Y' then
     l_tbs := lower(l_app_name || '_LOBS');
     
     l_filename := case 
                        when l_tbs_asm_use='Y' then l_tbs_asm_dgrp
                        else l_tbs_dir || '/' || l_tbs || '01.dbf'
                      end;
     
     l_sql := 'CREATE TABLESPACE ' || l_tbs || 
                    ' datafile ' ||
                    case when l_tbs_omf_use!='Y' then '''' || l_filename || '''' else '' end ||
                    ' SIZE ' || l_tbs_idx_size ||
                    case when l_tbs_auto='Y' then ' autoextend on maxsize unlimited' else '' end;
     
     if l_cre_scr then
        log(l_sql || ';');
     else                                            
        select count(*) into l_cnt from dba_tablespaces where upper(tablespace_name)=upper(l_tbs);
     
        if l_cnt=0 then
           begin
              execute immediate l_sql;
              log('Creating tablespace ' || l_tbs ||' succeeded.');
           exception when others then
              log('ERROR: Creating tablespace ' || l_tbs ||' failed:' || SQLERRM);
           end;
        else
           log('Tablespace ' || l_tbs || ' exists.');
        end if;
     end if;
  end if;     
END;
/

prompt *** --------------------------------------------- ***
prompt ***     Creating roles ... (waiting)              ***
prompt *** --------------------------------------------- ***

DECLARE
   l_ora_version   number          :=&ORA_VERSION;
   l_cre_scr       boolean         := case when '&CREATE_SCRIPT'='N' then false else true end;
   l_app_name      varchar2(10)    :='&APP_NAME';
   l_own_suff      varchar2(10)    :='&OWNER_SUFFIX';
   l_sup_suff      varchar2(10)    :='&SUPPORT_SUFFIX';
   
   l_xa_enable     boolean         := case when '&ATOMIKOS_ENABLE'='N' then false else true end;
   l_sql_xa_sel1    varchar2(1000);
   l_sql_xa_sel2    varchar2(1000);
   l_sql_xa_sel3    varchar2(1000);
   l_sql_xa_exe    varchar2(1000);
   
   l_role          dba_roles.role%type;
   l_cnt           number;
   l_sql           varchar2(1000);
   

   procedure log(txt_i varchar2) as
   begin
      dbms_output.put_line(txt_i);
   end;

BEGIN
   -- Creating RW role
   l_role   := l_app_name || '_RW';
   
   l_sql := 'CREATE ROLE ' || l_role;
   l_sql_xa_sel1 := 'GRANT SELECT ON sys.dba_pending_transactions TO ' || l_role;
   l_sql_xa_sel2 := 'GRANT SELECT ON sys.pending_trans$ TO ' || l_role;
   l_sql_xa_sel3 := 'GRANT SELECT ON sys.dba_2pc_pending TO ' || l_role;

   if l_ora_version>=11 then
     l_sql_xa_exe := 'GRANT EXECUTE ON sys.dbms_xa TO ' || l_role;
   else
     l_sql_xa_exe := 'GRANT EXECUTE ON sys.dbms_system TO ' || l_role;
   end if;
 
   if l_cre_scr then
      log(l_sql || ';');
		  
      if l_xa_enable then
			   log(l_sql_xa_sel1 || ';');
         log(l_sql_xa_sel2 || ';');
         log(l_sql_xa_sel3 || ';');
			   log(l_sql_xa_exe || ';');
		  end if;
   else
      select count(*) into l_cnt from dba_roles where upper(role)=upper(l_role);

      if l_cnt=0 then
         begin
            execute immediate l_sql;
            log('Creating role ' || l_role ||' succeeded.');
         exception when others then
            log('ERROR: Creating role ' || l_role ||' failed:' || SQLERRM);
         end;
		 
         if l_xa_enable then
          begin
            execute immediate l_sql_xa_sel1;
            execute immediate l_sql_xa_sel2;
            execute immediate l_sql_xa_sel3;
            execute immediate l_sql_xa_exe;
            log('Enabling Atomikos (grants) succeeded.');
          exception when others then
             log('ERROR: Granting XA (Atomikos) rights to ' || l_role ||' failed:' || SQLERRM);
          end;
         end if;
      else
         log('Role ' || l_role || ' exists.');
      end if;   
   end if;

   -- Creating RO role
   l_role   := l_app_name || '_RO';

   l_sql := 'CREATE ROLE ' || l_role;
   if l_cre_scr then
      log(l_sql || ';');
   else
      select count(*) into l_cnt from dba_roles where upper(role)=upper(l_role);

      if l_cnt=0 then
         begin
            execute immediate l_sql;
            log('Creating role ' || l_role ||' succeeded.');
         exception when others then
            log('ERROR: Creating role ' || l_role ||' failed:' || SQLERRM);
         end;
      else
         log('Role ' || l_role || ' exists.');
      end if;
   end if;

END;
/

prompt *** --------------------------------------------- ***
prompt ***     Creating users ... (waiting)              ***
prompt *** --------------------------------------------- ***

DECLARE
   l_cre_scr       boolean         := case when '&CREATE_SCRIPT'='N' then false else true end;
   l_app_name      varchar2(10)    :='&APP_NAME';
   l_own_suff      varchar2(10)    :='&OWNER_SUFFIX';
   l_sup_suff      varchar2(10)    :='&SUPPORT_SUFFIX';
   l_own_grnt      varchar2(1000)  :='&OWNER_GRANTS';
   l_tbs_lobs      char(1)         :='&TBS_LOBS';
   
   procedure log(txt_i varchar2) as
   begin
      dbms_output.put_line(txt_i);
   end;

   procedure grant_role_to_user(rw_i IN boolean, user_i IN varchar2) as
     p_sql varchar2(1000):= 'Not set';
     p_role dba_roles.role%type;
   begin
     p_role := l_app_name || case rw_i when false then '_RO' else '_RW' end;

     p_sql := 'GRANT ' || p_role || ' TO ' || user_i;
     
     if l_cre_scr then
       log(p_sql || ';');
     else
       execute immediate p_sql;
       log('User ' || user_i || ' granted ' || p_role || ' successfully.');
     end if;
   exception when others then
      log('ERROR: Granting role ' || p_role || ' to ' || user_i || ' failed:' || SQLERRM); 
   end;

   procedure create_user(user_i IN varchar2, owner_i IN boolean default false) as
     p_sql_usr       varchar2(2000);
     p_sql_grnt      varchar2(1000);
     p_sql_grnt_own  varchar2(1000);
     
     p_cnt         number;
   begin
      p_sql_usr :=  'CREATE USER ' || user_i ||' IDENTIFIED BY ' || lower(l_app_name) || 
                  ' DEFAULT TABLESPACE ' || 
                  case when owner_i=false 
                       then 'users' else l_app_name || '_DATA' end ||' TEMPORARY TABLESPACE temp ' ||
                  case when owner_i=false then '' 
                       else ' QUOTA UNLIMITED ON '|| l_app_name || '_DATA QUOTA UNLIMITED ON ' || l_app_name ||'_IDX' 
                  end ||
                  case when owner_i=true and l_tbs_lobs='Y' then ' QUOTA UNLIMITED ON ' || l_app_name || '_LOBS' else ''
                  end;
      p_sql_grnt     := 'GRANT create session TO '|| user_i;
      p_sql_grnt_own := 'GRANT ' || l_own_grnt || ' TO ' || user_i; 
      
      if l_cre_scr then
         log(p_sql_usr || ';');
         log(p_sql_grnt || ';');
         if owner_i then 
            log(p_sql_grnt_own || ';');
         end if;
      else
         select count(*) into p_cnt from dba_users where username=user_i;
        
         if p_cnt=0 then
            begin
               execute immediate p_sql_usr;
               log('User ' || user_i || ' created successfully.');
            exception when others then
               log('ERROR: Creating user ' || user_i || ' failed:' || SQLERRM);
            end;
                 
            begin
               execute immediate p_sql_grnt;
               log('User ' || user_i || ' granted CREATE SESSION successfully');
            exception when others then
               log('ERROR: Granting create session to ' || user_i || ' failed:' || SQLERRM);
            end;
        
        
            if owner_i then
               begin
                  execute immediate p_sql_grnt_own;
                  log('User ' || user_i || ' granted owner rights successfully.');
               exception when others then
                  log('ERROR: Granting owner rights to ' || user_i || ' failed:' || SQLERRM);
               end;
            end if;
         else
            log('User ' || user_i || ' allready exist!');
         end if;
      end if;
   end;

BEGIN
   create_user(l_app_name,false);
   create_user(l_app_name||l_own_suff,true);
   create_user(l_app_name||l_sup_suff,false);
   
   grant_role_to_user(true,l_app_name);
   grant_role_to_user(false,l_app_name||l_sup_suff);
END;
/

prompt *** --------------------------------------------- ***
prompt ***     Creating trigger ... (waiting)            ***
prompt *** --------------------------------------------- ***

DECLARE
   l_cre_scr       boolean         := case when '&CREATE_SCRIPT'='N' then false else true end;
   l_app_name      varchar2(10)    :='&APP_NAME';
   l_own_suff      varchar2(10)    :='&OWNER_SUFFIX';
   l_sup_suff      varchar2(10)    :='&SUPPORT_SUFFIX';
   l_trg_pref      varchar2(20)    :='&TRG_PREFIX';

   procedure log(txt_i varchar2) as
   begin
      dbms_output.put_line(txt_i);
   end;

   procedure create_logon_trigger(user_i IN varchar2) as
     p_sql varchar2(2000):= 'Not set';
     p_name varchar2(30);
   begin
     p_name := l_trg_pref || user_i;

     p_sql := 'CREATE OR REPLACE TRIGGER ' || p_name ||  chr(10) ||
              '    AFTER LOGON ON '|| user_i || '.SCHEMA' || chr(10) ||  
              'BEGIN ' || chr(10) ||
              '   EXECUTE IMMEDIATE ''ALTER SESSION SET current_schema=' ||
                                  l_app_name || l_own_suff || '''; ' || chr(10) ||
              'END;';
     if l_cre_scr then
           log(p_sql);
           log('/');
     else
        begin
           execute immediate p_sql;
           log('Trigger ' || p_name || ' created successfully.'); 
        exception when others then
           log('ERROR: Creating logon trigger for ' || user_i || ' failed: ' || SQLERRM);
        end;
     end if; 
   end;

BEGIN
   create_logon_trigger(l_app_name);
   create_logon_trigger(l_app_name||l_sup_suff);
END;
/

prompt *** --------------------------------------------- ***
prompt ***     Creating GRANT package ... (waiting)      ***
prompt *** --------------------------------------------- ***

DECLARE
   l_cre_scr       boolean         := case when '&CREATE_SCRIPT'='N' then false else true end;
   l_app_name      varchar2(10)    :='&APP_NAME';
   l_own_suff      varchar2(10)    :='&OWNER_SUFFIX';
   l_sup_suff      varchar2(10)    :='&SUPPORT_SUFFIX';
   
   l_pkg_name      varchar2(20)    :=l_app_name || '_GRANT';
   l_own           varchar2(30)    :=l_app_name || l_own_suff;
   l_sup           varchar2(30)    :=l_app_name || l_sup_suff;
   
   l_sql           varchar2(32000);

   procedure log(txt_i varchar2) as
   begin
      dbms_output.put_line(txt_i);
   end;

BEGIN
  -- Creating PACKAGE
  l_sql := 'CREATE OR REPLACE PACKAGE ' || l_own || '.' || l_pkg_name || ' AS ' || chr(10) ||
           '    APP_NAME       CONSTANT  varchar2(' || length(l_app_name) ||')    :=''' || l_app_name || ''';' || chr(10) ||
           '    SUPP_USR       CONSTANT  varchar2(' || length(l_sup) ||')    :=''' || l_sup || ''';' || chr(10) ||
           '    DATA_USR       CONSTANT  varchar2(' || length(l_own) ||')    :=''' || l_own || ''';' || chr(10) ||
           '    ROLE_NAME_RW   CONSTANT  varchar2(' || length(l_app_name||'_RW') ||')    :=''' || l_app_name || '_RW'';' || chr(10) ||
           '    ROLE_NAME_RO   CONSTANT  varchar2(' || length(l_app_name||'_RO') ||')    :=''' || l_app_name || '_RO'';' || chr(10) || chr(10) ||
           '    procedure grantToRoles;' || chr(10) ||
           'END;';
  if l_cre_scr then
        log(l_sql);
        log('/');
  else
     begin
        execute immediate l_sql;
        log('Package ' || l_pkg_name || ' created successfully.'); 
     exception when others then
        log('ERROR: Creating package ' || l_pkg_name || ' failed: ' || SQLERRM);
     end;
  end if;
  
  -- Creating PACKAGE BODY
  l_sql := 'CREATE OR REPLACE PACKAGE BODY ' || l_own || '.' || l_pkg_name || ' AS ' || chr(10) ||
           '    PROCEDURE log(txt_i IN varchar2) AS' || chr(10) ||
           '    BEGIN' || chr(10) ||
           '       dbms_output.put_line(txt_i);' || chr(10) ||
           '    END;' || chr(10) || chr(10) ||
           '    PROCEDURE grant_to_roles(obj_name_i IN varchar2, obj_type_i IN varchar2) AS ' || chr(10) ||
           '       p_sql varchar2(200);' || chr(10) ||
           '    BEGIN' || chr(10) ||
           '       -- Grant to RW role' || chr(10) ||
           '       p_sql := ''GRANT '' || case obj_type_i when ''TABLE''     then ''SELECT, INSERT, UPDATE, DELETE''' || chr(10) ||
           '                                            when ''VIEW''      then ''SELECT''' || chr(10) ||
           '                                            when ''SEQUENCE''  then ''SELECT''' || chr(10) ||
           '                                                             else ''EXECUTE'' end || ' || chr(10) ||
           '                        '' ON '' || obj_name_i || '' TO '' || ROLE_NAME_RW; ' || chr(10) ||
           '       begin' || chr(10) ||      
           '          execute immediate p_sql;' || chr(10) ||
           '          log(''Grant towards '' || obj_name_i || '' to '' || ROLE_NAME_RW || '' completed successfully.'');' || chr(10) || 
           '       exception when others then' || chr(10) ||
           '          log(''ERROR: Grant towards'' || obj_name_i || '' to '' || ROLE_NAME_RW || '' failed: '' || SQLERRM);' || chr(10) ||
           '       end;' || chr(10) || chr(10) ||
           '       -- Grant to RO role if table or view' || chr(10) ||
           '       if obj_type_i in (''TABLE'',''VIEW'') then ' || chr(10) ||
           '          p_sql := ''GRANT SELECT ON '' || obj_name_i || '' TO '' || ROLE_NAME_RO; '|| chr(10) ||
           '          begin' || chr(10) ||
           '             execute immediate p_sql;' || chr(10) ||
           '             log(''Grant towards '' || obj_name_i || '' to '' || ROLE_NAME_RO || '' completed successfully.'');' || chr(10) ||
           '          exception when others then' || chr(10) ||
           '             log(''ERROR: Grant towards'' || obj_name_i || '' to '' || ROLE_NAME_RO || '' failed: '' || SQLERRM);' || chr(10) ||
           '          end;' || chr(10) ||
           '       end if;' || chr(10) ||
           '    END;' || chr(10) || chr(10) ||
           '    PROCEDURE grantToRoles is' || chr(10) ||
           '    BEGIN ' || chr(10) ||
           '       dbms_output.enable(1000000);' || chr(10) ||
           '       FOR rec IN ( SELECT object_name,  object_type  FROM user_objects' || chr(10) ||
           '                    WHERE object_type IN (''TABLE'',''PACKAGE'',''PROCEDURE'',''FUNCTION'',''SEQUENCE'',''VIEW'',''TYPE'')' || chr(10) ||
           '                      AND NOT (object_type like ''%PACKAGE%'' and object_name=''' ||l_pkg_name ||'''))' || chr(10) ||
           '       LOOP' || chr(10) ||
           '          BEGIN' || chr(10) ||
           '             grant_to_roles(rec.object_name, rec.object_type);' || chr(10) ||
           '          EXCEPTION WHEN others THEN' || chr(10) ||
           '             dbms_output.   put_line(''Bad object_name=''  || rec.object_name);' || chr(10) ||
           '          END;' || chr(10) ||
           '       END LOOP;' || chr(10) ||
           '    END;' || chr(10) ||
           'END;';
           
  if l_cre_scr then
        log(l_sql);
        log('/');
  else
     begin
        execute immediate l_sql;
        log('Package body ' || l_pkg_name || ' created successfully.'); 
     exception when others then
        log('ERROR: Creating package body' || l_pkg_name || ' failed: ' || SQLERRM);
     end;
  end if;
END;
/

There is also a drop_dev_users.sql, to clean up when needed:

-- -------------------------------------------------------------------
--
-- Title: drop_dev_users.sql
--
-- Description: 
-- This script drops:
--      - Tablespaces <APP_NAME>_DATA, <APP_NAME>_IDX
--      - Users <APP_NAME><OWNER_SUFFIX>,<APP_NAME>,<APP_NAME><SUPPORT_SUFFIX>
--      - Roles <APP_NAME>_RW, <APP_NAME>_RO
--      - Triggers <APP_NAME>.AFTER_LOGON_TRG, <APP_NAME><SUPPORT_SUFFIX>.AFTER_LOGON_TRG
--
-- Usage:
--      - Run as SYSTEM (or other user with DBA role) or SYSDBA
--
-- Author: Lasse Jenssen, lasse.jenssen@gmail.com
-- Date:  20 Nov 2013
--
-- Version: 1.3
--
-- History
--    01.feb 2013 - v1.0: Initial script (for testing)
--    12.jan 2014 - v1.1: First official release
--    24.apr 2014 - v1.2: No changes - only relevant for create script
--    21.may 2015 - v1.3: Support for Oracle versions
--
-- -------------------------------------------------------------------

-- -------------------------------------------------------------------
-- Set the following parameters
-- -------------------------------------------------------------------
DEFINE ORA_VERSION=12
DEFINE PBD_NAME=ORCL
-- Note! Use Y/N for the boolean variables
DEFINE DROP_USR="Y"
DEFINE DROP_ROL="Y"
DEFINE DROP_TBS="Y"
DEFINE DROP_TRG="Y"
DEFINE APP_NAME=APP
DEFINE OWNER_SUFFIX=DATA
DEFINE SUPPORT_SUFFIX=SUPP

-- ------ DO NOT EDIT BELOW THIS LINE --------------------------------
set serveroutput on
set verify off
set feedback off
-- -------------------------------------------------------------------
-- Oracle version related settings
-- -------------------------------------------------------------------
DECLARE
   l_ora_version  number    		:=&ORA_VERSION;
   l_pbd_name     varchar2(50)		:='&PBD_NAME';
   procedure log(txt_i IN varchar2) as
   begin
     dbms_output.put_line('-- * '||rpad(txt_i,76,' ')||' * --');
   end;
BEGIN
    log(rpad('-',76,'-'));
	log('Your settings:');
	log('    Oracle version:' || l_ora_version);
	
	
	if l_ora_version >= 12 then
	    log('    Plugable Name:' || l_pbd_name);
	    execute immediate 'alter session set container=' || l_pbd_name ;
	end if;
	log(rpad('-',76,'-'));
END;
/

set serveroutput on
set verify off
set feedback off

prompt

-- Startup message
DECLARE
   procedure log(txt_i IN varchar2) as
   begin
     dbms_output.put_line('* '||rpad(txt_i,76,' ')||' *');
   end;
BEGIN
   log(rpad('-',76,'-'));
   log(chr(8));
   log('Script: drop_dev_users_dyn_vX_X.sql');
   log(chr(8));
   log('Description: This script is potensially dropping');
   log('             users, roles, tablespaces and login trigger.');
   log(chr(8));
   log('Author: Lasse Jenssen, CoE - Database mailto: lasse.jenssen@evry.com');
   log(chr(8));
   log('Note! Before running please set the required parameters ');
   log('      in the top of the script.');
   log(chr(8));
   log(rpad('-',76,'-'));
END;
/

prompt 
pause Press Enter to Continue ... (CNTR + C ENTER to abourt)
prompt * --------------------------------------------- *
prompt * Dropping users ... (waiting)                  *
prompt * --------------------------------------------- *

DECLARE
   l_drop_usr      varchar2(1) := '&DROP_USR';

   l_app_name      varchar2(10):='&APP_NAME';
   l_own_suff      varchar2(10):='&OWNER_SUFFIX';
   l_sup_suff      varchar2(10):='&SUPPORT_SUFFIX';

   l_user          varchar2(30);
   l_cnt           number;

   procedure log(txt_i IN varchar2) as
   begin
     dbms_output.put_line(txt_i);
   end;

BEGIN
   if l_drop_usr<>'Y' then
      log('Users not selected to be dropped(set DROP_USR config)');
      return;
   end if;

   -- Dropping APP user 
   l_user := l_app_name;
   select count(*) into l_cnt from dba_users where username = upper(l_user);
   
   if l_cnt>0 then
      begin
         execute immediate 'drop user ' || l_user || ' cascade';
         log('User '||l_user||' dropped');
      exception when others then
         log('ERROR: Dropping '||l_user ||' failed: ' || SQLERRM);
      end;
   else
      log('User '||l_user||' does not exist.'); 
   end if;

  -- Dropping DATA user
   l_user := l_app_name||l_own_suff;
   select count(*) into l_cnt from dba_users where username = upper(l_user);
   
   if l_cnt>0 then
      begin
         execute immediate 'drop user ' || l_user || ' cascade';
         log('User '||l_user||' dropped');
      exception when others then
        log('ERROR: Dropping '||l_user ||' failed: ' || SQLERRM);
      end;
   else
      log('User '||l_user||' does not exist.');
   end if;

   -- Dropping SUPP user
   l_user := l_app_name||l_sup_suff;
   select count(*) into l_cnt from dba_users where username = upper(l_user);
   
   if l_cnt>0 then
      begin
         execute immediate 'drop user ' || l_user || ' cascade';
         log('User '||l_user||' dropped');
      exception when others then
        log('ERROR: Dropping '||l_user ||' failed: ' || SQLERRM);
      end;
   else
      log('User '||l_user||' does not exist.');
   end if;

END;
/

prompt * --------------------------------------------- *
prompt * Dropping Tablespaces ... (waiting)
prompt * --------------------------------------------- *

DECLARE
   l_drop_tbs      varchar2(1) := '&DROP_TBS';
   l_app_name      varchar2(10):='&APP_NAME';

   l_tbs           varchar2(30);
   l_cnt           number;

   procedure log(txt_i IN varchar2) as
   begin
     dbms_output.put_line(txt_i);
   end;

BEGIN

   if l_drop_tbs<>'Y' then
      log('Tablespaces not selected to be dropped (set DROP_TBS ).');
      return;
   end if;

   -- Dropping DATA tablespace 
   l_tbs := l_app_name||'_DATA';
   select count(*) into l_cnt from dba_tablespaces where tablespace_name = upper(l_tbs);

   if l_cnt>0 then
      begin
         execute immediate 'drop tablespace ' || l_tbs || ' including contents and datafiles';
         log('Tablespace '||l_tbs ||' dropped');
      exception when others then
        log('ERROR: Dropping '||l_tbs ||' failed: ' || SQLERRM);
      end;      
   else
      log('Tablespace '||l_tbs ||' does not exist.');
   end if;

   -- Dropping INDEX tablespace
   l_tbs := l_app_name||'_IDX';
   select count(*) into l_cnt from dba_tablespaces where tablespace_name = upper(l_tbs);

   if l_cnt>0 then
      begin
         execute immediate 'drop tablespace ' || l_tbs || ' including contents and datafiles';
         log('Tablespace '||l_tbs ||' dropped.');
      exception when others then
        log('ERROR: Dropping '||l_tbs ||' failed: ' || SQLERRM);
      end;
   else
      log('Tablespace '||l_tbs ||' does not exist.');
   end if;
   
   -- Dropping LOB tablespace
   l_tbs := l_app_name||'_LOBS';
   select count(*) into l_cnt from dba_tablespaces where tablespace_name = upper(l_tbs);

   if l_cnt>0 then
      begin
         execute immediate 'drop tablespace ' || l_tbs || ' including contents and datafiles';
         log('Tablespace '||l_tbs ||' dropped.');
      exception when others then
        log('ERROR: Dropping '||l_tbs ||' failed: ' || SQLERRM);
      end;
   else
      log('Tablespace '||l_tbs ||' does not exist.');
   end if;
END;
/

prompt * --------------------------------------------- *
prompt * Dropping roles ... (waiting)                  * 
prompt * --------------------------------------------- *

DECLARE
   l_drop_rol      varchar2(1) := '&DROP_ROL';
   l_app_name      varchar2(10):='&APP_NAME';

   l_role          varchar2(30);
   l_cnt           number;

   procedure log(txt_i IN varchar2) as
   begin
     dbms_output.put_line(txt_i);
   end;

BEGIN
   if l_drop_rol<>'Y' then
      log('Roles not selected to be dropped(set DROP_ROL).');
      return;
   end if;

   -- Dropping RW role
   l_role := l_app_name||'_RW';
   select count(*) into l_cnt from dba_roles where role = upper(l_role);

   if l_cnt>0 then
      begin
         execute immediate 'drop role ' || l_role;
         log('Role '||l_role ||' dropped.');
      exception when others then
        log('ERROR: Dropping '||l_role ||' failed: ' || SQLERRM);
      end;
   else
      log('Role '||l_role ||' does not exist.');
   end if;

   -- Dropping RW role
   l_role := l_app_name||'_RO';
   select count(*) into l_cnt from dba_roles where role = upper(l_role);

   if l_cnt>0 then
      begin
         execute immediate 'drop role ' || l_role;
         log('Role '||l_role ||' dropped.');
      exception when others then
        log('ERROR: Dropping '||l_role ||' failed: ' || SQLERRM);
      end;
      
   else
      log('Role '||l_role ||' does not exist.');
   end if;

END;
/

prompt * --------------------------------------------- *
prompt * Dropping triggers ... (waiting)               *
prompt * --------------------------------------------- *

DECLARE
   l_drop_usr      varchar2(1) := '&DROP_USR';
   l_drop_trg      varchar2(1) := '&DROP_TRG';
   l_app_name      varchar2(10):='&APP_NAME';
   l_sup_suff      varchar2(10):='&SUPPORT_SUFFIX';

   l_trg           varchar2(30);
   l_cnt           number;

   procedure log(txt_i IN varchar2) as
   begin
     dbms_output.put_line(txt_i);
   end;

BEGIN

   if l_drop_trg<>'Y' then
      log('Triggers not selected to be dropped(set DROP_TRG).');
      return;
   end if;
   
   if l_drop_usr='Y' then
      log('Triggers dropped with user.');
      return;
   end if;

   -- Dropping APP trigger
   l_trg := 'set_def_schema_'||l_app_name;
   select count(*) into l_cnt from dba_triggers where trigger_name = upper(l_trg);

   if l_cnt>0 then
      begin
         execute immediate 'drop trigger ' || l_trg;
         log('Trigger '||l_trg ||' dropped');
      exception when others then
        log('ERROR: Dropping trigger '||l_trg ||' failed: ' || SQLERRM);
      end;
   else
      log('Trigger '||l_trg ||' does not exist(Possibly dropped with user).');
   end if;

   -- Dropping SUPPORT trigger 
   l_trg := 'set_def_schema_'||l_app_name||l_sup_suff;
   select count(*) into l_cnt from dba_triggers where trigger_name = upper(l_trg);

   if l_cnt>0 then
      begin
         execute immediate 'drop trigger ' || l_trg;
         log('Trigger '||l_trg ||' dropped');
      exception when others then
        log('ERROR: Dropping '||l_trg ||' failed: ' || SQLERRM);
      end;
   else
      log('Trigger '||l_trg ||' does not exist(Possibly dropped with user).');
   end if;

END;
/

Post a Comment

Your email is never published nor shared. Required fields are marked *