Skip to main content

ORA-01031: insufficient privileges

1765815540962

Si trabajas con Oracle desde hace tiempo, es muy probable que hayas visto este escenario:

  • Desde SQL, una operación funciona.
  • Desde un bloque PL/SQL anónimo, también.
  • Desde un procedimiento almacenado… ORA-01031: insufficient privileges.

La forma de resolverlo habitual suele ser (además de la queja al DBA) revisar grants, añadir permisos directamente, probar con otro rol, volver a probar. Incluso solicitar el rol DBA. Y, aun así, el error persiste.

Este artículo no pretende ofrecer una solución rápida, sino explicar por qué este problema sigue existiendo hoy, incluso en versiones actuales como Oracle AI Database 23ai / 26ai, y por qué no es un fallo puntual, sino una consecuencia directa del modelo de herencia de privilegios de Oracle.

El modelo básico de herencia de privilegios desde Definer’s Rights

En Oracle, el modelo básico es conocido:

  • Un privilegio define algo que un usuario puede hacer.
  • Un rol es un conjunto de privilegios.
  • Los privilegios se conceden con GRANT y se revocan con REVOKE.

En ejecución interactiva (SQL), este modelo funciona de forma bastante intuitiva pero el problema aparece cuando entramos en PL/SQL almacenado.

Para empezar, hay que entender que las unidades de PL/SQL almacenadas (procedimientos, funciones, paquetes… incluso vistas) se ejecutan desde el contexto de derechos del usuario creador. Es decir, «Definer’s Rights».

Para ello, en el momento de la ejecución (importante) esto implica que:

  • Oracle cambia el contexto de ejecución al propietario del objeto.
  • Los roles quedan deshabilitados (excepto PUBLIC).
  • Solo se consideran privilegios concedidos directamente al propietario.

Este comportamiento está perfectamente documentado y es consistente a lo largo de todas las versiones desde hace décadas.

El resultado práctico es que un privilegio que se resuelve correctamente desde desde SQL a través de un rol puede no existir a ojos de un procedimiento almacenado.

Y aquí es dónde aparece la primera incoherencia aparente.

Un bloque PL/SQL anónimo se ejecuta en el contexto de la sesión y utiliza los roles activos del usuario. Es decir, no cambia el contexto de identidad aunque se trate de PL/SQL. Los desarrolladores en este punto ejecutan en un bloque anónimo, no encuentran errores, crean el procedure, y al ejecutarlo éste falla, solicitan el rol DBA, y aun con ese rol concedido les sigue fallando mientras que el bloque anónimo les funciona siempre.

Y lo más importante, sin que haya cambiado ni el usuario ni la sesión. Es decir, ejecutan el procedure con el mismo usuario que lo han creado, y sobre el mismo código que ejecutan desde SQL y desde un bloque anónimo sin problemas.

Para muestra el siguiente ejemplo, ejecutado en una Oracle26AI Database.

Nota: El usuario DESARROLLO tiene únicamente CONNECT, RESOURCE, UNLIMITED TABLESPACE y CREATE MATERIALIZED VIEW

  SQL> create materialized view test as select * from dual;
  
  Materialized view created.
  
  SQL> drop materialized view test;
  
  Materialized view dropped.
  
  SQL> begin
    2     execute immediate 'create materialized view test as select * from dual';    
    3  end; 
    4  /
  
  PL/SQL procedure successfully completed.
  
  SQL> drop materialized view test;
  
  Materialized view dropped.
  
  SQL> create procedure crea_mv_test as
    2  begin
    3     execute immediate 'create materialized view test as select * from dual';   
    4  end;
    5  /
  
  Procedure created.
  
  SQL> exec crea_mv_test
  BEGIN crea_mv_test; END;
  
  *
  ERROR at line 1:
  ORA-01031: insufficient privileges
  ORA-06512: at "DESARROLLO.CREA_MV_TEST", line 3
  ORA-06512: at line 1
  Help: https://docs.oracle.com/error-help/db/ora-01031/
  

El motivo no está en la vista materializada en sí, sino en los privilegios implícitos que Oracle necesita internamente (como CREATE TABLE) y en cómo evalúa su procedencia.

