パスワード変更通知システム[Windows]

かつて、私たちの企業情報システムでは、名前がLDAPからインポートされたユーザーの保存されたパスワードをすばやく変更する必要がありました。







従来、企業クライアントは、 Microsoft Forefront Identity Manager(FIM)Oracle Identity ManagerIBM Security Identity Managerなど、事前に構成されたシステムを使用してパスワードを変更していました。



職場で死なず、企業のさまざまな創造性を研究し、xxxIManagersからパスワードの変更を取得しようとするために、新しいパスワードが何らかの形で届くドメインコントローラにすぐに連絡することをお勧めします。



さらに、Microsoft ADサービスでは拡張機能を使用できます。 そして、何人かのカスタマイザーが言うまではすべてうまくいきます-あなたが大規模で有名な国際企業であり、私たちはあなたの機器とソフトウェアを何十年も使用しているのは良いことですが、ADコントローラーを備えたサーバーに湾曲した特別なソフトウェアをインストールしません- ハードコアソリューションのみマイクロソフトから。







このような主な機能は、 パスワード変更通知サービス(PCNS)構成ユーティリティです。 このユーティリティはFIMの一部です。 希望の目標を達成する方法を学び始め、Microsoftからのすべての可能な記事を読み直し、誤解の恐怖で FIMがどのようにインストールしたか読みました。これには、MSSQLを含む数十の依存関係もあるSharePointなどのさまざまな製品への依存関係がありましたサーバー、音声検索、その他多くの不必要で重いソフトウェア。最終的にFIMは2つの基本的なHTMLページであり、それぞれにパスワードをリセットするための基本的なコントロールがいくつかあることを理解します。



そして、これをすべて実現するには、非酸性サーバー(Microsoftはこのために3〜4台のサーバーを推奨)と約1営業日を必要とします。 多くの時間を捨て、インターネットの半分を読み直したところ、Microsoftの見解では少なくとも3つあることに気付きました! パスワードパス:

-IM、DC(xxx識別マネージャーからドメインコントローラー);

-DCへのメールシステム(Exchange / GroupWise / Dominoからドメインコントローラー);

-DC to Mailシステム



これらの極端な多様性を考慮して、私はIMまたはメールシステムに触れたくないので、私が欲しかったものはこのリストに含まれていませんでした。 このパスワードの移動はすべて、FIM同期サービスとハードウェアレベルで渡され、私の怒りすべてに対して、最小構成の1台のサーバーで十分でした。



正式には、FIMSSは、あらゆるものと(当然、合理的な制限内で)あらゆるものの自動化されたデータ同期のための高度な環境であり、DC用の既製のエージェントおよび既知のすべてのメールエージェント、そしてもちろん多くのユーザー拡張機能を備えています。



マイクロソフトは、非常にわかりにくい手順ガイドをいくつか提供していますが、そのように金髪を路上から追い出すのは簡単ではありません。さらに、私が考えているように、 単純に必要なものでもありません。 拡張プロジェクトの例で多くの苦しみがあり、必要な結果が得られなかったため、適切な解決策を探して再びGoogleに注目しました。 (恐らく私は再びひどく見ていました)バシアンの男の子が何かをし 、それが機能する例(彼の言葉から)! 最も重要なことは、Googleに正しいコードワードIMAPasswordManagementを供給することです。



一般に、特定の方向に魔法のペンデルを受け取ったので、私はすぐに同様の構成をセットアップしました。なぜ同じような構成になったのですか?これを繰り返した後、十分になるまで機能しなかったため、パスワード送信の基本原理が科学的に突くことによってどのように機能するかを理解していませんでした



パスワードがC#で記述されたコードに届き、そこで必要なことを行うためにスポーツをすることができます-必要です:



1. FIM同期サービスをインストールして、パスワードを同期する機能を設定します。





