1. Trang chủ >
  2. Công nghệ thông tin >
  3. Hệ thống thông tin >

CHƯƠNG 10: NET::LDAP VÀ CÁC VẤN ĐỀ LIÊN QUAN

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.36 MB, 188 trang )


Giao thức LDAP



GVHD: TS. Lưu Thanh Trà



$ldap = Net::LDAP->new ("ldap.plainjoe.org", port =>389,

version => 3 );



Các script có thể kết nối tới các thư mục sau khi được xử lý bởi các server LDAP. Mặc định,

Net::LDAP dùng các kết nối ngầm ẩn danh, nhưng nó hỗ trợ tất cả các chuẩn kết nối được định

nghĩa bởi LDAPv3 RFCs (ẩn danh, đơn giản, và SASL). Bây giờ, ta sẽ chỉ tìm hiểu xem làm thể

nào để dùng một kết nối đơn giản.

Đầu tiên, trước khi kết nối với server, gọi lệnh start_tls( ) để mã hóa kết nối. Mã hóa password

và DN của người dùng. Dạng đơn giản nhất:

$ldap->start_tls( );



Kiểm tra lỗi:

Hầu hết các phương thức của Net::LDAP trả về một đối tượng với 2 phương pháp để đạt được

trạng thái trả về của hàm. Hàm code ( ) lấy giá trị số nguyên được trả về từ phương thức gọi là

khởi tạo đối tượng, hàm error ( ) trả về một chuỗi ký tự mô tả kết hợp với mã. Các hằng số cho

các lỗi LDAP khác nhau được liệt kê trong Net::LDAP::Constant. Các mã lỗi cụ thể được đưa

vào trong mã của bạn bằng cách thêm một dòng như sau:

use Net::LDAP::Constant qw(LDAP_SUCCESS);



Đoạn code sau kiểm tra một điều kiện lỗi sau lệnh gọi LDAP tùy ý:

if ($result->code( ) != LDAP_SUCCESS) {

die $result->error( );

}



Vì hầu hết các phương thức đều trả về 0 nếu thành công, nên việc kiểm ta lỗi có thể được rút

ngắn như sau:

die $result->error( ) if $result->code( );

Nên kiểm tra lỗi sau khi thiết lập một kênh giao tiếp an toàn. Nếu lệnh start_tls( ) bị fail, và đoạn

script vẫn tiếp tục, thì có thể nó sẽ vô tình truyền tải thông tin tài khoản một cách rõ ràng. Để

kiểm tra lỗi thì ta nên lưu lại các kết quả được trả về bởi start_tls ( ) và dùng lệnh code ( ) để tìm

hiểu liệu start_tls ( ) đã thành công hay chưa.

$result = $ldap->start_tls( );

die $result->error( ) if $result->code( );

Nếu script cố gắng thiết lập bảo mật tầng vận chuyển với một server không được hỗ trợ các hoạt động mở rộng, thì

sẽ xuất hiện thông báo lỗi:

Operations error at ./search.pl line XXX.

Bây giờ ta có thể gởi các dữ liệu đến server một cách an toàn. Thường thì yêu cầu kết nối chỉ gồm DN và password.

Đoạn



code



sau



tìm



cách



kết



nối



khách



hàng



tới



thư



mục







nội



dung



cn=Gerald



Carter,ou=people,dc=plainjoe,dc=org sử dụng password là hello. Một lần nữa, ta dùng error ( ) và code ( ) để kiểm

tra trạng thái trả về:



Chương 10



167



Lê Tiến Cường – Nguyễn Minh Đức

Lê Thạch Giang – Hoàng Ngọc Hưng



Giao thức LDAP



GVHD: TS. Lưu Thanh Trà



$result = $ldap->bind("cn=Gerald Carter,ou=people,dc=plainjoe,dc=org",

password => "hello");

die $result->error( ) if $result->code( );

Nếu không có lỗi, đoạn script được tìm kiếm trong thư mục. Hàm search ( ) chấp nhận các thông số chuẩn trong

công cụ truy vấn LDAP. Ví dụ:

$msg = $ldap->search(

base => "ou=people,dc=plainjoe,dc=org",

scope => "sub",

filter => "(cn=$ARGV[0])" );

Giá trị trả về của việc tìm kiếm là một đối tượng cố định của Net::LDAP::Search. Ta có thể thao tác với đối tượng

này để truy xuất bất cứ mục nào phù hợp với việc tìm kiếm. Đối tượng này có hàm count ( ) để đếm số mục, và hàm

all_entries ( ) trả về một mảng các đối tượng Net::LDAP::Entry, mỗi đối tượng đại diện cho thông tin liên quan tới

một nút thư mục duy nhất. Dùng hàm dump ( ) để xem các kết quả truy vấn.

if ( $msg->count( ) > 0 ) {

print $msg->count( ), " entries returned.\n";

foreach $entry ( $msg->all_entries( ) ) {

$entry->dump( );

}

}

Đầu ra của một mục:

dn:cn=Gerald Carter,ou=people,dc=plainjoe,dc=org

objectClass: inetOrgPerson

cn: Gerald Carter

sn: Carter

givenName: Gerald

o: Hewlett-Packard

mobile: 256.555.5309

mail: jerry@plainjoe.org

postalAddress: 103 Somewhere Street

l: Some Town

st: AL

postalCode: 55555-5555

Nếu bạn chỉ quan tâm tới địa chỉ email của một ai đó thì sao? Ta dùng hàm search ( ) để xuất ra các phần ta mong

muốn (ở đây là địa chỉ email). Việc tìm kiếm sẽ trả ra giá trị phù hợp với thuộc tính ta nêu ra.

$msg = $ldap->search(

base => "ou=people,dc=plainjoe,dc=org",

scope => "sub",

filter => "(cn=$ARGV[0])",



attrs => [ "cn", "mail" ] );

Và đây là kết quả:

dn:cn=Gerald Carter,ou=people,dc=plainjoe,dc=org



Chương 10



168



Lê Tiến Cường – Nguyễn Minh Đức

Lê Thạch Giang – Hoàng Ngọc Hưng



Giao thức LDAP



GVHD: TS. Lưu Thanh Trà



cn: Gerald Carter

mail: jerry@plainjoe.org

Dòng cuối cùng của đoạn mã là unbind( ) dùng để ngắt kết nối tới thư mục:



$ldap->unbind( );

Khi có lệnh này, kết nối tới máy chủ sẽ bị ngắt. Muốn kết nối lại ta phải dung lệnh bind ( ) một

lần nữa, và vẫn phải cung cấp DN và password lần nữa.

Đoạn mã search.pl toàn vẹn

#!/usr/bin/perl

##

## Usage: ./search.pl name

##

## Author: Gerald Carter

##

use Net::LDAP;

## Connect and bind to the server.

$ldap = Net::LDAP->new ("ldap.plainjoe.org", port =>389,

version => 3 )

or die $!;

$result = $ldap->start_tls( );

die $result->error( ) if $result->code( );

$result = $ldap->bind(

"cn=Gerald Carter,ou=people,dc=plainjoe,dc=org",

password => "hello");

die $result->error( ) if $result->code( );

## Query for the cn and mail attributes.

$msg = $ldap->search(

base => "ou=people,dc=plainjoe,dc=org",

scope => "sub",

filter => "(cn=$ARGV[0])",

attrs => [ "cn", "mail" ] );

## Print resulting entries to standard output.

if ( $msg->count( ) > 0 ) {

print $msg->count( ), " entries returned.\n";

foreach $entry ( $msg->all_entries( ) ) {

$entry->dump( );

}

}

## Unbind and exit.



$ldap->unbind( );



Chương 10



169



Lê Tiến Cường – Nguyễn Minh Đức

Lê Thạch Giang – Hoàng Ngọc Hưng



Giao thức LDAP



GVHD: TS. Lưu Thanh Trà



3. Làm việc với Net::LDAP::LDIF

Đầu tiên, ta phải thêm pragma use thứ hai để import module LDIF:

use Net::LDAP::LDIF;



Sau đó, script phải tạo một ví dụ của đối tượng Net::LDAP::LDIF. Đầu ra từ đối tượng này có

thể được link tới các file có sẵn chẳng hạn như STDOUT

$ldif = Net::LDAP::LDIF->new (STDOUT, "w")

or die $!;

Có thể điền tên file trong ngoặc của new(), hoặc ta có thể cho biết cách file đó được dùng (r là đọc, w là viết và cắt

ngắn, a là viết và nối thêm).

$ldif = Net::LDAP::LDIF->new ("./result.ldif", "w")

or die $!;

