SQL Server Server Logins and Database Users - sql-server

At work we use AD groups to control access to SQL Server databases.
I can see these groups in Security > Logins and (database) > Security > Users.
The problem is that some DBs have 50+ such AD groups as valid logins/users and I know I am a member of more than one.
Is there a way I can determine which of these AD groups I am logged in under?

You're effectively logged in as all of them. You'll have the union of all of the individual permissions granted to each group that you're a member of.

There are 2 straight forward built in commands that can help with what you are looking for:
First the extended procedure XP_LoginInfo (available at least since SS2000) will show you all the connection paths a particular login is allowed to use to connect to the instance with
DECLARE #LoginName sysname
SELECT #LoginName = SYSTEM_USER
EXEC xp_LoginInfo #AcctName = #LoginName, #Option = 'all'
All the group names shown under the last column "permission path" are the groups that the supplied LoginName is part of. Also note the "privilege" column; it will show if a login has admin or user level rights on the instance.
Now, the function fn_my_permissions (available since SS2005) will show you all the permissions the currently connected login has on the current database or the server.
SELECT * FROM fn_my_permissions(NULL, 'DATABASE');
SELECT * FROM fn_my_permissions(NULL, 'SERVER');
As Damien_The_Unbeliever responded on 11/28/12, basically the final list of permissions is the union of all the permissions assigned--both Grant and Deny--to each group's (and individually where an ID has been added explicitly) permission path you see by executing xp_LoginInfo.
So the answer basically is that you don't exactly connect with any one group when there are multiple allowed paths. Instead, in essence, you connect with them all. While nowhere does SQL Server clearly show or even state the 'unioned' nature of permissions, it can be inferred with the above 2 commands.
A ton of useful Security Catalog Views can be found on MSDN here.

Related

SQL owner chaining

