0

My organisation using a combination of AD and LDS. AD syncs to LDS and stores some information within the extensionAttribute fields [mainly 10, 11 and 12].

I can pull back the standard information okay from LDS, i.e. Title, Surname, Initials but can't get the exntensionAttributes.I have used the example to Extend the UserPrincipal but still am unable to see the attribute values.

[DirectoryRdnPrefix("CN")]
    [DirectoryObjectClass("user")]
    public class UserPrincipalEx : UserPrincipal
    {
        public UserPrincipalEx(PrincipalContext context)
            : base(context)
        { }

        public UserPrincipalEx(PrincipalContext context, string samAccountName, string password, bool enabled)
            :base(context, samAccountName,password,enabled)
        { }

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

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

        [DirectoryProperty("extensionAttribute10")]
        public string Ext10
        {
            get
            {
                if (ExtensionGet("extensionAttribute10").Length != 1)
                    return null;
                return (string)ExtensionGet("extensionAttribute10")[0];
            }
        }
    }

I then have:

PrincipalContext ctx = new PrincipalContext(ContextType.ApplicationDirectory, "LDSServerHere:389", "OU HERE", "Acccount Name Here", "Password HEre");

        UserPrincipalEx u = UserPrincipalEx.FindByIdentity(ctx, IdentityType.SamAccountName, login);
        string prop = string.Empty;
        try
        {
            prop = u.Ext10;
        }
        catch (Exception ex)
        {
            prop = ex.ToString();
        }

        return prop;

Keep getting a NULLReferenceException: Object reference not set to an instance of an object

Am i doing something stupid here?

Gareth
  • 512
  • 1
  • 4
  • 15

1 Answers1

1

Calling FindByIdentityWithType won't work. Looking at the documentation, it's inherited from Principal (not UserPrincipal) and it says it's "not intended to be called directly from your code". It likely just doesn't understand your derived class, so it's returning nothing because nothing it finds matches your class.

But there's another way to do it: use DirectoryEntry.

PrincipalContext ctx = new PrincipalContext(ContextType.ApplicationDirectory, "LDSServerHere:389", "OU HERE", "Acccount Name Here", "Password HEre");

UserPrincipal u = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, login);
string prop = string.Empty;

try
{
    var de = (DirectoryEntry) u.GetUnderlyingObject();
    if (de.Properties.Contains("extensionAttribute10")) {
        prop = de.Properties["extensionAttribute10"].Value;
    }
}
catch (Exception ex)
{
    prop = ex.ToString();
}

return prop;

Notice the null check on the property. If the attribute is empty, it won't exist in the Properties collection at all. You could probably add some extra null checks in there just to be safe.

UserPrincipal and other classes in the AccountManagement namespace just use DirectoryEntry in the background anyway. They just don't expose all of the available attributes. So sometimes you have to use DirectoryEntry directly.

Actually, I've found that it's much faster and more efficient to only use DirectoryEntry and not use the AccountManagement namespace at all, although it can be a little more complicated to use sometimes.

Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84
  • Thanks for responding Gabriel, but that still isn't working for me. I basically need to pass a SamAccountName from a textbook, query ADLDS, not AD and return those additional attributes. I'm define authenticated okay against the LDS Context but it fails within the try catch, and i know for certain the user has that attribute set! – Gareth May 10 '18 at 16:03
  • its probably my inexperience not the help you've provided as to why its not working. – Gareth May 10 '18 at 16:12
  • Are you finding the user successfully using `UserPrincipal.FindByIdentity`? (is `u` not null?) Are you sure those attributes are replicating to LDS? – Gabriel Luci May 10 '18 at 16:16
  • we sync some attributes from AD to LDS, as we have another system which can only read LDS [and not AD] - some attributes from LDS i can return no problem, i.e. Title, GivenName but its those extensionAttributes I can't get, only certain users have ext10, 11 and 12 set. The user I'm querying 100% has 10,11,12 as I can see them in another LDS application. – Gareth May 10 '18 at 16:20
  • So with my code, what is the exception and on what line? – Gabriel Luci May 10 '18 at 16:22
  • Not in work at the min, will get that info to you as soon as I can. Appreciate it. From memory the ?.Value was highlighting as wrong [underlined in red in Visual Studio] – Gareth May 10 '18 at 16:25
  • Oh I see. Your project doesn't support [C# 6](https://msdn.microsoft.com/en-ca/magazine/dn802602.aspx) then. I'll edit my answer to change that. – Gabriel Luci May 10 '18 at 16:27
  • I think its an issue with my ctx LDAP line. – Gareth May 10 '18 at 17:51
  • You don't need "LDAP://" with `PrincipalContext`. If `u` is null after `UserPrincipal.FindByIdentity`, then it's not finding your user. You will have to work on that first. – Gabriel Luci May 10 '18 at 17:52
  • yep, looks like its my ctx information. If I change to Context.Domain, user is found and can find some attributes [as I assume this is AD]. If I use Context.ApplicationDirectory it fails. I can ValidateCredentials okay. Do you have an example Context.Application string? I know OU information will be different etc. – Gareth May 10 '18 at 18:00
  • I can't help you too much there unfortunately. We don't have any LDS instances here, so I've never used it. But if you're providing the server name of your LDS server, but using `ContextType.Domain`, and it works, then isn't that still good? – Gabriel Luci May 10 '18 at 18:06
  • that gives 'the supplied context type does not match the server contacted. The server type is ApplicationDirectory' – Gareth May 10 '18 at 18:08
  • You can try [the other constructor for `PrincipalContext`](https://msdn.microsoft.com/en-us/library/bb341016(v=vs.110).aspx), without the `container` parameter, just to see if that works: `new PrincipalContext(ContextType.ApplicationDirectory, "LDSServerHere:389", "Acccount Name Here", "Password HEre")` – Gabriel Luci May 10 '18 at 18:16
  • must define container :-( – Gareth May 10 '18 at 18:25
  • As a policy, or does it throw an exception? – Gabriel Luci May 10 '18 at 18:25
  • throws an exception – Gareth May 10 '18 at 18:27