Using System.DirectoryServices to add, remove, and verify group membership
I've had several customers who have built SharePoint solutions to manage domain group membership in lieu of rolling out full on Forefront Identity Manager. I'm not one to debate the decision as to if SharePoint is the right tool or not but I do have occasion to support them on their endeavors.
There are several ways to skin this cat in .NET. You could use the System.DirectoryServices.AccountManagement (https://msdn.microsoft.com/en-us/library/system.directoryservices.accountmanagement(v=vs.110).aspx) namespace. It was introduced in .NET 3.5 so you can use it with SharePoint 2010 full trust code.
I'm a big fan of doing things the old fashioned way so to speak using System.DirectoryServices (https://msdn.microsoft.com/en-us/library/system.directoryservices(v=vs.110).aspx). That stuff has been around since .NET 1.1. By using ADSI you can query via LDAP and manually manipulate the DirectoryEntry objects. I find this solution just makes more sense to me. It also is transportable and if for some reason you weren't using Active Directory and instead you were using some other LDAP provider your code would still work.
To that end I created a simple helper class that can be used to add, remove, and verify group membership for a user. Here is a class you can use followed by an example of how to utilize it from a console app.
using System;
using System.DirectoryServices;
namespace ADHelper
{
public class ADHelper
{
private string username;
private string password;
public string domain;
public ADHelper(string username, string password, string domain)
{
this.username = username;
this.password = password;
this.domain = domain;
}
//Looks up the DN for a user based on the sAMAccountName
public string GetUserDN(string identity)
{
//Split out the identity to get just the username portion
if (identity.Contains("\\"))
{
string[] identityList = identity.Split('\\');
string userName = identityList[1];
using (var rootEntry = new DirectoryEntry("LDAP://" + domain, this.username, this.password, AuthenticationTypes.Secure))
{
using (var directorySearcher = new DirectorySearcher(rootEntry, String.Format("(sAMAccountName={0})", userName)))
{
var searchResult = directorySearcher.FindOne();
if (searchResult != null)
{
using (var userEntry = searchResult.GetDirectoryEntry())
{
return (string)userEntry.Properties["distinguishedName"].Value;
}
}
}
}
}
return null;
}
//Looks up the DN for the group based on the name
public string GetGroupDN(string groupname)
{
using (var rootEntry = new DirectoryEntry("LDAP://" + domain, this.username, this.password, AuthenticationTypes.Secure))
{
using (var directorySearcher = new DirectorySearcher(rootEntry, String.Format("(&(objectCategory=group)(cn={0}))", groupname)))
{
var searchResult = directorySearcher.FindOne();
if (searchResult != null)
{
using (var userEntry = searchResult.GetDirectoryEntry())
{
return (string)userEntry.Properties["distinguishedName"].Value;
}
}
}
}
return null;
}
//Checks to see if a user is in a group and returns a bool
public bool isUserInGroup(string userDn, string groupDn)
{
bool match = false;
DirectoryEntry user = new DirectoryEntry("LDAP://" + userDn, this.username, this.password, AuthenticationTypes.Secure);
foreach (string group in user.Properties["memberof"])
if (group == groupDn)
match = true;
return match;
}
//Adds a given user to a group
public bool AddToGroup(string userDn, string groupDn)
{
bool success = false;
try
{
DirectoryEntry dirEntry = new DirectoryEntry("LDAP://" + groupDn, this.username, this.password, AuthenticationTypes.Secure);
dirEntry.Properties["member"].Add(userDn);
dirEntry.CommitChanges();
dirEntry.Close();
success = true;
}
catch (System.DirectoryServices.DirectoryServicesCOMException ex)
{
success = false;
}
return success;
}
//Removes a user from a group
public bool RemoveUserFromGroup(string userDn, string groupDn)
{
bool success = false;
try
{
DirectoryEntry dirEntry = new DirectoryEntry("LDAP://" + groupDn);
dirEntry.Properties["member"].Remove(userDn);
dirEntry.CommitChanges();
dirEntry.Close();
success = true;
}
catch (System.DirectoryServices.DirectoryServicesCOMException ex)
{
success = false;
}
return success;
}
}
}
namespace ADHelper
{
class Program
{
static void Main(string[] args)
{
string username = "jason";
string password = "supersecretpassword";
string domain = "home.vallery.net";
//Create new helper object with the username and password of service account
ADHelper helper = new ADHelper(username, password, domain);
//Lookup the DN of our user
string userDN = helper.GetUserDN("home\\jason");
//Lookup the DN of our group
string groupDN = helper.GetGroupDN("AWESOME PEOPLE GROUP");
//Determine if our user is in the group
Console.WriteLine(string.Format("Is {0} a member of {1}: {2}", userDN, groupDN, helper.isUserInGroup(userDN, groupDN).ToString()));
//Add our user to the group
helper.AddToGroup(userDN, groupDN);
//Determine if our user is in the group
Console.WriteLine(string.Format("Is {0} a member of {1}: {2}", userDN, groupDN, helper.isUserInGroup(userDN, groupDN).ToString()));
//Remove user from the group
helper.RemoveUserFromGroup(userDN, groupDN);
//Determine if our user is in the group
Console.WriteLine(string.Format("Is {0} a member of {1}: {2}", userDN, groupDN, helper.isUserInGroup(userDN, groupDN).ToString()));
Console.ReadLine();
}
}
}
Comments
Anonymous
June 22, 2014
RemoveUserFromGroup is trying to do this anonymously? :)Anonymous
December 10, 2015
There seems to be a bug in the GetUserDN function in that, if the value passed to the 'identity' variable does NOT contain a slash, a null value is returned by the function. Took me ages to figure out that this was the reason my call of the isUserInGroup function kept failing.