【IDM】Active Directory から OpenLDAP への パスワードの同期 その2 ~ ADSI でパスワードを同期する - フィールドSEあがりの安納です - Site Home - TechNet Blogs

フィールドSEあがりの安納です

Microsoft Evangelist -- Junichi Anno

【IDM】Active Directory から OpenLDAP への パスワードの同期 その2 ~ ADSI でパスワードを同期する

【IDM】Active Directory から OpenLDAP への パスワードの同期 その2 ~ ADSI でパスワードを同期する

  • Comments 2
  • Likes

昔、「おしいれのぼうけん」ていう絵本がありました。いまでもトラウマです...ねずみばぁさん...。

そんなノスタルジックな想いはともかく、現実に戻って OpenLDAP にパスワードを同期する方法について考察します。

以前、以下の記事で、生パスワードを PowerShell を使用して SHA1  で暗号化する方法を書きました。

【IDM】Active Directory から OpenLDAP への パスワードの同期 その1 ~ パスワードを SHA1 で暗号化

今回は、SHA1 のことはひとまずおいといて、パスワード同期機能で作成された unixUserPassword を取り出し、ADSI を使用して OpenLDAP に同期してみます。

パスワード同期機能および unixUserPassword 属性については、以下で詳しく解説していますので参考にしてください。

# ここでは、パスワードの暗号化形式は DES を使用しています。 

解説はソースの中にインラインで書きます。ソースをダウンロードするには、こちらから どうぞ。

今回は、以下の環境を想定しています。

  • Active Directory ドメイン : example64.jp
  • パスワードを変更するユーザー:testuser01
  • 変更後のパスワード :ABC123@
  • OpenLDAP サーバー : fedora01.example-fedora01.jp
  • OpenLDAP上のユーザー :uid=testuser01,ou=People,dc=example-fedora,dc=jp
  • OpenLDAPの管理ユーザー: cn=Manager,dc=example-fedora,dc=jp
  • OpenLDAPの管理ユーザーのパスワード :password

変更の手順の大きな流れは以下の通りです。

  1. testuser01 のパスワードを Active Directory で変更する
  2. 変更されたパスワードが自動的に unixUserPassword に同期される
  3. unixUserPassword から DES で暗号化されたパスワードを取り出す
  4. OpenLDAPに接続し、testuser01 のパスワードを書き込み
  5. 確認のために testuser01 で OpenLDAPに接続してみる

では、上記を具体的なスクリプトに落としてみます。

よろしければ、OpenLDAP に接続可能なブラウザを用意しておいてください。「LDAP Browser」で検索していただくと、Windows で使用可能な LDAP ブラウザが見つかるでしょう。これがあると、値が書き込まれているかどうかを手軽に確認することができます。

まずは変数の定義です。これはよいですよね。

On Error Resume Next

strDomain = "dc=example64,dc=jp"
strUserName  = "testuser01"
strPassword  = "ABC123@"
strLdapServer  = "fedora01.example-fedora.jp"
strLdapUser    = "uid=" & strUserName & ",ou=People,dc=example-fedora,dc=jp"
strManagerDN       = "cn=Manager,dc=example-fedora,dc=jp"
strManagerPassword = "password"

はじめに、testuser01 のパスワードを Active Directory 上で変更します。これは、unixUserPassword にUNIXシステム用に暗号化されたパスワードを格納するためです。既に最新のパスワードが unixUserPassword に格納されているのであれば必要はありません。

testuser01 のパスワード変更にあたり、まずは Active Directory で testuser01 を検索し、DistinguishedName を取得します。


' ユーザーを検索
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Open "Provider=ADsDSOObject;"
Set objCommand = CreateObject("ADODB.Command")
objCommand.ActiveConnection = objConnection
objCommand.CommandText = _
        "<LDAP://" & strDomain & ">;" & _
        "(&(objectCategory=person)(objectClass=user)" & _
        "(sAMAccountName=" & strUserName & "));" & _
        "DistinguishedName,sAMAccountName,unixUserPassword;" & _
        "subtree"
Set objRecordSet = objCommand.Execute

次に、testuser01 のパスワードを変更します。パスワードの変更を ADSI で行うには、SetPassword メソッドを使用します。パスワード変更の場合、SetInfo は必要ないのですが、属性のリフレッシュのために念のために入れてあります...すいません、これは私の癖みたいなものです...。

' ユーザーのパスワード変更
Do Until objRecordset.EOF
   strDN = objRecordset.Fields("DistinguishedName")
   objRecordset.movenext
