Login or Sign Up to become a member!
LessThanDot Sit Logo

LessThanDot

Data Management

Less Than Dot is a community of passionate IT professionals and enthusiasts dedicated to sharing technical knowledge, experience, and assistance. Inside you will find reference materials, interesting technical discussions, and expert tips and commentary. Once you register for an account you will have immediate access to the forums and all past articles and commentaries.

LTD Social Sitings

Lessthandot twitter Lessthandot Linkedin Lessthandot friendfeed Lessthandot facebook Lessthandot rss

Note: Watch for social icons on posts by your favorite authors to follow their postings on these and other social sites.

Your profile

    Search

    XML Feeds

    Google Ads

    « SQL Advent 2011 Day 13: DDL TriggersZero-One-Some Testing »
    comments

    This will be my contribution to the T-SQL Tuesday Challenge that was originally created by Adam Machanic. This month, my good friend Allen White (Blog | Twitter) is hosting the challenge. The topic he has chosen is, “What T-SQL tricks do you use today to make your job easier?” I enjoy this topic and understand why he chose it. As our experience grows, we compose dozens if not hundreds of methods in order to get our job done quickly or simply. We’ve all been faced with challenges and found the trick to resolving them given our own unique installations of SQL Server. This is a great way to get a compilation of everyone’s tricks and see how we may share them with the community.



    The orphaned user script can be used to resolve database user disconnections from SQL Server logins after a restore is performed.  There are other applications for this script but the restore problem with user to logins is the one that will be focused on today.

    The problem defined

    A common misconception is that database users and logins are the same objects.  With SQL Server, these are two unique security objects and two completely different levels of security.  A database user can exist without a valid SQL login, and vice versa.  Although these two objects can exist without each other, a database user is usually only effective if a SQL Login is tied to it.  This is the path to connecting to the SQL Server instance itself and the database user is later evaluated internally to the database permissions the user has that is tied to the login.

     

    In SQL Server 2012 and the AdventureWorks database, right click the SecurityàUsers nodes and click New User…  Drop the list down and notice the “SQL user without login”.  If this choice is utilized, there will be an orphaned database login, since there is no valid SQL login tied to it.

     

    A common problem with this orphaned situation is when a database is restored.  If a database is restored using a default strategy and no steps other than the restore command are taken, all the database users that were created in that restored database will also be restored.  Since these database users did not have a login or the connection to the SQL login has been severed, there are steps that need to be taken to reattach these objects.

     

    Remapping User to Login

     

    To remap a database user to a SQL login, the system procedure SP_CHANGE_USERS_LOGIN is available.  This procedure is on the list to be removed from future SQL Server releases and has been from SQL Server 2012 as of RC0.  Instead, the ALTER USER command must be used.  Since the procedure is still used in all the current versions of SQL Server, it will be shown as well as the replacement method of using ALTER USER. 

    To call SP_CHANGE_USERS_LOGIN, use the following syntax.

     

    sp_change_users_login [ @Action = ] 'action'

    [ , [ @UserNamePattern = ] 'user' ]

    [ , [ @LoginName = ] 'login' ]

    [ , [ @Password = ] 'password' ]

    [;]

     

    The procedure is quite simple but to be effective on a database that was restored with hundreds of logins that may or may not even exist on the SQL Server instance the database was restored to, a script is required.  If a script was not created, the task could potentially take hours to create and remap all the database users.

     

    For SQL Server 2012, the ALTER USER is used by simply using dynamic T-SQL to generate the command and set the user name and password. The one feature that previous versions of this script lacked was the differentiation between SQL user logins and Windows logins.  With Windows logins, the password is not set.  When using the ALTER USER method, if a SQL Server login is not found, the CREATE LOGIN statement is called to create a login.  There should be a check for the type of database user first though.  Then the decision can be made on how to build the CREATE LOGIN statement.  This enhancement is added to the SQL Server 2012 version.

     

    The script

    The below script has a work flow of first identifying the orphaned database users by utilizing the same sp_change_users_login with the ‘report’ action called.  This returns the database users of the database it is executed in and then allows the script to check the sys.server_principals for a valid login.  If a login is not found, one is created with the same name as the database user.  The password is set as a default password.  This password should be immediately dealt with as a change method by the user or some other compliant method to prevent security problems.  Once the login is created, the sp_change_users_login is used to remap the database user to the new SQL login or to an existing login that was found.

     

    SQL Server 2005, 2008, 2008 R2 Versions

    1. SET NOCOUNT ON
    2. USE AdventureWorks
    3. GO
    4. DECLARE @loop INT
    5. DECLARE @USER sysname
    6.  
    7. IF OBJECT_ID('tempdb..#Orphaned') IS NOT NULL
    8.  BEGIN
    9.   DROP TABLE #orphaned
    10.  END
    11.  
    12. CREATE TABLE #Orphaned (UserName sysname, UserSID VARBINARY(85),IDENT INT IDENTITY(1,1))
    13.  
    14. INSERT INTO #Orphaned
    15. EXEC SP_CHANGE_USERS_LOGIN 'report';
    16.  
    17. IF(SELECT COUNT(*) FROM #Orphaned) > 0
    18. BEGIN
    19.  SET @loop = 1
    20.  WHILE @loop <= (SELECT MAX(IDENT) FROM #Orphaned)
    21.   BEGIN
    22.     SET @USER = (SELECT UserName FROM #Orphaned WHERE IDENT = @loop)
    23.     IF(SELECT COUNT(*) FROM sys.server_principals WHERE [Name] = @USER) <= 0
    24.      BEGIN
    25.         EXEC SP_ADDLOGIN @USER,'password'
    26.      END
    27.      
    28.     EXEC SP_CHANGE_USERS_LOGIN 'update_one',@USER,@USER
    29.     PRINT @USER + ' link to DB user reset';
    30.     SET @loop = @loop + 1
    31.   END
    32. END
    33. SET NOCOUNT OFF

    SQL Server 2005, 2008, 2008 R2 and 2012 Version with Windows Login check

    1. SET NOCOUNT ON
    2. USE AdventureWorks
    3. GO
    4. DECLARE @loop INT
    5. DECLARE @USER sysname
    6. DECLARE @sqlcmd NVARCHAR(500) = ''
    7.  
    8. IF OBJECT_ID('tempdb..#Orphaned') IS NOT NULL
    9.  BEGIN
    10.   DROP TABLE #orphaned
    11.  END
    12.  
    13. CREATE TABLE #Orphaned (UserName sysname,IDENT INT IDENTITY(1,1))
    14.  
    15. INSERT INTO #Orphaned (UserName)
    16. SELECT [name] FROM sys.database_principals WHERE [type] IN ('U','S') AND is_fixed_role = 0 AND [Name] NOT IN ('dbo','guest','sys','INFORMATION_SCHEMA')
    17.  
    18. IF(SELECT COUNT(*) FROM #Orphaned) > 0
    19. BEGIN
    20.  SET @loop = 1
    21.  WHILE @loop <= (SELECT MAX(IDENT) FROM #Orphaned)
    22.   BEGIN
    23.     SET @USER = (SELECT UserName FROM #Orphaned WHERE IDENT = @loop)
    24.     IF(SELECT COUNT(*) FROM sys.server_principals WHERE [Name] = @USER) <= 0
    25.      BEGIN
    26.         IF EXISTS(SELECT 1 FROM sys.database_principals WHERE [Name] = @USER AND type_desc = 'WINDOWS_USER')
    27.          BEGIN
    28.             SET @sqlcmd = 'CREATE LOGIN [' + @USER + '] FROM WINDOWS'
    29.             Exec(@sqlcmd)
    30.             PRINT @sqlcmd
    31.          END
    32.         IF EXISTS(SELECT 1 FROM sys.database_principals WHERE [Name] = @USER AND type_desc = 'SQL_USER')
    33.          BEGIN
    34.             SET @sqlcmd = 'CREATE LOGIN [' + @USER + '] WITH PASSWORD = N''password'''
    35.             Exec(@sqlcmd)
    36.             PRINT @sqlcmd
    37.          END
    38.      END
    39.      
    40.     SET @sqlcmd = 'ALTER USER [' + @USER + '] WITH LOGIN = [' + @USER + ']'
    41.     Exec(@sqlcmd)
    42.     PRINT @USER + ' link to DB user reset';
    43.     SET @loop = @loop + 1
    44.   END
    45. END
    46. SET NOCOUNT OFF

    About the Author

    Ted Krueger is a SQL Server MVP and has been working in development and database administration for 13+ years. Specialties range from High Availability and Disaster / Recovery setup and testing methods down to custom assembly development for SQL Server Reporting Services. Ted blogs and is also one of the founders of LessThanDot.com technology community. Some of the articles focused on are Backup / Recovery, Security, SSIS and working on SQL Server and using all of the SQL Server features available to create stable and scalable database services. @onpnt Personal Blog over at http://onpnt.wordpress.com/
    Social SitingsTwitterLinkedInLTD RSS Feed
    3298 views
    InstapaperVote on HN

    No feedback yet

    Leave a comment


    Your email address will not be revealed on this site.

    To mislead the spambots.

    Your URL will be displayed.
    (Line breaks become <br />)
    (Name, email & website)
    (Allow users to contact you through a message form (your email will not be revealed.)