Este es uno de los casos más habituales… y más frustrantes. De hecho, lo he visto tantas veces que fue motivo de escribir un artículo que publiqué en el año 2012 en Experts Exchange.

Aquí lo tienes:

https://www.experts-exchange.com/articles/9749/The-strange-case-of-the-insufficient-privileges-error-when-creating-a-materialized-view-using-execute-immediate-inside-a-PL-SQL-procedure.html

A lo largo de los años, Oracle ha ido introduciendo mecanismos para sortear estas limitaciones.

  • AUTHID CURRENT USER para ejecutar código con privilegios del invocador (es decir, del usuario que ejecuta el procedure).
  • BEQUEATH CURRENT_USER para evitar que las vistas actúen como frontera de seguridad ya que siempre se ejecutan desde el modelo de «Definer’s Rights».
  • Privilegios como INHERIT PRIVILEGES para controlar la herencia entre esquemas, sobre todo al acceder a bases de datos remotas a través de DBLinks.

Siempre teniendo en cuenta que estos mecanismos no sustituyen el modelo original, existente desde los orígenes de PL/SQL.

Son un workaround al comportamiento esperado.

¿Estamos ante un cambio de paradigma?

Quizás por este motivo, en la última versión de Oracle AI Database 23ai / 26ai, asistimos a un elemento nuevo: El rol DB_DEVELOPER_ROLE.

Este rol introduce un nuevo comportamiento que rompe muchas de las explicaciones clásicas y operaciones que antes fallaban en procedimientos almacenados por usar los privilegios del creador, ahora funcionan sin cambiar una sola línea del código.

Esto es importante porque Oracle no ha anunciado un rediseño del modelo de seguridad, pero el comportamiento observado indica que algo ha cambiado en cómo ciertos privilegios son evaluados en contextos PL/SQL.

Cuidado, estamos hablando de una excepción (al menos, la primera que se da a conocer).

Sigue sin ser una ruptura del modelo antiguo… pero de algún modo supone un «abrir la puerta» a un nuevo contexto de herencia que seguro implica una convivencia incómoda entre modelos, el existente durante décadas y el demandado por los DBAs y programadores. El resultado es un sistema potente, pero difícil de razonar sin entender identidad, contexto y herencia como piezas separadas.

Y la pregunta inevitable: Si Oracle ha introducido mecanismos que hacen la vida mucho más fácil en desarrollo…

¿cómo se traslada todo esto a producción sin romper el principio de mínimo privilegio?

Esta pregunta es crítica, porque ha solucionado esta casuística en el lado del programador, pero no tiene una traducción directa a los sistemas de seguridad necesarios para trasladarlo a entornos productivos.

La respuesta, obviamente, no está en la documentación oficial.

En ella no se menciona este cambio de comportamiento del rol DB_DEVELOPER_ROLE frente a cómo se comportan los roles clásicos, ni se puede llegar a una comprensión real del problema únicamente leyendo documentación o ejecutando fragmentos de código de forma aislada.

Conclusión

El error de insufficient privileges en PL/SQL no es un accidente ni un descuido.

Es el síntoma visible de un modelo de herencia de privilegios que, desde su concepción inicial, se diseñó bajo una aproximación que parecía segura y consistente, pero que en la práctica ha requerido múltiples correcciones, extensiones y mecanismos auxiliares para cubrir sus limitaciones.

Prueba de ello son la constante insistencia en la recomendación de aplicar el principio de mínimo privilegio —difícil de materializar de forma limpia en este modelo— y la necesidad de proporcionar herramientas adicionales para auditoría y captura efectiva de privilegios.

En definitiva, estamos ante un modelo que ha evolucionado por acumulación y no por rediseño, lo que explica muchas de las incoherencias y comportamientos inesperados que siguen apareciendo hoy en día, incluso en versiones recientes de Oracle.

En resumen, un modelo evolucionado por acumulación y no por rediseño.

En los próximos días realizaré una Café Database Session abierta, en formato laboratorio, donde recorreremos estos escenarios paso a paso, ejecutando el código y analizando el comportamiento real del motor en tiempo real.

Si quieres asistir y ver todo esto con calma, podrás apuntarte en el enlace que compartiré próximamente.