Is it possible to have SQL Server create a temp table inside a particular database upon a user connecting to the database in such a way that the connecting user is the only one with access to the contents in this table (or even better, the connecting user is the only one that can even see the table)?
I tried using a logon trigger (including using a 'with execute as caller' clause) but although this creates the temp table, the connecting user can never see it/select from it.
All of this has to run inside SQL Server and require no user interaction at all...
Basically, this is the scenario I want to support:
user connects
a temp table is created inside a particular DB inside SQL (by SQL, kicked off by establishing of the connection)
some specific information is populated inside the table
for the duration of the connection; the user has (Read) access to the contents in this table; the information in this table is used by a sub-system inside a particular database
user disconnects
the temp table and all its contents is dropped by SQL
Thanks
First thoughts:
modify your client code to create the table on connection? Then it can be done only when needed not all the time
use a common, persisted table with a SessionID based on a GUID? This will provide some audit + troubleshooting information too
use table value parameters to send data on demand rather than have any server-side caching
And what I'd probably do:
create the table when it's populated when I need it. The user can connect to the database for a variety of reasons (I assume). So "connection" should be decoupled from "CREATE TABLE".
Using temp tables for this would not be the right approach if your data access is properly designed to open a connection-do an operation/query-close the connection. The moment you closed the connection, the temp table would be destroyed. It would be better to use a view or stored procedure to filter the information to which the user should have access. The structure of that view will depend greatly on how users connect to the database. Do users connect to the database using their own personal windows authentication account or do they connect indirectly through another account like many web servers do?
IMO, the better approach is the second bullet point of gbn's answer: a common persisted table with an indicator as to the session or user.
Related
I am not sure what the correct forum is for a question like this, so if it would go better on a different one could you move it there please?
I have split my database into a front and back-end database. The front end is using linked tables which are linked to the back-end real tables. If a user changes something in a table on the front-end database, the changes are carried over to the backend database.
Why is this and how can I prevent this from happening? Is there a way to change the settings to make the database read only? Whether it's through VBA or not, I would accept either answer.
That's a feature, not a bug. You're using a linked table, it's linked.
If you want a separate table, make a separate table, and make some ETL (extract/transform/load) process to keep the two tables in sync as needed, accordingly with whatever business rules you need to implement.
If your Access DB is connecting to SQL Server via SQL authentication, you could have the SQL user on the SQL Server side only authorized to SELECT, and denied UPDATE, DELETE and INSERT permissions. Expect errors on the Access side when the linked table is modified then.
I'm a little lost and need some guidance on how to approach this feature I'd like to add.
Many operations I use require retrieving data from a remote server. My goal is to be able to receive an email notification if new data has been added to the remote server.
I thought about creating a stored procedure that uses "openquery" and compare data to a local table with a conditional statement that will send out an email if there are differences. Then scheduling a job that will execute this stored procedure frequently. But this does not feel elegant at all...
If I understood your question correctly, all depends on the permissions.
If I was the owner of the system
Find out which job is adding data to the system. Modify the process (ETL/ SQL job etc.) to send you an email. (best way)
If you have create permissions on the remote system
Create an after insert trigger, see the first example here. Refer to this link as well. (2nd best way)
If you have just permissions to create linked server
Whatever you wrote/ you can bring the data from the server (just the primary keys from the table) and keep on checking that by creating a job for new primary keys if any by copying the data to local.
How to choose between these two: depends on the size of data. Second method mentioned in point 3 will work even without a linked server.
But you will have to run this again and again, I can't think of any other way. Set up a SQL job/ ETL to do this for you.
I have a web application which currently only supports PostgreSQL as a backend and has it's own user management. Connection to the database is done using a generic user account using Postgres auth mechanisms. This application should now get a audit log for some created and changed data hopefully based on triggers and stored procedures only and for performance reasons it would be nice if everything works async and independent from the web application.
There is one main problem: We want to know which user of the web application made some changes or created data, but this piece of information is normally not available in stored procedures out of the box because we connect to Postgres using a generic account. What I would like to avoid doing is calling the stored procedures in the web application and provide user ids that way, as this would mean to add the relevant calls in may places in the web application. Besides that we make updates to the data model directly using the database without the web application, meaning we would need the triggers in any case.
Currently the web application is working with a transaction started on every request and committed on its end. Therefore I though of creating a temporary table within the transaction in every request which always gets the current user id of the request which should be available for the stored procedures executed by the triggers on created or changed data.
Some things I don't know are if the stored procedures executed can even access the current transaction of the database and therefore are able to retrieve the current user id from the temporary table? The table is not part of the changed data the trigger was created for. How would performance be affected if each request creates a temporary table to store just one Integer in the worst case? If the trigger is able to access the temporary table, the request may finish at any time because it's work is done or of errors. How would that affect a trigger which would have access to the temporary table which only exits within the transaction which gets committed or reverted as the stored procedures want to read the user id?
Is there any other way with which I can map a user id to some unique identifier of a transaction which the trigger has access to? Besides a temporary table, I could create a normal table in which I map user ids to transaction ids on start of every request but independent of the current transaction. If the trigger would now get the transaction id which was responsible for executing the trigger the stored procedures could use the transaction id to look up the user id which used the transaction.
Any thoughts? Thanks!
I've added a question about trigger lifetime and execution context which fits to this question:
execution context of database trigger in PostgreSQL
A temporary table seems overkill when you could just use a session setting.
Up to version 9.1, custom session variables needed to be declared in postgresql.conf through the
custom_variable_classes parameter, which made it a bit cumbersome, deployment-wise.
Since 9.2, it's no longer necessary. So you could just issue at connect time:
SET myapp.myusername='foobar';
and then in a trigger or in fact anywhere within the session, SELECT current_setting('myapp.myusername'), or SHOW myapp.myusername would get back the value.
my question is rather simple.
Can i grant permissions on a database table wise? something in the lines:
User Management has permission to select, update, insert and delete on table Projects
User Supervisor has permission to select, update, insert on table Projects
User Colaborator has permission to select on table Projects
If so, I could set up a system to create database users based on the levels of access of my application, much like the examples above.
Is it a valid mechanism to use this to secure a application?
is it worth on a real world application?
i've used PHP with Oracle and MySQL, but I'm look for a database/language agnostic answer, but any example would be useful.
pushing my luck a bit, what about per record permission granting?
also, what about table schemas, are they a more acceptable then table based permissions?
The main problem with using database security would be that you need separate connections for each user rather than being able to use a "service user" for the connection from your application server to your DB server. That would mean that you would no longer be able to use database connection pooling have to "connect" and "disconnect" from the database for every user request, which is not very efficient as connections are relatively expensive.
Having said that, there is good reason for using separate users in the database, such as DATA_USER (which the application server connects as) and DATA_OWNER (which owns all the tables but is used only for DB maintenance) and then only give DATA_USER the permissions that it needs to, e.g. only select on a lookup table. By separating DATA_USER and DATA_OWNER you can add an additional level of confidence that your application won't issue DDL commands (e.g. dropping a table).
Answer to part 1:
Yes as long as you handle the responses correctly.
Part 2:
It's not as good as implementating security in the application layer, as most applications will need flexibility in the solution (what if you want a user to get increased privledges, have to code in lots of alter/deny/grant scripts)
Part 3: (Speaking from purely MSSQL) Row-level permissions aren't possible. Create custom views for this purpose.
I'm not sure how to formulate that question but:
you have a webpage
the webpage got a specific user/pass in the web.config for the connection string
on a webpage you ask for a user/pass that is connected to a table (id, name, pass)
the user is recognized with a valid user/pass and now you know the id from the table above
the user change some data in a table and that table got a trigger
from that trigger, how to retrieve the user id from step 4
Let's say the user is logged using the asp.net membership table
Use SET CONTEXT_INFO and CONTEXT_INFO() to pass out-of-band parameters. Your Web layer must ensure it sets this correctly on each connection it uses prior to calling into the database, which means one extra additional round-trip to the database.
In step 4, when you say that YOU know it, what you really mean is that your application knows what user id is logged in. Your application's authentication is completely separate from your database authentication (excepting maybe using windows authentication with SQL server, but I don't think that's what you're doing).
As KM mentions, you would need to pass the application user id to the trigger by means of a "LastUpdatedUserID" column or some such thing on the table being updated.
#KM, or move your users into AD and use integrated auth. No other option here.
you need to have a LastChgID column (or similar) on the table they are changing based on the web page user/password, then INSERTED.LastChgID will tell you. otherwise, you are out of luck.
EDIT
When you save the change, store the web apps user ID into the table's LastChgID column, this may require passing it into the stored procedure, or just SET that column in the UPDATE statement. When the trigger fires, INSERTED.LastChgID will have the web apps user ID.
Since the username is just data it is tough to capture via a trigger.
Option #1 is similar to what KM said and your developer would have to pass the username via a query and update an audit column in the database. and the trigger would grab that column vlue on updates and do what ever you want with it.
Option #2 would be to programatically create the user in SQL server or your windows domain structure, give it access to the application and then impersonate that user upon entry for subsequent logins. This would be an administrative maintenance issue, but the application users would then access the database using their unique ID instead of the one configured in web.config and all updates to the database are as that user instead of the generic one supplied in web.config.
Hope this helps.
As has already been suggested (by Remus Rusanu) using the SET CONTEXT_INFO for this means you don't have to add parameters on all your stored procs to do this. A similar question from myself can be found here:
SQL Server: Modifying the "Application Name" property for auditing purposes