Probier mal folgendes:
Ausgangssituation:
- default User --> sys, system, usw.
- 2 User --> Krei_Owner und Krei_User
- Krei_Owner besitzt eine Tabelle "t_log"
--> t_log-Aufbau
GRANTED_TO_USER (VARCHAR2(4000))
OWNER (VARCHAR2(4000))
OBJECT_NAME (VARCHAR2(4000))
OBJECT_TYPE (VARCHAR2(4000))
DATUM (DATE)
Ich habe mit dem User "sys" einen Trigger angelegt, welcher vor dem Grant durchlaufen wird:
*******************************************************************
* Before Trigger
*******************************************************************
CREATE OR REPLACE TRIGGER grant_test
BEFORE GRANT ON DATABASE
DECLARE
user_list ora_name_list_t;
BEGIN
FOR i IN 1 .. ora_grantee(user_list)
LOOP
IF ora_dict_obj_type = 'ROLE PRIVILEGE' THEN
INSERT INTO Krei_owner.t_log
VALUES(user_list(i), 'ROLE PRIVILEGE', '', 'ROLE', SYSDATE);
ELSE
INSERT INTO Krei_owner.t_log
VALUES(user_list(i), ora_dict_obj_owner, ora_dict_obj_name, (SELECT object_type
FROM all_objects
WHERE owner = ora_dict_obj_owner
AND object_name = ora_dict_obj_name), SYSDATE);
END IF;
END LOOP;
END;
Hierbei ist zu beachten, dass der Trigger zuerst abfragt, ob es sich um einen Grant für eine Rolle handelt.
Wenn ja, fügt er in die Tabelle "t_log" nur den "granted_to_user" ein, beim "Object_Owner" trägt er 'ROLE PRIVILEGE' ein, das Feld "Object_Name" lässt er leer, "Objekt_Type" wird 'ROLE' eingetragen und im Feld "DATUM" das aktuelle Datum mit Uhrzeit.
Wenn es kein Grant für eine Rolle ist, trägt er alle Daten in die Felder ein, inklusive Object_Name, da der Trigger diesen Namen dann hat, wenn es ein Objekt ist.
Dann habe ich noch einen AFTER TRIGGER geschrieben (ebenfalls unter dem User "sys"), der nach dem GRANT durchlaufen wird:
*******************************************************************
* After Trigger
*******************************************************************
CREATE OR REPLACE TRIGGER grant_test2
AFTER GRANT ON DATABASE
DECLARE
user_list ora_name_list_t;
BEGIN
FOR i IN 1 .. ora_grantee(user_list)
LOOP
UPDATE Krei_owner.t_log t
SET t.object_name = (SELECT granted_role
FROM dba_role_privs
WHERE grantee = user_list(i)
AND granted_role NOT IN (SELECT object_name
FROM Krei_owner.t_log
WHERE grantee = granted_to_user
AND object_name IS NOT NULL))
WHERE granted_to_user = user_list(i)
AND object_name IS NULL;
END LOOP;
END;
Hierbei ist zu beachten, dass der Trigger sich die Tabelle "t_log" ansieht gefiltert durch den granted_to_user und wo objekt_name NULL ist. Denn dadurch bekommen wir den Datensatz des zugeordneten Users, aus der Liste, der angelegt wurde bei einem GRANT auf eine Rolle (Denn bei einem Grant auf eine Rolle ist das Feld Objekt_Name nicht ausgefüllt worden).
Er editiert den Datensatz und fügt die Rolle hinzu, welche noch nicht unter dem User in der Tabelle "t_log" vorhanden ist (Vergleich mit "dba_role_privs").
Wenn ein Grant auf ein Objekt durchgeführt wurde, findet er keinen Datensatz mit leerem Feld "Objekt_name" und brauch somit keinen Datensatz zu editieren.
Vorsicht: Es dürfen vorher keine Rechte auf Rollen vergeben worden sein. denn ansonsten fliegt der AFTER TRIGGER auf die Nase.
Eine Absicherung müsste noch eingebaut werden. Hatte aber keine Zeit mehr. Sorry.
Ich hoffe, dass diese Lösung dir ein wenig weiterhilft. Sie ist zwar bestimmt nicht das Optimum, aber fürs erste reicht, denke ich.
mfg
schawenn