/[A3C]/lib/A3C/LDAP.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /lib/A3C/LDAP.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 106 - (show annotations)
Thu May 1 17:06:02 2008 UTC (14 years, 1 month ago) by dpavlin
File size: 4706 byte(s)
massive re-structuring to enable models specified in configuration file

- version bump [0.04]
- SyncOrganization now accept org_uid as argument
- objectClass(es) for person and organization are now in config.yml
  as well as link between them (filter on person)
- config.yml is now checked for validity in A3C::LDAP
1 package A3C::LDAP;
2
3 use strict;
4 use warnings;
5
6 use Net::LDAP;
7 use Data::Dump qw/dump/;
8 use base qw(Jifty::Object Class::Accessor::Fast);
9 our @config_fields = keys %{ Jifty->config->app('LDAP') };
10 Jifty->log->debug("using fields from configuration: ",dump( @config_fields ));
11 __PACKAGE__->mk_accessors( qw(ldap current_search), @config_fields );
12
13
14 =head1 NAME
15
16 A3C::LDAP
17
18 =head1 DESCRIPTION
19
20 This object turn L<Net::LDAP> into something with looks like
21 L<Jifty::Collection>
22
23 =head1 METHODS
24
25 =head2 new
26
27 my $ldap = A3C::LDAP->new;
28
29 =cut
30
31 sub new {
32 my $class = shift;
33
34 my $args = { @_ };
35
36 my $ldap_config = Jifty->config->app('LDAP');
37 Jifty->log->debug( "config->app(LDAP) = ",dump( $ldap_config ) );
38
39 foreach my $f ( @config_fields ) {
40 if ( my $v = $ldap_config->{$f} ) {
41 $args->{$f} = $v;
42 }
43 }
44
45 # configuration sanity testing
46 foreach ( qw/server dn password base objectClass link/ ) {
47 die "missing required field $_ in LDAP from etc/config.yaml" unless $args->{$_};
48 }
49 foreach ( qw/person organization/ ) {
50 die "missing required field $_ in LDAP.objectClass.$_ from etc/config.yaml" unless $args->{objectClass}->{$_};
51 }
52 foreach ( qw/person_filter display_from value_from/ ) {
53 die "missing required field $_ in LDAP.link.$_ from etc/config.yaml" unless $args->{link}->{$_};
54 }
55
56 my $ldap = Net::LDAP->new( $args->{server} ) or die "$@";
57
58 # an anonymous bind
59 #$ldap->bind;
60 $ldap->bind( $args->{dn}, password => $args->{password} );
61
62 Jifty->log->info("Connected to ", $args->{server}, " with DN ", $args->{dn});
63
64 $args->{ldap} = $ldap;
65
66 $class->SUPER::new( $args );
67 }
68
69 =head2 search
70
71 my $msg = A3C::LDAP->search(
72 base => 'dc=skole,dc=hr',
73 filter => '(objectClass=hrEduOrg)',
74 sizelimit => 10,
75 );
76
77 =cut
78
79 sub search {
80 my $self = shift;
81
82 my $search = $self->ldap->search( @_ );
83 if ( $search->code != 0 ) {
84 Jifty->log->error( $search->error, ' for ', dump( @_ ) );
85 }
86 return $self->current_search( $search );
87 }
88
89 =head2 next
90
91 Syntaxtic shugar to look more like L<Jifty::DBI::Collection>
92
93 my $entry = ldap->next;
94
95 =cut
96
97 sub next {
98 my $self = shift;
99
100 die "no current LDAP search" unless $self->current_search;
101
102 return $self->current_search->shift_entry;
103 }
104
105 =head2 count
106
107 my $search_results = $ldap->count;
108
109 =cut
110
111 sub count {
112 my $self = shift;
113 $self->current_search->count;
114 }
115
116 =head2 collection
117
118 my $connection = $ldap->collection(
119 # name of model to use
120 $ldap->objectClass->{organization},
121 # optional params
122 limit => $limit,
123 filter => '(uid=foobar)',
124 );
125
126 =cut
127
128 my $collection2filter = {
129 'Person' => '(objectClass=hrEduPerson)',
130 'Organization' => '(objectClass=hrEduOrg)',
131 };
132
133 sub collection {
134 my $self = shift;
135 my $model = shift or die "no model?";
136 my $args = {@_};
137
138 $args->{limit} ||= 0; # unlimited by default
139
140 my $filter = $collection2filter->{$model};
141 # die "unknown model $model" unless $filter;
142 # fallback to model named as objectClass
143 $filter ||= "(objectClass=$model)";
144
145 # add user filter
146 $filter = '(&' . $filter . $args->{filter} . ')' if $args->{filter};
147
148 $self->search(
149 base => $self->base,
150 filter => $filter,
151 sizelimit => $args->{limit},
152 );
153
154 Jifty->log->info(
155 "Searching LDAP for $model with $filter ",
156 $args->{limit} ? 'limit ' . $args->{limit} . ' ' : '',
157 'returned ', $self->count, ' results'
158 );
159
160 my $class = Jifty->app_class('Model', $model . 'Collection' ) or die "can't create ${model}Collection";
161 my $collection = $class->new() or die "can't $class->new";
162
163 while ( my $entry = $self->next ) {
164 my $model_obj = Jifty->app_class('Model',$model)->new;
165 #warn dump( $model_obj );
166 my $additional;
167 $self->model_from_entry( $model_obj, $entry, %$additional );
168 $collection->add_record( $model_obj );
169 }
170
171 return $collection;
172 }
173
174 =head1 INTERNAL METHODS
175
176 Following methods map directly into L<Net::LDAP>
177
178 =head2 current_search
179
180 Result of last C<< $ldap->search >> request
181
182 =head2 model_from_entry
183
184 $ldap->model_from_entry( $model, $entry, $additional );
185
186 =cut
187
188 sub model_from_entry {
189 my ( $self, $model, $entry, $additional ) = @_;
190 my $data;
191
192 my @columns = map { $_->name } $model->columns;
193 #warn "# columns = ",dump( @columns );
194
195 foreach my $attr ( $entry->attributes ) {
196 if ( grep(/^\Q$attr\E$/, @columns ) ) {
197 $data->{$attr} = $entry->get_value( $attr );
198 # } elsif ( $attr !~ m/^(objectClass)$/i ) {
199 } else {
200 Jifty->log->warn(ref($model)," doesn't have $attr");
201 }
202 }
203
204 Jifty->log->debug( ref($model), ' = ', dump( $data ) );
205
206 my ( $id, $message ) = $model->load_or_create( %$data, %$additional );
207
208 if ( $id ) {
209 Jifty->log->info( $message || 'Added', ' ', ref($model), ' ', $model->id, ' ', $model->name );
210 } else {
211 Jifty->log->error( ref($model), " ", $message );
212 }
213 }
214
215
216
217 1;

  ViewVC Help
Powered by ViewVC 1.1.26