Proper use of SPWeb.EnsureUser and alternatives
Often in SharePoint development, you’ll get a domainusername from which you want to get the corresponding SPUser object or other SharePoint objects related to an NT login. The SharePoint object model provides a handy method, SPWeb.EnsureUser to check whether a NT login belongs is associated with a web, and if not, it handles creating the user on that web. When code is doing more than reading from SharePoint objects, you’re going to need elevated privileges. Why? Because that code could run under the context of a user without administrative privileges, and you’ll get errors. Using SPSecurity.RunWithElevatedPrivileges is probably the best way to elevate the code to run with system-account privileges.
In the example below, I use the domainusername to add a permission to a list item for that user. The code is geared toward an item-event receiver, but can be adapted to other uses.
/// <summary> /// Adds an item-level permission for a user. /// </summary> /// <param name="loginNameField">the username, such as DOMAINuseralias</param> /// <param name="permissionName">the permission name, such as Contribute</param> /// <param name="properties">the item event properties object</param> public static void addUserPermission(string loginNameField, string permissionName, SPItemEventProperties properties) { try { SPSecurity.RunWithElevatedPrivileges(delegate() { using (SPSite site = new SPSite(properties.SiteId)) { site.AllowUnsafeUpdates = true; using (SPWeb web = site.OpenWeb(properties.RelativeWebUrl)) { web.AllowUnsafeUpdates = true; SPUser user = web.EnsureUser(properties.ListItem[loginNameField].ToString()); SPRoleAssignment userPermission = new SPRoleAssignment(user); SPRoleDefinition role = web.RoleDefinitions[permissionName]; userPermission.RoleDefinitionBindings.Add(role); SPListItem item = web.GetListItem(properties.RelativeWebUrl + "/" + properties.ListItem.Url); item.RoleAssignments.Add(userPermission); item.SystemUpdate(); } } }); } catch (Exception ex) { //TODO: Handle error } }
What if SPWeb.EnsureUser doesn’t work for you? Are you sure you’re passing the domainuseralias and not just the user alias? If you only have the user alias, you can use the System.Security.Principal namespace. For example, the following code takes the user alias, which the NTAccount constructor takes as a parameter (it also takes the domain name if you’ve got it). Thanks to my colleague David Cooper for the code example. Check out this blog for more background on SIDs. I’m not sure what would happen if you had more than one alias in a forest, e.g., DOMAIN1john.doe and DOMAIN2john.doe.
/// <summary>
/// Gets the login name for a user alias.
/// </summary>
/// <param name="alias">the user alias (no domain name)</param>
/// <returns>the DOMAINalias string</returns>
private static string GetLoginName(string alias)
{
NTAccount nt = new System.Security.Principal.NTAccount(alias);
SecurityIdentifier sid = (SecurityIdentifier)nt.Translate(typeof(SecurityIdentifier));
nt = (NTAccount)sid.Translate(typeof(NTAccount));
return nt.Value;
}
Last but not least, try using the SPUtility methods such as IsLoginValid, ResolvePrincipal, and SearchPrincipals.
Posted on March 11, 2009, in SharePoint. Bookmark the permalink. 2 Comments.
Good article.
Hello!
Very nice article. I worked with EnsureUser and faced with problems you described. Eventually, I’ve developed a small method-wrapper for EnsureUser. It’s shown in my blog – http://dotnetfollower.com/wordpress/2011/05/sharepoint-wrapper-over-ensureuser/
Thanks!