2008年12月26日金曜日

ActiveDirectoryへのパスワード変更をフックする

IdM案件をやっていると、どうしても出てくるのがパスワード同期のお話。
基本的にIdM側のパスワード変更画面を使ってもらうのがベターなのですが(システム構造的にも、機能面でも)、中にはやっぱりCTRL+ALT+DELでのパスワード変更がやめられない!というユーザさんもいらっしゃるのかと。

恐らくそのような要件を満たすためにパッケージベンダ各社はいろいろな努力をしていると思います。
例えば、
・Microsoft(Identity Lifecycle Manager 2007)
・SunMicrosystems(Sun Java System Identity Manager):
・SAP(NetWeaver Identity Management)
・エクスジェン・ネットワークス(LDAP Manager)
などではActiveDirectoryへのパスワード変更をIdM側へ取り込む機能を実装してきています。
※ILM"2"でのクライアント側へのモジュールインストールは反則かと・・・

今回はそのあたりの仕掛け(どうなっているのか?)をひも解いてみようと思います。
まず、Windowsのパスワード変更の仕組みを整理します。

ユーザからのパスワード変更要求があると、
1.Local Security Authority(LSA)が要求を受け付ける
2.レジストリに登録されているパスワードフィルタDLLでパスワード検査を行う
3.検査をパスしたらSecurity Account Manager(SAM)にパスワードを保管する
4.正常に保管できたらレジストリに登録されているパスワードフィルタDLLに変更通知を行う
という流れでパスワードが変更されます。













それぞれのプロセスを細かく見ていくと、以下のような流れになっています。

1.Local Security Authority(LSA)が要求を受け付ける
  lsass.exeというサービスプロセスが要求を受け付けます。

2.レジストリに登録されているパスワードフィルタDLLでパスワード検査を行う
  以下のレジストリに登録されているDLLに実装されているPasswordFilter()が順番に呼び出され、パスワードポリシーのチェックなどのフィルタリング処理が行われます。

  [レジストリエントリ]
  HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Notification Packages











  この関数がFALSEを返すとその時点でパスワードポリシー違反としてユーザへ通知されます。







3.検査をパスしたらSecurity Account Manager(SAM)にパスワードを保管する
  これは文字通りアカウントDBへのデータ更新です。

4.正常に保管できたらレジストリに登録されているパスワードフィルタDLLに変更通知を行う
  これも2と同じく各DLLのPasswordChangeNotify()が呼び出されます。


最後のPasswordChangeNotify()の引数に対象ユーザのユーザ名とクリアテキストのパスワードがわたってくるのを利用して、あたかもActiveDirectoryのパスワードを吸い出しているような動きに見せている、というのが各IdM製品の実際の仕掛けです。(たぶん)
また、この動きを見るとわかりますが、あくまでlsass.exeがローカルのDLLに実装された関数を使うので、パスワード変更要求を受け付けるコンピュータ上にフィルタを配置する必要があります。
つまり、ローカルユーザのパスワードをフックする場合はローカルコンピュータ上に、ActiveDirectoryユーザの場合はすべてのドメインコントローラ上に配置する必要があります。

※ちなみに2のPasswordFilter()の引数にもユーザ名とパスワードはわたってきますが、実際にパスワードが更新される前ですし、他のライブラリを使ったパスワードポリシーチェックが完了していないのでこの段階で吸い出してもあまり意味がありません。


ということで、実際の動きをみるためにもDLLを実装してみました。(久しぶりにベタベタなアンマネージコードを書いたので恥ずかしいのですが・・・)

開発環境は、
・OS/AD:Windows Server 2003 R2
・開発ツール:Visual Studio 2005/VC++
です。

ビルドし、出来たDLLをC:\Windows\system32(%systemroot%\system32)以下にコピーし、上記のレジストリに出来上がったDLLの拡張子を除いたファイル名を登録してシステムを再起動すると配置完了です。
上手くいけばパスワードを変更するとCドライブ直下に「PasswordChangeLog.txt」というファイルが出来上がります。
中身は、
 sAMAccountName=変更したユーザ名,unicodePwd=新しいパスワード
