So basically I'm building an app for my company and it NEEDS to be built using MS Access and it needs to be built on SQL Server.
I've drawn up most of the plans but am having a hard time figuring out a way to handle the auditing system.
Since it is being used internally only and you won't even be able to touch the db from outside the building we are not using a login system as the program will only be used once a user has already logged in to our internal network via Active Directory. Knowing this, we're using a system to detect automatically the name of the Active Directory user and with their permissions in one of the DB tables, deciding what they can or cannot do.
So the actual audit table will have 3 columns (this design may change but for this question it doesn't matter); who (Active Directory User), when (time of addition/deletion/edit), what (what was changed)
My question is how should I be handling this. Ideally I know I should be using a trigger so that it is impossible for the database to be updated without an audit being logged, however I don't know how I could grab the Active Directory User that way. An alternate would be to code it directly into the Access source so that whenever something changes I run an INSERT statement. Obviously that is flawed because if something happens to Access or the database is touched by something else then it will not log the audit.
Any advice, examples or articles that may help me would be greatly appreciated!
Does this work for you?
select user_name(),suser_sname()
Doh! I forgot to escape my code.
Ok, it's working here. I'm seeing my windows credentials when I update my tables. So, I bet we missed a step. Let me put together a 1,2,3 sequence of what I did and maybe we can track down where this is breaking for you.
Create a new MSAccess database (empty)
Click on the tables section
Select external data
Pick ODBC database
Pick Link to the datasource by creating a linked table
Select Machine datasource
Pick New...
System Datasource
Pick SQL Server from the list and click Next, Finish.
Give the new datasource a name and description, and select (local) for the server. Click Next.
Pick "With Windows NT authentication using the network login ID". Click Next.
Check Change the default database to, and pick the DB. Click Next. Click Finish.
Test the datasource.
Pick the table that the Trigger is associated with and click OK.
Open the table in Access and modify one of the entries (the trigger doesn't fire on Insert, just Update)
Select * from your audit table
If you specify SSPI in your connection string to Sql, I think your Windows credentials are provided.
I tried playing with Access a bit to see if I could find a way for you. I think you can specify a new datasource to your SQL table, and select Windows NT Authentication as your connection type.
Sure :)
There should be a section in Access called "External Data" (I'm running a new version of Access, so the menu choice might be different).
Form this there should be an option to specify an ODBC connection.
I get an option to Link to the datasource by creating a linked table.
I then created a Machine datasource. I selected SqlServer from the drop down list. Then when I click Next, I'm prompted for how I want to authenticate.
CREATE TRIGGER testtrigger1
ON testdatatable
AFTER update
AS
BEGIN
INSERT INTO testtable (datecol,usercol1,usercol2) VALUES (getdate(),user_name(),suser_sname());
END
GO
We also have a database system that is used exclusively within the organisation and use Window NT logins. This function returns the current users login name:
CREATE FUNCTION dbo.UserName() RETURNS varchar(50)
AS
BEGIN
RETURN (SELECT nt_username FROM master.dbo.sysprocesses WHERE spid = ##SPID)
END
You can use this function in your triggers.
It should be
select user name(),suser sname()
replace spaces with underscores
you need to connect with integrated security aka trusted connection see (http://www.connectionstrings.com/?carrier=sqlserver)
How many users of the app will there be? Is there possibility of using windows integrated authentication for SQL authentication?
Updated: If you can give each user a SQL login (windows integrated) then you can pickup the logged on user using the SYSTEM_USER function.
My solution would be not to let Access modify the data with linked tables.
I would only create the UI in Access and create an ADO connection to the server using windows authenticated in the connection string. Compile you Access application as dbe to protect the VB code.
I would not issue SQL statement, but I would call stored procedures to perform the changes in the database, and create the audit log entry in an atomic transaction.
The UI (Access) does not need to know the inner works on the server. All it needs to do is request and update/insert/delete using the stored procedures you would create for this purpose. The server should handle the work.
Retrieve a record set with ADO using a view with the hint NOLOCK implemented in the server and cache this data in Access for local display. Or retrieve a single record and lock only that row for editing.
Using linked tables your users will be locking each other.
With ADO connections you will not have the trouble to set ODBCs on every single client.
Create a table to set the server status. You application will check it before any action. you can use it to close the server to the application in case that you need to perform changes or maintenance.
Access is a great tool. But it should only handle its local data and not be allowed to mess with the precious server.
Related
I have been using DBeaver as a replacement for SQL Server Management Studio, and I am loving it. The only thing I cannot figure out is how to associate a script with a database. For example, in SSMS I can right click a database (let's call it A) in the object explorer and click "New Query" (or ctrl+n) to open a script that is active within database A. If I open another script in a different database (B), that script is associated with the database B. When I switch back to the original script, I am back to working with database A without having to manually select from the database list or executing a USE statement. Obviously, switching back to the second script will make database B active again.
Unfortunately, in DBeaver, there appears to be only one active database for all scripts. Is there a way to set this up in DBeaver to act like SSMS in this manner?
Edit: DBeaver refers to individual databases as catalog/schema. That is what I am trying to associate with individual scripts.
I am using DBeaver community and i have using with multiple DB's. You have to just select Data base from drop down to change DB, it is for current script that open .
i current not have my company system connected , find one sample image from internet .
I don't know that DBeaver has this capability, but you could always Preface your scripts with the USE DBNAME statement...
UPDATE
Version 6.3.1 (2019-12-22) now supports this by default! Here is the first note of the description for 6.3.1:
SQL editor:
Active database/schema change now affects current editor only
Note: This does seem to have changed some behavior such as "Set active" from the database navigator as well as the "Auto-sync xx with navigator." These two used to take affect to the active database/schema. Now they are tied to the current connection.
Original Answer
For anyone who finds this in the future, I did find a work around that provides the desired behavior. The answer is to use projects. Unfortunately, this means creating a duplicate connection to the server.
There is also another catch here. If you want to set a schema for a specific script, you should avoid setting the schema via the "Database Navigator." This will, however, work if you want to change the schema for a script that is already in the active project. If the script is not in the active project, and you set an active schema through the Database Navigator, it will change the active schema for all open scripts associated with that server. To keep it simple, I try to avoid the Database Navigator all together.
All is not lost by avoiding the Database Navigator. By default, the "Projects" window is a tab right next to the Database Navigator. If you expand (click the + next to the name) [Project Name] -> Connections -> [Connection Name], you will have your list of databases/schema right there. Use this as your new Database Navigator and you are all set.
I've been trying for a while to connect the database to visualstudio.net and it just doesn't work.
First I made the database and made everything I needed there and when I tried connecting it in visual.net through datagridview (trying to get it displayed there) it only gives me access to the "System databases" in which I can't make a database.
After that I decided to make the tables under the "master" database to see if that worked and yeah I can select the database and everything but it says it's empty when I know it's not. It says it has no tables when I've checked multiple times and saw the tables I've created there.
I would appreciate some help to either be able to get for visual to accept a database I make (to be able to automatically detect it once I enter the server name) or to see how can I use the master one properly.
You can add a data source to your project and it will be able to connect to the user databases. Also, it is highly inadvisable to create any user objects in the master database.
master database is a system database and you should not create user objects in the system database. In the connection string, provide the user database name explicitly. If you dont provide the database name, it defaults to master database.
Refer to connection strings for Sql Server for providing the right connection string for SQL Server in .net.
I'm using SQL Server 2008 R2, someone is using my database via a macro code in Excel, is there any way to prevent another application (like Excel) to access my database?
If your users are supposed to acces the database (they have login and rights on it) but only with a limited range of software, you have to tell them not to use Excel.
There is a workaround based on an after connect trigger wich check the application_name in session, but its not very effective.
If they do not have to connect directly to the database, you have to delete their logins (or revoke rights) or change password if they shared a common user.
Create a service (e.g.in C#.NET) which will be used to query the database. In programming language like C# you can easily lock the database via "lock" statement.
I am having some trouble creating a new SQL user in SQL Server 2008 R2. When I use SQL Server Management Studio it checks db_owner role membership by default. I just want to create a new sql user with read only access. Even with the following raw SQL it still creates the user with db_owner level permission.
<!-- language: lang-sql -->
CREATE LOGIN readonlyuser
WITH PASSWORD = '12345',CHECK_POLICY = OFF, DEFAULT_DATABASE=mydatabase
GO
USE mydatabase
GO
CREATE USER readonlyuser FOR LOGIN readonlyuser
GO
EXEC sp_addrolemember 'db_datareader', 'readonlyuser'
Now if I log on to SQL Server Management Studio with newly created user I can basically access any table and modify any data any way that I want. This is exactly what I not want to do. I want only to be read data and not to modify any data
Strange thing is if I look at the roles for database the readonlyuser is inside db_datareader and not in db_owner.
So why is SQL creating this user with db_owner level permissions, thus allowing the user to modify data?
Update 2013/08/07
This seems to be happening with just one specific database. I created brand new database and created bunch of tables and then ran the same script above and it is working perfectly fine. But if i try with the actual database where i need this change, it doesn't work like that. It created the user and gave way too much permission.
Is there anything that i can check on that database? Please note that specific database was not designed by me. It is from a 3rd party vendor. So not sure exactly what modifications they might have done.
Any help is greatly appreciated.
I ran into the same issue.
The solution: sp_changedbowner. That fixed it. (Somehow the owner was corrupted)
I don't see any problem in query. And it worked as expected when i tested it. Just for confirmation, verify if user is properly mapped to required database (mydatabase) and db_datareader is selected from user property window.
I found that this happens to me when adding logins to databases that I restored to a new server. In the Files tab of the database's properties, the owner field is blank, even though it lists a user in the General tab. If I populate the owner field with a valid login, then the problem is resolved: new logins don't have "db_owner" checked by default.
To expand on Greg's comment, this probably happens when the restored database was owned on the source server by a login that's not present on the current (the destination) server. The info on the General tab is the original owner (on the source server), which cannot be reflected on the Files tab, since that logion is missing on the current server. In a certain sense this is an "orphaned database" then.
I have been asked to maintain a site created in ASP classic that uses a SQL Server database.
I was given the database in the form of a backup. I restored the database on my local computer and created a DSN connection to it. However when I attempt to load my site, the stored procedures the site relies on give an error that execute permission was denied.
The stored procedures in question have a user named UserSecure showing as the only person with EXECUTE permission, I have tried creating a user by that name but that does not work, even though I can manually login to SQL Server Management Studio using UserSecure trying to connect from the web page using those credentials gives a login failed error.
If I run sp_helplogins my Windows credentials are shown as being owner of the database, and I can in fact execute from within SSMS but not from an ADO connection.
On another note the connection in the webpage was coded like this, I am not familiar with the application part of the connection. Perhaps this is part of the problem? I have tried connecting with a DSN and DSN-less connection and can connect but not do anything with the database?
You should make sure the database server login is mapped to the appropriate database user (this problem crops up often when dealing with database backups). If it is not, then you need to fix the mapping. Fortunately, there is a command called sp_change_users_login that you can use to fix this problem.
First, check if your login is mapped to your database user. Using SQL Server Management Studio (assuming SQL Server 2008), look under Security/Logins for UserSecure. If you see it in the list, double click on it and select User Mapping. From there, locate the database you are trying to connect to, and see if UserSecure is mapped to that database. If it is not, you may be able to fix it using the following command (assuming UserSecure is the name of both the login and the user):
EXEC sp_change_users_login AUTO_FIX, UserSecure
See MSDN for more info on sp_change_users_login:
http://msdn.microsoft.com/en-us/library/ms174378.aspx
One issue that has bitten me a few times:
If your stored procedure (or view) requires permission from a user (let's say userA), and the stored procedure calls another database's table or view (say viewB), it is not sufficient to just make a login on viewB's database, you must also explicitly grant userA permission to select/execute/etc. on viewB (which in turn requires a user on viewB's database)
So in your case, you may need to explicitly grant UserSecure execute permission on a stored procedure on an existing database referenced by the one you restored.
This may not be the most elegent fix, but I quit focusing on the one procedure and instead granted execute permission to the guest user on the entire DB. Since this is only running on my personal machine security is not an issue and it seems to have fixed the problem.
Know the problem all too well,
The ID of the user(name) will be different from the backed up database to the restored one. MSSQL stores the ID of the user and not the username (text), so the ID will be different (99% of the time) per machine and backup. So when the ID does not match you don't have access.
All you need to do is delete the user and recreate it, make sure you do it in both places:
Delete the user from the database first:
DATABASE -> SECURITY -> USERS -> Right click (username) + delete
Then goto
SECURITY -> LOGINS -> Right click (username) + delete
Then recreate the user and give the account the correct permissions and you're all good.