dsbenghe / Novell.Directory.Ldap.NETStandard

.NET LDAP client library for .NET Standard >= 2.0, .NET Core >=1.0, NET5/NET6/NET7/NET8 - works with any LDAP protocol compatible directory server (including Microsoft Active Directory).
MIT License
555 stars 151 forks source link

GSSAPI/Windows SASL authentication #28

Open long2know opened 7 years ago

long2know commented 7 years ago

I was looking through the source code for LdapBindRequest and RfcBindRequest, and it doesn't appear to be any way to use the currently logged in Windows User for authentication in the case of connecting to an Active Directory server.

Is there any possibility of support this scenario? Ideally, I would like to run my .NET Core service as a specific user and let the that user's identity be used for the Ldap "bind" rather than storing username and password in my application's configuration.

gfoidl commented 7 years ago

To my understanding this could be done via kerberos tickets, and a bind via GSSAPI. For later see issue #7. So right now there is no possibility to do this. Unfortunately 😢

dsbenghe commented 7 years ago

@gfoidl is correct - this is how is supposed to work, but is not implemented.

winnieryl commented 5 years ago

@gfoidl is correct - this is how is supposed to work, but is not implemented.

Is this implemented in the latest code?

vletoux commented 5 years ago

the GSSAPI data can be produced on Windows with InitializeSecurityContext

The data provided by GSSAPI "just" need to be embedded into LDAP.

I can help: I've a c code performing the authentication using GSSAPI and the code to answer manually a NTLM challenge/response (fallback) https://github.com/vletoux/DetectPasswordViaNTLMInFlow/blob/master/DetectPasswordViaNTLMInFlow.cpp InitializeSecurityContext is really painful to pinvoke but nothing impossible.

I can write a prototype to produce the GSSAPI data if someone is doing the LDAP part to embed it.

For linux, after some research, it seems that the API to use is gss_init_sec_context. Unfortunately, I'm not a linux guy.

lkspencer commented 4 years ago

Have you looked at what's been done here? maybe something over there will help. That project's kerberos authentication does appear to work, at least in my simple tests.

Evengard commented 3 years ago

Actually this library IS extensible enough to be able to implement your own SASL provider. I actually managed to implement auth into Ldap using Kerberos tickets via SPNEGO. Implementing InitializeSecurityContext may be actually even easier.

Just look at RegisterSaslClientFactory and the whole ISaslClientFactory/ISaslClient interfaces and their realization.

lolligd commented 1 year ago

Has there been any movement on this? Would love to know if anyone has a good pattern setup that actually implements this properly.

ststeiger commented 1 year ago

Hey guys, take a look at ldap4net: https://github.com/flamencist/ldap4net#setoption It has GSSAPI-support and works on Linux and Mac, too !


namespace ConsoleAdBrowser
{

    using LdapForNet;

    class Program
    {

        public static void GetAdController(out string url, out int port)
        {
            System.Net.NetworkInformation.IPGlobalProperties ipgp =
                System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties();

            // IDnsResolver resolver = new RecursiveDnsResolver(); // Warning: Doesn't work
            ARSoft.Tools.Net.Dns.IDnsResolver resolver = new ARSoft.Tools.Net.Dns.DnsStubResolver();

            string magicUrl = "_ldap._tcp." + ipgp.DomainName;

            System.Collections.Generic.List<ARSoft.Tools.Net.Dns.SrvRecord> srvRecords =
                resolver.Resolve<ARSoft.Tools.Net.Dns.SrvRecord>(
                    new ARSoft.Tools.Net.DomainName(magicUrl.Split('.')),
                    ARSoft.Tools.Net.Dns.RecordType.Srv
            );

            foreach (ARSoft.Tools.Net.Dns.SrvRecord thisRecord in srvRecords)
            {
                // System.Console.WriteLine(thisRecord.Name);
                System.Console.WriteLine(thisRecord.Target);
                System.Console.WriteLine(thisRecord.Port);

                // Note: OR LDAPS:// - but Novell doesn't want these parts anyway 
                url = thisRecord.Target.ToString();
                port = thisRecord.Port;
                return;
            } // Next thisRecord

            url = null;
            port = -1;
        } // End Sub GetAdController 

