2012-09-26 22 views
28

.NET 4.5アプリケーションを.NET 4.5でテストすると、メソッドの問題がUserPrincipalに発生しました。次のコードは、.NET 4.0ランタイムで実行したときに動作しますが、.NET 4.5の下で失敗します。ここでは.NET 4.5 UserPrincipal.FindByIdentity(System.DirectoryServices.AccountManagement)のバグ

[Test] 
public void TestIsAccountLockedOut() 
{ 
    const string activeDirectoryServer = "MyActiveDirectoryServer"; 
    const string activeDirectoryLogin = "[email protected]"; 
    const string activeDirectoryPassword = "MyADAccountPassword"; 
    const string userAccountToTest = "[email protected]"; 
    const string userPasswordToTest = "WRONGPASSWORD"; 

    var principalContext = new PrincipalContext(ContextType.Domain, activeDirectoryServer, activeDirectoryLogin, activeDirectoryPassword); 

    var isAccountLockedOut = false; 
    var isAuthenticated = principalContext.ValidateCredentials(userAccountToTest, userPasswordToTest, principalContext.Options); 
    if (!isAuthenticated) 
    { 
     // System.DirectoryServices.AccountManagement.PrincipalOperationException : Information about the domain could not be retrieved (1355). 
     using (var user = UserPrincipal.FindByIdentity(principalContext, IdentityType.UserPrincipalName, userAccountToTest)) 
     { 
      isAccountLockedOut = (user != null) && user.IsAccountLockedOut(); 
     } 
    } 
    Assert.False(isAuthenticated); 
    Assert.False(isAccountLockedOut); 
} 

は、例外スタックトレースです:

System.DirectoryServices.AccountManagement.PrincipalOperationException : Information about the domain could not be retrieved (1355). 
at System.DirectoryServices.AccountManagement.Utils.GetDcName(String computerName, String domainName, String siteName, Int32 flags) at System.DirectoryServices.AccountManagement.ADStoreCtx.LoadDomainInfo() at 
System.DirectoryServices.AccountManagement.ADStoreCtx.get_DnsDomainName() at System.DirectoryServices.AccountManagement.ADStoreCtx.GetAsPrincipal(Object storeObject, Object discriminant) at 
System.DirectoryServices.AccountManagement.ADStoreCtx.FindPrincipalByIdentRefHelper(Type principalType, String urnScheme, String urnValue, DateTime referenceDate, Boolean useSidHistory) at 
System.DirectoryServices.AccountManagement.ADStoreCtx.FindPrincipalByIdentRef(Type principalType, String urnScheme, String urnValue, DateTime referenceDate) at 
System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithTypeHelper(PrincipalContext context, Type principalType, Nullable`1 identityType, String identityValue, DateTime refDate) at 
System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithType(PrincipalContext context, Type principalType, IdentityType identityType, String identityValue) at 
System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity(PrincipalContext context, IdentityType identityType, String identityValue) 

は、誰が見て、この問題を解決しましたか?そうでない場合は、IsAccountLockedOutのActive Directoryアカウントのステータスを確認する良い方法がありますか?

参考までに、すべてのテストマシンは同じサブネット内にあります。さまざまなドメイン機能モード(下記参照)で、Windows Server 2003、2008および2012を実行する別々のActive Directoryサーバーがあります。このコードは.NET 4.0を実行しているマシンからは動作しますが、.NET 4.5を実行しているマシンでは動作しません。私たちはからコードを実行した

3 .NETマシンは以下のとおりです。
- Windows 7の.NET 4.0
を実行している - .NET 4.5
を実行しているWindows Vistaの - のWindows Server 2012は、.NET 4.5

アクティブを実行しています私たちが試したディレクトリサーバーは、
- ADドメイン機能モードをWindows 2000ネイティブに設定した場合
- ADドメイン機能モードをWindows Server 2003に設定したWindows 2003
- ADドメイン機能モードのWindows 2008 Windowsの2012

に設定ADドメインの機能モードでWindows 2012 - Windows Server 2008の
に設定ADドメインの機能モードでWindows 2008 - Windows Server 2003で
に設定ADドメインの機能モードでのWindows 2008 - Windows 2000のネイティブ
へら

これらのActive Directoryサーバーはすべてシンプルな単一のフォレストとして構成され、クライアントマシンはドメインの一部ではありません。この動作をテストする以外の機能は使用されず、Active Directory以外は実行されません。


EDIT - 答えた皆様に2012年10月9日

感謝。以下は、問題を示すC#コマンドラインクライアントと、Active DirectoryおよびDNS構成について何も変更する必要のない短期的な回避策です。例外は、PrincipalContextのインスタンスで1回だけスローされたようです。 .NET 4.0マシン(Windows 7)と.NET 4.5マシン(Windows Vista)の出力を含めました。

using System; 
using System.DirectoryServices.AccountManagement; 

namespace ADBug 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      const string activeDirectoryServer = "MyActiveDirectoryServer"; 
      const string activeDirectoryLogin = "MyADAccount"; 
      const string activeDirectoryPassword = "MyADAccountPassword"; 
      const string validUserAccount = "[email protected]"; 
      const string unknownUserAccount = "[email protected]"; 

      var principalContext = new PrincipalContext(ContextType.Domain, activeDirectoryServer, activeDirectoryLogin, activeDirectoryPassword); 

      // .NET 4.0 - First attempt with a valid account finds the user 
      // .NET 4.5 - First attempt with a valid account fails with a PrincipalOperationException 
      TestFindByIdentity(principalContext, validUserAccount, "Valid Account - First Attempt"); 
      // Second attempt with a valid account finds the user 
      TestFindByIdentity(principalContext, validUserAccount, "Valid Account - Second Attempt"); 
      // First attempt with an unknown account does not find the user 
      TestFindByIdentity(principalContext, unknownUserAccount, "Unknown Account - First Attempt"); 
      // Second attempt with an unknown account does not find the user (testing false positive) 
      TestFindByIdentity(principalContext, unknownUserAccount, "Unknown Account - Second Attempt"); 
      // Subsequent attempt with a valid account still finds the user 
      TestFindByIdentity(principalContext, validUserAccount, "Valid Account - Third Attempt"); 
     } 

     private static void TestFindByIdentity(PrincipalContext principalContext, string userAccountToTest, string message) 
     { 
      var exceptionThrown = false; 
      var userFound = false; 
      try 
      { 
       using (var user = UserPrincipal.FindByIdentity(principalContext, IdentityType.UserPrincipalName, userAccountToTest)) 
       { 
        userFound = (user != null); 
       } 
      } 
      catch (PrincipalOperationException) 
      { 
       exceptionThrown = true; 
      } 
      Console.Out.WriteLine(message + " - Exception Thrown = {0}", exceptionThrown); 
      Console.Out.WriteLine(message + " - User Found = {1}", userAccountToTest, userFound); 
     } 
    } 
} 

.NET 4.0出力

Valid Account - First Attempt - Exception Thrown = False 
Valid Account - First Attempt - User Found = True 
Valid Account - Second Attempt - Exception Thrown = False 
Valid Account - Second Attempt - User Found = True 
Unknown Account - First Attempt - Exception Thrown = False 
Unknown Account - First Attempt - User Found = False 
Unknown Account - Second Attempt - Exception Thrown = False 
Unknown Account - Second Attempt - User Found = False 
Valid Account - Third Attempt - Exception Thrown = False 
Valid Account - Third Attempt - User Found = True 

.NET 4.5出力

Valid Account - First Attempt - Exception Thrown = True 
Valid Account - First Attempt - User Found = False 
Valid Account - Second Attempt - Exception Thrown = False 
Valid Account - Second Attempt - User Found = True 
Unknown Account - First Attempt - Exception Thrown = False 
Unknown Account - First Attempt - User Found = False 
Unknown Account - Second Attempt - Exception Thrown = False 
Unknown Account - Second Attempt - User Found = False 
Valid Account - Third Attempt - Exception Thrown = False 
Valid Account - Third Attempt - User Found = True 
+1

あなたがこれをまだGoogleで検索しているかどうかはわかりませんが、さまざまなシーンの修正に関するコメントがある投稿がありますこれが原因かもしれない:http://elegantcode.com/2009/03/21/one-scenario-where-the- systemdirectoryservices-accountmanagement-api-falls-down/私はそれを自分で見たことがないが、興味のある役に立ったと思ったので、私はこのことを分かりやすいと思った。 – David

+0

たとえば、DCとCNで渡してみましたか? PrincipalContext ctx =新しいPrincipalContext( ContextType.Domain、 "fabrikam.com"、 "CN =ユーザー、DC = fabrikam、DC = com"、 "administrator" 、 "securelyStoredPassword"); – MethodMan

+0

DJ、CN&DC文字列を渡してみましたが、それでも.NET 4.0では動作し、.NET 4.5では失敗します。 –

答えて

12

我々は(クロスドメインのクエリは、4.5へのアップデートに失敗)正確に同じ問題が発生している - 私は考えるだろうこれは既存の(4.0)コードを破るので、これはバグです。

しかし、それが動作することの利益のために - 顧客を失敗(今)の1を見てみると、私は、フォームの、失敗したSRVレコードのDNS要求の束があったことに気づい:

_ldap._tcp.MYSERVER1.mydomain.com,INet,Srv 
_ldap._tcp.dc._msdcs.mydomain.com,INet,Srv 

ドメイン上のいずれかのDCへのすべてのmydomain.comトラフィックに対して、私たちのDNSサーバー(障害のあるクライアントが使用するDNS)を変更しても問題は解決しました。

nslookupを使用すると、前回(失敗時)から今すぐ(動作中)までの動作は、これらのクエリが「存在しないドメイン」を返す前の動作でしたが、今では「* SRV以下のために利用可能 ..."。失敗のポイントは、SRVレコードを失うのではなく、ドメインが認識されていないように見えます。うまくいけば、MSはこの動作を元に戻しますが、その間に失敗したクライアントのDNSを制御できるならば、DNS転送ゾーンを作成することができます。

5

私たちには、同じ問題がありました(回答を助けてくれた他の人)。私たちの開発環境では、インストールされたVS2012とアプリケーションは、ログイン時に実行時に破損しました(上記のAD問題)。だから私は自分のシステムを拭き取り、2010年を使い続けました。毎回、Idが新しいブログ投稿を読んで毎年涙を流しながら、素晴らしい2012年が何とかなるのです。

だから、このスレッドはScott Hanselmanに感謝しました。私は自分の開発ボックスにVMをインストールしました.Windows 8の開発者は90日のプレビューとVS2012をインストールしました。私たちのアプリケーションを起動して実行し、すぐにログインADにぶつかった。試しにFindByIdentityをラップし、最初のキャッチ後にもう一度試してみましょう。その小さなトリックを見つけた人に感謝!

これはマイナーな修正と、地元の開発に役立つ「ハック」なので、すぐに生産に4.5を投入しているわけではないので、生産に影響を与えるべきではありません。

しかし、欠点は、我々は2010年の下で実行したときにローカルで、今でログインすると、秒対2分のようにかかることである:(

私は本当に私が実際に事態を解決しようとする提供することができます他に何かわかりません

+3

フィードバックいただきありがとうございます。同じ動作を確認し(最初の試行は失敗し、それ以降はすべて成功します)、上記のテストクライアントを投稿しました。 Microsoftから受け取った最後のフィードバックは、次のとおりです。_ "Net4.5のSDS.AMには、クライアント側でドメインDNS解決が必要な制限が追加されました。これは、DNSのベストプラクティスが正しいDNSエントリを持つように設計されています。フォーラムからのフィードバックは、将来のリリースで制限を取り除くことを検討しています。」_ –

+0

ありがとう!私が気づいたことの1つは、最初の試行失敗を追加した後に、ADへの呼び出しでもかなりの遅延が3分以上かかることです。この種の問題を解決するために追加できるローカルホストへのエントリがありますか?フィードバックに感謝します。 – jkat98

+0

これが関連しているかどうかはわかりませんが、サーバーのIPアドレス(192.168.14.3など)の代わりにホスト名(たとえばmyserverなど)を使用すると、パフォーマンス上の問題が常に顕著になっています。私たちはこの問題のtry-catch回避策のパフォーマンステストを行っていませんが、テストケースを一緒に投げて、どのような数字が出てくるかを見ていきます。 –

0

4.0から4.5への.netフレームワークのアップグレード後に同じ問題が発生しました 私はフレームワークを.net 4.5.1にアップグレードしていました。

関連する問題