Access control monitoring in Oracle - oracle

Is there any table or log that shows the connection attempts to an oracle database (I don't mean the active sessions, but attempts, even though they've failed or been denied)?
The information I need is the IP from which has been done the attempt, the user used, the executable used (sqlplus, toad, sqldeveloper, java ...), etc.

I guess you need Oracle Listener logging.

You can use a DATABASE TRIGGER, see CREATE TRIGGER
Example:
CREATE OR REPLACE TRIGGER MY_TRIGGER
AFTER LOGON ON DATABASE
DECLARE
BEGIN
INSERT INTO LOG_TABLE
SELECT
USERNAME, OSUSER, MACHINE, PROGRAM, --> columns in V$SESSION
ora_client_ip_address, ora_login_user, ora_sysevent --> Event Attributes from Trigger
FROM V$SESSION
WHERE SID = SYS_CONTEXT('USERENV', 'SID')
COMMIT;
END;
/
Here you see a list of all System-Defined Event Attributes: Coding Triggers
However, as stated this is a AFTER LOGON trigger, so failed attempts due to wrong password are not covered!

Related

Oracle SERIAL# changing for the same SID

I'm using Oracle19c with a thin client and I'd like to set traces on the 5 application connections with
EXEC DBMS_SYSTEM.set_sql_trace_in_session(sid, serial#, true ) so I created a stored procedure.
When I select the SID and SERIAL# with:
select sid, serial#, osuser, machine, program, module, username
from v$session WHERE username IS NOT NULL ORDER BY username ASC;
I noticed that the SERIAL# keeps changing every minute or so, but I don't have any connection timeout set for the user: it's using the DEFAULT profile and LIMIT='UNLIMITED'.
Is there a way to "extend the life" of those connections?
A new serial# is a new session. This probably means the application doing the connecting is diconnecting/reconnecting, possibly by design at regular intervals, or possibly by error and its dropping the connection and recovering by commencing a new one.
But you'll need to look inside the app to see that, not the database.
If you want to trace such an app, you could create a LOGON trigger to turn on trace as soon as they connect, rather than trying to catch it with a query to v$session, eg
create or replace
trigger TRACE_ALL_LOGINS
after logon on MY_DB_ACCOUNT.schema
begin
execute immediate 'alter session set tracefile_identifier = BLAH';
execute immediate 'alter session set events = ''10046 trace name context forever, level 12''';
exception
when others then null;
end;
/
I keep the when-others-then-null in this special case to ensure that if the trigger fails for some reason, we don't block the ability to connect at all.

Oracle 'after create' trigger to grant privileges

I have an 'after create on database' trigger to provide select access on newly created tables within specific schemas to different Oracle roles.
If I execute a create table ... as select statement and then query the new table in the same block of code within TOAD or a different UI I encounter an error, but it works if I run the commands separately:
create table schema1.table1 as select * from schema2.table2 where rownum < 2;
select count(*) from schema1.table1;
If I execute them as one block of code I get:
ORA-01031: insufficient privileges
If I execute them individually, I don't get an error and am able to obtain the correct count.
Sample snippet of AFTER CREATE trigger
CREATE OR REPLACE TRIGGER TGR_DATABASE_AUDIT AFTER
CREATE OR DROP OR ALTER ON Database
DECLARE
vOS_User VARCHAR2(30);
vTerminal VARCHAR2(30);
vMachine VARCHAR2(30);
vSession_User VARCHAR2(30);
vSession_Id INTEGER;
l_jobno NUMBER;
BEGIN
SELECT sys_context('USERENV', 'SESSIONID'),
sys_context('USERENV', 'OS_USER'),
sys_context('USERENV', 'TERMINAL'),
sys_context('USERENV', 'HOST'),
sys_context('USERENV', 'SESSION_USER')
INTO vSession_Id,
vOS_User,
vTerminal,
vMachine,
vSession_User
FROM Dual;
insert into schema3.event_table VALUES (vSession_Id, SYSDATE,
vSession_User, vOS_User, vMachine, vTerminal, ora_sysevent,
ora_dict_obj_type,ora_dict_obj_owner,ora_dict_obj_name);
IF ora_sysevent = 'CREATE' THEN
IF (ora_dict_obj_owner = 'SCHEMA1') THEN
IF DICTIONARY_OBJ_TYPE = 'TABLE' THEN
dbms_job.submit(l_jobno,'sys.execute_app_ddl(''GRANT SELECT
ON '||ora_dict_obj_owner||'.'||ora_dict_obj_name||' TO
Role1,Role2'');');
END IF;
END IF;
END IF;
END;
Jobs are asynchronous. Your code is not.
Ignoring for the moment the fact that if you're dynamically granting privileges that something in the world is creating new tables live in production without going through a change control process (at which point a human reviewer would ensure that appropriate grants were included) which implies that you have a much bigger problem...
When you run the CREATE TABLE statement, the trigger fires and a job is scheduled to run. That job runs in a separate session and can't start until your CREATE TABLE statement issues its final implicit commit and returns control to the first session. Best case, that job runs a second or two after the CREATE TABLE statement completes. But it could be longer depending on how many background jobs are allowed to run simultaneously, what other jobs are running, how busy Oracle is, etc.
The simplest approach would be to add a dbms_lock.sleep call between the CREATE TABLE and the SELECT that waits a reasonable amount of time to give the background job time to run. That's trivial to code (and useful to validate that this is, in fact, the only problem you have) but it's not foolproof. Even if you put in a delay that's "long enough" for testing, you might encounter a longer delay in the future. The more complicated approach would be to query dba_jobs, look to see if there is a job there related to the table you just created, and sleep if there is in a loop.

Oracle kill inactive sessions stored procedure

I would like to write kill_inactive sessions stored procedure for Oracle.
something like
create or replace procedure kill_inactive_sessions as
begin
for rec in (select sid, serial# from sys.v_$session where status = 'INACTIVE')
loop
execute immediate 'alter system kill session '''|| rec.sid || ',' || rec.serial# || ''' IMMEDIATE';
end loop;
end kill_inactive_sessions;
Previous doesn't work (table or view does not exists).
But next select is working perfectly for the same user:
select sid, serial# from sys.v_$session where status = 'INACTIVE';
What I'm missing?
The ORA-00942: table or view does not exist error almost certainly indicates that your access to the v$session view is via a role rather than a direct grant.
If you want to write a definer's rights stored procedure, the owner of the procedure must have the necessary privileges granted directly to the user, not via a role (and remember that DBA is just another role). Most likely, if you disabled roles in your session, the SELECT statement outside of the procedure would not work. In SQL*Plus, for example
SQL> set role none;
SQL> select sid, serial# from sys.v_$session where status = 'INACTIVE';
will likely throw the same ORA-00942 error. Assuming it does, you need to grant the user that owns the stored procedure privileges directly. For example
GRANT SELECT ANY DICTIONARY
TO user_that_owns_the_procedure;
The same thing will also apply to the ALTER SYSTEM command that you are building and running. The owner of the stored procedure will need to have privileges to run that command via a direct grant not via a role.
All that said, a procedure that kills all inactive sessions is highly problematic. The vast majority of sessions are going to be inactive the vast majority of the time. That doesn't mean that they should be killed. Even if you're cleaning up after an application server crash, you really ought to be applying some additional predicates (for example, looking for sessions from a particular machine that are logged in as a particular user that were established before the application server crashed). Long-term, though, I'd suggest enabling dead connection detection so that the database can automatically take care of closing sessions when the client process dies unexpectedly.

In oracle, can I associate a default Schema with my USER ID where SCHEMA <> USERID?

I would like to connect to an Oracle database with UserId "MY_SCHEMA" and then be able to perform queries where the table name was not qualified with the schema name:
SELECT * FROM TABLE1
When executing SQL, I would like my unqualified queries to go against a different schema other than my own. In other words, I would like this to be equivalent to
SELECT * FROM SCHEMA_OTHER.TABLE1
instead of
SELECT * FROM MY_SCHEMA.TABLE1
I know it seems a little weird and so I expect that this is not possible.
I do not have any sort of admin rights to the database to see if I can associate a default schema with a login.
After you login, you can run the following:
ALTER SESSION SET CURRENT_SCHEMA=schema_other;
If you really want this to happen automatically, you can create a system trigger for the logon action that looks for your username and uses execute immediate to run the alter session command:
CREATE OR REPLACE TRIGGER my_schema_logon
AFTER LOGON
ON DATABASE
BEGIN
IF SYS_CONTEXT ('USERENV', 'CURRENT_USER') = 'MY_SCHEMA' THEN
EXECUTE IMMEDIATE 'ALTER SESSION SET CURRENT_SCHEMA=schema_other';
END IF;
END my_schema_logon;
/

Calling a function on a remote database requires commit. SQL Developer

I have a requirement to call a function on a remote database (defined by a public database link) within a query. Everything works as expected except that when selecting "Disconnect" from the local database connection in SQL Developer it brings up the dialog:
Connection "localDB" has uncommited changes....
even though the remote function only reads from tables, and the invoking query isn't an update / insert / delete. I'm concerned that using this architecture may cause problems in the future where uncompleted transactions on the localDB diminish resources.
Have tried using the "PRAGMA AUTONOMOUS_TRANSACTION;" instruction in the remote db but to no avail. Any suggestions?
The following demonstrates the behaviour I'm experiencing:
RemoteDB function:
create or replace
FUNCTION FN_test (inempid in number) RETURN varchar2 is PRAGMA AUTONOMOUS_TRANSACTION;
sReturn varchar2(20);
BEGIN
sReturn:=to_char(sysdate,'dd-Mon-yyyy HH24:mi');
return sReturn;
END FN_test;
Invoke from localDB:
select fn_test#RemoteDB.World(123) from Dual;
Thanks!
Any remote call opens transaction - even this executes just query. Oracle can't predict what exactly you do on remote side and tries to prevent uncommitted distributed transaction.
In example below I mere created local database link connecting to native host and just requested data from DUAL table using db link. Oracle has opened the local transaction in respond:
SQL> create database link locallink connect to scott identified by tiger
2 using '127.0.0.1:1521/test';
Database link created.
SQL> select dbms_transaction.local_transaction_id from dual;
LOCAL_TRANSACTION_ID
--------------------------------------------------------------------------------
SQL> select * from dual#locallink;
D
-
X
SQL> select dbms_transaction.local_transaction_id from dual;
LOCAL_TRANSACTION_ID
--------------------------------------------------------------------------------
17.13.10520
Autonomous transaction is useless because it opens and closes the transaction what is differ from the main one. So you need to commit changes in main transaction if you use remote calls.

Resources