        public static string GetDefaultNamingContext(LdapConnection cnn)
        {
            // https://ldapwiki.com/wiki/RootDSE
            LdapEntry rootDse = cnn.GetRootDse();
            DirectoryAttribute attr = rootDse.DirectoryAttributes["defaultNamingContext"];

            return attr.GetValue<string>();
        }

        // https://github.com/flamencist/ldap4net#getRootDse
        // https://github.com/ststeiger/ldap4net
        static void Main(string[] args)
        {
            string ldapHost = null;
            int ldapPort = -1;

            GetAdController(out ldapHost, out ldapPort);

            using (LdapConnection cnn = new LdapConnection())
            {

                // connect use Domain Controller host from computer hostname and default port 389
                // Computer hostname - mycomp.example.com => DC host - example.com
                // cnn.Connect();
                cnn.Connect(ldapHost, ldapPort);
                // cnn.Connect("dc.example.com", 389);
                // cnn.Connect("dc.example.com", 636);

                // int ldapVersion = (int)LdapForNet.Native.Native.LdapVersion.LDAP_VERSION3;
                // cnn.SetOption(LdapForNet.Native.Native.LdapOption.LDAP_OPT_PROTOCOL_VERSION, ldapVersion);
                // cnn.SetOption(LdapForNet.Native.Native.LdapOption.LDAP_OPT_DEREF, 1);

                // https://learn.microsoft.com/en-us/troubleshoot/windows-server/identity/ldap-paged-queries-subordinate-referrals-not-chased
                // Note: If you are not getting results beyond the first page,
                // this could because subordinate referrals are turned on as explained here.
                // In that case, one option is to turn off subordinate referrals
                // (as described in option 3 in the link's suggested workarounds).
                // This can be done as follows:
                cnn.SetOption(LdapForNet.Native.Native.LdapOption.LDAP_OPT_REFERRALS, System.IntPtr.Zero);

                // bind using kerberos credential cache file
                cnn.Bind();
                // cnn.Bind(loginDN, password);
                // cnn.Bind(ldapVersion, loginDN, password);

                // System.Collections.Generic.IList<LdapEntry> entries =cnn.Search("dc=example,dc=com", "(objectClass=*)");

                string searchBase = GetDefaultNamingContext(cnn);
                string searchFilter = null;

                System.Collections.Generic.IList<LdapEntry> lsc = cnn.Search(searchBase,
                    searchFilter, null, LdapForNet.Native.Native.LdapSearchScope.LDAP_SCOPE_ONE);

                string authzId = cnn.WhoAmI().Result;
                System.Console.Write("== Who am i ? ");
                System.Console.Write(authzId);
                System.Console.WriteLine("! === ");

                // string authzId = await cnn.WhoAmI();

                foreach (LdapEntry thisEntry in lsc)
                {
                    System.Console.Write(" - ");
                    System.Console.WriteLine(thisEntry.Dn);

                    ListDetails(thisEntry).Wait();
                } // Next thisEntry 

            } // End Using cnn 

            System.Console.WriteLine(" --- Press any key to continue --- ");
        } // End Sub Main 

        private static string[] GetStringValues(DirectoryAttribute attribute)
        {
            System.Collections.Generic.List<string> ls = new System.Collections.Generic.List<string>();

            foreach (string stringValue in attribute.GetValues<string>())
            {
                ls.Add(stringValue);
            } // Next stringValue 

            string[] arr = ls.ToArray();
            ls.Clear();
            ls = null;

            return arr;
        }

        private static byte[][] GetByteValues(DirectoryAttribute attribute)
        {
            System.Collections.Generic.List<byte[]> ls = new System.Collections.Generic.List<byte[]>();

            foreach (byte[] bytesValue in attribute.GetValues<byte[]>())
            {
                ls.Add(bytesValue);
            } // Next bytesValue 

            byte[][] arr = ls.ToArray();
            ls.Clear();
            ls = null;

            return arr;
        }

        private static readonly uint[] _lookup32 = CreateLookup32();

        private static uint[] CreateLookup32()
        {
            var result = new uint[256];
            for (int i = 0; i < 256; i++)
            {
                string s = i.ToString("X2");
                result[i] = ((uint)s[0]) + ((uint)s[1] << 16);
            }
            return result;
        }