という形で、パスワード変更がどんどん記録されていきます。
※悪用厳禁ですね。。。

以下、実際のコードです。

■PasswordHook.cpp

#include
#include
#include

#define LOGFILE "C:\\PasswordChangeLog.txt"

#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif

//
// ログ出力
//
void WriteToLog(const char* str)
{
 if (NULL == str)
 {
  return;
 }
 FILE* log;
 log = fopen(LOGFILE, "a+");
 if (NULL == log)
 {
  return;
 }
 fprintf(log, "%s\r\n", str);
 fclose(log);
 return;
}

//
// パスワードの変更・保管に成功した際に呼び出される
//
NTSTATUS NTAPI PasswordChangeNotify(
  PUNICODE_STRING UserName,
  ULONG RelativeId,
  PUNICODE_STRING NewPassword
)
{
 int nLen=0;

 // 文字列変換(ワイド文字列→マルチバイト文字列)
 // UserName
 nLen = wcslen(UserName->Buffer)+1;
 LPSTR username = (LPSTR)malloc(nLen * sizeof(CHAR));
 ZeroMemory(username,nLen);
 wcstombs(username, UserName->Buffer, nLen);

 // NewPassword
 nLen = wcslen(NewPassword->Buffer)+1;
 LPSTR password = (LPSTR)malloc(nLen * sizeof(CHAR));
 ZeroMemory(password,nLen);
 wcstombs(password, NewPassword->Buffer, nLen);

 // 記録用文字列生成
 LPSTR LogEntry = (LPSTR)malloc(strlen(username)+strlen(password)+28);
 ZeroMemory(LogEntry,sizeof(LogEntry));
 sprintf(LogEntry,"sAMAccountName=%s,unicodePwd=%s",username,password);
 WriteToLog(LogEntry);

 return STATUS_SUCCESS;
}

//
// パスワード変更要求があった際に呼び出される
// パスワードポリシー等のフィルタがある場合はここに記載する
//
BOOL NTAPI PasswordFilter(
  PUNICODE_STRING AccountName,
  PUNICODE_STRING FullName,
  PUNICODE_STRING Password,
  BOOLEAN SetOperation
)
{
 return TRUE;
}

//
// DLLロード時に呼び出される(lsass.exeより呼び出される)
//
BOOL NTAPI InitializeChangeNotify(void)
{
 return TRUE;
}


■PasswordHook.def

LIBRARY "PasswordHook"

EXPORTS
 InitializeChangeNotify
 PasswordChangeNotify
 PasswordFilter

2008年12月18日木曜日

ILM"2" RC0環境構築「同期ルール設定編その3~OSR」(12/28 追記)

さて、前回はCSVファイルからILM"2"へのユーザの取り込み設定を行いましたが、今回はCSVから取り込んだユーザをActive Directoryへ同期してみます。また、同時にILM"2"ポータル上でユーザ情報を編集した場合もCSVファイル上のユーザ情報と合わせてActive Directoryへ同期できるようにします。

1.Identity Lifecycle Manager用MAの設定
 前回のISR設定時に定義したILMSDB MAに逆方向(ILM"2" ポータル上で作成したユーザもMetaverseに取り込みたいので)の属性フローを設定します。 ただ、RC0では既存のMAのプロパティを変更して保存しようとするとエラーが出るので、Export Management Agent→手動でXMLファイルの編集→Update Management Agentをするか、MA自体を再作成します。(私の環境の問題かも知れませんが・・・)
12/28 connectサイトにMicrosoft Identity Integration Serverサービスを再起動すれば直るとの情報がありました。試してみると確かに治ります。が、何をトリガーに事象が発生するのかは依然不明です・・・








 変更箇所はAttribute Flow部分です。前回はExportのみを設定しましたが、今回は同じ属性についてImportも設定します。
 Configure Attribute Flow
  Datasource(ILMSDB) Metaverse
  AccountName → accountName
  LastName → sn
  FirstName → givenName
  DisplayName → displayName
  Email → email
  Department → department
  JobTitle → title
  Manager → manager














