Book: Perlを使ったLDAPアクセス -Net::LDAP Modify, 属性の操作-

LDAPのエントリーの操作のうち、検索、追加、削除は、比較的簡単でした。

サンプル:
Search and Add: http://www.knowd.co.jp/yamazaki/?q=node/134
Search and Delete: http://www.knowd.co.jp/yamazaki/?q=node/136

次は、エントリが持っている属性を操作するサンプルをあげます。

属性を操作するには、まず、対象のエントリを取得(検索)した後、対象のエントリに対して、属性の追加、更新、削除などの操作を行っていきます。
この際、Net::LDAP->modify を使用します。

属性の追加: Net::LDAP->modify( $dn, add... )
エントリに対して、"mail: xxxx" という属性を追加します。

test-ldap3.pl

use Net::LDAP;
#
# bind as priviledged user for modify.
#
$ldap = Net::LDAP->new( "localhost" );
$message = $ldap->bind( "cn=Directory Manager", password=>"password" );

if( $message->code == 0 ) {
        print "bind success\n";
} else {
        warn "error with bind: " . $message->error ."\n";
        exit( 1 );
}


#
# search entry.
#
$uid = "test.0";
$dn = "uid=$uid,ou=People,dc=example,dc=com";
$result = $ldap->search( base=>$dn, scope=>"base", filter=>"objectclass=*" );

@entries = $result->entries;
$entry = $entries[0];

if( !defined( $entry ) ) {
        $ldap->unbind;
        warn "$user not found.\n";
        exit( 1 );
}


#
# add mail attribute to the entry.
#
$result = $ldap->modify( $entry,
        add => {
                mail => [ $uid.'@example.com' ]
        }
);

if( $result->code != 0 ) {
        $ldap->unbind;
        warn $result->error;
        exit( $result->code );
}
$ldap->unbind;
もし、属性がマルチバリューを許可していれば、次のように複数の値をまとめて追加することもできます。
...
# add mail attribute to the entry.
#
$result = $ldap->modify( $entry,
        add => {
                mail => [ $uid.'@example.com', $uid.'@example.net' ]
        }
);
...
もし、すでに、同一の属性に同一の値がある場合、つまり、属性に重複した値が存在するような追加を試みた場合、以下のようなエラーとなり、結果としてadd操作は実行されません。
# perl  test-ldap3.pl
bind success
エントリ uid=test.0,ou=People,dc=example,dc=com を変更できません。変更により、属性 mail の重複する値が 1 つ以上生成されます: uid=test.0@example.com, uid=test.0@example.net at test-ldap3.pl line 45,  line 466.
一見して、コードが長くなってきているように感じられます。エントリの検索に加え、属性操作が加わるためでしょう。。 これまでのサンプルは、プログラムをサブルーチン化せず、べたーっと書いてきましたが、この辺から、Perlのテクニックが必要になってきそうです。 属性の削除: Net::LDAP->modify( $dn, delete... ) 属性を削除します。以下のように記述すると、mail属性に複数の値が設定されていたとしても、すべて削除します。 test-ldap4.pl
use Net::LDAP;

#
# bind as priviledged user for modify.
#
$ldap = Net::LDAP->new( "localhost" );
$message = $ldap->bind( "cn=Directory Manager", password=>"password" );

if( $message->code == 0 ) {
        print "bind success\n";
} else {
        warn "error with bind: " . $message->error ."\n";
        exit( 1 );
}


#
# search entry.
#
$uid = "test.0";
$dn = "uid=$uid,ou=People,dc=example,dc=com";
$result = $ldap->search( base=>$dn, scope=>"base", filter=>"objectclass=*" );

@entries = $result->entries;
$entry = $entries[0];

if( !defined( $entry ) ) {
        $ldap->unbind;
        warn "$user not found.\n";
        exit( 1 );
}


#
# delete mail attribute from the entry.
#
$result = $ldap->modify( $entry,
        delete => ['mail']
);

if( $result->code != 0 ) {
        $ldap->unbind;
        warn $result->error;
        exit( $result-code );
}
$ldap->unbind;
mail属性から、特定の値だけを削除したければ、削除対象として値を指定します。 たとえば、mail属性にxxx@example.com, xxx@example.netの2つの値があるときに、xxx@example.netだけを削除したい場合の例です。
...
# delete paticular mail attribute from the entry.
#
$result = $ldap->modify( $entry,
        delete => { mail=> $uid.'@example.net' }
);
...
もし、指定した属性に指定した値が存在しない場合は、エラーになります。
# perl  test-ldap4.pl
bind success
エントリ uid=test.0,ou=People,dc=example,dc=com を変更できません。属性 mail の更新を試みると、存在しない属性から 1 つ以上の値が削除されます: uid=test.0@example.net at test-ldap4.pl line 43,  line 466.
属性の置換: Net::LDAP->modify( $dn, replace... ) 値の置き換え(replace)は、特定の属性を指定した単数あるいは複数の値に置き換えます。 現行の値がどうであれ、置き換えるので、上記のadd, deleteに比較するとエラーが発生しにくい操作です。 以下の例は、mail属性をxxx@example.co.jpに置き換えます。 mail属性に値があろうがなかろうが、エラーなしに置き換えてくれます。
use Net::LDAP;

#
# bind as priviledged user for modify.
#
$ldap = Net::LDAP->new( "localhost" );
$message = $ldap->bind( "cn=Directory Manager", password=>"password" );

if( $message->code == 0 ) {
        print "bind success\n";
} else {
        warn "error with bind: " . $message->error ."\n";
        exit( 1 );
}


#
# search entry.
#
$uid = "uid=test.0";
$dn = "$uid,ou=People,dc=example,dc=com";
$result = $ldap->search( base=>$dn, scope=>"base", filter=>"objectclass=*" );

@entries = $result->entries;
$entry = $entries[0];

if( !defined( $entry ) ) {
        $ldap->unbind;
        warn "$user not found.\n";
        exit( 1 );
}


#
# replace mail attribute from the entry.
#
$result = $ldap->modify( $entry,
        replace => { mail=> $uid.'@example.co.jp' }
);

if( $result->code != 0 ) {
        $ldap->unbind;
        warn $result->error;
        exit( $result-code );
}
$ldap->unbind;
複数の値を指定する場合は、以下のように指定できます。
...
$result = $ldap->modify( $entry,
        replace => { mail=> [ $uid.'@example.co.jp',
                              $uid.'@example.com',
                              $uid.'@example.net' ]
                    }
);
...
また、属性の値を空にする、つまり、値を削除するには次のように指定できます。
...
$result = $ldap->modify( $entry,
        replace => { mail=> [] }
);
...
つまり、replaceは、追加、削除を含みます。 値の追加時の値の重複、削除時の値が存在しない場合、それぞれでエラーを出したい(つまり操作をキャンセルしたい)場合は、add, deleteを使えばよいのでしょうが、エラーを出さない操作を行いたい場合はreplaceが便利でしょう。