We have SQLserver2008 and the error log is filling up with these lines:
Login failed for user 'user1'. Reason: Failed to open the explicitly specified database. [CLIENT: xxx.xxx.xx.xxx]
We use user1 many places on many web-applications (classic asp). There must be some faulty password somewhere. All the applications seem to be working fine. We are getting hundreds of those messages per day.
We do know the ip-of source computer but there are thousands of classic asp-scripts. How to trace the one causing the login errors?
Your error does not indicate a password error. It instead indicates that the SQL login specifies a database that the login should open, or the connection string specifies a database to open.
However, the database you're trying to open either does not exist, or the login has no permission to access the database.
Suggested Diagnosis Procedure
Can you open 'user1' in management studio by right clicking it and viewing its properties? If so, on the General page, see if there is a default database specified. Then on the User Mapping page, ensure that the login has permissions to said database.
If it does, then the connection string specifies a database to open, and User1 has no permissions or the database does not exist.
To test if the database exists without checking each and every database, you could go one-by-one through the database and give user1 db_datareader permissions until the errors stop. Please don't simply assign user1 a sysadmin role to test this, since that is a real security danger.
If you cannot make the errors disappear by giving db_datareader permissions to other user databases, then the connection string is trying to open a non-existent database.
Prevention
I encourage you to eliminate this User1 login ASAP, and replace it with well-designed integrated security. IIS application pools can be assigned a domain user, and those user(s) can be given SQL logins with tailored permissions.
If you cannot do that, then set up SQL logins for each web-app with tailored permissions and change those connection strings one-by-one. The project may be laborious, but the user1 login is a serious security vulnerability, especially since you don't have control over its use at this time.
At the same time, the connection strings in a classic ASP application should be moved into global.asa and administered there so that you have one connection string (or set of connection strings) for each app, rather than individual ASP scripts all containing 1,000 redundant strings (which is what it sounds like to me).
Not trying to be preachy, but this is a problem I see all the time.
I can't see how there's any other way than searching all the files for everywhere where user1 is used and compare the lines (personally if I had thousands, I'd write a program to search a folder and sub folders and return the whole string of the line the match was found on. As it's at the point of connection it makes it hard to narrow down to which script and all scripts using the same user will produce the same error.
EDIT: Actually, as you know what the password should be, you could check the line and if it doesn't contain the correct password then it's going to error.
Regards
Liam
Related
Evening,
I would like some practical confirmation in relation to an issue we are having.
We have a K2/SourceCode solution that turns upon the successful use of EXECUTE AS with Sql Server 2008 R2.
We have no direct control over how this solution is implemented, i.e. we cannot modify the queries that are submitted to the Sql Server engine. We can, of course, capture them using Profiler, and they tend to follow this pattern:
DECLARE #cookie VARBINARY(100);
EXECUTE AS LOGIN = 'DOMAIN\username' WITH COOKIE INTO #cookie;
SELECT #cookie;
exec [dbo].[SomeStoredProcedure] /* ... various params ...*/
exec sp_executesql N'REVERT WITH COOKIE = #cookie;',N'#cookie varbinary(100)',#cookie=/* some cookie value */
So what is happening is that [SomeStoredProcedure] is being executed in the security context of the user [Domain\username], with the service (application) account impersonating that user. Again, I emphasise that we have no control over this pattern. That's what the app does.
Outwardly this behaviour is perfectly-desirable, because we want things arranged in such a way that the stored procedure is effectively executed by whichever user is at the front-end of the application at the time.
However, these queries were consistently failing, and our investigation eventually led us to this, from the Sql Server documentation (my emphasis):
Specifying a User or Login Name
The user or login name specified in EXECUTE AS must exist as a principal in
sys.database_principals or sys.server_principals, respectively, or the
EXECUTE AS statement fails. Additionally, IMPERSONATE permissions
must be granted on the principal. Unless the caller is the database
owner, or is a member of the sysadmin fixed server role, the principal
must exist even when the user is accessing the database or instance of
SQL Server through a Windows group membership. For example, assume the
following conditions: CompanyDomain\SQLUsers group has access to the
Sales database. CompanyDomain\SqlUser1 is a member of SQLUsers and,
therefore, has implicit access to the Sales database. Although
CompanyDomain\SqlUser1 has access to the database through membership
in the SQLUsers group, the statement EXECUTE AS USER =
'CompanyDomain\SqlUser1' fails because CompanyDomain\SqlUser1 does not
exist as a principal in the database. If the user is orphaned (the
associated login no longer exists), and the user was not created with
WITHOUT LOGIN, EXECUTE AS will fail for the user.
We have a group of around 30 end users who need to be able to use this application, and the requirement is that the application security account must be able to impersonate any one of those users for the execution of these stored procedures. This requirement is fixed and non-negotiable.
The above documentation seems to preclude the possibility of meeting this requirement by adding all 30 users to an AD group, adding that group as a SQL Server login, and granting the group adequate permissions. And our practical testing results support this - EXECUTE AS fails.
Take one of those Users and give them their own, individual AD login on the Sql Server and the solution will work successfully for that user. EXECUTE AS succeeds, and the necessary permissions do not need to be assigned to the individual account because they have already been assigned by way of the AD group.
So, at this point, I am reasonably confident that I know what I am going to have to do. The requirement will be that every user has to have their AD account added as an individual Sql Server Windows login.
However, before I proceed with the rigmarole of implementing this, I wanted to ask the question publicly: is there something I am missing here?
It's instructive to imagine a similar scenario on an Enterprise-scale application - this model would somewhat fall apart, because of the need to add hundreds of individual, Windows-authenticated, Sql Server logins. Setting aside the possibility of automating this process, and the administrative burden that would ultimately result, I'm just finding it a bit of a stretch to imagine that this is the only way.
I would be grateful for confirmation and/or comments.
Thanks
Robert
As no-one has responded to the contrary (or indeed at all) we have assumed that BOL is accurate, and that there is no alternative resolution.
I'm working on an application right now that requires a link to a couple of SQL Server tables. My windows network account has permission to connect to this server, but I am not going to be the only one using this application. I'm going to send it out for people to save to their PC or just put it on the company shared drive to use (I know, that's asking for problems sometimes). It's inconvenient to make a windows account for users to share because they would need to log out and in to use the app, so I was wondering if the application or ODBC connection file itself can store the credentials to access the table.
Should I configure the connection object to use something other than the windows login information (maybe a SQL server username/password), and just store the connection object in a shared location? I don't have much experience with this and haven't tried out many different solutions and I am open to suggestions.
Thank you for the suggestions
As suggested in a comment to the question, one solution would be to
create a User Group in Windows on the SQL Server,
create a SQL Server login for that group,
assign permissions within SQL Server to that login,
and then just add or remove particular Windows Users from that group as required.
That way you don't need to mess with the various SQL Server permissions for each database user, and your application can connect to the SQL Server using Windows Authentication so you don't have to mess with saved SQL Server credentials (in connection strings, or elsewhere).
You certainly can specify the username & password in the connection string -- ConnectionStrings.Com is highly recommended if you are having trouble with connection strings -- their first example for Sql Server is
Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;
The issue is security, if users can see this in a configuration file, they can do anything that account can do. You have to handle security within you application if you do this. Most apps that handle their own security have to create users and passwords in a database table (best not to store password at all, much less plaintext -- a one way hash is recommended).
One good strategy is the create a "login user" account with well known name and password, grant no read / write, etc. for that account at all, and grant execute access to single stored proc
IsLoginPermitted #ID, #PASS
When successful, IsLoginPermitted returns the ID & PASS for subsequent use (of course these are hidden from the user) and you create your new connection string based on these.
I am trying to figure out what SQL Server Login gets used when I connect to SQL Server, in code, via a connection string that specifies Integrated Security=No and then specifies a user and password.
Note that I don't mean the user I'm specifying (I do know that of course), but the login that user maps to. I'm just now reading about logins vs users in SQL Server, and one point that is hammered home is that you always, always, always need a login to connect, and then a user per database that login needs to access. So I am looking in SSMS for the login that maps to the user I always specify on the databases I care about, but I see no such login.
Fyi, the reason I am asking, is I need to permission a new legacy app for this database, and the app is coded to use SQL Server authentication. I am trying to determine if I simply need users on the necessary database, or if I need to create a login. But now I've gotten myself curious about the general question itself.
Edit - a quick query of syslogins shows only 2 logins. So, my theory that SQLS was maintaining trivial '1 per user' logins but SSMS was hiding them, appears not to be the case
Edit - Querying syslogins, or sys.server_principals, appears to be misleading. On a database for which I have 2 different working SQLS (not Win) logins, I logged in as each and did select * from sys.server_principals. Two different answers: each time I got sa and the login I was logged in as. I would not see the 'other' login, though it was clearly there. I am guessing this may have something to do with schemas, which I also know little about. In any case, I am guessing that generally, logins do in fact exist for all users, though I will not see all these logins when I connect to SSMS as any one login. Does this sound right?
Solved (sort of)
From playing around, on a database on which I have sa, it is clear that SSMS only shows you all logins if you are sa, or perhaps have that specific permission. Otherwise, your view of logins is restricted. Therefore there is no real mystery as to why I was not seeing logins I was expecting. Apparently SSMS hides them. I say 'sort of' and 'apparently' because I never came across anything documenting this. It is just an observation.
Thanks to all for your help.
It is a server-level login unless you are connecting to a contained database. If you mean the database user that the server-level login maps to, you can find out using:
SELECT u.name
FROM sys.server_principals AS l
INNER JOIN sys.database_principals AS u
ON l.sid = u.sid
WHERE l.name = 'user id in your connection string';
If you are not using a contained database, this is how you would provision your user:
USE master;
GO
CREATE LOGIN your_login_name
WITH PASSWORD = 'f00b#r!', CHECK_POLICY = OFF;
GO
USE your_database;
GO
CREATE USER your_login_name -- doesn't have to match, but should for sanity
FROM LOGIN [your_login_name];
GO
-- then apply permissions of course.
In general logins maps to a database user
So for instance if by some unfortunate circumstance the app expected database owner access
You'd create this here login on the server (if it's not already there) and then map it to the dbo user in the database in question.
If it's not a built in user, then you are going to have to look at a db that this legacy app can already access, find out which user it's mapped to
Create that user on your new DB, set the required permission roles etc
Then map the login to it.
There are some subtle differences between sql server versions, so it's hard to do a step by step
If the user the apps login maps to is a custom one, then you are going to have to figure out an equivalent in the new database. Doesn't have to have the same name though (unless the app is using that) and it could even have more permissions.
We have a third-party vendor setting up software on a server. They have full access to that server and the sql-server on it with the sa account. We would like to set up a linked server so that a trigger can update data on a remote machine. Does access to the sa account necessarily mean that they have full access to the linked server or is there a way to protect yourself from sa?
EDIT: We wanted to give them full control of the server because we want them to have full responsibility. It takes the blame off us when it stops working. "hey, we didn't touch it, you fix it, you have full permissions". That way, they can do whatever they need to to get their software working, but it's in a sand boxed environment. We just need a trigger to get the final records out of their database and insert into our production database. That requires permissions we don't want to give them. The question was meant to ask if there was a way to save the password in that sand boxed environment under there noses. so to speak.
Never give anyone access to the SA account.
Instead, give them a named user account even if it still has full system level privileges.
Second, the linked server is going to be set up with a named user that is allowed to impersonate a named user on the other end. If they have an account with full privileges on the first server then they will be able to get to the other. It's as simple as changing the password of the user account that is granted access to the remote server.
Which brings us to another item: Never give an external entity full rights to anything unless they OWN the box. If, for some weird reason, you have no other choice then you should find an alternate way of transferring the data from this server to your production server.
One way would be to set up SSIS packages that drop the data in a directory the remote server will monitor for pickup. Sure this adds a bit more complexity, but in the end it will mean your stuff is still secure.
Finally, Linked Servers are notorious for being flaky in general. You are much better off finding a different way to transfer the data... Such as using the SSIS method.
You can set up the linked server to use a named user -- your third party contractor will still be able to see "the other end" of the link, but only with the rights granted to that named user.
So far, after creating DB with all the schema, all I have done so for was accessing them (tables) by reference through ConnectionStrings.
Now, twice, I've read that it's better to create a DB user and access the DB trhough that user by including him in the connectionString.
I'd like to know why so?
Thank for helping
Your question isn't that clear. It seems that you're asking if it is better to use windows security ("Integrated Security=SSPI" in the connection string) or a username/password ("User ID=myUsername;Password=myPassword;").
Its always better to use windows security. Having login information within the connection string is a security risk. Its in cleartext (unless you take some complicated steps to secure that section), and is sent across the wire as cleartext unless you set up a trusted connection between application and server.
Is it better to "create a db user and access the db trhough that user by including him in the connection string?" No. Its better to create a sql server login for user's windows identities and let them use those credentials to access the server.
You do this if you wish to connect as a specific user, rather than (for example) just using the context of the current user which your application is running under. However, if you use SQL Server authentication (i.e. username and password), you'd need to provide that password in the connection string, which is something of a security problem.
If the application has a group of anonymous users (or manages users/passwords itself) then its better to use a Windows login and run the application under a service account (which has minimal required access to the database).
If you're running an interactive application on the desktop, you should let those users connect to SQL server in their own context, by adding them to SQL Server with the required rights (e.g. db read/write , remove any higher functions). Obviously you would use groups to make administration simpler rather than adding individual users.