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.
Related
Suppose I have a login metamanager\test which shows when I execute T-SQL, but it is not there when when I expand Security -> Login in SSMS.
Same with a database user.
I try to replicate but failed
use master
select * from sys.syslogins is used for login
use DB
select * from sys.sysusers is used for database user
A LOGIN and a USER are completely different objects.
A LOGIN is a server object, and appear in sys.syslogins, as you see.
A USER is a database object, and for a LOGIN to have access to a database, it needs to have a USER mapped to the LOGIN in that database. A LOGIN with no mapped logins in any databases, and without any server level roles, will be unable to access any of the database on the instance, apart from those that the public roles has in tempdb and master.
It appears, here, you need to create the user in the database, and then give it the appropriate permissions. You can create the USER with the following:
USE {YourDatabase};
GO
CREATE USER 'metamanager\test' FOR LOGIN 'metamanager\test';
You'll need to give it the appropriate permissions afterwards.
Also, after you have created the user, ensure you have refreshed your object explorer. Object explorer doesn't automatically refresh after you create an object.
Not sure if you explaining it correctly, but syslogins and server_principals are about the same. Only the difference that server_principals include "Roles".
As far as I know it is impossible to have something in syslogins, which does not exist in server_principals.
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 am confused with Login and User. I found following in articles :
A "Login" grants the principal entry into the SERVER.
A "User" grants a login entry into a single DATABASE.
One "Login" can be associated with many users (one per database).
I can understand it theoretically. But, I think I might not have understood this practically.
I created a Login in my SQL server 2008 management studio by right clicking SERVERNAME=>SECURITY=>LOGIN. The default database was "master". Now, I can log into sql server with this login name and password. I noticed that if I change the default database in Login properties to a specific database, I cannot login again with this credential. I reverted back to "master" and it works. What happened here?
Also, why do we need users? I created a user by right clicking DATABASENAME=>SECURITY=>USERS. I cannot relogin with this user credential. So, what is the purpose we need this for. I can understand the theory of this answer but I need little more explanations to make sense.
Also, I am a .net developer, so I would like to know, what are the credentials provided in sql connection strings. Are they login or user or can be any of these?
The simplest explanation is that the SQL Server login gets you into the server, and the settings on that login control how it works in each database.
Don't worry about the database logins for the moment. You already went to SERVERNAME=>SECURITY=>LOGIN. Let's look at what you do with this login - right click and go into properties if you already created the login. Look under Roles - there are a number of different ones with different purposes on the server. But for an app, generally speaking, the average user should only have the Public role.
As far as the Database login, you go to the Mapping section to point your login to whichever databases it needs access to. When you map the login to the database, this CREATES the database login you saw under DATABASENAME=>SECURITY=>USERS if it does not already exist. The mapping is the most important part though, it's what literally gives the login the ability to see data in the database.
For applications, you're using the server login. If you set up the links to the databases you need in mapping, you don't really need to think about the database level login info.
The login only exists at the server level, which is why it maps automatically to the master database.
Users control access to individual databases. When you create a user, you can map it to a login (see Create User on MSDN for the syntax). If you create a user mapped to the login in the database, you can set it as the default and log in.
One reason this is done is to allow multi-tenant environments where a single server hosts many databases that not everyone who can access the server should be able to access. For example, say we provide services to Company A and Company B, and we host the database for each on the same server. We don't want someone from Company A (or, more importantly, someone who has compromised the credentials of someone from Company A) to be able to access the data for Company B, so we only create a user for the Company A login in the Company A database. Here's a brief code setup for you to experiment with:
-- This script assumes whoever is running it has sysadmin permissions on the instance of
-- SQL Server on which it is running. Do not run this on a production instance.
-- Create a database for each company on the server instance.
create database CompanyA;
create database CompanyB;
go
-- Create a login for each company on the server instance.
-- SQL Server integrated security has it's issues, but it's useful for an example like this.
create login CompanyA_Login with password = 'pa55wOrd1', default_database = CompanyA;
create login CompanyB_Login with password = 'pa55wOrd2', default_database = CompanyB;
go
-- Create a user in the appropriate database for each login.
-- We need to tell the server that we want to use a specific database
use CompanyA;
create user CompanyA_User for login CompanyA_Login;
-- We're granting it dbo for the purposes of our example here;
-- a broad permission set like that is a bad practice.
alter role db_owner add member CompanyA_User;
go
-- Repeat the process...
use CompanyB;
create user CompanyB_User for login CompanyB_Login;
alter role db_owner add member CompanyB_User;
go
-- Create a table in each database and populate it with some data.
use CompanyA;
create table dbo.sensitiveInformation
(
sensitiveInformation NVARCHAR(50) NOT NULL
);
insert dbo.sensitiveInformation (sensitiveInformation)
values ('Oh man, it would be bad if this got out!');
go
use CompanyB;
create table dbo.sensitiveInformation
(
sensitiveInformation NVARCHAR(50) NOT NULL
);
insert dbo.sensitiveInformation (sensitiveInformation)
values ('Oh man, it would be even worse if THIS got out!');
go
-- Now, feel free to log in as either user and see what you can and can't do.
-- You will find that the CompanyA_Login will never be able to access CompanyB's
-- data and vice versa. This allows for secure multi-tenant environments.
-- Once you're done playing around, we'll clean up our samples.
use CompanyB;
drop table dbo.sensitiveInformation;
drop user CompanyB_User;
go
use CompanyA;
drop table dbo.sensitiveInformation;
drop user CompanyA_User;
go
use master;
drop login CompanyB_Login;
drop login CompanyA_Login;
drop database CompanyB;
drop database CompanyA;
If you need separate, discrete security/permission sets, and you need one user to have more than one of these sets, you want to use database roles. This article from Tech Republic gives a decent gloss of the benefits of roles, though I'd recommend checking MSDN for the most current ways of creating them.
I just enabled remote connections on my SQL Server Express 2012 installation. Now I am a little bit worried about the server security because allowing connections to everybody sounds like a big security hole for me.
Is it possible to tell the SQL Server to disconnect if the user is trying to authenticate with a user which is not on my "allow" list? If so, I could add my monitoring user to this list and don't have to worry that my administration accounts are accessible.
First of all, this is probably a question that should be asked in the DBA site. Anyway, you can set up the security of the server so that only certain users are allowed to login.
When you set up the server, you add Logins to the Server Level and then Users at the database level. Only the users that are setup can, obviously, use a particular database. You can place users into roles, so, for example, they will have read-only access to a database. You can control, down to the object level, who has access to what.
There is a good article on what SQL Server security is about here
Having said that, sometimes, after, you have setup your security, you need to disallow certain users to not be allowed to Logon. Perhaps you are doing some major upgrade to the database. One option in this case is to create a Logon trigger.
A Logon Trigger will fire every time a user Logs in. You could create a table of "allowed" users and, in the trigger, if they are not in the table you ROLLBACK, effectively disallowing the Logon.
Here is information about creating a Logon trigger
You should be able to set up the db server to only accept connections from certain IP addresses, rather than to all of them. I'm unsure of the T-SQL syntax, but someone will surely chime in with the correct one.
If you really mean business, that being said, you'll want to authenticate clients using certificates that you give them. See this and the various articles it links to:
https://security.stackexchange.com/questions/14589/advantages-of-client-certificates-for-client-authentication
Being able to connect remotely to a SQL Server instance does not mean that they can Login to it. If they are not authorized properly, they should still get kicked-off by the SQL Server Login Authentication sequence.
This is silent/invisible for "Trusted Logins" (where the authorization comes from their Windows Login/Domain Account), but it still happens.
If you look under the "Security" folder of your Server (in SSMS), you will see the list of authorized Logins to you SQL Server. By adding or removing these you can control who can actually create a session on your SQL Server.
The scenario:
Trying to restore from a bacpac taken from SQL Azure.
Either to a new SQL Azure database instance, or an on premises server. For the earlier with the Management portal or the DAC Framework Client Side Tools.
It seems to work fine, and naturally the SQL users are not mapped to SQL logins after the restore.
What I tried:
When I try to map it with:
alter user MyUser with login = MyLogin, it fails with:
Msg 33016, Level 16, State 1, Line 6 The user cannot be remapped to a login. Remapping can only be done for users that were mapped to Windows or SQL logins.
Running select * from sys.database_principals does list the users, but with a much longer SID than a SQL authenticated user I created to compare it to.
On premises if I run a sp_change_users_login 'Report' the users are Not listed, so are not being detected as orphaned.
On premises if I try using sp_change_users_login, it fails with:
Msg 15291, Level 16, State 1, Procedure sp_change_users_login, Line 114 Terminating this procedure. The User name 'MyUser' is absent or invalid.
On premises if I try it through the User Mapping section of the Login Properties UI, I get:
Create failed for User 'My User'. ... User, group, or role 'MyUser'
already exists in the current database.
I tried doing it all over again, in case something was corrupted when restoring for some reason, same results.
The question:
How can I remap these SQL Users?
I'd like to avoid having to re-create those from scratch and any relation those have to the schema objects in the database?
Some extra info:
One type of SQL users that look a lot like what I'm seeing for the SQL Azure users, are ones created with
create user AnotherUser without login
Those fail in the exact same way in all the 3 mapping approaches I used above. That is not the case in any of the approaches for regular SQL users. Additionally the sid is also long, and begins with the same "0x010500000000000903000000"
A sqlmatters article explains that
A user without login is a special type of user that has deliberately
been set up without an associated login.
one can check if it is such a case by examining the SID:
-- SQL to run to identify users without login :
SELECT CASE WHEN DATALENGTH(sid) = 28
AND type = 'S' -- only want SQL users
AND principal_id > 4 -- ignore built in users
THEN 1 ELSE 0 END AS is_user_without_login,*
FROM sys.database_principals
where users without login have longer SID than regular (orphaned) users.
These special users cannot be mapped to a login because they are made that way. Someone must have intentionally or by mistake created a user WITHOUT LOGIN.
You can also find users that can be mapped to a login with the following:
SELECT *
FROM sys.database_principals
WHERE 1=1
AND [type] = 'S'
AND [name] NOT IN ('dbo','guest','INFORMATION_SCHEMA','sys')
AND authentication_type_desc IN ('WINDOWS','INSTANCE')
If you ever get that, it is Most likely a corrupt backup. Just like the linked on premises scenario, the behaviour comes out of nowhere and was traced to a corrupt backup.
In my case, it was the same. Right before posting the question, my last try was: a different backup of the database, it worked without issues.