Oracle Scheduler Jobs e Database Vault

This post is also available in: English

Como todos já sabem, o "Oracle Scheduler" é o agendador de tarefas oficial do Banco de Dados Oracle. Ele é uma ferramenta robusta e complexa, permitindo criar cadeias de execuções, intervalos parametrizados em diversas métricas de datas, janelas de execuções, etc.

Artigo Publicado na OTN: http://www.oracle.com/technetwork/pt/articles/database-performance/oracle-scheduler-jobs-3021419-ptb.html

Na maioria dos casos, quando um job é criado, alterado e executado pelo seu próprio dono, não há muitas complicações. No entanto, as coisas podem ficar realmente confusas principalmente quando trabalhamos em sistemas que envolvem a camada de segurança do Oracle Database Vault e se o job for criado por um usuário diferente do seu proprietário.

Neste artigo, irei mostrar os usuários envolvidos em um Scheduler Job e o papel de cada um.

Bom, para começar, existem basicamente 3 usuários que participam de um Oracle Scheduler Job. São eles:

  • O Dono do Job –  Coluna "OWNER" da view all_scheduler_jobs.
  • O Criador do Job –  Coluna "JOB_CREATOR" da view all_scheduler_jobs.
  • O Último "modificador" do Job – Essa informação não está presente na view all_scheduler_jobs e precisa ser obtida através de consultas em tabelas do dicionário.

Para que serve cada usuário é o que iremos ver a seguir.

1 – O Dono do Job

O dono do job é o schema informado dentro do parâmetro JOB_NAME ao se criar um Job. Se omitido, o dono será o mesmo usuário que executou o comando de criação. No exemplo abaixo, o owner é o usuário "SCOTT".

BEGIN
 DBMS_SCHEDULER.CREATE_JOB(JOB_NAME  => 'SCOTT.JOB1', ..........);
END;
/

O dono do job será também o seu executor. Se a tarefa roda uma procedure ou PL/SQL, este usuário precisa, portanto, ter a permissão de executar a procedure ou privilégios nos objetos acessados pelo código PL/SQL. Caso contrário, receberá um erro como "ORA-00942: table or view does not exist".

Em caso de execução de um PL/SQL, as variáveis de ambiente CURRENT_USER (esquema cujos privilégios estão ativos no momento) e CURRENT_SCHEMA (esquema default ativo no momento) serão obviamente o dono do job pois, como já informado, ele é o executor.

No entanto, em caso de execução de uma Procedure, as variáveis  CURRENT_USER e CURRENT_SCHEMA apontarão para o dono da Procedure, já que uma procedure ao ser chamada é executada com os privilégios e padrões de seu proprietário (exceto se ela possuir "AUTHID CURRENT_USER" que, neste caso, se comportaria similar a um bloco PL/SQL informado acima).

E se lockarmos o usuário que é proprietário? Neste cenário, nada interfere e a tarefa continuará executando na forma agendada sem problemas. No entanto, se o proprietário do job for removido, por pertencê-lo o agendamento também será apagado.

2 – O Criador do Job

O criador do job é o schema que executou a procedure DBMS_SCHEDULER.CREATE_JOB. Caso você crie um job para outro usuário, você será definido como o criador daquele job.

OBS: Lembrando que para criar um job em outro schema é necessário ter o privilégio "CREATE ANY JOB".

O criador do job será o usuário que se conectará na base antes de executá-lo, apesar do executor ser o proprietário. Portanto, a variável de ambiente SESSION_USER apontará sempre para o criador. No entanto, quem cria não precisa de quaisquer privilégios nos objetos envolvidos e executados pelo job.

Durante a execução do agendamento, se consultarmos a coluna "USERNAME" da v$session, ela retornará o usuário criador (pois é ele quem efetuou o login).

No exemplo do item anterior, se o job SCOTT.JOB1 tiver sido criado pelo usuário INFRAUSR, este seria o output da v$session durante a execução da tarefa:

SQL> select username,schemaname,status,program,type,module,action from v$session where module='DBMS_SCHEDULER';
 
USERNAME       SCHEMANAME      STATUS   PROGRAM                      TYPE       MODULE              ACTION
-------------- --------------- -------- ---------------------------- ---------- ------------------- --------
INFRAUSR       SCOTT           ACTIVE   oracle@localhost (J000)      USER       DBMS_SCHEDULER      JOB1
 
SQL>

