source: LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Ldap.pm @ 354

Last change on this file since 354 was 288, checked in by nanardon, 15 years ago
  • add (open)ldap support
File size: 5.1 KB
Line 
1package LATMOS::Accounts::Bases::Ldap;
2
3use 5.010000;
4use strict;
5use warnings;
6
7use base qw(LATMOS::Accounts::Bases);
8use Net::LDAP;
9use Net::LDAP::Entry;
10use Net::LDAP::Control::Paged;
11use Net::LDAP::Constant qw( LDAP_CONTROL_PAGED ); 
12use Net::LDAP::Util     qw( escape_filter_value );
13use Unicode::Map8;
14use Unicode::String qw(utf16);
15use LATMOS::Accounts::Log;
16
17our $VERSION = (q$Rev: 653 $ =~ /^Rev: (\d+) /)[0];
18
19=head1 NAME
20
21LATMOS::Ldap - Perl extension for blah blah blah
22
23=head1 SYNOPSIS
24
25  use LATMOS::Ldap;
26  blah blah blah
27
28=head1 DESCRIPTION
29
30Stub documentation for LATMOS::Ldap, created by h2xs. It looks like the
31author of the extension was negligent enough to leave the stub
32unedited.
33
34Blah blah blah.
35
36=head1 FUNCTIONS
37
38=cut
39
40=head2 new(%options)
41
42Create a new LATMOS::Ldap object for windows AD $domain.
43
44options:
45
46=over 4
47
48=item domain
49
50The Active directory domain
51
52=item server (optional)
53
54If set, try to connect to this server, if not set, a dns query is performed
55to find AD server, first responding is used.
56
57=item ssl
58
59If set, try to connect using ssl
60
61=item OBJECT_container
62
63The sub path where to find object type of OBJECT and where they should
64be created
65
66=back
67
68=cut
69
70sub new {
71    my ($class, %options) = @_;
72   
73    my $self = {
74        _server => $options{server},
75        _top_dn => $options{topdn},
76        _login => $options{login},
77        _password => $options{password},
78        _ssl => $options{ssl},
79        _param => { %options },
80    };
81
82    bless($self, $class);
83}
84
85sub param {
86    my ($self, $var) = @_;
87    return $self->{_param}{$var}
88}
89
90sub object_base_dn {
91    my ($self, $otype) = @_;
92    return join(',',
93        ($self->param($otype . '_container') || 'cn=Users'),
94        $self->top_dn,
95    );
96}
97
98sub load {
99    my ($self) = @_;
100    # At this point, if still no $server, DNS search
101
102    my $ldapurl = $self->_ldap_url($self->{_server});
103    my $ldap = Net::LDAP->new($ldapurl);
104       
105
106    if($ldap) {
107        $self->log(LA_DEBUG, "Connected to ldap server %s", $ldapurl);
108    } else {
109        $self->log(LA_ERR, "Cannot connect to %s", $ldapurl);
110        return; # cannot connect to any ldap :\
111    };
112
113
114    my $msg = $ldap->bind($self->{_login}, password => $self->{_password});
115    $msg->code and do {
116        $self->log(LA_ERR, "Cannot bind ldap: %s", $msg->error);
117        return;
118    };
119
120    $self->{_ldap} = $ldap;
121    return 1;
122}
123
124sub _ldap_url {
125    my ($self, $host, $port) = @_;
126
127    sprintf(
128        '%s://%s%s/',
129        $self->{_ssl} ? 'ldaps' : 'ldap',
130        $host,
131        $port ? ":$port" : '',
132    )
133}
134
135sub ldap {
136    return $_[0]->{_ldap};
137}
138
139=head2 top_dn
140
141Return the TOP DN of the AD zone.
142
143=cut
144
145sub top_dn {
146    return $_[0]->{_top_dn}
147}
148
149# _unlimited_search
150
151# By default, ldap servers limit results to avoid deni of services.
152# LDAP protocol provide a paging feature to fetch all results.
153
154#This function works like Net::LDAP::search functions, but return nothing,
155#use "callback" option to get entries.
156
157sub _unlimited_search {
158    my $self = shift;
159    my @args = @_;
160
161    my ($page, $cookie) = (Net::LDAP::Control::Paged->new( size => 100 ));
162
163    while (1) {
164        my $search = $self->ldap->search(
165            @args,
166            control => [ $page ],
167        );
168        if ($search->code) {
169            return $search;
170        }
171
172        ### After foreach loops ends, client checks LDAP server reponse of how many search results total.
173        ### This is a control to end the infinite while loop if there are no search results to go through
174        ### If there are search results, this control will always return the total number of results. It is
175        ### never decremented
176        my ($resp) = $search->control( LDAP_CONTROL_PAGED ) or last;
177
178
179        ### Obtaining the cookie from the search result. When no more results, cookie will be NULL
180        ### and infinite while loop will terminate.
181        $cookie = $resp->cookie or last;
182
183        ### Sets cookie so server knows the next search result to send
184        $page->cookie($cookie);
185    }
186    ### This is a control to check for abnormal exit of the while loop.
187    ### If this occurs ### we need to tell the LDAP server that remaining
188    ### search results are no longer needed ### by sending a search request with a page size of 0
189    if ($cookie)    {
190        $page->cookie($cookie);
191        $page->size(0);
192        $self->ldap->search(@args, control => [ $page ]);
193    }
194    return 1;
195}
196
197# _get_object_from_dn($dn)
198#
199# Return Net::LDAP::Entry for $dn
200
201sub _get_object_from_dn {
202    my ($self, $dn) = @_;
203
204    my $mesg = $self->ldap->search(
205        base => $dn,
206        scope => 'base',
207        filter => '(objectClass=*)',
208    );
209    if ($mesg->code) {
210        $self->log(LA_ERR, "Cannot get object: %s", $mesg->error);
211        return;
212    }
213
214    return ($mesg->entries)[0];
215}
216
2171;
218
219__END__
220
221=head1 SEE ALSO
222
223=head1 AUTHOR
224
225Olivier Thauvin, E<lt>olivier.thauvin@aerov.jussieu.frE<gt>
226
227=head1 COPYRIGHT AND LICENSE
228
229Copyright (C) 2008 CNRS SA/CETP/LATMOS
230
231This library is free software; you can redistribute it and/or modify
232it under the same terms as Perl itself, either Perl version 5.10.0 or,
233at your option, any later version of Perl 5 you may have available.
234
235
236=cut
Note: See TracBrowser for help on using the repository browser.