Ta mở file sau khi script đã kiểm tra rằng $msg->count( ) > 0:

if ( $msg->count( ) > 0 ) {

print $msg->count( ), " entries returned.\n";

$ldif = Net::LDAP::LDIF->new (scalar, "w")

or die $!;

Cuối cùng, thay vòng lặp foreach trên mỗi mục bởi 1 lệnh gọi write_entry( )



$ldif->write_entry($msg->all_entries( ));

write_entry( ) chấp nhận một Net::LDAP::Entry hoặc mảng 1 chiều của các đối tượng này. Vòng

lặp mới là:

if ( $msg->count( ) > 0 ) {

print $msg->count( ), " entries returned.\n";

$ldif = Net::LDAP::LDIF->new (scalar, "w")

or die $!;

$ldif->write_entry($msg->all_entries( ));

}



Bây giờ, đầu ra của script sẽ như sau:

dn: cn=Gerald Carter,ou=contacts,dc=plainjoe,dc=org

cn: Gerald Carter

mail: jerry@samba.org



Trông có vẻ không có gì thay đổi, nhưng nó rất quan trọng. Vì dữ liệu bây giờ là LDIF, các công

cụ khác như là ldapdmodify có thể phân tích cú pháp (parse) đầu ra của script.

Khi script tạo file LDIF, ta có thể đóng file bằng done ()

$ldif->done( );



Chương 10



170



Lê Tiến Cường – Nguyễn Minh Đức

Lê Thạch Giang – Hoàng Ngọc Hưng



Giao thức LDAP



GVHD: TS. Lưu Thanh Trà



4. Cập nhật thư mục

Việc tìm kiếm đối tượng trong thư mục chỉ là khởi đầu. Sức mạnh thật sự của viết code là ta có

thể chỉnh sửa thư mục, ta có thể thêm nội dung, xóa nội dung, và tùy chỉnh các nội dung đã có

sẵn.



4.1Thêm nội dung:

Đầu tiên, import.pl đọc nội dung của một file LDIF và thêm mỗi mục trong file LDIF đó vào thư

mục. Đây là điểm bắt đầu, nó tương tự như phiên bản cuối cùng của đoạn mã search.pl:

#!/usr/bin/perl

##

## Usage: ./import.pl filename

##

## Author: Gerald Carter

##

use Net::LDAP;

use Net::LDAP::LDIF;

## Connect and bind to the server.

$ldap = Net::LDAP->new ("ldap.plainjoe.org", port =>389,

version => 3 )

or die $!;

## Secure data and credentials.

$result = $ldap->start_tls( );

die $result->error( ) if $result->code( );

## Bind to the server. The account must have sufficient privileges because you will

## be adding new entries.

$result = $ldap->bind(

"cn=Directory Admin,ou=people,dc=plainjoe,dc=org",

password => "secret");

die $result->error( ) if $result->code( );

## Open the LDIF file or fail. Check for existence first.

die "$ARGV[0] not found!\n" unless ( -f $ARGV[0] );

$ldif = Net::LDAP::LDIF->new ($ARGV[0], "r")

or die $!;



Một khi đoạn mã xử lý file đầu vào, ta có thể thao tác với các nội dung trong đó.

Net::LDAP::LDIF có hàm eof ( ) để biết được đâu là phần kết thúc của file đầu vào. Vòng lặp sẽ

lặp lại tới khi giá trị kiểm tra trả về của hàm sau là true:

while ( ! $ldif->eof ) {

## Get next entry and process input here.

}



Việc lấy nội dung của LDIF tiếp theo trong file là vô cùng dễ dàng vì các module của

Net::LDAP::LDIF đã làm hết tất cả, bao gồm cả việc kiểm tra cú pháp của file. Nếu mục tiếp

theo của file là valid, hàm read_entry ( ) sẽ trả về nó như là một đối tượng của Net::LDAP::Entry

$entry = $ldif->read_entry( );

Nếu không có lỗi xảy ra, script sẽ thêm nội dung nó vừa đọc được trong file vào thư mục, dùng

add ( ):

$result = $ldap->add( $entry );



Chương 10



171



Lê Tiến Cường – Nguyễn Minh Đức

Lê Thạch Giang – Hoàng Ngọc Hưng



Giao thức LDAP



GVHD: TS. Lưu Thanh Trà



warn $result->error( ) if $result->code( );



Vòng lặp cuối cùng sẽ như sau:

## Loop until the end-of-file.

while ( ! $ldif->eof( ) ) {

$entry = $ldif->read_entry( );

## Skip the entry if there is an error.

if ( $ldif->error( ) ) {

print "Error msg: ", $ldif->error( ), "\n";

print "Error lines:\n", $ldif->error_lines( ), "\n";

next;

}

## Log to STDERR and continue in case of failure.

$result = $ldap->add( $entry );

warn $result->error( ) if $result->code( );

}



Chú ý rằng bạn kiểm tra lỗi sau khi đã thêm nội dung vào thư mục. Bạn không thể giả sử rằng

các nội dung được thêm thành công dựa trên các giá trị trả về của hàm read_entry ( ). Hàm này

chỉ đảm bảo các nội dung được nhập cú pháp chính xác, và đưa cho bạn một đối tượng

Net::LDAP::Entry có giá trị, nhưng các loại lỗi khác có thể có khi bạn thêm nội dung vào thư

mục. Lý do phổ biến nhất là sự vi phạm lược đồ.

Sau khi đã hoàn thành vòng lặp, ta ngắt kết nối và thoát:

$ldap->unbind( );

exit(0);



4.2Xóa bớt nội dung:

Tiếp theo ta sẽ nói tới việc xóa các nội dung. Hàm delete ( ) yêu cầu một DN để xác định nội

dung cần xóa. Hàm rmtree.pl chấp nhận DN từ dòng lệnh (ví dụ: rmtree.pl

"ou=test,dc=plainjoe,dc=org") và xóa các cây tương ứng với DN đó.

Nên thực hiện các đoạn mã đó như thế nào? Tốt nhất là xóa các mục từ phía dưới cây đi lên. Việc

này sẽ hạn chế việc để lại nội dung trống trong cây, vì ta xóa từ dưới lên thì không có node nào ở

dưới phần ta xóa. Để thực hiện việc xóa từ dưới lên, dùng hàm chương trình con DeleteLdapTree( ),

nó sẽ xóa một mục chỉ khi nào các mục con của mục đó đã được xóa.

#!/usr/bin/perl

##

## Usage: ./rmtree.pl DN

##

## Author: Gerald Carter

##

use Net::LDAP;

#######################################################

## Perform a depth-first search on the $dn, deleting entries from the bottom up.

## Parameters: $handle (handle to Net::LDAP object)

##

$dn

(DN of entry to remove)

sub DeleteLdapTree {

my ( $handle, $dn ) = @_;

my ( $result );



Chương 10



172



Lê Tiến Cường – Nguyễn Minh Đức

Lê Thạch Giang – Hoàng Ngọc Hưng



Giao thức LDAP



GVHD: TS. Lưu Thanh Trà



$msg = $handle->search( base => $dn,

scope => one,

filter => "(objectclass=*)" );

if ( $msg->code( ) ) {

$msg->error( );

return;

}

foreach $entry in ( $msg->all_entries ) {

DeleteLdapTree( $handle, $entry->dn( ) );

}

$result = $handle->delete( $dn );

warn $result->error( ) if $result->code( );

print "Removed $dn\n";

return;

}



Vòng lặp sẽ lặp lại tới khi nào xóa hết các mục cần thiết, nó là hàm đệ quy, gọi lại chính nó sau

mỗi lần xóa.

Để thực hiện đoạn mã này, đầu tiên phải kết nối tới server thư mục và ràng buộc server như một

người dùng đặc biệt với các đặc quyền thích hợp. Như vậy, đoạn code sẽ là:

## Connect and bind to the server.

$ldap = Net::LDAP->new ("ldap.plainjoe.org", port =>389,

version => 3 )

or die $!;

## Secure data and credentials.

$result = $ldap->start_tls( );

die $result->error( ) if $result->code( );

## Bind to the server. The account must have sufficient privileges because you will

## be adding new entries.

$result = $ldap->bind(

"cn=Directory Admin,ou=people,dc=plainjoe,dc=org",

password => "secret");

die $result->error( ) if $result->code( );



Để thực hiện việc xóa, đoạn mã sẽ xác nhận DN trong command line có đúng trong thư mục hay

không.

$msg = $ldap->search( base => $ARGV[0],

scope => base,

filter => "(objectclass=*)" );

die $msg->error( ) if $msg->code( );



Khi đã chắc chắn các nội dung đã có sẵn, đoạn mã chỉ cần gọi chương trình con DeleteLdapTree( )

là xong.

DeleteLdapTree( $ldap, $ARGV[0] );

Sau khi cây con đã được xóa, đoạn mã ngắt kết nối và thoát:

$ldap->unbind( );

exit(0);



4.3Chỉnh sửa nội dung:

Chương 10



173



Lê Tiến Cường – Nguyễn Minh Đức

Lê Thạch Giang – Hoàng Ngọc Hưng



Giao thức LDAP



GVHD: TS. Lưu Thanh Trà



Có 2 cách để chỉnh sửa nội dung trong thư mục. Hàm update( ) thêm 1 nội dung vào thư mục; để

sử dụng hàm này, đầu tiên phải copy đối tượng cần chỉnh sửa, sau đó chỉnh sửa và gởi cho

server. Hàm modify( ) cho phép ta xác định một danh sách các thay đổi, và thực hiện thay đổi trực

tiếp trên server.

4.3.1 Net::LDAP::Entry

Chúng ta bắt đầu bài tập mới bằng việc viết một hàm tùy chọn in. Tên nó là DumpEntry( ). Nó sẽ

in các nội dung DN theo sau bởi mỗi giá trị của mỗi thuộc tính mà nó chứa. ví dụ:

sub DumpEntry {

my ( $entry ) = @_;

my ( $attrib, $val );

print $entry->dn( ), "\n";

foreach $attrib in ( $entry->attributes( ) ) {

foreach $val in ( $entry->get_value( $attrib ) ) {

print $attrib, ": ", $val, "\n";

}

}

}



Đoạn code này có 3 hàm

dn( )

Nếu không có tham số, dn ( ) sẽ trả về tên của thư mục là 1 chuỗi ký tự. Nếu có đối số, thì

đối số đó sẽ được dùng để thiết lập nội dung của DN.

attributes( )

Hàm này trả về một mảng chứa các thuộc tính của nội dung.

get_value( )

Chấp nhận một tên thuộc tính và trả một mảng của giá trị của thuộc tính đó.

DumpEntry( ) tương tự như dump( ), nó chỉ in các thuộc tính và các giá trị được lưu trong bản copy

cục bộ của đối tượng Net::LDAP::Entry. Các thuộc tính thêm vào có thể được lưu trữ trong thư

mục.

Ba cách để thao tác với các thuộc tính và giá trị của mục: add( ), delete( ), and replace( ). add( ) chèn

một thuộc tính hoặc một giá trị mới vào đối tượng. Đoạn code sau thêm một địa chỉ email của

một mục được đại diện bởi hằng số $e. Nếu thuộc tính không có sẵn trong nội dung, thì nó được

thêm vào. Còn nếu thuộc tính đã có sẵn, thì giá trị mới sẽ được thêm vào thay cho giá trị cũ.

$e->add ( "mail" => "jerry@plainjoe.org" );

Hàm add( )chỉ làm việc trên bản copy



cục bộ của nội dung. Nếu thuộc tính mail không được hỗ

trợ bởi các lớp đối tượng được đăng ký trong nội dung, bạn không thể tìm thấy chúng cho tới khi

bạn trả các nội dung về server thư mục. Tương tự, add( ) cho phép bạn gán nhiều giá trị cho một

thuộc tính chỉ cho phép có một giá trị duy nhất (ví dụ, thuộc tính uidNumber trong

posixAccount).

Nhiều giá trị có thể được gán cho một thuộc tính bằng cách dùng:

$e->add( "mail" => [ "jerry@plainjoe.org",

"jerry@samba.org"] );



Hàm này cũng hỗ trợ việc thêm nhiều thuộc tính với chỉ 1 lệnh gọi hàm.

Chương 10



174



Lê Tiến Cường – Nguyễn Minh Đức

Lê Thạch Giang – Hoàng Ngọc Hưng



Giao thức LDAP



GVHD: TS. Lưu Thanh Trà



$e->add( "mail" => "jerry@plainjoe.org",

"cn" => "Gerald Carter" );



Để xóa một thuộc tính trong một mục địa phương, chỉ cần gọi hàm delete ( ). Hàm này chấp

nhận các tên thuộc tính cần xóa, hoặc như là một giá trị vô hướng, hoặc như là một mảng.

$e->delete ( [ "mail", "cn" ] );



Nó có thể xóa một giá trị cá nhân từ một thuộc tính có nhiều giá trị bằng cách đưa ra một mảng

các mục cần xóa. Ví dụ dưới đây xóa email jerry@samba.org từ địa chỉ email của mục:

$e->delete( mail => [ "jerry@samba.org" ] );

Cuối cùng, bạn có thể xóa một thuộc tính và các giá trị của chúng và thay thế nó bằng cách gọi

replace( ). Cách này chấp nhận 1 cặp thuộc tính/giá trị giống như là hàm add ( ). Đoạn code dưới

đây thay thể tất cả các giá trị gán cho thuộc tính mail bằng một địa chỉ email mới là

jerry@plainjoe.org.

$e->replace( "mail" => "jerry@plainjoe.org" );



Khi bạn làm việc với các đối tượng Net::LDAP::Entry, nhớ rằng các ví dụ khách hàng chỉ là bản

sao, các thay đổi bạn làm chỉ ảnh hưởng đến bản copy cục bộ của nội dung. Phần tiếp theo chỉ

dẫn cách để dẫn các thay đổi đó vào trong thư mục.

4.3.2 Đẩy bản cập nhật nội dung về server

Không có một thay đổi nào ở bản copy cục bộ của đối tượng Net::LDAP::Entry được phản ánh

trong thư mục cho tới khi gọi hàm update ( ). Để chỉ cách làm thế nào để cập nhật thư mục, ta sẽ

dùng một đoạn mã đơn giản khi một user muốn thay đổi mật khẩu. Đoạn mã này có hai giả định:

• Tất cả các user đều có mục trong thư mục, một tên đăng nhập sẽ khớp với thuộc tính uid

• Tất cả các user đều có thể cập nhật giá trị thuộc tính userPassword

Bạn cần thêm 2 modun cho chương trình này. Term::Readkey giúp bạn đọc loại user mà không

cần hiển thị trên màn hình. Digest::MD5cho phép tạo ra một đoạn mã hóa Base64. Đoạn mã bắt

đầu như sau:

#!/usr/bin/perl

use Net::LDAP;

use Term::ReadKey;

use Digest::MD5 qw(md5_base64);



Bạn có được tên đăng nhập bằng cách tìm trong UID của các chương trình đang chạy:

$username = getpwuid($>);

print "Changing password for user ", $username, "\n";



Sau đó đoạn mã sẽ thực thi các thiết lập kết nối LDAP quen thuộc:

ldap = Net::LDAP->new( "ldap.plainjoe.org",

version => 3)

or die $!;

$result = $ldap->start_tls( );

die $result->error( ) if $result->code( );



Tiếp theo, chương trình ngầm liên kết với các thư mục ẩn danh và cố gắng xác định vị trí các

mục nhập cho người sử dụng. Câu truy vấn là một tìm kiếm cây con bằng cách sử dụng các bộ

lọc (uid = $ username). Nếu tìm thấy nhiều kết quả phù hợp, nó sẽ trả về mục đầu tiên. Nếu

không tìm thấy, đoạn mã sẽ báo và thoát.

$msg = $ldap->search(

base => "ou=people,dc=plainjoe,dc=org",



Chương 10



175



Lê Tiến Cường – Nguyễn Minh Đức

Lê Thạch Giang – Hoàng Ngọc Hưng



Giao thức LDAP



GVHD: TS. Lưu Thanh Trà



scope => "sub",

filter => "(uid=$username)" );

die $msg->error( ) if $msg->code( );

die "No such user in directory [$username]!\n"

if !$msg->count;



Nếu bạn biết user có trong thư mục LDAP, nhắc nhở user gõ mật khẩu cũ và mật khẩu mới. Yêu

cầu gõ mật khẩu mới 2 lần, và kiểm tra 2 lần gõ như nhau:

## Read old and new password strings. Use ReadMode to prevent the passwords from

## being echoed to the screen.

ReadMode( 'noecho' );

print "Enter Old Password: ";

$old_passwd = chomp( ReadLine(0) );

print "\nEnter New Password: ";

$new_passwd = chomp( ReadLine(0) );

print "\nEnter New Password again: ";

$new_passwd2 = chomp( ReadLine(0) );

print "\n";

ReadMode( 'restore' );

## Check that new password was typed correctly.

if ( "$new_passwd" ne "$new_passwd2" ) {

print "New passwords do not match!\n";

exit (1);

}



Để chuyển kết quả tìm kiếm thành một đối tượng, đoạn mã gọi entry ( ). Chương trình con này

nhận một chỉ số nguyên vào mảng các mục tạo ra bởi tìm kiếm trước đó. Trong trường hợp này,

chúng ta chỉ làm việc với mục đầu tiên, chúng ta đang giả sử rằng việc tìm kiếm sẽ chỉ trả về một

mục:

$entry = $msg->entry(0);

Bây giờ bạn đã có cả DN của mục của user và cả giá trị của mật khẩu cũ. Bây giờ bạn có thể xác

thực người dùng bằng cách liên hệ với server thư mục. Nếu liên kết bị fail, đoạn mã sẽ thông báo

rằng mật khẩu cũ bị sai:

$result = $ldap->bind( $entry->dn( ),

password => $old_passwd );

die "Old Password is invalid!\n" if $result->code( );



Công việc còn lại là update mật khẩu của user vào thư mục.

## Generate Base64 md5 hash of the new passwd.

$md5_pw = "{MD5}" . md5_base64($new_passwd) . "= =";



“= =” là để đảm bảo chuỗi ký tự là một bội số của 4 bytes. Tiếp theo, viết đè lên mật khẩu cũ

bằng cách gọi hàm replace( ):

$entry->replace( userPassword => $md5_pw );



Để chuyển các thay đổi này vào thư mục, gọi update( ).

$result = $entry->update( $ldap );

die $result->error( ) if $result->code( );



Bây giờ thông báo cho user là mật khẩu của user đã được update và thoát:

print "Password updated successfully\n";

exit (0);



Khi thực hiện, kết quả của passwd.pl trông giống như tiện ích chuẩn passwd của Unix:

Chương 10



176



Lê Tiến Cường – Nguyễn Minh Đức

Lê Thạch Giang – Hoàng Ngọc Hưng



Giao thức LDAP



GVHD: TS. Lưu Thanh Trà



$ ./passwd.pl

Changing password for user jerry

Enter Old Password: secret

Enter New Password: new-secret

Enter New Password again: new-secret

Password updated successfully



4.3.3 Thay đổi nội dung thư mục:

Mặc dù LDAPv3 không đặc biệt hỗ trợ cho việc thực hiện trên nhiều mục 1 lúc, nhưng RFCs xác

định rằng các thay đổi trên một mục riêng biệt nào đó phải được làm một cách tự động. Khi nào

chúng ta quan tâm tới việc update tự động? Giả sử rằng, trong mạng của bạn, tất cả các tài khoản

user được tạo trong thư mục LDAP trung tâm, bằng cách sử dụng lớp đối tượng posixAccount.

Nhưng ở trong một mạng lớn, bạn có nhiều admin, mỗi admin lại có thể quản trị trong 1 khoảng

thời gian bất kỳ. Bạn cần đảm bảo rằng các công cụ quản lý user luôn luôn có được số UID và

GID khả dụng tiếp theo mà không có sự trùng lặp số ID khi 2 đoạn mã cùng chạy 1 lúc.

Ở đây, việc dùng thư mục để lưu trữ các giá trị UID và GID khả dụng được xem như là việc khờ

khạo. Tất cả những gì bạn cần là chương trình con lấy số ID tiếp theo và lưu trữ giá trị tăng dần.

Các hoạt động này phải là tự động. Để làm được điều này, bạn phải khai báo 2 lớp đối tượng

mới, một cho uidPool và một cho gidPool. Giản đồ cho 2 đối tượng này được minh họa trong

hình 10-1 sau:



Đây là cách thực thi của hàm get_next_uid( ). Nó yêu cầu đối tượng Net::LDAP xem nó như là

tham số duy nhất. get_next_gid( ) hầu như giống nhau;

#########################################################

## Get the next available UID from the idPool. Spin until you get one.

##

sub get_next_uid {

my ( $ldap ) = @_;

my ( $uid, $msg, $entry );

my ( @Add, @Delete, @Changes );



Chương 10



177



Lê Tiến Cường – Nguyễn Minh Đức

Lê Thạch Giang – Hoàng Ngọc Hưng



Xem Thêm
Tải bản đầy đủ (.docx) (188 trang)

×