2.Active Directory Domain Service用MAの作成

 以下の通りMAを作成します。
  MA名:ADDS MA
  Connect to Active Directory Forest
   Forest name:ilm2.local
   User name:Administrator
   Password:xxx
   Domain:ilm2.local
  Configure Directory Partitions
   Select directory partitions:DC=ilm2,DC=local
   Select containers for this partition:OU=ilm2users,DC=ilm2,DC=local
  Select Object Types
   userを追加でチェック
  Select Attributes
   displayName
   givenName
   mail
   manager
   sAMAccountName
   sn
   title
   unicodePwd
   userAccountControl

 次に以下の実行プロファイルを作成しておきます。
  Full Import
  Full Synchronization
  Export

3.Outbound Synchronization Rule(OSR)の作成

 次はILM"2"ポータルの管理画面よりOSRを作成します。操作方法は前回のISR作成時とほぼ同じです。

 General Information
  Name:OSR ADDS
  Flow Type:Outbound
 Scope
  Metaverse Object Type:person
  Connected System:ADDS MA
  Connected Object Type:user
 Relationship
  Relationship Criteria
   MetaverseObject:person(Attribute):accountName
   ConnectedSystemObject:user(Attribute):sAMAccountName
  Object Creation in Connected System:True
 Outbound Attribute Flow
  Metaverse    ADDSコネクタ空間
  ○accountName → sAMAccountName
  ○"CN="+accountName+",ou=ilm2users,dc=ilm2,dc=local" → dn
  ○512(数値) → userAccountControl
  ○"P@ssw0rd" → unicodePwd
   email → mail
   sn → sn
   givenName → givenName
   manager → manager
   displayName → displayName
   department → department
   title → title
  ※○は初期同期のみ











4.同期対象ユーザセットの作成

 同期対象のユーザを絞り込むため、オブジェクトセットを作成します。 ここではシステムユーザ以外は全員対象としたいので、ilm2adminとBuilt-inユーザ以外でセットを作成します。

 Basic Info
  Name:[SET]NonSystemUsers
 Dynamic Membership
  対象:people
  条件:match all
     Display Name is not ilm2admin
     Display Name not starts with Built-in
   →Display Nameがilm2adminではなく、Built-inで始まらないユーザのみを対象とします。










5.OSR適用フローの作成(Action Flow)

 OSRを実際に実行するためのアクションフローを作成します。
 Basic Information
  Workflow Name:AW ADDS
  Workflow Type:Action
 Activities
  Activity Picker:Synchroniozation Rule Activity
  Synchronization Rule:OSR ADDS
  Action Selection:Add











6.管理ポリシールール(Management Policy Rule/MPR)の作成

 4て定義したオブジェクトセットに5で定義したアクションフローが実行できるようにMPRを作成します。

 General Information
  Display Name:MPR ADDS
 Requesters and Operations
  Requesters:Specific Set of Requesters:[SET]NonSystemUsers
  Operation:Create resource、Modify resource attributes
 Target Resources
  Target Resource Definition Before Request:
   Specific Set of Objectes:[SET]NonSystemUsers
  Target Resource Definition After Request:
   Specific Set of Objectes:[SET]NonSystemUsers
 Policy Workflows
  Action:AW ADDS


7.同期の実行

 実際に定義したルールを動かしてみます。
 まず、Active Directoryのツリー構造を一旦コネクタ空間へ取り込むため、ADDS MAのFull Importを実行します。
 次にILMSDBのFull Importを行い、先ほど作成した同期ルールを含む情報をコネクタ空間へ取り込みます。
 その状態でILMSDBのコネクタ空間とMetaverseの同期を行います。 すると、OSRが実行されるので、ADDS MA(CS)へユーザが追加されます。
 そこまで来たら後はADDS MAでExportすればAD上へユーザが作成されます。