        private static string ByteArrayToHexViaLookup32(byte[] bytes)
        {
            var lookup32 = _lookup32;
            var result = new char[bytes.Length * 2];
            for (int i = 0; i < bytes.Length; i++)
            {
                var val = lookup32[bytes[i]];
                result[2 * i] = (char)val;
                result[2 * i + 1] = (char)(val >> 16);
            }

            return new string(result);
        }

        private static async System.Threading.Tasks.Task ListDetails(
             // System.Text.Json.Utf8JsonWriter jsonWriter,
            LdapEntry thisEntry)
        {

            try
            {
                foreach (DirectoryAttribute attribute in thisEntry.DirectoryAttributes)
                {
                    // jsonWriter.WriteStartObject();

                    string attributeName = attribute.Name;
                    string attributeVal = attribute.GetValue<string>();
                    byte[][] bvs = GetByteValues(attribute);
                    string[] svs = GetStringValues(attribute);

                    try
                    {
                        attributeVal = string.Join(System.Environment.NewLine, GetStringValues(attribute));
                    }
                    catch (System.Exception ex)
                    {
                        System.Console.WriteLine(ex.Message);
                    }

                    // This comes with MS-DirectoryService, but not with Novell-DirectoryService
                    // nTSecurityDescriptor System.__ComObject
                    // if ("nTSecurityDescriptor".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase))
                    // System.Console.WriteLine(attributeName);

                    if (
                        "objectGUID".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                        || "msExchMailboxGuid".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                        || "mS-DS-ConsistencyGuid".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                        || "msDFSR-ReplicationGroupGuid".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                    )
                    {
                        string[] fo = new string[bvs.Length];

                        for (int i = 0; i < bvs.Length; ++i)
                        {
                            fo[i] = new System.Guid(bvs[i]).ToString();
                        }

                        attributeVal = string.Join(System.Environment.NewLine, fo);
                    }
                    else if (System.StringComparer.OrdinalIgnoreCase.Equals(attributeName, "objectSid"))
                    {
                        string[] fo = new string[bvs.Length];

                        for (int i = 0; i < bvs.Length; ++i)
                        {
                            // Windows-only ...
                            // System.Security.Principal.SecurityIdentifier sid = new System.Security.Principal.SecurityIdentifier(bvs[i], 0);
                            // fo[i] = sid.ToString();
                            fo[i] = SidConverter.ConvertSidToString(bvs[i]);
                        }

                        attributeVal = string.Join(System.Environment.NewLine, fo);
                    }
                    else if (
                           "msExchWhenMailboxCreated".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                        || "dSCorePropagationData".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                        || "whenCreated".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                        || "whenChanged".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                    )
                    {
                        try
                        {
                            for (int i = 0; i < svs.Length; ++i)
                            {
                                System.DateTime result = System.DateTime.ParseExact(svs[i], "yyyyMMddHHmmss.0Z", System.Globalization.CultureInfo.InvariantCulture);
                                svs[i] = result.ToString("dd'.'MM'.'yyyy' 'HH':'mm':'ss") + " (" + svs[i] + ")";
                            }

                            attributeVal = string.Join(System.Environment.NewLine, svs);
                        }
                        catch (System.Exception ex)
                        {
                            attributeVal = ex.Message;
                        }

                    }
                    else if (
                        System.StringComparer.OrdinalIgnoreCase.Equals(attributeName, "userCertificate")
                    )
                    {
                        string[] fo = new string[bvs.Length];

                        for (int i = 0; i < bvs.Length; ++i)
                        {
                            System.Security.Cryptography.X509Certificates.X509Certificate cert = new System.Security.Cryptography.X509Certificates.X509Certificate(bvs[i]);
                            fo[i] = cert.ToString();
                        }

                        attributeVal = string.Join(System.Environment.NewLine, fo);
                    }
                    else if (
                           "mSMQSignCertificates".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                        || "mSMQDigest".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                        || "mSMQDigests".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)

                        || "msDS-GroupMSAMembership".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                        || "msDS-ManagedPasswordId".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                        || "ManagedPasswordPreviousId".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                        || "logonHours".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                        || "msExchMailboxSecurityDescriptor".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                        || "msDS-GenerationId".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                        || "msDS-ManagedPasswordPreviousId".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                        || "samDomainUpdates".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                    )
                    {
                        string[] fo = new string[bvs.Length];

                        for (int i = 0; i < bvs.Length; ++i)
                        {
                            fo[i] = "0x" + ByteArrayToHexViaLookup32(bvs[i]);
                        }

                        attributeVal = string.Join(System.Environment.NewLine, fo);
                    }
                    else if (System.StringComparer.OrdinalIgnoreCase.Equals(attributeName, "msExchRemoteRecipientType"))
                    {
                        try
                        {
                            long lngSomeVersion = long.Parse(attributeVal, System.Globalization.CultureInfo.InvariantCulture);

                            string strVersion = lngSomeVersion.ToString();
                            // http://memphistech.net/?p=457
                            // https://blogs.technet.microsoft.com/johnbai/2013/09/11/o365-exchange-and-ad-how-msexchrecipientdisplaytype-and-msexchangerecipienttypedetails-relate-to-your-on-premises/

                            switch (lngSomeVersion)
                            {
                                case 1:
                                    strVersion = "ProvisionedMailbox (Cloud MBX)";
                                    break;
                                case 2:
                                    strVersion = "ProvisionedArchive (Cloud Archive)";
                                    break;
                                case 3:
                                    strVersion = "ProvisionedMailbox, ProvisionedArchive";
                                    // (mailbox provisioned in Cloud & Archive provisioned in Cloud)* either via EMC or new-remotemailbox cmd
                                    break;
                                case 4:
                                    strVersion = "Migrated mailbox from on-prem";
                                    break;
                                case 6:
                                    strVersion = "Migrated mailbox from on-prem, ProvisionedArchive in EXO";
                                    // (mailbox migrated from on-prem & archive provisioned in Cloud)
                                    break;
                                case 16:
                                    strVersion = "DeprovisionArchive";
                                    break;
                                case 20:
                                    strVersion = "DeprovisionArchive, Migrated";
                                    break;
                                case 32:
                                    strVersion = "RoomMailbox";
                                    break;
                                case 36:
                                    strVersion = "Migrated, RoomMailbox";
                                    break;
                                case 64:
                                    strVersion = "EquipmentMailbox";
                                    break;
                                case 68:
                                    strVersion = "Migrated, EquipmentMailbox";
                                    break;
                                case 96:
                                    strVersion = "SharedMailbox";
                                    break;
                                case 100:
                                    strVersion = "Migrated, Shared Mailbox in EXO";
                                    break;
                                default:
                                    strVersion = lngSomeVersion.ToString();
                                    break;
                            }

                            attributeVal = strVersion;
                        }
                        catch (System.Exception ex)
                        {
                            attributeVal = ex.Message;
                        }

                    }
                    else if (System.StringComparer.OrdinalIgnoreCase.Equals(attributeName, "msExchRecipientDisplayType"))
                    {
                        try
                        {
                            long lngSomeVersion = long.Parse(attributeVal, System.Globalization.CultureInfo.InvariantCulture);

                            string strVersion = lngSomeVersion.ToString();
                            // http://memphistech.net/?p=457

                            switch (lngSomeVersion)
                            {
                                case 0:
                                    strVersion = "MailboxUser";
                                    break;
                                case 1:
                                    strVersion = "DistrbutionGroup";
                                    break;
                                case 2:
                                    strVersion = "PublicFolder";
                                    break;
                                case 3:
                                    strVersion = "DynamicDistributionGroup";
                                    break;
                                case 4:
                                    strVersion = "Organization";
                                    break;
                                case 5:
                                    strVersion = "PrivateDistributionList";
                                    break;
                                case 6:
                                    strVersion = "RemoteMailUser";
                                    break;
                                case 7:
                                    strVersion = "ConferenceRoomMailbox";
                                    break;
                                case 8:
                                    strVersion = "EquipmentMailbox";
                                    break;
                                case 1073741824:
                                    strVersion = "ACLableMailboxUser";
                                    break;
                                case 1043741833:
                                    strVersion = "SecurityDistributionGroup";
                                    break;
                                case -2147483642:
                                    strVersion = "SyncedMailboxUser";
                                    break;
                                case -2147483391:
                                    strVersion = "SyncedUDGasUDG";
                                    break;
                                case -2147483386:
                                    strVersion = "SyncedUDGasContact";
                                    break;
                                case -2147483130:
                                    strVersion = "SyncedPublicFolder";
                                    break;
                                case -2147482874:
                                    strVersion = "SyncedDynamicDistributionGroup";
                                    break;
                                case -2147482106:
                                    strVersion = "SyncedRemoteMailUser";
                                    break;
                                case -2147481850:
                                    strVersion = "SyncedConferenceRoomMailbox";
                                    break;
                                case -2147481594:
                                    strVersion = "SyncedEquipmentMailbox";
                                    break;
                                case -2147481343:
                                    strVersion = "SyncedUSGasUDG";
                                    break;
                                case -2147481338:
                                    strVersion = "SyncedUSGasContact";
                                    break;
                                case -1073741818:
                                    strVersion = "ACLableSyncedMailboxUser";
                                    break;
                                case -1073740282:
                                    strVersion = "ACLableSyncedRemoteMailUser";
                                    break;
                                case -1073739514:
                                    strVersion = "ACLableSyncedUSGasContact";
                                    break;
                                case -1073739511:
                                    strVersion = "SyncedUSGasUSG";
                                    break;
                                default:
                                    strVersion = lngSomeVersion.ToString();
                                    break;
                            }

                            attributeVal = strVersion;
                        }
                        catch (System.Exception ex)
                        {
                            attributeVal = ex.Message; ;
                        }
                    }
                    else if (System.StringComparer.OrdinalIgnoreCase.Equals(attributeName, "msExchRecipientTypeDetails"))
                    {
                        try
                        {
                            long lngSomeVersion = long.Parse(attributeVal, System.Globalization.CultureInfo.InvariantCulture);
                            string strVersion = lngSomeVersion.ToString();
                            // http://memphistech.net/?p=457
                            // https://blogs.technet.microsoft.com/johnbai/2013/09/11/o365-exchange-and-ad-how-msexchrecipientdisplaytype-and-msexchangerecipienttypedetails-relate-to-your-on-premises/

                            switch (lngSomeVersion)
                            {

                                case 1:
                                    strVersion = "User Mailbox";
                                    break;
                                case 2:
                                    strVersion = "Linked Mailbox";
                                    break;
                                case 4:
                                    strVersion = "Shared Mailbox";
                                    break;
                                case 8:
                                    strVersion = "Legacy Mailbox";
                                    break;
                                case 16:
                                    strVersion = "Room Mailbox";
                                    break;
                                case 32:
                                    strVersion = "Equipment Mailbox";
                                    break;
                                case 64:
                                    strVersion = "Mail Contact";
                                    break;
                                case 128:
                                    strVersion = "Mail User";
                                    break;
                                case 256:
                                    strVersion = "Mail-Enabled Universal Distribution Group";
                                    break;
                                case 512:
                                    strVersion = "Mail-Enabled Non-Universal Distribution Group";
                                    break;
                                case 1024:
                                    strVersion = "Mail-Enabled Universal Security Group";
                                    break;
                                case 2048:
                                    strVersion = "Dynamic Distribution Group";
                                    break;
                                case 4096:
                                    strVersion = "Public Folder";
                                    break;
                                case 8192:
                                    strVersion = "System Attendant Mailbox";
                                    break;
                                case 16384:
                                    strVersion = "System Mailbox";
                                    break;
                                case 32768:
                                    strVersion = "Cross-Forest Mail Contact";
                                    break;
                                case 65536:
                                    strVersion = "User";
                                    break;
                                case 131072:
                                    strVersion = "Contact";
                                    break;
                                case 262144:
                                    strVersion = "Universal Distribution Group";
                                    break;
                                case 524288:
                                    strVersion = "Universal Security Group";
                                    break;
                                case 1048576:
                                    strVersion = "Non-Universal Group";
                                    break;
                                case 2097152:
                                    strVersion = "Disabled User";
                                    break;
                                case 4194304:
                                    strVersion = "Microsoft Exchange";
                                    break;
                                case 8388608:
                                    strVersion = "Arbitration Mailbox";
                                    break;
                                case 16777216:
                                    strVersion = "Mailbox Plan";
                                    break;
                                case 33554432:
                                    strVersion = "Linked User";
                                    break;
                                case 268435456:
                                    strVersion = "Room List";
                                    break;
                                case 536870912:
                                    strVersion = "Discovery Mailbox";
                                    break;
                                case 1073741824:
                                    strVersion = "Role Group";
                                    break;
                                case 2147483648L:
                                    strVersion = "Remote Mailbox";
                                    break;
                                case 137438953472L:
                                    strVersion = "Team Mailbox";
                                    break;
                                default:
                                    strVersion = lngSomeVersion.ToString();
                                    break;
                            }

                            attributeVal = strVersion;
                        }
                        catch (System.Exception ex)
                        {
                            attributeVal = ex.Message;
                        }

                    }
                    else if (System.StringComparer.OrdinalIgnoreCase.Equals(attributeName, "msExchVersion"))
                    {
                        try
                        {
                            long lngSomeVersion = long.Parse(attributeVal, System.Globalization.CultureInfo.InvariantCulture);
                            string strVersion = "";

                            // http://blogs.metcorpconsulting.com/tech/?p=1313
                            if (lngSomeVersion < 4535486012416L)
                            {
                                strVersion = "Exchange 2003 and earlier (" + lngSomeVersion.ToString() + ")";
                            }
                            else if (lngSomeVersion == 4535486012416L)
                            {
                                strVersion = "Exchange 2007 (4535486012416)";
                            }
                            else if (lngSomeVersion == 44220983382016L)
                            {
                                strVersion = "Exchange 2010 (44220983382016)";
                            }
                            else
                            {
                                strVersion = lngSomeVersion.ToString();
                            }

                            attributeVal = strVersion;
                        }
                        catch (System.Exception ex)
                        {
                            attributeVal = ex.Message;
                        }
                    }
                    else if ("lastLogon".Equals(attributeName, System.StringComparison.InvariantCultureIgnoreCase)
                           || System.StringComparer.OrdinalIgnoreCase.Equals(attributeName, "lastLogoff")
                            || System.StringComparer.OrdinalIgnoreCase.Equals(attributeName, "lastLogonTimestamp")

                            || System.StringComparer.OrdinalIgnoreCase.Equals(attributeName, "pwdLastSet")
                            || System.StringComparer.OrdinalIgnoreCase.Equals(attributeName, "badPasswordTime")
                            || System.StringComparer.OrdinalIgnoreCase.Equals(attributeName, "lockoutTime")

                            || System.StringComparer.OrdinalIgnoreCase.Equals(attributeName, "uSNCreated")
                            || System.StringComparer.OrdinalIgnoreCase.Equals(attributeName, "uSNChanged")

                            || System.StringComparer.OrdinalIgnoreCase.Equals(attributeName, "accountExpires")

                        )
                    {
                        long lngSomeAdTime = long.Parse(attributeVal, System.Globalization.CultureInfo.InvariantCulture);

                        System.DateTime someAdTime = System.DateTime.MaxValue;

                        if (lngSomeAdTime == long.MaxValue || lngSomeAdTime <= 0 || System.DateTime.MaxValue.ToFileTime() <= lngSomeAdTime)
                        {
                            someAdTime = System.DateTime.MaxValue;
                        }
                        else
                        {
                            // someAdTime = System.DateTime.FromFileTime(lngSomeAdTime);
                            someAdTime = System.DateTime.FromFileTimeUtc(lngSomeAdTime).ToLocalTime();
                        }

                        attributeVal = someAdTime.ToString("dd.MM.yyyy HH:mm:ss");
                    }

                    System.Console.Write("   -- ");
                    System.Console.Write(attributeName);
                    System.Console.Write(":\t");
                    System.Console.WriteLine(attributeVal);

                    // jsonWriter.WriteString(attributeName, attributeVal);
                } // Whend 

                // jsonWriter.WriteEndObject();
            }
            catch (System.Exception ex)
            {
                System.Console.WriteLine(ex.Message);
            }

        } // End Task ListDetails

    } // End Class 

} // End Namespace 
Evengard commented 1 year ago

Honestly, I like this library more, it is more easily extensible, doesn't have a dependency on a non-C# library and allows mixing with Kerberos.NET - and as a result authenticating with an already existing Kerberos TGT.

ststeiger commented 1 year ago

@Evengard: Even then, seems to be based on the same base library as Novell. So now you can look at how it's done and port the relevant bits into fully-managed code.