Loop
Set objUser = GetObject("LDAP://" & strDN)
objUser.SetPassword strPassword
objUser.SetInfo

パスワードの変更後、パスワード同期機能による unixUserPassword の生成には若干のタイムラグがあります。以下では、念のために 3000ms の待ちを入れています。

' AD内でunixUserPassword が同期されるまで待つ
Wscript.Sleep 3000

unixUserPassword が生成されたことを想定し、以前にも解説した方法で DES で暗号化されたパスワードを取得します。なお、unixUserPassword を取得するに当たり、冒頭で事前に ADSI に対してクエリーを再実行しています。

なお、取得したパスワードは、strUnixUserPassword に格納されます。

'  変更後のパスワードを取得
'  クエリーを再実行
Set objRecordSet2 = objCommand.Execute

Do Until objRecordset2.EOF
 arrUNIXUSERPASSWORD = objRecordset2.Fields("unixUserPassword")
 For i = 1 To LenB(arrUNIXUSERPASSWORD(0))
     strA = MidB(arrUNIXUSERPASSWORD(0), i, 1)
     strB = AscB(strA)
     strUnixUserPassword = strUnixUserPassword & Chr(strB)
 Next
 objRecordset2.movenext
Loop

さて、ここからが OpenLDAP に対する操作の始まりです。

はじめに、OpenLDAP 上の testuser01 に接続し、objUser オブジェクトを生成します。このとき使用するのが、OpenDSObject というメソッドです。引数に指定するのは、以下の通りです。

  • OpenLDAP上のオブジェクトのパス
    LDAP://fedora01.example-fedora01.jp/uid=testuser01,ou=People,dc=example-fedora,dc=jp
  • OpenLDAP管理用ユーザーのDN
    cn=Manager,dc=example-fedora,dc=jp
  • OpenLDAP管理用ユーザーのパスワード
    password

OpenDSObject は、LDAPサーバーへの認証でも使用するメソッドです。覚えておくと、ユーザーIDとパスワードの整合性をチェックするときにも使えて便利です。このメソッドは、変更後のパスワードが正しく同期されているかどうかをチェックする際にも使用します。

' OpenLDAPに接続してユーザーオブジェクトを取得
set objLDAP = GetObject("LDAP:")
set objUser = objLDAP.OpenDSObject("LDAP://" & strLdapServer & "/" & strLdapUser, _
                                   strManagerDN, _
                                   strManagerPassword, _
                                   0)

OpenLDAP 上のユーザーのパスワードを変更する際は、Active Directory のときのように SetPassword を使用しません。通常の属性変更用のメソッドである、Put を使用して、userPassword 属性に直接暗号化されたパスワードを格納します。

パスワードの格納にあたり、頭に {CRYPT} を付加します。これは、OpenLDAP 上の userPassword 属性が DES で暗号化されていることを示しています。この部分は、環境に合わせて {MD5} や {SHA} 等に変更します。

パスワードの変更後は、Active Directory 同様、SetInfo でコミットしてください。

'パスワードを変更
objUser.Put "userPassword", "{CRYPT}" & strUnixUserPassword
objUser.SetInfo

最後に、本当にパスワードが同期されたかどうかを、OpenDSObject を使用して確認します。ただし、これができるのは、生パスワードがわかっているときだけです。単純に、unixUserPassword の中身を userPassword に同期する場合には、生パスワードがわかりませんから、このチェックは行いようがありません。

'パスワードが変更されたかどうかをチェック
set objChkUser = objLDAP.OpenDSObject("LDAP://" & strLdapServer, _
                                   strLdapUser, _
                                   strPassword, _
                                   0)

If Err.Number = 0 then
 Wscript.Echo "パスワードは正しく同期されました(" & strLdapUser & ")"
else
 Wscript.Echo "パスワードの同期でエラーが発生しました(" & strLdapUser & ")"
End If

以上で完了です。

意外に簡単なスクリプトで実現できることに驚きませんか?

小規模なシステムや負荷が小さなシステムでは十分使える方法だと思いますので、是非試してみてください。

Comments
  • PingBack from http://blogs.technet.com/junichia/pages/adsi-openldap.aspx

  • ※2008/08/29 Tech・Ed会場にてリンク切れを指摘していただきましたので修正いたしました。(汗) ある調べごとがあり、「'watch node'」 という単語を 某検索エンジンに放り込んだところ、以下の表示が。

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment