Welcome to TechNet Blogs Sign in | Join | Help

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

Microsoft Evangelist -- Junichi Anno

News

  • お正月はオンラインセミナー 愛の戦士ですが何か?

    新着動画

    ・PowerPivotデモ

    ・SQL Azureの管理

    Twitter Updates

      follow me on Twitter

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

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

    そんなノスタルジックな想いはともかく、現実に戻って 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

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

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

    # August 29, 2008 1:24 AM
    Anonymous comments are disabled
    Page view tracker