8.AD上のユーザ確認

 ドメインコントローラにログインし、ActiveDirectoryユーザとコンピュータでユーザが作成されていることが確認できます。






















これで基本的に入方向と出方向の両方の同期ができました。
他にもパスワードの同期や承認フローの設定など色々と試すことがあるので、いずれ解説したいと思います。(それよりもMPR、AW、SETの考え方、ERL属性の仕組みを整理した方が全体の理解が進むかもしれませんが。。。このあたりがこの製品をややこしくしている根源な気がします)

2008年12月12日金曜日

ASP.NETでOpenID対応サイト作成

PerlやPHPでのOpenID対応サイトの作り方は結構あるので、ASP.NETで作ってみました。
OpenIDのライブラリはGoogleが公開しているものを以下からダウンロードしました。
http://code.google.com/p/dotnetopenid/downloads/list

開発環境は、
OS:WindowsXP Pro SP3
IDE:Visual Studio 2005 Professional Edition
.NET Framework:2.0.50727
です。

以下の手順で作成・確認します。
1.Visual Studioで新規Webアプリケーションを作成








2.参照設定にGoogleからダウンロードしたライブラリ(DLL)を設定









3.ツールボックスにダウンロードした部品(OpenIdLogin)を追加し、Webページに追加








ツールボックス→右クリック→アイテム選択→参照より先ほどのDLLを追加する。








Webページ上へOpenIdLoginをドラッグ&ドロップする。










4.認証状態を表示するための部品(ラベルなど)をWebページに追加








ページがロードされたときに状態をラベルに表示するため、以下のコードを追加する。(Default.aspx.vb)

Partial Class _Default
Inherits System.Web.UI.Page

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Lbl_UserID.Text = User.Identity.Name
lbl_IsAuthenticated.Text = IIf(User.Identity.IsAuthenticated, "True", "False")
End Sub

End Class


5.フォーム認証を使う様に環境を設定

WebサイトメニューよりASP.NET構成を開き、Webサイト管理ツールより、
セキュリティ→認証の種類の選択のリンクをたどり、ユーザがサイトにアクセスする方法を「インターネットから」へ変更する。









6.ビルド、テスト

実行すると、認証前の状態ではUserIDは空白、IsAuthenticatedはFalseになっているので、先日紹介したWindowsLiveのOpenIDを入力してLoginをクリックする。









WindowsLiveの認証ページへリダイレクトされるので、パスワードを入力してサインインする。









認証が成功すると、UserIDにOpenID、IsAuthenticatedにTrueが返される。











とりあえずということもあり単純にログインおよび状態の表示のみをしましたが、その他の機能もそのうち使ってみたいと思います。

2008年12月6日土曜日

ILM"2" RC0環境構築「同期ルール設定編その2~ISR」

しばらく間が空いてしまいました。
出張続き&家族全員でノロにかかったりとばたばたしてました。

さて、前回の予告通り実際の同期ルールの設定を試してみます。
今回はその中でもISR(Inbound Synchronization Rules)、要するにMetaverseおよびILM Serviceへのエントリの取り込みを行います。

流れとしてはシンプルに人事データの入ったCSVファイルを取り込んでいきます。

0.準備
 用意したCSVファイル(hr.csv)は以下の通り。

  カラム ヘッダ列
  -------------------------
  従業員ID empId  
  姓 sn  
  名 givenName
  組織名 department
  役職 title
  上長 manager

  デリミタ:カンマ
  クォート:なし

  例)
  empId,sn,givenName,department,title,manager
  e0001,鈴木,一郎,開発部,部長,
  e0002,田中,二郎,開発部,,e0001
  e0003,斎藤,三郎,営業部,部長,
  e0004,武田,四朗,営業部,,e0003


早速、設定をしていきます。