Basically I have a front end application called AdminProgram. In SQL Server I have a role called AdminProgramUsers.
Now this role has permissions to various SPs and the like but, crucially, there is no select permission on any table. Everything they see or modify is done through SPs.
Now I've just written a new SP for them. I have had no choice but to use dynamic SQL, that is constructing the actual SQL query in a String variable called #FinalQuery and then running EXECUTE #FinalQuery.
Now initially I was getting a lot of user doesn't have access to the tables, needed to either grant SELECTs to the columns in question, but that solution won't work due to internal politics.
The other thing I seem to understand is that I need to use EXECUTE AS somehow. I have Googled, but I'm struggling to get this right.
And to pre-emptively answer a couple of questions, there is no option but to use dynamic SQL in this SP much to my displeasure, we're talking about SQL Server 2005 and there will be no way of signing any SPs with certificates (mainly as the DBA will flip a nut at the prospect of anything complicated).
So... I think the answer lies somewhere in EXECUTE AS with ownership chaining... but I need to know how to do it... assuming that the role available is AdminProgramUsers...
The current solution I have is:
CREATE SP MySp AS
DECLARE #FinalTable (columns)
DECLARE #FinalQuery
SET #FinalQuery = "EXECUTE AS CALLER
SELECT blah blah"
INSERT #FinalTable
EXECUTE (#QueryString) AS user ='AdminProgramUsers'
Do some more processing on #FinalTable
Select * from #FinalTable
The error I get is:
Unexpected Error in My Sp
Cannot execute as the database principal because the principal "AdminProgramUsers" does not exist, this type of principal cannot be impersonated, or you do not have permission.
here is an excerpt from ms documentation about execute on sql server 2005:
The user or login name specified in AS { LOGIN | USER } = ' name '
must exist as a principal in sys.database_principals or
sys.server_principals, respectively, or the statement will fail.
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.
in your code you feed the execute a role but a user or login is expected instead.
the above text is not very clear if you don't read this:
LOGIN
Specifies the context to be impersonated is a login. The scope
of impersonation is the server.
USER
Specifies the context to be
impersonated is a user in the current database. The scope of
impersonation is restricted to the current database. A context switch
to a database user does not inherit the server-level permissions of
that user.
you can specify a user or a login as impersonation context; a role is neither a login nor a user.

IS_ROLEMEMBER erroneously returns 0 for database role members?

Running a local instance of SQL Server 2012.
I have created a custom role:
CREATE ROLE [my_user] AUTHORIZATION [dbo]
For all my users (local Windows users and SQL users), I have specified this role for my database (under the User Mappings setting). Thus, the following query should return 1:
SELECT IS_ROLEMEMBER('my_user')
For my Windows-authenticated users it does indeed return 1, but as soon as I'm logged on as an SQL user, it returns 0. I have triple-checked that the SQL user does indeed have this role. What am I missing here?
Update
Performed some more testing. This certainly is weird behavior. I performed these steps:
On my local SQL Server I created a database test with user sa. Role my_user added.
Logged on as sa in the Management Studio and added MYDOMAIN\MyUser to this role.
Re-logged on with Windows Authentication and executed IS_ROLEMEMBER('my_user'). Returns 0.
Tried the query using both sa (specifying the username) and the Windows user. Same problem.
Tried restarting the SQL Server, just in case.
This makes no sense! If I right-click the role I can see that my Windows user is indeed a member of it. The IS_ROLEMEMBER function is flawed! When I run the following query, it shows that my user is indeed a member of the database role:
SELECT
USER_NAME(memberuid), USER_NAME(groupuid)
FROM
sys.sysmembers
WHERE
USER_NAME(groupuid) = 'my_user'
This also shows my membership:
select r.name as role_name, m.name as member_name from sys.database_role_members rm
inner join sys.database_principals r on rm.role_principal_id = r.principal_id
inner join sys.database_principals m on rm.member_principal_id = m.principal_id
Some additional information:
I'm on a domain, but currently disconnected. I have seen this problem when connected too though.
Running Windows 8.1 64-bit.
Update 2
If I explicitly specify the principal as some have suggested, I get this error (executing as sa):
SELECT IS_ROLEMEMBER('my_user', 'MYDOMAIN\UserX')
Msg 15404, Level 16, State 19, Line 1
Could not obtain information about Windows NT group/user 'MYDOMAIN\UserX',
error code 0x54b.
Could it be that IS_ROLEMEMBER experiences the same problem, but does not print the error?
I just had this same issue... I found that the user in question had server roles also assigned to them. When I removed all server roles except 'public', suddenly the is_rolemember query started correctly reporting a 1 instead of the zero..... I tested this back and forth a few times to confirm.
Also had this issue. Turns out I had to remove sysadmin server role, then it worked.
This is taken from: https://learn.microsoft.com/en-us/sql/t-sql/functions/is-member-transact-sql
Members of the sysadmin fixed server role enter every database as the dbo user. Checking permission for member of the sysadmin fixed server role, checks permissions for dbo, not the original login. Since dbo can't be added to a database role and doesn’t exist in Windows groups, dbo will always return 0 (or NULL if the role doesn't exist).
Try specifying the principal explicitly.
SELECT IS_ROLEMEMBER('my_user', 'SqlLogin')
I tested this and it returned 1.
CREATE DATABASE TestDatabase;
GO
USE TestDatabase;
GO
CREATE ROLE TestRole AUTHORIZATION dbo;
GO
CREATE USER TestUser WITHOUT LOGIN;
GO
EXEC sp_addrolemember 'TestRole', 'TestUser';
GO
SELECT IS_ROLEMEMBER('TestRole', 'TestUser');
GO

how to deal with "remapping can only be done for users that were mapped to Windows or SQL logins"

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.

Resolving permissions when using SQL Server Windows Authentication

