Есть ли класс .NET, который может анализировать CN = строки из LDAP?
У меня есть строка, которую я извлекаю из LDAP для членства в группе Active Directory, и мне нужно проанализировать ее, чтобы проверить, является ли пользователь членом группы AD. Есть ли класс, который может разобрать это для меня?
Пример:
CN=Foo Group Name,DC=mydomain,DC=com
Ответы
Ответ 1
Кроме того, если вы запросите AD для членов группы, вы сможете напрямую сравнить все отличительные элементы членов без кода разбора через класс DirectoryEntry
пространства имен System.DirectoryServices
.
В противном случае я просто не знаю такого класса. =)
Надеюсь, это так или иначе поможет!
РЕДАКТИРОВАТЬ № 1
Здесь ссылка, с которой я многому научился работать с AD и пространством имен System.DirectoryServices
: Howto: (Almost) Everything In Active Directory via C#
Я дам вам пример кода через несколько дней, если вы все еще требуете его, где я буду использовать класс объекта System.DirectoryServices.DirectorySearcher
для извлечения членов группы.
Надеюсь, эта ссылка поможет вам, как и для меня! =)
РЕДАКТИРОВАТЬ № 2
Вот пример кода, о котором я вам рассказывал. Это должно сделать более эффективным запрос к AD без необходимости работать bakc и вперед AD.
public IList<string> GetMembers(string groupName) {
if (string.IsNullOrEmpty(groupName))
throw new ArgumentNullException("groupName");
IList<string> members = new List<string>();
DirectoryEntry root = new DirectoryEntry(@"LDAP://my.domain.com");
DirectorySearcher searcher = new DirectorySearcher();
searcher.SearchRoot = root;
searcher.SearchScope = SearchScope.Subtree;
searcher.PropertiesToLoad.Add("member");
searcher.Filter = string.Format("(&(objectClass=group)(sAMAccountName={0}))", groupName);
SearchResult result = searcher.FindOne();
DirectoryEntry groupFound = result.GetDirectoryEntry();
for (int index = 0; index < ((object[])groupFound.Properties["member"].Value).Length; ++index)
members.Add((string)((object[])groupFound.Properties["member"].Value)[index]);
return members;
}
Отказ от ответственности. Этот код предоставляется как есть. Я тестировал его на своей локальной машине, и он отлично работает. Но так как мне пришлось перепечатать его здесь, потому что я не мог просто скопировать его, я, возможно, допустил некоторые ошибки при наборе текста, чего я не хотел.
Ответ 2
Если вы не хотите добавлять дополнительные зависимости и просто хотите разобрать строку.
Этот тип строки легко анализируется с помощью string.Split. Чтобы получить значения CN, было бы что-то вроде.
string[] split = "CN=Foo Group Name,DC=mydomain,DC=com".Split(',');
List<string> cnValues = new List<string>();
foreach(string pair in split){
string[] keyValue=pair.Split('=');
if(keyValue[0]=="CN")
cnValues.Add(keyValue[1]);
}
Ответ 3
Они называются отличительными именами.
CodeProject имеет проект парсера, который, как представляется, выполняет то, что вам нужно: http://www.codeproject.com/KB/IP/dnparser.aspx
Ответ 4
Чтобы разобрать DistinquishedName, вы должны обратить внимание на escape-символы. Здесь метод, который будет правильно разбирать строку и возвращать список пар значений ключа.
public static List<KeyValuePair<string, string>> ParseDistinguishedName(string input)
{
int i = 0;
int a = 0;
int v = 0;
var attribute = new char[50];
var value = new char[200];
var inAttribute = true;
string attributeString, valueString;
var names = new List<KeyValuePair<string, string>>();
while (i < input.Length)
{
char ch = input[i++];
switch(ch)
{
case '\\':
value[v++] = ch;
value[v++] = input[i++];
break;
case '=':
inAttribute = false;
break;
case ',':
inAttribute = true;
attributeString = new string(attribute).Substring(0, a);
valueString = new string(value).Substring(0, v);
names.Add(new KeyValuePair<string, string>(attributeString, valueString));
a = v = 0;
break;
default:
if (inAttribute)
{
attribute[a++] = ch;
}
else
{
value[v++] = ch;
}
break;
}
}
attributeString = new string(attribute).Substring(0, a);
valueString = new string(value).Substring(0, v);
names.Add(new KeyValuePair<string, string>(attributeString, valueString));
return names;
}
static void Main(string[] args)
{
const string TestString = "CN=BY2STRAKRJOB2,OU=MSNStorage,OU=RESOURCE,OU=PRODUCTION,DC=phx,DC=gbl,STREET=street address,L=locality Name,C=Country Name,UID=user id,STUFF=\\,\\.\\+\"<>;\\=\\0A";
var names = ParseDistinguishedName(TestString);
foreach (var pair in names)
{
Console.WriteLine("{0} = {1}", pair.Key, pair.Value);
}
}
Ответ 5
Using System.DirectoryServices;
namespace GetGroups
{
public string GetGroupName(string LDAPGroupEntry)
{
// LDAPGroupEntry is in the form "LDAP://CN=Foo Group Name,DC=mydomain,DC=com"
DirectoryEntry grp = new DirectoryEntry(LDAPGroupEntry);
return grp.Properties["Name"].Value.ToString();
}
}
Ответ 6
Чтобы ответить на вопрос о синтаксическом анализе, используйте PInvoke с DsGetRdnW
. Для кода см. Мой ответ на другой вопрос: fooobar.com/info/282894/....
Но похоже, что вы делаете это неправильно. Во-первых, получите SID для вашей целевой группы:
string targetGroupName = //target group name;
DirectorySearcher dsTargetGroup = new DirectorySearcher();
dsTargetGroup.Filter = string.Format("(sAMAccountName={0})", targetGroupName);
SearchResult srTargetGroup = dsTargetGroup.FindOne();
DirectoryEntry deTargetGroup = srTargetGroup.GetDirectoryEntry();
byte[] byteSid = (byte[])deTargetGroup.Properties["objectSid"].Value;
SecurityIdentifier targetGroupSid = new SecurityIdentifier(byteSid, 0);
Тогда это зависит от того, что у вас есть. Если пользователь запускает ваше приложение (или аутентифицируется на ваш сайт/услугу), перечислите идентификаторы SID в токене. Например, в настольных приложениях используйте WindowsIdentity.GetCurrent().Groups
. В противном случае вам нужно получить DirectoryEntry для пользователя, а затем получить атрибут tokenAttributes
, например, предложенный spoulson:
DirectoryEntry deTargetUser = //target user;
DirectorySearcher dsTargetUser = new DirectorySearcher(deTargetUser);
dsTargetUser.SearchScope = SearchScope.Base; //tokenGroups is a constructed attribute, so have to ask for it while performing a search
dsTargetUser.Filter = "(objectClass=*)"; //this is closest thing I can find to an always true filter
dsTargetUser.PropertiesToLoad.Add("tokenGroups");
SearchResult srTargetUser = dsTargetUser.FindOne();
foreach(byte[] byteGroupSid in srTargetUser.Properties["tokenGroups"])
{
SecurityIdentifier groupSid = new SecurityIdentifier(byteGroupSid, 0);
if(groupSid == targetGroupSid)
{
//success
}
}
На всякий случай вам нужно получить DirectoryEntry из SID, вы можете получить строку поиска:
public static string GetSIDSearchFilter(SecurityIdentifier sid)
{
byte[] byteSid = new byte[sid.BinaryLength];
sid.GetBinaryForm(byteSid, 0);
return string.Format("(objectSid={0})", BuildFilterOctetString(byteSid));
}
public static string BuildFilterOctetString(byte[] bytes)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
sb.AppendFormat("\\{0}", bytes[i].ToString("X2"));
}
return sb.ToString();
}