简体   繁体   English

从ASP.NET应用程序查询Active Directory对象属性将返回旧结果

[英]Querying an Active Directory object property from ASP.NET application returns old results

For quite a few days now I have been trying to get some custom Active Directory based authentication to work. 几天以来,我一直在尝试使一些基于Active Directory的自定义身份验证起作用。 It all works in theory but apparently my theory is wrong. 这一切都在理论上起作用,但显然我的理论是错误的。 Users who are logged on to a domain write a string token (eg PIN code) to their own property field in Active Directory (doesn't really matter which one, but I used primaryInternationISDNNumber for this) upon logging on to the ASP.NET application This PIN is always generated and written programmatically. 登录到域的用户在登录ASP.NET应用程序时,将字符串令牌(例如PIN码)写入Active Directory中自己的属性字段(这并不重要,但是我使用primaryInternationISDNNumber )。始终以编程方式生成和写入此PIN。

To explain it roughly, the web browser loads a Java applet which then loads a native DLL written in C++, which generates and writes the PIN to current user's Active Directory field. 粗略地解释一下,Web浏览器将加载Java小程序,然后再加载用C ++编写的本机DLL,该DLL将PIN写入当前用户的Active Directory字段中。 That DLL then returns the generated PIN to the applet which then passes it to the browser, which performs an AJAX call with the data returned to initiate the authentication. 然后,该DLL将生成的PIN返回给applet,然后将其传递给浏览器,该浏览器对返回的数据执行AJAX调用以启动身份验证。 The application, which has got access to the AD, reads this field value for the connecting user object and checks if it matches with the one the user supplied. 有权访问AD的应用程序读取连接用户对象的该字段值,并检查其是否与用户提供的值匹配。 If PIN codes match, the user is successfully authenticated. 如果PIN码匹配,则表明用户已成功通过身份验证。

This is the sample code the ASP.NET application used to read the AD: 这是ASP.NET应用程序用于读取AD的示例代码:

        using (var de = new DirectoryEntry("LDAP://" + domainName))
        {
            using (var adSearch = new DirectorySearcher(de))
            {
                // Get user from active directory.
                adSearch.Filter = "(sAMAccountName=" + userName.Trim().ToLower(CultureInfo.CurrentCulture) + ")";
                var adSearchResult = adSearch.FindOne();
                var entry = adSearchResult.GetDirectoryEntry();
                var pinCodeProp = entry.Properties["primaryInternationISDNNumber"];
                return pinCodeProp != null ? pinCodeProp.Value : string.Empty;
            }
        }

This works fine, often. 通常,这很好。 But often is not acceptable. 但是通常是不能接受的。 It needs to always be working. 它需要一直在工作。

The trouble is that the ASP.NET application sometimes gets the value which was previously in that field, not the actual value. 问题在于ASP.NET应用程序有时会获取该字段中先前的值,而不是实际值。 As if there is some kind of caching. 好像有某种缓存。 I have tried to add de.UsePropertyCache = false but that yielded the same results. 我尝试添加de.UsePropertyCache = false但结果相同。

I have created two Win32 console applications for test purposes. 我已经创建了两个Win32控制台应用程序用于测试。 One writes the PIN code, the other reads the PIN code. 一个写PIN码,另一个读PIN码。 They always work fine! 他们总是很好!

I thought, this gotta be some problem with IIS application pool. 我以为,这一定是IIS应用程序池出现的问题。 So I have created a native DLL which gets loaded by the ASP.NET application using Platform Invoke. 因此,我创建了一个本机DLL,它可以使用Platform Invoke由ASP.NET应用程序加载。 This DLL creates a new thread, calls CoInitialize and reads the PIN code. 该DLL创建一个新线程,调用CoInitialize并读取PIN码。 This is the code: 这是代码:

    pszFqdn = argv[1];
    pszUserName = argv[2];
    pszPassword = argv[3];

    IADs *pObject = NULL;
    HRESULT hr = S_OK;

    hr = CoInitialize(NULL);
    if (SUCCEEDED(hr))
    {
        hr = ADsOpenObject(pszFqdn, pszUserName, pszPassword, ADS_SECURE_AUTHENTICATION, IID_IADs, (LPVOID*)&pObject);

        if (SUCCEEDED(hr) && pObject)
        {
            VARIANT var;
            VariantInit(&var);

            hr = pObject->Get(CComBSTR("primaryInternationalISDNNumber"), &var);
            if ((SUCCEEDED(hr) && var.bstrVal) || hr == 0x8000500d)
            {
                if (hr != 0x8000500d)
                {
                    // convert the BSTR received to TCHAR array
                    std::wstring wsValue(var.bstrVal, SysStringLen(var.bstrVal));
                    // copy the received value to somewhere
                    // ... not relevant
                }

                VariantClear(&var);
            }

            pObject->Release();
        }
    }

    CoUninitialize();

To my tremendous and unpleasant surprise, this code after a day of working properly, started returning the previous values, just like the managed code before! 令我感到极大和不愉快的是,经过一天的正常工作,该代码开始返回以前的值,就像之前的托管代码一样!

So now I thought, alright, I wasn't able to escape the IIS application pool and since this gotta be a problem with IIS application pool, I will create a native Windows application which I will execute by using Process.Start method. 所以现在我想,好的,我无法逃脱IIS应用程序池,并且由于这一定是IIS应用程序池的问题,因此我将创建一个本机Windows应用程序,将使用Process.Start方法执行该应用程序。 I will return my PIN code by means of process exit code (since it's an integer anyway). 我将通过进程退出代码返回PIN码(因为它始终是整数)。 The application uses the similar C++ code as the DLL above. 该应用程序使用与上面的DLL类似的C ++代码。

