System.DirectoryServices.AccountManagement.UserPrincipal с несколькими объектами DirectoryObjectClassAttribute - PullRequest
0 голосов
/ 17 февраля 2012

У нас есть службы Active Directory облегченного доступа к каталогам (AD LDS), синхронизированные с Active Directory с помощью userProxy obect.Мы также создаем объект класса пользователя в AD LDS.

Кажется, что объект UserPrincipal ограничен объектом класса пользователя в AD.Я знаю, что могу создать userProxyPrincipal на основе объектов класса userProxy.Но я хочу создать один объект для обработки обоих случаев.

Так как в документации DirectoryObjectClassAttribute указано, что вы можете использовать несколько DirectoryObjectClassAttribute, мне интересно, как мне этого добиться.

Если я укажу свой собственный объект UserPrincipal с двумя атрибутами (один с «user» и один с «userProxy»), он скомпилируется, но сопоставит только объект с тем же классом, что и первый указанный.(Я пытался поменять их местами, и это всегда первое совпадение)

Если я указываю два атрибута DirectoryPropertyAttribute для свойства, теперь оно сопоставляет только объект с таким же классом, что и второй.

Итак, я вижу, что он может переходить от одного к другому, но я не понимаю, как правильно его реализовать.

Есть предложения?

(извините за отсутствие примера кода, я дома и первым делом опубликую их завтра на работе)

Обновление - добавление фрагмента кода

Вот мой класс UserProxyPrincipal

namespace System.DirectoryServices.AccountManagement
{
    [DirectoryRdnPrefix("CN")]
    [DirectoryObjectClass("userProxy")]
    [DirectoryObjectClass("user")]
    public class UserProxyPrincipal : UserPrincipal
    {
        public UserProxyPrincipal(PrincipalContext context)
            : base(context) { }
        public UserProxyPrincipal(PrincipalContext context, string samAccountName, string password, bool enabled)
            : base(context, samAccountName, password, enabled) { }

        public static new UserProxyPrincipal FindByIdentity(PrincipalContext context, string identityValue)
        {
            return (UserProxyPrincipal)FindByIdentityWithType(context, typeof(UserProxyPrincipal), identityValue);
        }
        public static new UserProxyPrincipal FindByIdentity(PrincipalContext context, IdentityType identityType, string identityValue)
        {
            return (UserProxyPrincipal)FindByIdentityWithType(context, typeof(UserProxyPrincipal), identityType, identityValue);
        }

        [DirectoryProperty("objectSid")]
        public string ObjectSid
        {
            get
            {
                var values = ExtensionGet("objectSid");
                return ((values != null) && (values.Length > 0) ? values[0].ToString() : null);
            }
            set { ExtensionSet("objectSid", value); }
        }

        [DirectoryProperty("name")]
        public new string Name
        {
            get
            {
                var values = ExtensionGet("name");
                return ((values != null) && (values.Length > 0) ? values[0].ToString() : null);
            }
            set { ExtensionSet("name", value); }
        }
    }
}

Вот программа для его проверки

namespace FunWith.MTO.Framework.Security
{
    class Program
    {
        static void Main(string[] args)
        {
            PrincipalContext context = new PrincipalContext(ContextType.ApplicationDirectory, "servername.some.domain:636", "DC=dev,DC=local", ContextOptions.SimpleBind);
            Console.WriteLine("Log AdamUser : {0}", context.ValidateCredentials("AdamUser", "somePassword%"));
            Console.WriteLine("Log AdProxiedUser : {0}", context.ValidateCredentials("AdProxiedUser", "somePassword;"));
            var p = UserProxyPrincipal.FindByIdentity(context, "AdProxiedUser");
            var t = UserProxyPrincipal.FindByIdentity(context, "AdamUser");
            Console.WriteLine("User AdProxiedUser is {0}" ,p != null ? p.DistinguishedName : "null");
            Console.WriteLine("User AdamUser is {0}", t != null ? t.DistinguishedName : "null");

        }
    }
}

Это мой вывод с кодом, как было отправлено:

    Log AdamUser : True
    Log AdProxiedUser : True
    User AdProxiedUser is CN=AdProxiedUser,OU=Usagers,DC=dev,DC=local
    User AdamUser is null

Сейчасесли я поменяю два объекта DirectoryObjectClass на свой UserProxyPrincipal следующим образом:

    [DirectoryObjectClass("user")]
    [DirectoryObjectClass("userProxy")]

У меня будет такой результат (результат обмена):

    Log AdamUser : True
    Log AdProxiedUser : True
    User AdProxiedUser is null
    User AdamUser is CN=AdamUser,OU=AdamUsers,OU=Usagers,DC=dev,DC=local

Видя, что я могу определить два разных DirectoryObjectClassAttribute, я начинаюдумая, что это может быть, я должен установить tow diffrent DirectoryPropertyAttribute, как это:

    [DirectoryProperty("objectSid")]
    [DirectoryProperty("objectSid")]
    public string ObjectSid
        [...]

    [DirectoryProperty("name")]
    [DirectoryProperty("name")]
    public new string Name
        [...]

В результате получен результат перестановки один раз (я сохранил перестановку DirectoryObjectClassAttribute)

    Log AdamUser : True
    Log AdProxiedUser : True
    User AdProxiedUser is CN=AdProxiedUser,OU=Usagers,DC=dev,DC=local
    User AdamUser is null

Надеюсь, что поможетпонять, в чем моя проблема

Да, и, кстати, если я удаляю двойные атрибуты, оставляя только этот:

    [DirectoryObjectClass("userProxy")]

И специально использую UserPrincipal для моего AdamUser (uкласс объекта ser) и мой UserProxyPrincipal для моего AdProxiedUser (класс объекта userProxy):

var p = UserProxyPrincipal.FindByIdentity(context, "AdProxiedUser");
var t = UserProxy.FindByIdentity(context, "AdamUser");

Оба совпадают.Смотрите результат:

    Log AdamUser : True
    Log AdProxiedUser : True
    User AdProxiedUser is CN=AdProxiedUser,OU=Usagers,DC=dev,DC=local
    User AdamUser is CN=AdamUser,OU=AdamUsers,OU=Usagers,DC=dev,DC=local

Ответы [ 2 ]

2 голосов
/ 30 апреля 2014

Я знаю, что это было опубликовано некоторое время назад (2 года).Но я подошел к аналогичной проблеме, которую хотел решить.Я хотел, чтобы «GeneralPrincipal» наследовал от базового класса «Principal», чтобы можно было одновременно запрашивать компьютер, группу и пользователя.

Во-первых, я предполагаю, что используется только один из атрибутов DirectoryObjectClassAttributes (класс System.DirectoryServices.AccountManagement.ExtensionHelper в Reflector):

internal static string ReadStructuralObjectClass(Type principalType)
{
    DirectoryObjectClassAttribute[] attributeArray = (DirectoryObjectClassAttribute[]) Attribute.GetCustomAttributes(principalType, typeof(DirectoryObjectClassAttribute), false);
    if (attributeArray == null)
    {
        return null;
    }
    string objectClass = null;
    for (int i = 0; i < attributeArray.Length; i++)
    {
        if (!attributeArray[i].Context.HasValue && (objectClass == null))
        {
            objectClass = attributeArray[i].ObjectClass;
        }
    }
    return objectClass;
}

Как я решил это:

Я «одурачил» читателя атрибута, выполнив подобное (посмотрите на DirectoryObjectClassAttribute):

[DirectoryRdnPrefix("CN")]
[DirectoryObjectClass("*)(|(objectClass=computer)(objectClass=group)(objectClass=user)")]
public class GeneralPrincipal : Principal
{
    private static readonly FieldInfo _unpersistedField = typeof(Principal).GetField("unpersisted", BindingFlags.Instance | BindingFlags.NonPublic);

    #region Constructors

    public GeneralPrincipal(PrincipalContext context)
    {
        if(context == null)
            throw new ArgumentNullException("context");

        this.ContextRaw = context;
        _unpersistedField.SetValue(this, true);
    }

    #endregion
}

Надеюсь, это кому-нибудь поможет

С уважением, Ганс

0 голосов
/ 17 февраля 2012

Даже если этот вопрос имеет для меня смысл, я думаю, что ответ не слишком далек от того, который я даю Фильтр запросов ArgumentException при расширении принципала OU .

Дело в том, что Active-Directory (и ADAM / LDS), как и другие каталоги, построены с концепцией иерархии классов. Таким образом, вы можете использовать DirectoryObjectClass, чтобы указать класс в ветви иерархического дерева схемы, но не два класса в разных ветвях.

Насколько я понимаю, чтобы делать то, что вы хотите, класс userProxy должен быть подклассом класса пользователя (или в обратном порядке) в вашей схеме Справочника. Другими словами, вы пытаетесь создать с использованием C # класс, который наследует от двух классов (в разных ветвях) в вашей схеме Справочника, и поскольку каталоги C # не поддерживают множественное наследование.

Пишу так, я не отвечаю на ваш вопрос, но постараюсь объяснить, почему он не работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...