This is for SQL Server 2005 or later, but I'd be interested to know if SQL Server 2000 works in the same way. Consider the following situation.
Two SQL Server Windows Authentication logins whose Login name is a Windows group:
MyDomain\Group1
MyDomain\Group2
A database with two users that are mapped to these logins:
USE MyDatabase
CREATE USER [User1] FOR LOGIN [MyDomain\Group1]
CREATE USER [User2] FOR LOGIN [MyDomain\Group2]
User1 and User2 are granted disjoint permissions in the database, e.g.:
GRANT SELECT ON Table1 TO User1
DENY SELECT ON Table1 TO User2
GRANT SELECT ON Table2 TO User2
DENY SELECT ON Table2 TO User1
A client connects to SQL Server using a Windows Identity that is a member of both groups MyDomain\Group1 and MyDomain\Group2.
Which database user is the client mapped to? I.e. does SELECT USER_NAME() return User1or User2?
What permissions does the client have? Is there a defined precedence which determines whether the client connects as User1 or User2? Where is this documented in BOL?
Background
This concerns a database which is currently accessed by multiple applications, each of which currently has its own SQL Server login, and has application-specific permissions on database objects.
I want to switch to using Windows Authentication to improve security, and I'd prefer to use Windows Groups rather than users for flexibility (I don't want the DBAs to have to manage logins for all the individual users).
However a given user may use multiple applications (and hence be a member of multiple Windows Groups that map to SQL logins), hence the potential for ambiguity in the mapping of a connection to a database user.
I've googled and searched Books Online, and can't find explicit information on how such ambiguity is resolved (e.g. precedence rules).
Any tips and best practices would be welcome in addition to an answer to the questions above.
That's an interesting question.
I'd assume that your client should have no access at all to those tables, ad DENY takes precedence over GRANT. In SQL Server, there is an exception to the DENY-overrides-GRANT principle though: when a GRANT is done on column level, it will allow access even if the table as a whole has been denied access, as MSDN states.
Edit: To understand what applies it is important to notice that the Logins (to the server) are not the same as the database users. Users which logged on through the means of a Windows group membership will get an implicitly created user, and permissions will need to be applied on that. See also this blog article for more information.

Finding out the windows group by virtue of which a user is able to access a database in sql server?

There is a SQL Server 2005 database with mixed-mode authentication.
Among others, we have the following logins on the server: our-domain\developers-group-1, and our-domain\developers-group-2 which are AD groups.
The our-domain\developer-group-2 is added to the sysadmin role on the server, by virture of which all domain users of that group can access any database as SQL Server implictly maps the sysadmin role to the dbo user in each database.
There are two users our-domain\good-user and our-domain\bad-user
The issue is the following: Both the good-user and the bad-user have the exact same AD group memberships. They are both members of our-domain\developers-group-1 and our-domain\developers-group-2. The good-user is able to access all the databases, and the bad-user is not. The bad-user is able to login, but he is unable access any databases. By the way, I am the good-user.
How do I go about finding out why?
Here's what I tried so far:
When I do print current_user, I get dbo
When I do print system_user, I get my-domain\good-user
When I do select * from fn_my_permissions(NULL, 'SERVER'), I see permissions.
But if do execute as user='my-domain\good-user'; select * from fn_my_permissions(NULL, 'SERVER'), I dont see any permisisons.
And When I do, execute as user='my-domain\bad-user'; select * from fn_my_permissions(NULL, 'SERVER'), I dont see any permisisons.
Also, I was wondering if there is a sql command that will tell me, "hey! the current database user is able to access this database because he is a member such-and-such ad-group, which is a login that is mapped to such-and-such user in this database".
If you have the relevant permissions within Management Studio, this shouldn't take too long to work out. It sounds like the bad-user AD group has limited permissions within SQL Server.
You need to check the settings in Security in the GUI, and check the mappings for each of these AD groups - clicking on the databases to see what permissions they have on each database.
Is it possible that you simply have implicit permissions as the creator/owner of the objects, yet no explicit permissions have been granted on the AD groups/roles or to your user individually?

Resources