授予sys.server_principals授予usersys角色的权限。怎么样?

时间:2018-06-19 23:08:39

标签: sql-server permissions user-roles grant

我找不到答案。问题是我需要使用主数据库,然后我不知道如何指定将这个选择授予另一个数据库中的角色。使用“使用母版”时,它不起作用,因为主体位于另一个数据库中,并且您无法添加例如原则的Database.dbo.role前缀。我怎么做?甚至无法通过SSMS UI授予权限。

我需要这个:将Syf.sys.server_principals授予Syf.dbo.usersys

我想念什么?我是在以错误的方式思考吗?

即使我在master数据库上与用户一起尝试并调用“以user ='user'身份执行”,然后从sys.server_principals中进行选择,它仍然仅返回一些记录。我显然不了解这些权限的工作原理,这超出了我的逻辑。似乎还需要授予其他对象权限。

我需要使用“ with execute as'privilegedUser'”,当我这样做时,我们就处于该SP数据库的用户上下文中,并且该用户无权访问sys.server_principals。我需要这样做,因为如果存在具有相同名称的登录名,该SP会删除用户并登录。我需要与特权用户一起执行的原因是因为我的数据库具有多租户,并且每个用户都绑定到一个TenantId,并且当他或其他用户删除该用户时,安全策略抱怨他对此无权。

我找到了一种方法,我必须向master db上的来宾用户授予sys.server_principals的select权限,这为来宾提供了更多特权。

2 个答案:

答案 0 :(得分:2)

从sys.server_principals上的文档中,所需的权限是:

  

任何登录名都可以看到他们自己的登录名,系统登录名和固定服务器角色。要查看其他登录名,需要ALTER ANY LOGIN或该登录名的权限。要查看用户定义的服务器角色,需要具有ALTER ANY SERVER ROLE或角色成员身份。

     

目录视图中元数据的可见性仅限于用户拥有的或已授予用户某些权限的安全性。有关更多信息,请参见元数据可见性配置。

但是一切并没有丢失。我们可以使用模块签名来创建一个存储过程,该存储过程可以使您执行所需的操作。

use master;

create master key encryption by password = 'an unguessable password!'
alter master key add encryption by service master key
create certificate [CodeSigningCert]
    with expiry_date = '2018-12-31',
        subject = 'Code signing'
go
create login [CodeSigningLogin] from certificate [CodeSigningCert]
grant alter any login to [CodeSigningLogin]
go

SELECT 'CREATE CERTIFICATE ' + QUOTENAME([name]) 
    + ' AUTHORIZATION ' + USER_NAME([c].[principal_id]) 
    + ' FROM BINARY = ' + CONVERT(VARCHAR(MAX), CERTENCODED([c].[certificate_id]), 1)
    + ' WITH PRIVATE KEY (BINARY = ' 
    + CONVERT(VARCHAR(MAX), CERTPRIVATEKEY([c].[certificate_id], 'f00bar!23'), 1)
    + ', DECRYPTION BY PASSWORD = ''f00bar!23'')'
FROM [sys].[certificates] AS [c]
WHERE [name] = 'CodeSigningCert'

use tempdb
go
create master key encryption by password = 'foobar!23'
-- c/p the create certificate code generated above here
-- to create the same certificate in tempdb
create user CodeSigningUser from certificate CodeSigningCert
go
create login [foobar] with password = 'foobar!23'
create user [foobar]
go
create procedure dbo.listServerPrincipals
as
begin
    select *
    from sys.server_principals
end
go
grant execute on dbo.listServerPrincipals to foobar
go
execute as login = 'foobar'
go
exec dbo.listServerPrincipals
revert
go

add signature to dbo.listServerPrincipals by certificate [CodeSigningCert]
go

execute as login = 'foobar'
go
exec dbo.listServerPrincipals
revert
go

看起来很多,但实际上您正在执行以下操作:

  1. 在主服务器中创建证书
  2. 从该证书创建登录名
  3. 在用户数据库中创建相同的证书(我在这里用tempdb代替)
  4. 为此证书创建一个用户
  5. 创建一个登录名/用户代表您的应用程序用户
  6. 创建一个执行选择的过程
  7. 尝试将其作为应用程序登录名执行。它“有效”,但看起来和您自己选择就没什么不同
  8. 向过程添加签名
  9. 尝试再次执行该过程。这次,它应该返回所有数据

答案 1 :(得分:0)

我想出了一个解决方案,在该第一个过程中不需要使用“以所有者身份执行”,而在第二个过程中则需要第一个过程使用。在第一个中,我可以从sys表中选择所需的所有内容,并将信息传递给第二个具有“ with执行为拥有者”的信息,该用户在该模式中被禁止。

更好的解决方案:

 alter trigger [dbo].[AfterInsertUpdateTenant_Korisnici]
    on [dbo].[Korisnici]
    with execute as owner
    for insert 
    as 
    execute as user = original_login();
    declare @TenantId int = dbo.GetCurrentTenantId();
    revert;

    update dbo.Korisnici
    set TenantId = @TenantId
    from Inserted i
    where dbo.Korisnici.Id = i.Id;