>
Blog
Book
Portfolio
Search

10/22/2006

7645 Views // 0 Comments // Not Rated

Converting Between String And Byte Array Representations Of SIDs

I've been at a client for quite some time doing SharePoint work, and came across an interesting issue. They have about 1,000 "corporate" users and 5,000 "field" users, with account names that follow a first-initial-last-name naming convention. And despite some minor dyslexia floating around the domain administrators casing the occasional mis-named or no-named login, all was well. Whenever I needed to identify my users, I would rarely have to look beyond System.Environment.UserName to get it.

Then I was told that all new employees (which were a lot, resultant from the recent merger) were going to be taking the form of first-name-dot-last-name.

Then I was politely informed that all users' logins were going to be mapped to first-name-dot-last-name...next week...

Great.

By the time this was done, Active Directory was a mess, half of my apps were broken, and no one could log into anything. We dug into this issue, and found that AD correctly had its SAM account name field set to first-name-dot-last-name, but SharePoint still listed users as first-initial-last-name.

What would happen is that if an administrator added a user to a site, he or she would be entered as domain\first-name-dot-last-name. The next screen would absolutely find them, and offer to add the user as first-name-dot-last-name. The admin would hit okay, be taken back to the site users screen, and sure enough, the new user would be there as first-initial-last-name (unless they were one of the new employees, who were always first-name-dot-last-name).

I came up with a theory, but it could not be confirmed since the network team became very reclusive after this conversion. It seemed as though the Alias field in an Outlook contact window matched the "mailnickname" property in AD and that is what fed the account name in SharePoint. Apparently, this was still the case despite SharePoint's settings to sync with AD three times a week. However, I can't come up with any concrete evidence beyond, so far, all user' we've looked at fitting this model.

So I took a deep breath, swore off the frivolous parsing of login names, and quickly turned to a better way to uniquely identify my users: Security ID (SID). Every object in AD has a SID that will never change, regardless of account inactivity or other identifier information modification.

In order to use these, however, programmers have to be careful, since they are stored and retrieved in different ways in different systems. The four that I have worked with are AD, SQL Server Reporting Services, SharePoint, and, of course, the Windows API. The remainder of this post will be how these different systems store and retrieve SIDs.

Active Directory

The actual field name in Active Directory for the SID is ObjectSID. When querying AD with a SID to get other user data, it takes in a string (for example: S-1-5-21-37293473-4535985394-2344535339-32094). Then, when AD returns a SID, it actually comes back as a byte array. Normally, converting between the two is an easy task using the GetString() or GetBytes() methods in the System.Text.ASCII.Encoding class. However, this method will not work with SIDs.

Since we can't use a simple .NET method to convert between the two, we have to get a little bit crafty. Two ways to do this are to either use the Windows API, or to query into one user data store with a SID in a particular formatting to get the SID in the other format. The following descriptions of the other data stores that understand SIDs will show how to do this.

SharePoint

You can send an SID or a SAM Account Name to the SharePoint Portal API's UserProfileManager and get other user information. The following code takes a SID (in byte array format) and returns it as a string.

Code Listing 1

  1. using System;
  2. using Microsoft.SharePoint.Portal;
  3. using Microsoft.SharePoint.Portal.Topology;
  4. using Microsoft.SharePoint.Portal.UserProfiles;
  5. ...
  6. //get a reference to the portal
  7. TopologyManager server = new TopologyManager();
  8. PortalSite portal = Server.PortalSites(new Uri("http://server"));
  9. PortalContext context = PortalApplication.GetContext(portal);
  10. UserProfileManager users = new UserProfileManager(context);
  11. //convert byte array to string
  12. string sidString = users.GetUserProfile(sidByteArray).Item("SID").ToString();

But probably the most useful technique in SharePoint regarding SIDs is the ability to get the current user's SID as string with two lines of code:

Code Listing 2

  1. using Microsoft.SharePoint;
  2. ...
  3. using (SPSite site = new SPSite("http://server"))
  4. {
  5. string sidString = site.RootWeb.CurrentUser.SID;
  6. ...
  7. }

SQL Server 2005 Reporting Services

Report permissions are stored in Reporting Services' database. Users are referenced both by SID and SAM Account Name. The SIDs in the User's table are stored as hexadecimal characters, and when queried, return the SID in the byte array format. Although code written against SQL Server Reporting Services should reference the web service, this knowledge could be useful.

Windows API

When you get down to it, this is the quickest and cleanest way to convert between byte array and string representations of SIDs. The only drawback, I feel, is that you might have to write some cryptic C-ish code using pointers, Marshalling, and other Windows API calls to get the code to work properly. However, at essence, there are only two methods needed to do the conversions. Microsoft can explain them in detail better than I could, so here are some links:

Converting a byte array SID to a string

Converting a string SID to a byte array

No Tags

No Files

No Thoughts

Your Thoughts?

You need to login with Twitter to share a Thought on this post.


Loading...