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

Last change on this file since 1144 was 1114, checked in by nanardon, 12 years ago

remove useless module usage

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