Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Granting access to one db to users/roles of another

Short version: Can I grant access to external databases to a role?

Long version:

I am working on reports using Crystal which is retrieving data from an applications SQL Server Instance (database1).

The application is running the reports and overwriting the connection in the report, I have no access to the applications code.

I have added a new DB to the server (database2) which is collecting information from a telephone exchange and I want to join some of this information to the applications data (database1).

I can join the data and the reports work when run within the designer (logged in as SA) but when the reports are run externally through the application they fail with a fairly generic error (Failed to retrieve data).

I am assuming the error is being caused by the new DB permissions as if I log into the application as SA the error goes away.

The Application has a special DB Role for users that run reports, when adding a table/view/sp to the application db (database1) I can simply grant select/execute to this role to allow the reports to access the object.

Now I have object in a different db however the role isn't easily accessible.

Is there any way I can reference the second db (database2) through the existing role?

eg:

USE [database1]
GRANT EXECUTE ON [database2].[dbo].[CUSTOM_PROCEDURE] TO [applicationrole1] 

OR

USE [database2]
GRANT EXECUTE ON [dbo].[CUSTOM_PROCEDURE] TO [database1].[dbo].[applicationrole1]

Ideally I want to be able to link to the Role somehow rather than re-creating a new role as the role is updated by the application regularly when new users are added/configured.

(Not tagged with Crystal-Reports as this isn't related to the problem)

Edit:

Is there any way to do something like:

INSERT INTO Database2.sys.database_principals
SELECT * FROM Database1.sys.database_principals
WHERE [type] = 'S'

To copy over the Users (not logins) and then add the role members?

like image 466
bendataclear Avatar asked Jun 18 '12 10:06

bendataclear


2 Answers

Presumably, you'd be using a login that has access to both databases (such as the case with SA). You'd create the appropriate role and grant rights to each database, then create the user (linked to the login you're using) in both, adding each to the role you created.

The T-SQL will look something like this:

use master
go
create login testuser with password = 'mypassword123'
go

use test
go

create role reporting
grant select on something to reporting -- grant your permissions here

create user testuser for login testuser
exec sp_addrolemember 'reporting', 'testuser'
go

use test2
go

create role reporting
grant select on something2 to reporting -- grant your permissions here

create user testuser for login testuser
exec sp_addrolemember 'reporting', 'testuser'
go

Now I can connect to test and execute

 select * from something
 select * from test2.dbo.something2

Of course, you'd change your grants to EXECUTE on the desired stored procedures, but it looks like you've already got that covered.

After that, it's just about executing a simple script to create logins, users, and add them to the role.

declare @sql nvarchar(max), @username nvarchar(50), @password nvarchar(50)

-- ########## SET PARAMETERS HERE
SET @username = N'testguy'
SET @password = N'test123'
-- ########## END SET PARAMETERS

set @sql = N'USE master; CREATE LOGIN [' + @username + N'] WITH PASSWORD = N''' + @password + N'''; USE database1; CREATE USER [' + @username + N'] FOR LOGIN [' + @username + N']; EXEC sp_addrolemember ''reporting'', ''' + @username + N''';  USE database2; CREATE USER [' + @username + N'] FOR LOGIN [' + @username + N']; EXEC sp_addrolemember ''reporting'', ''' + @username + N''';'
exec sp_executesql @sql

Syncing logins, users, and roles automatically

This script will find all SQL logins (you can change this to whatever makes sense to you; windows AND SQL accounts, accounts that contain a certain string, whatever), ensure the user has been created in database1 and database2, and ensures they are both added to the reporting role. You will need to ensure the reporting role is created on both databases, but you only need to do this once.

After that, you can run this script periodically, either manually, or using a SQL Agent job. All you need to do is create the login for the server; when the script runs it will do the rest.

declare @login nvarchar(50), @user1 nvarchar(50), @user2 nvarchar(50), @sql nvarchar(max), @rolename nvarchar(50)

SET @rolename = 'reporting'

declare c cursor for 
select sp.name as login, dp1.name as user1, dp2.name as user2 from sys.server_principals as sp
    left outer join database1.sys.database_principals as dp1 on sp.sid = dp1.sid
    left outer join database2.sys.database_principals as dp2 on sp.sid = dp2.sid
where sp.type = 'S' 
    and sp.is_disabled = 0

open c

fetch next from c into @login, @user1, @user2

while @@FETCH_STATUS = 0 begin

    -- create user in db1
    if (@user1 is null) begin
        SET @sql = N'USE database1; CREATE USER [' + @login + N'] FOR LOGIN [' + @login + N'];'
        EXEC sp_executesql @sql
    end

    -- ensure user is member of role in db1
    SET @sql = N'USE database1; EXEC sp_addrolemember '''+ @rolename + ''', ''' + @login + N''';'
    EXEC sp_executesql @sql

     -- create user in db2
    if (@user2 is null) begin
        SET @sql = N'USE database2; CREATE USER [' + @login + N'] FOR LOGIN [' + @login + N'];'
        EXEC sp_executesql @sql
    end

    -- ensure user is member of role in db2
    SET @sql = N'USE database2; EXEC sp_addrolemember '''+ @rolename + ''', ''' + @login + N''';'
    EXEC sp_executesql @sql

    fetch next from c into @login, @user1, @user2
end


close c
deallocate c

You will want to add a transaction and error handling to roll off incomplete changes, but I'll leave that up to you.

like image 167
moribvndvs Avatar answered Sep 18 '22 12:09

moribvndvs


Set the stored procedure to execute as owner.

http://msdn.microsoft.com/en-us/library/ms188354.aspx

Set trustworthy on the database where the stored procedure is located.

http://technet.microsoft.com/en-us/library/ms187861.aspx

Ensure that you have the same owner on both databases.

http://msdn.microsoft.com/en-us/library/ms188676(v=sql.105).aspx

Grant execute permissions on the stored procedure to the appropriate user or role on the database with the procedure.

like image 44
JStead Avatar answered Sep 21 '22 12:09

JStead