SSDT: Adding Logins for “Execute As” and editing system db dacpacs
We recently encountered an issue requiring us to use “Execute As” syntax in some of our stored procedures. Of course, we have multiple environments which all have different permission definitions so this would cause a bit of an issue. In this case, the login itself is standard in all of our environments, but we don’t define those within the project for the most part.
First problem: Add a new user called “MyLogin” to the project.
Solution: This was easy enough, I just added a new user to the project. However, I then ran into an issue that the Login for “MyLogin” did not exist in our master.dacpac reference.
Second Problem: Create a SQL Login reference within the master dacpac file that could be seen by all of our projects.
Solution: This proved to be a bit trickier. The model.xml file inside the default master.dacpac files contains many system-level objects. We would need to find the appropriate XML syntax for a new SQL Login element, add it to the model.xml file, and then update the hash for the dacpac file.
Extract the Model.xml file from our master.dacpac file
This can be easily done by finding your master.dacpac file that you referenced in your project and either renaming it to a .zip file or using a tool such as 7-zip to right-click the file and open it. Extract its “model.xml” file to some working folder.
Add a new SQL Login element to the model.xml file
Now that there’s a copy of model.xml to edit, open it in your favorite XML or Text editor. I like Notepad++, but even plain Notepad will work. Navigate to the very bottom of the file. We want to add the new element just before the tag. (for ease of use, not a requirement) The example XML is below. Note the “GloballyScoped” annotation type. This treats the entity as something that is available outside of the current database.
msFT7_&#$!~Make a new Dacpac file
msFT7_&#$!~Now that we’ve added the new login to our model.xml file, either add it back to the existing dacpac file by using something like 7-zip, or re-compress everything that was extracted from the old dacpac into a new zip file, then rename it to master.dacpac.
msFT7_&#$!~But what about the checksum?
msFT7_&#$!~All of the above works great, but the dacpac files provided by MS all have a checksum associated with them. If that checksum is off, it means that someone tampered with the file and it won’t work when you try to use it as a database reference. I will now give props to Gert Drapers (twitter) for writing up how to add objects to the master.dacpac file (site now gone).
msFT7_&#$!~To summarize, you basically extract the model.xml, edit it, re-add it to the dacpac, but then you can run a small app Gert wrote called dacchksum.exe (also shared here) to modify the checksum. I’m quoting Gert’s article here, but you basically put that exe in a place in your path or in the folder you want to use and run something like this:
dacchksum.exe /i:Master.dacpac /u /v
This will change the checksum of your master.dacpac file so it will now work as a database reference.
Add your user to the project
Now that there’s a Login for the user to reference, you can now add the user to the project. Right-click the project, select “Add”, and then choose the “User” option. You’ll have a new User created which you can easily set up to reference the new login in your master file.
Overall, not my favorite way to do these things, but if I know that a login will exist on the server I am more comfortable with adding a user to the project than I would be otherwise. You could still run into issues if this login doesn’t exist everywhere you want to use the project.
As Gert mentions, this trick is for adding any object to master. If you have a copy of sp_whoisactive or sp_blitz that you want to reference for some reason, you can add them to some one-off project, then copy that XML Element node into your master’s model.xml, regen the hash, and enjoy a new globally referenced object. It’s a useful trick, though one I hope not to have to use very often.