Forms Based Authentication - groups

cathiec

Freshman
Joined
Mar 8, 2004
Messages
28
i have recently used the article http://msdn.microsoft.com/library/en-us/dnnetsec/html/SecNetHT02.asp?frame=true
to implement forms-based authentication. i am having a problem with the GetGroups method. The method will not return the group name of a user that is currently in the Domain Users group only. I get the error: Error authenticating. Error obtaining group names. Object reference not set to an instance of an object The program runs perfectly and returns group names for users that are members of other groups. If a user is a member of four groups including the Domain Users group then the other three group names are returned.
 
Here's the fix we came up with, just replace your GetGroups method with the code below:

Code:
		public string GetGroups(string domain, string username, string pwd)
		{
			string domainAndUsername = domain + @"\" + username;
			DirectoryEntry entry = new DirectoryEntry( _path, 
				domainAndUsername,
				pwd);
			DirectorySearcher search = new DirectorySearcher(entry);
			search.Filter = "(cn=" + _filterAttribute + ")";
			search.PropertiesToLoad.Add("memberOf");
			StringBuilder groupNames = new StringBuilder();
			try
			{
				SearchResult result = search.FindAll()[0];
				int propertyCount = result.Properties["memberOf"].Count;
				String dn;
				int equalsIndex, commaIndex;

				for( int propertyCounter = 0; propertyCounter < propertyCount;
					propertyCounter++)
				{
					dn = (String)result.Properties["memberOf"][propertyCounter];

					equalsIndex = dn.IndexOf("=", 1);
					commaIndex = dn.IndexOf(",", 1);
					if (-1 == equalsIndex)
					{
						return null;
					}
					groupNames.Append(dn.Substring((equalsIndex + 1), 
						(commaIndex - equalsIndex) - 1));
					groupNames.Append("|");
				}
			}
			catch(Exception ex)
			{
				throw new Exception("Error obtaining group names. " +
					ex.Message);
			} 
			return groupNames.ToString();
		}
 
Hi!
Thank you so much for the reply. This was driving me crazy! After a lot of research I found out that the "memberOf" property does not supply the user's primary groups. This is why the other goups were being supplied and not Domain Users and also why if a user was only a member of Domain Users then no group was supplied. I came up with the following solution which is similar to yours but uses the security id to find all the groups that the user is part of including Primary groups and nested groups.

(below is the c# version but this article http://www.wwwcoder.com/main/parentid/260/site/2208/68/default.aspx explains the situation and supplies the code in vb.)
public string Groups(string domain, string username, string pwd)
{

byte[] sid = null;
string domainAndUsername = domain + @"\" + username;
StringBuilder groupNames = new StringBuilder();

DirectoryEntry rootEntry = new DirectoryEntry(_path, domainAndUsername, pwd);

try
{

rootEntry.RefreshCache(new string[] {"tokenGroups"});

foreach (object groupSid in rootEntry.Properties["tokenGroups"])
{

sid = ((byte[])(groupSid));

DirectoryEntry groupEntry = new DirectoryEntry(string.Format("LDAP://<sid={0}>", ConvertToOctetString(sid)));
PropertyCollection propcoll = groupEntry.Properties;

//loop through all of the properties for this record
foreach (string key in propcoll.PropertyNames)
{
//loop through all the values associated with our key
foreach (object values in propcoll[key])
{

if (key.ToLower() == "distinguishedname")
{
string temp = values.ToString();

int equalsIndex, commaIndex;

equalsIndex = temp.IndexOf("=", 1);
commaIndex = temp.IndexOf(",", 1);

if (-1 == equalsIndex)
{
return null;
}

groupNames.Append(temp.Substring((equalsIndex + 1),
(commaIndex - equalsIndex) - 1));
groupNames.Append("|");


}
}
}
}

}
catch (Exception ex)
{
//process exception
}
return groupNames.ToString();
}

public static string ConvertToOctetString(byte[] values)
{
return ConvertToOctetString(values, false, false);
}


public static string ConvertToOctetString(byte[] values, bool isAddBackslash)
{
return ConvertToOctetString(values, isAddBackslash, false);
}

//This is where the work really comes in. This method allows us to convert the sid
//into a usable string that LDAP can use to search for the groups this user belongs to.
public static string ConvertToOctetString(byte[] values, bool isAddBackslash, bool isUpperCase)
{
int iterator = 0;
System.Text.StringBuilder builder = null;

string slash = "";
if (isAddBackslash)
{
slash = "\\";
}
else
{
slash = string.Empty;
}
string formatCode = "";
if (isUpperCase)
{
formatCode = "X2";
}
else
{
formatCode = "x2";
}
builder = new System.Text.StringBuilder(values.Length * 2);

for (iterator = 0; iterator <= values.Length - 1; iterator++)
{
builder.Append(slash);
builder.Append(values[iterator].ToString(formatCode));
}

return builder.ToString();

}
 
Back
Top