So I start my application, wait for it to finish, read the exit code. 因此,我启动了我的应用程序,等待它完成,阅读退出代码。 Returns the bad value! 返回错误值!

But okay, I'd say, the process is started using the current user credentials, which is again IIS application pool. 但是好吧,我要说的是,该过程是使用当前的用户凭据启动的,该凭据又是IIS应用程序池。 So I start the application under different credentials. 因此,我以不同的凭据启动该应用程序。 And guess what..... it returns the old value again (?!?!?!). 猜猜是什么.....它再次返回旧值(?!?!!?!)。

And I thought Java was hell... Anyone has got any idea about what could possibly be going on here? 我以为Java真是个地狱...任何人对这里可能发生的事情一无所知?

It was the replication indeed. 确实是复制。 As I didn't want to force the replication before reading the field (that would have been a time-expensive operation probably anyway), I came to an idea to read this field from each domain controller and check if any of them matches with the value supplied. 由于我不想在读取该字段之前强制进行复制(无论如何这可能都是耗时的操作),因此我想到了从每个域控制器读取该字段并检查它们是否与该域控制器匹配的想法。提供的价值。

As it might prove helpful to someone, I did that using the following code. 因为它可能对某人有用,所以我使用以下代码做到了这一点。

        var ctx = new DirectoryContext(
            DirectoryContextType.DirectoryServer,
            ipAddress,
            userName, // in the form DOMAIN\UserName or else it would fail for a remote directory server
            password);
        var domain = Domain.GetDomain(ctx);
        var values = new List<string>();
        foreach (DomainController dc in domain.DomainControllers)
        {
            using (var entry =
                    new DirectoryEntry(
                        "LDAP://" + dc.IPAddress,
                        userName,
                        password))
            {
                using (var search = new DirectorySearcher(entry))
                {
                    search.Filter = "(&(primaryInternationalISDNNumber=*)(sAMaccountName=" + userName + "))";
                    var result = search.FindOne();
                    var de = result.GetDirectoryEntry();
                    if (de.Properties["primaryInternationalISDNNumber"].Value != null)
                    {
                        values.Add(de.Properties["primaryInternationalISDNNumber"].Value.ToString());
                    }
                }
            }
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从 ASP.NET 应用程序连接到 Azure Active Directory - Connecting to Azure Active Directory from ASP.NET application 在旧的Asp.net网站上对Active Directory Azure进行身份验证 - Authentification Active Directory Azure on an old Asp.net WebSite 没有Active Directory的来自ASP.NET应用程序的Office365 SSO - Office365 SSO from ASP.NET application with no Active Directory 如何通过交互式提供凭据从 asp.net web forms 应用程序连接到 Azure Active Directory? - How to connect to Azure Active Directory from asp.net web forms application by providing credentials interactively? 如何从ASP.NET C#应用程序中筛选Active Directory中的特定组 - How to filter a specific group in Active Directory from asp.net c# application ASP.NET错误从Active Directory获取用户详细信息 - ASP.NET error getting user details from Active Directory 如何从asp.net中的活动目录中删除用户帐户 - how to remove user account from active directory in asp.net 从ASP.net App访问Active Directory - Accessing Active Directory from ASP.net App 从 .NET 中的桌面应用程序读取和写入 Active Directory 中的“uid”属性 - Read and write "uid" property in Active Directory from a desktop application in .NET 使用linq查询ASP.NET表单对象 - Querying the ASP.NET form object with linq
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM