source: LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Ad/User.pm @ 197

Last change on this file since 197 was 197, checked in by nanardon, 15 years ago
  • fix create user in AD, trap some error
  • Property svn:keywords set to Id Rev
File size: 5.8 KB
Line 
1package LATMOS::Accounts::Bases::Ad::User;
2
3use 5.010000;
4use strict;
5use warnings;
6
7use base qw(LATMOS::Accounts::Bases::Ad::objects);
8use Net::LDAP;
9use Net::LDAPS;
10use Net::LDAP::Entry;
11use Net::LDAP::Control::Paged;
12use Net::LDAP::Constant qw( LDAP_CONTROL_PAGED ); 
13use Net::LDAP::Util     qw( escape_filter_value );
14
15our $VERSION = (q$Rev$ =~ /^Rev: (\d+) /)[0];
16
17=head1 NAME
18
19LATMOS::Ad - Perl extension for blah blah blah
20
21=head1 SYNOPSIS
22
23  use LATMOS::Ad;
24  blah blah blah
25
26=head1 DESCRIPTION
27
28Stub documentation for LATMOS::Ad, 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 _class_filter { '(&(ObjectClass=user) (!(ObjectClass=computer)))' }
39
40sub _key_attr { 'cn' } 
41
42sub _delayed_fields {
43    my ($self)= @_;
44    return qw(memberOf);
45}
46
47sub _canonical_fields {
48    my ($self, $base, $mode) = @_;
49    (
50        qw(
51        sn name givenName
52        sAMAccountName uid gecos
53        homeDirectory loginShell
54        uidNumber gidNumber gecos
55        userPassword
56        shadowLastChange shadowMin shadowMax
57        shadowWarning shadowInactive shadowExpire
58        shadowFlag
59        description
60        mail
61        ipPhone otherTelephone department
62        title modbile homePhone
63        memberOf
64        accountExpires
65        streetAddress postalCode postOfficeBox l
66        physicalDeliveryOfficeName
67        company st
68        displayName
69        initials
70        manager
71        userAccountControl
72        locked
73        ),
74        ($mode !~ /w/
75            ? qw(cn dn uSNCreated uSNChanged directReports)
76            : ()
77        )
78    )
79}
80
81sub _create {
82    my ($class, $base, $id, %data) = @_;
83
84    my $entry = Net::LDAP::Entry->new();
85
86    $entry->dn(join(',',
87        sprintf('cn=%s', escape_filter_value($id)),
88        $base->object_base_dn($class->type),
89    ));
90    $entry->replace('sAMAccountName', $id);
91    $entry->replace(objectClass => [ qw(top person organizationalPerson user)],);
92    $entry->replace(userAccountControl => 66112);
93    # This attributes cannot be set via LDAP:
94    #$entry->replace(sAMAccountType => 0x30000000);
95    $entry->replace(accountExpires => '9223372036854775807'); # TODO hardcoded, burk
96    $entry->replace(userPrincipalName => "$id\@" . $base->ad_domain);
97    foreach (keys %data) {
98        $class->_populate_entry($entry, $_, $data{$_});
99    }
100    my $msg = $base->ldap->add($entry);
101    warn $msg->error if ($msg->code);
102    return $msg->code ? 0 : 1;
103}
104
105sub get_field {
106    my ($self, $field) = @_;
107
108    $field eq 'memberOf' and do {
109        my @res;
110        $self->base->_unlimited_search(
111            base => $self->base->object_base_dn('group'),
112            filter => sprintf(
113                '(&(objectClass=group)(member=%s))',
114                escape_filter_value($self->{entry}->dn),
115            ),
116            callback => sub {
117                my ($mesg, $entry) = @_;
118                ref $entry eq 'Net::LDAP::Entry' or return;
119                push(@res, $entry->get_value('cn'));
120            },
121        );
122        return [ sort(@res) ];
123    };
124    $field eq 'directReports' and do {
125        my $res = $self->SUPER::get_field($field);
126        return [
127            map { $self->base->_get_object_from_dn($_)->get_value('cn') }
128            @{ ref $res ? $res : [ $res ] }
129        ];
130    };
131    $field eq 'manager' and do {
132        my $dn = $self->SUPER::get_field($field) or return;
133        return $self->base->_get_object_from_dn($dn)->get_value('cn');
134    };
135    $self->SUPER::get_field($field);
136}
137
138sub set_fields {
139    my ($self, %data) = @_;
140    my %ndata;
141    while (my ($f, $val) = each(%data)) {
142        $f eq 'memberOf' and do {
143            my %users;
144            $users{$_}{e} = 1 foreach (@{ $self->get_field('memberOf') || []});
145            $users{$_}{n} = 1 foreach (@{ $val || []});
146            foreach (keys %users) {
147                $users{$_}{e} && $users{$_}{n} and next;
148                my $user = $self->base->get_object('group', $_) or next;
149                if ($users{$_}{e}) {
150                    $self->{entry}->del(memberOf => $user->get_field('dn'));
151                } elsif ($users{$_}{n}) {
152                    $self->{entry}->add(memberOf => $user->get_field('dn'));
153                } # else {} # can't happen
154                my $mesg = $self->{entry}->update($self->base->ldap);
155            }
156            next;
157        };
158        $f eq 'manager' && $val and do {
159            my $user = $self->base->get_object('user', $val) or next;
160            $ndata{$f} = $user->get_field('dn');
161            next;
162        };
163        $f eq 'locked' and do {
164            my $uac = $self->get_field('userAccountControl');
165            if ($val) {
166                $uac |= 0x00000002;
167            } else {
168                $uac &= (0xFFFFFFFF ^ 0x00000002);
169            }
170            $ndata{userAccountControl} = "$uac";
171            next;
172        };
173        $ndata{$f} = $val;
174    }
175    $self->SUPER::set_fields(%ndata);
176}
177
178sub set_password {
179    my ($self, $clear_pass) = @_;
180    my $charmap = Unicode::Map8->new('latin1')  or  die;
181    my $newUniPW = $charmap->tou('"'.$clear_pass.'"')->byteswap()->utf16();
182    my $mesg = $self->base->ldap->modify(
183        $self->get_c_field('dn'),
184        changes => [
185        #replace => [ userPassword => $clear_pass ],
186        replace => [ unicodePwd => $newUniPW ],
187
188        ]
189    );
190    if ($mesg->code && $mesg->code != 82) {
191        warn $mesg->error;
192        return;
193    } else { return 1 }
194}
195
1961;
197
198__END__
199
200=head1 SEE ALSO
201
202=head1 AUTHOR
203
204Olivier Thauvin, E<lt>olivier.thauvin@aerov.jussieu.frE<gt>
205
206=head1 COPYRIGHT AND LICENSE
207
208Copyright (C) 2008 CNRS SA/CETP/LATMOS
209
210This library is free software; you can redistribute it and/or modify
211it under the same terms as Perl itself, either Perl version 5.10.0 or,
212at your option, any later version of Perl 5 you may have available.
213
214
215=cut
Note: See TracBrowser for help on using the repository browser.