Apesar do usuário que criou ser o utilizado para logar, se ele for lockado (ou revogarem os seus privilégios de CREATE SESSION), o job continuará executando normalmente. Isso porque a forma do login para a execução de um job é diferente. No entanto, fique atento pois jobs disparam triggers de "BEFORE LOGIN".

E se deletarmos o usuário que criou o job? Nesta situação, o job não é deletado, apenas é desativado. Ao tentar ativá-lo, o status do job na all_scheduler_job_logs será de BROKEN. Será necessário recriá-lo para que volte a funcionar.

3 – O Último "modificador" do Job

O que pouca gente sabe, é que o Oracle mantém em seus registros qual foi o usuário que alterou um job pela última vez. Esse papel é importante apenas em Banco de Dados que possuem Database Vault configurado e quando o job está protegido por um Realm.

Isto porque a última pessoa que alterou uma determinada tarefa passa a ser monitorada pelo Oracle Database Vault e apenas usuários que possuem liberação em uma camada especial serão liberados.

Qual o motivo desta proteção? Um usuário com o privilégio "CREATE ANY JOB" poderia facilmente comprometer o BD ou conseguir uma escalação de privilégios, criando/alterando um job de um outro usuário que é DBA fazendo com que aquele processo fizesse o que ele bem desejasse.

Exemplo:

BEGIN
 DBMS_SCHEDULER.CREATE_JOB(
  JOB_NAME => 'SCOTT.JOB_TEMP',
  JOB_TYPE => 'PLSQL_BLOCK',
  JOB_ACTION => q'[BEGIN EXECUTE IMMEDIATE 'GRANT SELECT ON SCOTT.EMP TO MYUSER'; END;]',
  ENABLED => TRUE);
END;
/ 

No Oracle Database Vault, isso não seria possível.

Para obtermos o ultimo usuário que alterou um job, precisamos consultar a coluna "RUN_INVOKER" da tabela SYS.SCHEDULER$_JOB:

SQL> col job_creator format a25
SQL> col job_owner format a25
SQL> col job_name format a25
SQL> col perms_check_user format a25
 
SQL> SELECT JU.NAME   "JOB_OWNER",
  2         JO.NAME   "JOB_NAME",
  3         J.CREATOR "JOB_CREATOR",
  4         JR.NAME   "JOB_MODIFIER"
  5  FROM   SYS.SCHEDULER$_JOB J,
  6         SYS.USER$ JU,
  7         SYS.USER$ JR,
  8         SYS.OBJ$ JO
  9  WHERE  J.RUN_INVOKER = JR.USER# (+)
 10  AND    J.OBJ# = JO.OBJ#
 11  AND    JO.OWNER# = JU.USER#
 12  AND    JO.NAME = 'JOB_TEST';
 
JOB_OWNER                 JOB_NAME                  JOB_CREATOR               JOB_MODIFIER
------------------------- ------------------------- ------------------------- -------------------------
SCOTT                     JOB_TEST                  INFRAUSR                  OPERUSR

No exemplo acima, o job foi modificado pela última vez pelo usuário do Oracle OPERUSR. Isso significa que caso o OPERUSR não tenha privilégios no DB Vault para executá-lo, o job apresentará o erro:

ORA-12012: error on auto execute of job "SCOTT"."JOB_TEST"
ORA-01031: insufficient privileges
ORA-06512: at line 2

Este erro não tem nada a ver com as permissões nos objetos envolvidos, até porque os privilégios nos objetos envolvidos, como já dito, quem precisa ter é o dono do job, que no caso é o SCOTT.

Então qual privilégio é necessário? Apenas o simples privilégio de que aquele job estará liberado a executar para o usuário que o modificou pela última vez.

No Database Vault, logado como DV Owner, esta autorização pode ser concedida/consultada executando:

SQL> EXEC DVSYS.DBMS_MACADM.AUTHORIZE_SCHEDULER_USER(UNAME => 'OPERUSR', SNAME => 'SCOTT');
 
PL/SQL procedure successfully completed.
 
SQL> col grantee format a30
SQL> col schema format a30
SQL> select * from dvsys.dba_dv_job_auth;
 
GRANTEE                        SCHEMA
------------------------------ ------------------------------
OPERUSR                        SCOTT

Por fim, como pudemos ver neste artigo, um job pode ser mais complexo do que parece. Caso você esteja tendo problemas de privilégio em alguma de suas tarefas agendadas, não esqueça de consultar qual é o papel de cada usuário que está participando e se todos têm os privilégios adequados.

 

Gostou? Não deixe de comentar ou deixar um 👍!

Deixe um comentário

Seu e-mail não será publicado.