1.CSV取り込み側のMA(Management Agent)設定

 これまでと同様にIdentity Managerからの設定となります。

 まずはMAを以下の通り作成します。
  MA名:HR CSV MA
  MAタイプ:Delimited text file
  Anchor:empId
  ObjectType:person








 


 ポイントは、設定する内容は
 ・入力ファイルの定義
 ・取り込む属性の定義
 ・マッピングするオブジェクトタイプの定義
 のみが必要で、それ以外のAttribute Flowなどの設定はMA設定時には行わない、という点です。
 ※ちなみにmanager属性は他のエントリへの参照となるのでreferenceタイプ属性として定義します。

 MAの定義が終わったら、実行プロファイルの作成はしておきます。
 今回作成したのは以下の2つです。
 ・Full Import
 ・Full Synchronization

2.ILM側のMA(Management Agent)設定

 次はILM用のMAを同じくIdentity Managerから作成します。

 MA名:ILMSDB MA
 MAタイプ:Identity Lifecycle Manager
 Primary Connection
  Server:.(ピリオド。DBサーバ同居構成なので)
  Database:MSILM(これはお決まり)
 Authentication mode
  Windows integrated authentication
  Usernamae:ilm2admin
  Domain:ilm2.local
 Configure Object Type Mappings
  Person:person










 こちらは他のMAとは違い、従来通りのAttribute Flowの設定を行います。

 Configure Attribute Flow
  Datasource(ILMSDB) Metaverse
  AccountName ← accountName
  LastName ← sn
  FirstName ← givenName
  DisplayName ← displayName
  Email ← email
  Department ← department
  JobTitle ← title
  Manager ← manager
  ExpectedRulesList → expectedRulesList(これはお決まり)










 MAの定義が終わったら、実行プロファイルの作成はしておきます。
 今回作成したのは以下の2つです。
 ・Full Import
 ・Full Synchronization
 ・Export

3.ISR(Inbound Synchronization Rule)設定

 さていよいよILM"2"からの新しい設定です。
 ILM"2" Portal(http://ILM Portalサーバ/identitymanagement/default.aspx)を開き、AdministrationリンクからSynchronization Rulesを開き、[NEW]より新しい同期ルールを作成します。

 今回はHR.CSVからの入り方向の同期ルールを設定します。










 General Information
  Name:HR CSV
  Flow Type:Inbound
 Scope
  Metaverse Object Type:person
  Connected System:HR CS MA(Identity Managerで先ほど作成したMAが選択できるようになっている)
  Connected Object Type:person(こちらもMAに定義したObject Typeを選択する)










 Relationship
  Relationship Criteria
   accountName=empId(CSとMVのエントリの紐付け条件)
  Object Creation in ILM:true(ILMポータル上にユーザを作成するかどうか)











 ここからがこれまでMAに設定してきたAttribute Flowの設定です。
 ある程度の文字列操作関数などはあらかじめ用意されているのでRules Extensionをガリガリ書く、というのは減ったかもしれません。またMIISやILM2007では「同期」と「プロビジョニング」が明確にわかれていしたが、今回からコードを書かなくてもプロビジョニングしてもらえます。











 Inbound Attribute Flow
  Source → Destination
  empId → accountName
  sn → sn
  givenName → givenName
  givenName+" "+sn → displayName
  empId+"@ilm2.local" → email
  department → department
  title → title
  manager → manager

 属性値の結合や固定文字列の挿入もWebダイアログで定義します。










4.同期の準備(初期化)

 MAとISRの作成が完了したら実際に取り込みを行ってみます。
 以下の実行プロファイルを実行し、実際の同期の準備を行います。

 ILMSDB MA
  Full Import
  Full Synchronization
  Export

5.同期の実行

 次に実際のHR.CSVを取り込んで見ます。

 それぞれのMAにて以下の順番でプロファイルを実行します。

 HR CSV MA
  Full Import
  Full Synchronization
 ILMSDB MA
  Full Synchronization
  Export

6.画面で確認
 ILM Portalのユーザ管理ページを見るとユーザが作成されているのがわかります。











さて、取り込み側の同期Ruleはそれほど難しくないので、問題はOSR(外向きの同期)です。こちらも現在いろいろと試しているので、まとまったらアップしていきます。