MVExtension.DLLおよびユーザー同期エージェントは、FIMSSから直接生成されます(C#またはVB.NETのテキスト)。



RPCサービスを有効にする必要があります( パスワード変更通知サービス(PCNS)構成ユーティリティとの通信に使用)。



2.エージェントをFIMSS 2に挿入します-両方とも既に準備ができています:







すべてのエージェントには、インポート、エクスポート、同期という3つの主要なプロパティがあります。 この例では、インポートと同期の2つで十分です。

なぜ-私は後で言います。



1. DCAgent:DCからユーザーのリストをインポートします

2. RNAgent:独自の企業サービスからユーザーのリストをインポートします(同じユーザーの縮小リスト、つまり名前で一致-エージェントはLDAPから取得した名前のみを受け取ります)。 このエージェントは、SQLエージェントに基づいて作成されます(つまり、MSSQLからデータ(ユーザーのリスト)を受け取ります)



簡単な紹介です-パスワードは、両方のエージェントの名前が名前で一致する場合にのみ送信されます。

これを実現するために、FIMSSエージェントにはプロファイルが構成されており、プロファイルは必要なコマンド(最初のインポート、次に同期)で起動されます。



内部では、FIMSSはすべてをMSSQLデータベースに保持します。ソフトウェアのリストの制限について心配する必要がない場合は、DCAgentによってリストが作成された内部FIMSSテーブルからユーザーのリストを直接読み取ることをお勧めします[FIMSynchronizationService]からのaccountName。[dbo]。[mms_metaverse]:







別の方法は、ホームベースからユーザーのリストを直接読み取ることですが、ここでは、アクセス権も制限されていたため、すべてのデータをひどい力で暗号化するdllを使用しました。



エージェントの設定も簡単なことではなく、おそらく別の記事が必要になるでしょうが、Microsoftの記事にはそのようなものはありません。 非常に重要ないくつかのポイントのみを示します。



1. RNAgentがパスワード拡張機能(C#テキストもFIMSSから生成されます)をヤンクできるように、指定する必要があります。







このメソッドでは、アカウント名とパスワードをクリアな形式で取得し、C ++ DLLからメソッドを呼び出して、結果を暗号化し、RESTサービスを企業サーバーに渡します。 ビンゴ



public void SetPassword( CSEntry csentry, string NewPassword ) { Log(String.Format("SetPassword entered: [{0}] is : [{1}]", csentry.DN.ToString(), NewPassword)); UNICODE_STRING User = InitLsaString(csentry.RDN); UNICODE_STRING Pwd = InitLsaString(NewPassword); SendPasswordToMyServer(User, Pwd); }
      
      







2. DCAgent:パスワードの受け渡し先を示します





エージェントが作成された後、インポートと同期が定期的に行われるように、誰かがそれらをキックする必要があります。 1日1回で十分であることがわかりましたが、わずか5分でできます。 主な問題は、数万人の従業員を抱える大企業では、DCインポートに非常に長い時間がかかる場合があるため、通常のインポートにはフルインポートよりもデルタインポートを使用することをお勧めします。 マイクロソフトは、 タスクスケジューラを使用して、次のソリューションプルプロファイルを提供しています。

リンクをたどると、プロファイル作成ダイアログで、スケジュールに従って実行できるC#/ VBを生成できることがわかります。



誰かにとっては、これで十分ですが、タスクを複雑にし、標準のMicrosoftツールを使用せずに暗号化されたチャネルを介してリモートサーバーからユーザーのリストを転送することにしました。



つまり、同じマシン上で、タイマーでxmlを読み取り、デコードしてデータベースプレートに貼り付け、RNAgentが既に読み取るC#Windowsサービスを使用します。



プライマリサービスコード
  protected bool Process() { IntPtr ptrUserList = new IntPtr(); bool result = false; try { ptrUserList = GetUserList(); string userList = StringFromNativeUtf8(ptrUserList); int cnt_imported = -1; result = SaveAccounts(userList, ref cnt_imported); // LDAP users will appear in [RNService].[dbo].[CoreAccount] result = result ? DCAgent(m_dcagent_guid) : false; // sync users from DC result = result ? RNAgent(m_rnagent_guid) : false; // sync users from [RNService].[dbo].[CoreAccount] eventLogRN.WriteEntry("Imported users: " + cnt_imported ); } catch (Exception ex) { eventLogRN.WriteEntry("Process: " + ex.Message, EventLogEntryType.Error); return false; } DisposeUserList(ptrUserList); m_timer.Interval = m_servicePollInterval; // use interval from registry return result; } public bool SaveAccounts(string userList, ref int cnt_imported) { string con_str = @"Data Source=" + m_serverName + ";Initial Catalog=RNService;Integrated Security=True"; cnt_imported = -1; using (SqlConnection cnn = new SqlConnection(con_str)) { cnn.Open(); using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = cnn; cmd.CommandType = CommandType.Text; cmd.CommandText = "TRUNCATE TABLE CoreAccount;" + " INSERT INTO CoreAccount SELECT XCvalue(N'@name', N'nvarchar(448)') FROM " + " (SELECT @data AS XML_DATA) DATA CROSS APPLY DATA.XML_DATA.nodes(N'/response/users/user') as X(C); " + " SELECT @@ROWCOUNT AS usercnt; "; cmd.Parameters.Add("@data", SqlDbType.Xml); try { cmd.Parameters[0].Value = userList; SqlDataReader SqlDataReader = cmd.ExecuteReader(); if (!SqlDataReader.IsClosed && SqlDataReader.HasRows) { if( SqlDataReader.Read() ) { cnt_imported = SqlDataReader.GetInt32(0); } } } catch (Exception ex) { eventLogRN.WriteEntry("UpdateCoreAccounts: " + ex.Message, EventLogEntryType.Error); cnn.Close(); return false; } } cnn.Close(); return true; } }
      
      











同じサービスで、生成したエージェントのプロファイルを取得します。これにより、TASK SCHEDULERによる顧客の苦痛を軽減できます。

私の場合、彼らは単にスクリプトからプロファイルガイドを削除し、それらを登録簿に入れます。



  public bool Agent(string agentName, string guid) { if (guid == null_guid) { return true; // required manual syncronization } try { ConnectionOptions opt = new ConnectionOptions(); opt.Authentication = AuthenticationLevel.PacketPrivacy; ManagementScope myScope = new ManagementScope("root\\MicrosoftIdentityIntegrationServer", opt); string sQuery = "GUID='{" + guid + "}'"; SelectQuery myQuery = new SelectQuery("MIIS_ManagementAgent", sQuery); ManagementObjectSearcher searcher = new ManagementObjectSearcher(myScope, myQuery); foreach (ManagementObject ma in searcher.Get()) { eventLogRN.WriteEntry(agentName + ".Execute( \"ImportSync\" )..."); ma.InvokeMethod("Execute", new object[1] { "ImportSync" }); } } catch (Exception ex) { eventLogRN.WriteEntry( ex.Message, EventLogEntryType.Error); } return true; }
      
      






All Articles