active directory のスキーマを拡張してみた。
active directoryのスキーマを拡張する方法について説明します。
ちなみに何かあって責任は取りませんので自己責任でどうぞ。
はじめに、まずは愚痴。
activedirectoryはldapという聳え立つクソの上に、GUIをつけたものなので非常に難解で大変です。
データベースだったら、 alter 一発なのに、、なんでこんなに簡単なことをクソめんどくさくできるか、それが知りたい。
マジわけわかんないんですけどー。
武器の調達。
一度作ったスキーマは2度と消すことができませんww そのため絶対に本番機でやってはいけません。
テスト機でも失敗してやり直すためには、、、OSの再インストールものだと思います。
ストレスで死にたくない人は、VMWare のスナップショットを利用して常にもとの環境に戻せるようにしておきましょう。
そうしないと発狂します。
こんなアホな仕様は、、、ActiveDirectoryっていうか、LDAPの仕様?信じられぬ。
- VMWare Server(個人的にversion1 の ネイティブアプリベースが好きです。)
http://www.vmware.com/jp/download/server/
- Windows 2003 Server (180 日限定評価版)
http://www.microsoft.com/japan/windowsserver2003/evaluation/trial/default.mspx
何か非常にわかりづらいんですが、適当に入れて登録しましょうwww
0円のものを購入するってなんてわかりづらいんだww
- この記事の元になった資料
ここの不思議な機械翻訳
http://technet.microsoft.com/ja-jp/library/bb727064.aspx
すべてが終わった後に発見したwordの資料ww
http://download.microsoft.com/download/6/e/0/6e0c44fc-20c7-4eb8-aaa7-cb2f784803bb/A2.doc
- linux機w
ldapsearchをインストールしたlinux機が一台あれば非常に便利です。
私はlinux機からこんな感じでテストしてます。
ldapsearch -V 3 -h 192.168.1.99 -x -b 'CN=abc,cn=Users,dc=rtitest,dc=local' -D 'binduser@rtitest.local' -w binduser "*"
192.168.1.99 っていうのが、ActiveDirectoryマシンです。
rtitest.local が私のActiveDirectoryのドメイン名です。
rtitest.local の binduser のパスワードは binduser です。
この環境で、 ユーザ abc の情報を問い合わせています。
さぁ、クレージーな世界に行きますよ!!
ActiveDirectoryを拡張する。
まず、スキーマを拡張する機能を有効にします。
windows2003 server では、以下のディフォルトでは ActiveDirectory スキーマの拡張ができないようです。
cmd なコマンドラインから以下を入力し、ActiveDirectory スキーマを拡張できるようにします。
regsvr32 schmmgmt.dll
mmc から ActiveDirectory スキーマ まで
OK。次は mmc から ActiveDirectory スキーマを呼び出します。
cmdなコマンドラインから入力
mmc
「ActiveDirectory スキーマ」を選択して「追加」
ここで「ActiveDirectory スキーマ」が表示されないあなた。最初の 「regsvr32 schmmgmt.dll」を忘れてます。zap!
お断り。
注意! 最初にも書きましたが、「一度作った値やクラスは削除できません」そのため絶対に本番機では試さないでください。死にます。本番気以外のマシンがないなら、すべてを忘れてブラウザを閉じてこれ以上進むのをやめましょう。
何か
編集許可とか、ドメインマスターがどうこうのというのがありますが、一台でやっている限りやらなくても問題ないみたいです。
というか、ここの画面が windows 2000server と windows 2003 server では違っていて、「このドメインコントローラーでスキーマの修正が可能」というチェックがありません。やるだけ時間の無駄です。
属性の登録
ldapでは属性を作成してから、クラスに登録します。
ActiveDirectory スキーマところの + ボタンで開くと、「クラス」と「属性」があります。
それでは、属性を登録します。
この辺は資料に書いてあるとおりです。
属性から「新規登録」をクリックして、属性を追加します。
次に給料のレベルですか。
入力内容は、資料を参考にしてください。wordの方が日本語なのでお勧めです。
間違って入れてた場合は、二度と修正できません。ご愁傷様です。
次に、クラスを登録します。
クラスの種類は「補助型」にしてください。
何で補助型なのか、それは「構造型」と動違うのか、どういう意味なのかはさっぱりわかりませんwww
入力したら「次へ」で次の画面に。
「完了」でクラスが確定します。これも一度作ったら二と度削除できません。
userクラスに関連付ける。
先ほど作った HumanResource を user クラスに関連付けます。
クラスの中から、user クラスを選択して、右クリックのプロパティを出します。
「関係」のタブをクリックして、
補助クラスのところにある、「クラスの追加」をクリック。
さっき作った HumanResource を追加。
もし、ここに HumanResource が現れない場合、、、あなたは、 HumanResource を 補助型で作成しませんでしたね。
もう取り返しが付きませんので、 VMを巻き戻してください。zap!
HumanResource を追加したら、「OK」で確定します。
ここで、エラーが発生してうまくいかないことがあります。
英語だと、「The Change was rejected by the directory service」 っていうらしいです。
#この記事を書いている前は散々発生したのに、文章を書いているとまったく再発しなくなったので日本語のエラーは不明になりました。。。メモには英語のヤツしか取ってなかったんだ。
いろいろ試しているんですが、 クラス名を HumanResource ではなく HumanResource1 にしたらうまく動作したりします。
また、HumanResource のままでもうまくいくときもあります。
うまくいくときとうまくいかないときの再現方法がまだよくわかりません。
どういうことなの?
うまくいった場合、これで設定はおしまいです。
だめだったら、VMを巻き戻して、 HumanResource を HumanResource1 とかにして試してください。
コレでいいのかは知りません。
値を追加する。
こんなにがんばったのに、ActiveDirectoryのタブには何も表示されません。
ってゆーか既存のモデルには、追加した HumanResource の値も入りません。
資料にある vbscript で追加する必要があります。
ここで注意なので、ドメイン名です。
資料では、 とか書いてますが、ここをあなたのドメイン名に直してください。
私の場合は、 rtitest.local なのでこうなりました。
オリジナルは、 http://technet.microsoft.com/ja-jp/library/bb727064.aspx
です。
Sub ModifyUsers(oObject) Dim oUser For Each oUser in oObject Select Case oUser.Class Case "user" oUser.Put "SalaryLevel","10000" oUser.Put "SocialSecurityNumber",CStr(Int(9999*Rnd()+1)) oUser.SetInfo Case "organizationalUnit" , "container" ModifyUsers(oUser) End select Next End Sub Dim oDomain Set oDomain=GetObject("LDAP://CN=Users,DC=rtitest,DC=local") ModifyUsers(oDomain) Set oDomain = Nothing MsgBox "Finished" WScript.Quit
これで HumanResource1の値が正しくセットされました。
資料にあるvbscript で覗くのもいいんですが、 ldapsearch で見るのがスマートだと思います。
こんな感じに追加されているのがわかります。
ldapsearch -V 3 -h 192.168.1.99 -x -b 'CN=binduser,cn=Users,dc=rtitest,dc=local' -D 'binduser@rtitest.local' -w binduser "*" # binduser, Users, rtitest.local dn: CN=binduser,CN=Users,DC=rtitest,DC=local objectClass: top objectClass: person objectClass: organizationalPerson objectClass: user 中略 userPrincipalName: binduser@rtitest.local objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=rtitest,DC=local dSCorePropagationData: 20091024155428.0Z dSCorePropagationData: 20091024155428.0Z dSCorePropagationData: 20091024155428.0Z dSCorePropagationData: 16010108151056.0Z SocialSecurityNumber: 5334 ←これ SalaryLevel: 10000 ←これ
ちなみに、ユーザーを新規作成した場合は、こんな感じで当然のように何も入ってませんwww最悪です。
ldapsearch -V 3 -h 192.168.1.99 -x -b 'CN=newuser,cn=Users,dc=rtitest,dc=local' -D 'binduser@rtitest.local' -w binduse "*" # newuser, Users, rtitest.local dn: CN=newuser,CN=Users,DC=rtitest,DC=local objectClass: top objectClass: person objectClass: organizationalPerson objectClass: user 中略 userPrincipalName: newuser@rtitest.local objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=rtitest,DC=local
もう一度プログラムを実行するか、資料の最後に載っているGUI追加プログラムで修正します。
GUI追加プログラム
実はこのプログラム webの方を実行してもダメです。
webの方のプログラムが追加している409は英語の方です。
日本語で利用しているので、 411 の方に追加しないとダメです。
wordの方は大丈夫です。
×英語 409に追加 "LDAP://CN=409, CN=DisplaySpecifiers," oRoot.get("configurationNamingContext")) ↓ ○日本語 411に追加 "LDAP://CN=411, CN=DisplaySpecifiers," oRoot.get("configurationNamingContext"))
それと、webの方は行がつぶれていてコンパイルエラーになっちゃいます。
私の方で 改行をまともに修正したのと、 英語の409を日本語の411 にしたのを作ったのでおいときます。
オリジナルは、 http://technet.microsoft.com/ja-jp/library/bb727064.aspx
です。
Dim oRoot Dim oDisp Dim oCont Dim aMenu Dim iCount Dim sNewMenu Dim oFileSystem Dim sOutFile Dim sSystemFolder Set oFileSystem = WScript.CreateObject("Scripting.FileSystemObject") sSystemFolder = oFileSystem.GetSpecialFolder(1) 'Connect to Display Specifiers Container set oRoot = Getobject("LDAP://RootDSE") set oCont = GetObject("LDAP://CN=411, CN=DisplaySpecifiers," & oRoot.get("configurationNamingContext")) Set oDisp = oCont.GetObject("displaySpecifier","cn=user-Display") MsgBox "Display Specifier: " & oDisp.Name 'Add Attribute Display Names oDisp.PutEx 3,"attributeDisplayNames" , Array("SalaryLevel,Annual Salary","SocialSecurityNumber,Social Security Number") oDisp.SetInfo 'Add Shell Context Menu MsgBox "Adding Shell Context Menu item" iCount = 0 If Not IsEmpty(oDisp.shellContextMenu) Then aMenu = oDisp.GetEx("shellContextMenu") For iCount = LBound(aMenu) to UBound(aMenu) MsgBox "Existing Menu item: " & aMenu(iCount) Next iCount = iCount + 1 End If sNewMenu = CStr(iCount) & ",&HR Info...,hrshell.vbs" oDisp.PutEx 3,"shellContextMenu" , Array(sNewMenu) oDisp.SetInfo MsgBox "Adding Shell Context Menu Program" Set sOutFile = oFileSystem.CreateTextFile(sSystemFolder & "\hrshell.vbs",True) sOutFile.WriteLine "Dim Args" sOutFile.WriteLine "Dim oUser" sOutFile.WriteLine "Set Args = Wscript.Arguments" sOutFile.WriteLine "MsgBox " & Chr(34) & "LDAP Path: " & Chr(34) & " & Args(0)" sOutFile.WriteLine "MsgBox " & Chr(34) & "Object Class: " & Chr(34) & " & Args(1)" sOutFile.WriteLine "Set oUser = GetObject(Args(0))" sOutFile.WriteLine "MsgBox " & Chr(34) & "HR Info" & Chr(34) & " & vbCRLF & " & Chr(34) & "Salary: " & Chr(34) & " & oUser.SalaryLevel & vbCRLF & " & Chr(34) & "Soc Sec No: " & Chr(34) & " & oUser.SocialSecurityNumber" sOutFile.WriteLine "Set oUser = Nothing" sOutFile.WriteLine "WScript.Quit" sOutFile.Close 'Add Admin Context Menu MsgBox "Adding Admin Context Menu item" iCount = 0 If Not IsEmpty(oDisp.adminContextMenu) Then aMenu = oDisp.GetEx("adminContextMenu") For iCount = LBound(aMenu) to UBound(aMenu) MsgBox "Existing Menu item: " & aMenu(iCount) Next iCount = iCount + 1 End If sNewMenu = CStr(iCount) & ",&HR Admin...,hradmin.vbs" oDisp.PutEx 3,"adminContextMenu" , Array(sNewMenu) oDisp.SetInfo MsgBox "Adding Admin Context Menu Program" Set sOutFile = oFileSystem.CreateTextFile(sSystemFolder & "\hradmin.vbs",True) sOutFile.WriteLine "Dim Args" sOutFile.WriteLine "Dim oUser" sOutFile.WriteLine "Dim temp" sOutFile.WriteLine "Set Args = Wscript.Arguments" sOutFile.WriteLine "MsgBox " & Chr(34) & "LDAP Path: " & Chr(34) & " & Args(0)" sOutFile.WriteLine "MsgBox " & Chr(34) & "Object Class: " & Chr(34) & " & Args(1)" sOutFile.WriteLine "Set oUser = GetObject(Args(0))" sOutFile.WriteLine "temp = InputBox(" & Chr(34) & "Old Salary: " & Chr(34) & " & oUser.SalaryLevel & vbCRLF & " & Chr(34) & "New Salary" & Chr(34) & ")" sOutFile.WriteLine "if temp <> " & Chr(34) & Chr(34) & " then oUser.Put " & Chr(34) & "SalaryLevel" & Chr(34) & ",temp" sOutFile.WriteLine "temp = InputBox(" & Chr(34) & "Soc Sec Number: " & Chr(34) & " & oUser.SocialSecurityNumber & vbCRLF & " & Chr(34) & "New Number" & Chr(34) & ")" sOutFile.WriteLine "if temp <> " & Chr(34) & Chr(34) & " then oUser.Put " & Chr(34) & "SocialSecurityNumber" & Chr(34) & ",temp" sOutFile.WriteLine " oUser.SetInfo" sOutFile.WriteLine "Set oUser = Nothing" sOutFile.WriteLine "WScript.Quit" sOutFile.Close MsgBox "Quit..." Set oDisp = Nothing Set oCont = Nothing Set oRoot = Nothing Set oFileSystem = Nothing WScript.Quit
実行して成功しましたか?
資料にも書いてあるとおり、2回実行すると悲惨なことになるので、注意しましょう。
タブに入らないってマジですよ
さて、これでGUIで値が変更できるようになりました。
ldapsearchでみると変更されているのがちゃんとわかります。
ldapsearch -V 3 -h 192.168.1.99 -x -b 'CN=newuser,cn=Users,dc=rtitest,dc=local' -D 'binduser@rtitest.local' -w binduser "*" # newuser, Users, rtitest.local dn: CN=newuser,CN=Users,DC=rtitest,DC=local objectClass: top objectClass: person objectClass: organizationalPerson objectClass: user 中略 userPrincipalName: newuser@rtitest.local objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=rtitest,DC=local SocialSecurityNumber: 1234 SalaryLevel: 123
よかった、よかった、、、、ってよくねーよ。
ActiveDirectory のタブで編集できるようにしてくれよ。
これぢゃあかっこが悪すぎるだろう。
何か、タブに追加するには、プログラムを作らないとダメみたいです。
この掲示板に書いてあったんですが、
http://social.technet.microsoft.com/forums/ja-JP/windowsserver2003ja/thread/87042715-852c-439f-a88e-9551f2191e78/
一応こんな感じでいけるらしい。
http://msdn2.microsoft.com/en-us/library/ms677632.aspx
左側のメニューからたどっていくとサンプルソースもあります。
http://msdn.microsoft.com/en-us/library/ms676867%28VS.85%29.aspx
しかし、面倒だなぁ。。。
本当は、sshの公開鍵をADで管理したかったんだ、、、
OpenLDAPでsshの鍵を管理するってやつのAD番がやりたかった。
http://gihyo.jp/admin/serial/01/ldap/0006
しかし、道のりは遠いぜ。
一応スキーマの定義を上の方法でやれば、、、ある程度は何とかなるんだろうけど、俺はもう疲れ果てた。。。
http://integ.jp/server/opends/schema/10-openssh-lpk-opends.ldif