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

Last change on this file since 2488 was 2488, checked in by nanardon, 3 years ago

Fix ldap class upgrade

File size: 7.3 KB
Line 
1package LATMOS::Accounts::Bases::Ldap::objects;
2
3use 5.010000;
4use strict;
5use warnings;
6
7use base qw(LATMOS::Accounts::Bases::Objects);
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 LATMOS::Accounts::Log;
14
15our $VERSION = (q$Rev: 652 $ =~ /^Rev: (\d+) /)[0];
16
17=head1 NAME
18
19LATMOS::Ldap - Perl extension for blah blah blah
20
21=head1 SYNOPSIS
22
23  use LATMOS::Ldap;
24  blah blah blah
25
26=head1 DESCRIPTION
27
28Stub documentation for LATMOS::Ldap, created by h2xs. It looks like the
29author of the extension was negligent enough to leave the stub
30unedited.
31
32Blah blah blah.
33
34=head1 FUNCTIONS
35
36=cut
37
38sub _get_attr_schema {
39    my ($class, $base, $info) = @_;
40    $info ||= {};
41
42    foreach (qw(
43            createTimestamp
44            creatorsName
45            entryUUID
46            modifiersName
47            modifyTimestamp
48            entryCSN
49            )) {
50        $info->{$_} = { ro => 1 };
51    }
52
53    $info->{$class->_key_attribute($base)}{ro} = 1;
54    $info->{$class->_dn_attribute($base)}{ro} = 1;
55
56    return $info;
57}   
58
59sub _key_attribute {
60    my ($self, $base) = @_;
61    $base ||= $self->base;
62
63    $base->config($self->type . '_key_attribute') || $self->_key_attr || 'cn';
64}
65
66sub _dn_attribute {
67    my ($self, $base) = @_;
68    $base ||= $self->base;
69
70    $base->config($self->type . '_dn_attribute') || $self->_key_attr || 'cn';
71}
72
73sub list {
74    my ($class, $base) = @_;
75   
76    my @uids;
77    eval {
78    my $xx = $base->_unlimited_search(
79        attrs => [ $class->_key_attribute($base) ],
80        base => $base->object_base_dn($class->type),
81        filter => $class->_class_filter,
82        callback => sub {
83            my ($mesg, $entry) = @_;
84            #$mesg->code and die $mesg->error;
85            $entry or return;
86            ref $entry eq 'Net::LDAP::Entry' or return;
87            push(@uids, $entry->get_value( $class->_key_attribute($base) ));
88        },
89    );
90    };
91
92    return @uids;
93
94}
95
96sub new {
97    my ($class, $base, $uid) = @_;
98   
99    my $mesg = $base->ldap->search(
100        filter => sprintf(
101            '(&%s (%s=%s))',
102            $class->_class_filter,
103            $class->_key_attribute($base),
104            escape_filter_value($uid),
105        ),
106        base => $base->object_base_dn($class->type),
107        attrs => [ $class->_canonical_fields($base, 'r') ],
108    );
109
110    if ($mesg->code)  {
111        $base->log(LA_ERR, 'Cannot fetch %s/%s: %s', $class->type, $uid, $mesg->code);
112        return;
113    }
114
115    my ($entry, @others) = $mesg->entries;
116
117    if(@others) { # we cannot have multiple entries...
118        $base->la_log(LA_ERR, 'Multiple entry found for %s/%s', $class->type, $uid);
119        return;
120    }
121    if (!$entry) {
122        $base->log(LA_DEBUG, 'Cannot fetch %s/%s: no entry returned', $class->type, $uid);
123        return;
124    }
125    bless({ entry => $entry, _base => $base, _id => $uid }, $class);
126}
127
128sub _delete {
129    my ($class, $base, $uid) = @_;
130    my $obj = $class->new($base, $uid) or return;
131
132    my $mesg = $base->ldap->delete($obj->{entry}->dn);
133
134    if ($mesg->code) {
135        $base->log(LA_ERR, "Cannot delete object %s: %s", $uid, $mesg->error);
136        return;
137    } else {
138        $base->log(LA_INFO, "Object (%s) %s deleted", $class->type, $uid);
139        return 1
140    }
141}
142
143sub _rename {
144    my ($class, $base, $uid, $newuid) = @_;
145    my $obj = $class->new($base, $uid) or return;
146
147    my $mesg;
148
149    if ($class->_key_attribute($base) ne
150                $class->_dn_attribute($base)) {
151
152        my $entry = $obj->{entry}->clone;
153        $entry->add(
154            $class->_key_attribute($base),
155            $newuid
156        );
157        $mesg = $entry->update($base->ldap);
158        if ($mesg->code && $mesg->code ne 20) {
159            $base->log(LA_ERR, "Cannot update key_attribute for object %s: %s", $uid, $mesg->error);
160            return;
161        }
162    }
163
164
165    $mesg = $base->ldap->moddn(
166        $obj->{entry},
167        newrdn => $class->_dn_attribute($base) . '=' .  escape_filter_value($newuid),
168        deleteoldrdn => 1,
169    );
170    if ($mesg->code) {
171        $base->log(LA_ERR, "Cannot rename object %s: %s", $uid, $mesg->error);
172        return;
173    }
174
175    $mesg = $base->ldap->search(
176        filter => sprintf(
177            '(&%s (%s=%s))',
178            $class->_class_filter,
179            $class->_key_attribute($base),
180            escape_filter_value($newuid),
181        ),
182        base => $base->object_base_dn($class->type),
183        attrs => [ $class->_canonical_fields($base, 'r') ],
184    );
185
186    if ($mesg->code)  {
187        $base->log(LA_ERR, 'Cannot fetch %s/%s: %s', $class->type, $uid, $mesg->code);
188        return;
189    }
190
191    my ($entry, @others) = $mesg->entries;
192
193    $obj->{entry} = $entry;
194
195    $obj->{entry}->replace(
196        $class->_key_attribute($base),
197        $newuid
198    );
199    $mesg = $obj->{entry}->update($base->ldap);
200
201    if ($mesg->code) {
202        $base->log(LA_ERR, "Cannot rename object %s: %s", $uid, $mesg->error);
203        return;
204    } else {
205        return 1;
206    }
207}
208
209=head2 ldap
210
211A shortcut to return the L<Net::LDAP> object
212
213=cut
214
215sub ldap {
216    return $_[0]->base->{_ldap};
217}
218
219sub get_field {
220    my ($self, $field) = @_;
221
222    $field eq 'dn' and return $self->{entry}->dn;
223    my ($first, @others) = $self->{entry}->get_value($field);
224    return @others ? [ sort($first, @others) ] : $first;
225}
226
227sub _populate_entry {
228    my ($self, $entry, $field, $value, $base) = @_;
229    my $val = ref $self ? $self->get_field($field) : undef;
230    my $tr =  join(', ', map { $_ || '' } ($field, $val, $value));
231    if ($value) {
232        if ((!$val) || $val ne $value) {
233            $entry->replace($field, $value);
234        }
235    } elsif($val) {
236        $entry->delete($field);
237    }
238}
239
240sub _set_c_fields {
241    my ($self, %fields) = @_;
242
243    {
244        my $oclass = join(',', sort $self->{entry}->get_value('objectClass'));
245        my $cclass = join(',', sort $self->_my_ldap_classes);
246        if ($oclass ne $cclass) {
247            $self->_update_class();
248        }
249    }
250
251    $self->SUPER::_set_c_fields(%fields);
252
253    my $mesg = $self->{entry}->update($self->base->ldap);
254
255    if ($mesg->code && $mesg->code != 82) {
256        $self->base->log(LA_ERR, "Cannot set attributes: %s", $mesg->error);
257        return;
258    } else { return 1 }
259}
260
261sub set_fields {
262    my ($self, %fields) = @_;
263
264    foreach (keys %fields) {
265        my $attr = $self->attribute($_) or do {
266            $self->base->log(LA_ERR, "Unknow attribute %s (%s)",
267                $_, $self->type);
268            return;
269        };
270        $attr->ro and next;
271        $self->_populate_entry($self->{entry}, $_, $fields{$_});
272    }
273   
274    return 1;
275}
276
277sub _update_class {
278    my ($self, %attr) = @_;
279
280
281    $self->base->log(
282        LA_NOTICE,
283        "Updating ObjectClass for %s/%s: %s",
284        $self->type, $self->id, join(', ', $self->_my_ldap_classes)
285    );
286    $self->base->log(
287        LA_NOTICE,
288        "Updating ObjectClass Attribute %s",
289        join(', ', %attr)
290    ) if (%attr);
291    $self->{entry}->replace(
292        'objectClass' => [ $self->_my_ldap_classes ],
293        %attr,
294    );
295}
296
2971;
298
299__END__
300
301=head1 SEE ALSO
302
303=head1 AUTHOR
304
305Olivier Thauvin, E<lt>olivier.thauvin@aerov.jussieu.frE<gt>
306
307=head1 COPYRIGHT AND LICENSE
308
309Copyright (C) 2008 CNRS SA/CETP/LATMOS
310
311This library is free software; you can redistribute it and/or modify
312it under the same terms as Perl itself, either Perl version 5.10.0 or,
313at your option, any later version of Perl 5 you may have available.
314
315
316=cut
Note: See TracBrowser for help on using the repository browser.