I got a task from my customer on his existing SQL Server database.
They have a database with 1 user with all admin rights. They manage the accessibility rights on the application level.
The task is to create an audit table, to audit who INSERT, UPDATE, & DELETE from database tables.
The structure of this table is simple:
TableName
Operation {INSERT, UPDATE, or DELETE}
TimeStamp,
UserName
The audit log is requested to be on server side through triggers.
So it is an EASY Task: Add Trigger to each table & each Event. Inside the trigger, insert a new row to Audit Table with Values of (TableName, Operation, TimeStamp, & UserName).
The problem is the username (SQL: SYSTEM_USER) is always the same for all users as they all connect with the same admin account.
Is there anyway, in SQL server, to get the network user name who is making the transaction?
I am sorry I should have made some researches before asking. Anyway, it could be useful to others.
I found this function [Host_Name()], which returns the name of the computer that makes the transaction.
Related
I have a user that cannot update stored procedures because he gets an error that an INSERT cannot be done on one of our changelog tables. We checked his permissions to insert on that table and he has it, so we were confused as to why he couldn't insert. When we dug deep into this, it looks like we gave him the explicit permission to insert into the table, but for some reason he does not list INSERT as an effective permission. Our layout is server -> database -> table (pretty simple setup).
Note - for some reason when writing this question, it kept interpreting my inserted pictures as code and wouldn't let me post with embedded pics, so I had to use links instead.
Explicit server permissions:
ALTER ANY DATABASE
CONNECT SQL
CREATE ANY DATABASE
Effective server permissions:
ALTER ANY DATABASE
CONNECT SQL
CREATE ANY DATABASE
VIEW ANY DATABASE
VIEW ANY DEFINITION
Explicit database permissions:
ALTER
CONNECT
CREATE TABLE
DELETE
INSERT
SELECT
SHOW PLAN
UPDATE
VIEW DEFINITION
Effective database permissions:
Explicit table permissions:
ALTER
CONTROL
DELETE
INSERT
REFERENCES
SELECT
TAKE OWNERSHIP
UPDATE
VIEW CHANGE TRACKING
VIEW DEFINITION
Effective table permissions:
I would like to somehow protect databases on my SQL Server from being deleted without entering a password, even by someone with administrative access. There are times where a database has been deleted accidentally (for example, when two databases have similar names) and I'd like to prevent this from being an easy mistake to make.
I'm also open to any suggestions or alternative ideas on how to handle this. Thank you!
Create a Server Level Trigger that Rolls back any attempt to delete a database.
The Trigger will need to be disabled then re-enabled to perform any legitimate deletions.
USE [master]
GO
CREATE TRIGGER [Trig_Prevent_Drop_Database] ON ALL SERVER
FOR DROP_DATABASE
AS
RAISERROR('Dropping of databases has been disabled on this server.', 16,1);
ROLLBACK;
GO
DISABLE TRIGGER [Trig_Prevent_Drop_Database] ON ALL SERVER
GO
Or as a process:
Create a single-column, one row table in Master that will hold a database name.
Insert the name of the database in the Table.
Add an If statement to the trigger to check if the Database being dropped is identical to the Database in the table created in step 1. Otherwise Roll-back.
In this case you wouldn't need to disable the Trigger. But you're creating 2 points in the process where you define the database name.
Capturing the Database Name in a Server Level Trigger should be possible with:
SELECT CAST(eventdata().query('/EVENT_INSTANCE/DatabaseName[1]/text()') as NVarchar(128))
A database user was unexpectedly removed, I would like to know the details of the operation that caused it. It did not have audit enable at that point.
I tried querying sys.event_log_ex without success. What table/view would contain that information?
SELECT TOP (1000) [database_name]
,[start_time]
,[end_time]
,[event_category]
,[event_type]
,[event_subtype]
,[event_subtype_desc]
,[severity]
,[event_count]
,[description]
,[additional_data]
FROM [sys].[event_log_ex]
where [database_name] like 'DbInstance-2338'
The user is a "database-contained" user, i.e., its credentials allows connecting to the database only.
Based on my test, it seems the only method to retrieve such info is using audit. If you don't have audit at that moment, i'm afraid it's not possible to find the details anymore.
I have an MS Access 2003 mdb and mdw which is connected to a SQL server backend. The tables are linked using a system DSN. I have a trigger on a SQL back end table which inserts a record into another back end audit table on insert, update, and delete. This all works well, but the trigger is using system_user to get the person making the record change, and the table is just recording the username the DSN is setup to use when that change is made in the linked Access table. If the DSN is set to use the generic sql username 'foo' and the MDW is using the user specific name 'bar', the audit table on the backend if recording all changes by all users as the user 'foo'. The users are logging in to the mdb with an mdw file, and I'd like to record the username from the mdw in the SQL backend. Is this at all possible?
From Access VBA you can use the CurrentUser() function to return the MDW user name. You need to find a way to tell SQL Server about that name. If you're building and submitting the DML statements from Access, you could add the CurrentUser value as a field expression.
I'm curious about using both Access user level security and SQL Server authentication. At first blush it sounds like a "belt and suspenders" approach ... except that SQL Server can be a very effective belt, while Access user level security is a comparatively ineffective set of suspenders. I would question what benefit ULS adds to your application.
Consider discarding ULS and switching to Windows Authentication for SQL server. That could be a simpler, cleaner, and more secure approach.
I bet ##spid in the trigger works because it is executed by the process doing the DML.
Just be aware that this may not always be reliable because sometimes Access opens additional connections without having any way of running your special code to log the user against the spid in use.
Update
Have you considered using the CONTEXT_INFO variable that is specific to each SQL Server session?
DECLARE #Info varbinary(30)
SET #Info = Convert(varbinary(30), 'My Username')
SET CONTEXT_INFO #Info
SELECT Left(Convert(varchar(30), CONTEXT_INFO()), CharIndex(0x0, CONTEXT_INFO()) - 1)
This may mean hitting a table behind the scenes anyway, but it's surely going to be faster than doing it yourself.
"I'll use an Access ADP" I said, "it's only a tiny project and I've got better things to do", I said, "I can build an interface really quickly in Access" I said.
</sarcasm>
Sorry for the rant, but it's Friday, I have a date in just under two hours, and I'm here late because this just isn't working - so, in despair, I turn to SO for help.
Access ADP front-end, linked to a SQL Server 2008 database
Using a SQL Server account to log into the database (for testing); this account is a member of the role, "Api"; this role has SELECT, EXECUTE, INSERT, UPDATE, DELETE access to the "Api" schema
The "Api" schema is owned by "dbo"
All tables have a corresponding view in the Api schema: e.g. dbo.Customer --> Api.Customers
The rationale is that users don't have direct table access, but can deal with views as if they were tables
I can log into SQL using my test login, and it works fine: no access to the tables, but I can select, insert, update and delete from the Api views.
In Access, I see the views, I can open them, but whenever I try to insert or update, I get the following error:
The SELECT permission was denied on the object '[Table name which the view is using]', database '[database name]', schema 'dbo'
Crazy as it sounds, Access seems to be trying to access the underlying table rather than the view.
Any ideas?
Could it be because of this: "To update a partitioned view, the user must have INSERT, UPDATE, and DELETE permissions on the member tables."
http://msdn.microsoft.com/en-us/library/ms187956.aspx