/[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 208 - (show annotations)
Thu Jun 19 21:24:26 2008 UTC (15 years, 9 months ago) by dpavlin
File size: 4771 byte(s)
another round of re-factoring

- re-organize LDAP-related pages under /ldap with new view A3C::View::LDAP
- move record multi-value support into A3C::Record
- document multi-value solution which started it all
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 use Jifty;
10 our @config_fields = keys %{ Jifty->config->app('LDAP') };
11 Jifty->log->debug("using fields from configuration: ",dump( @config_fields ));
12 __PACKAGE__->mk_accessors( qw(ldap current_search), @config_fields );
13
14
15 =head1 NAME
16
17 A3C::LDAP
18
19 =head1 DESCRIPTION
20
21 This object turn L<Net::LDAP> into something with looks like
22 L<Jifty::Collection>
23
24 =head1 METHODS
25
26 =head2 new
27
28 my $ldap = A3C::LDAP->new;
29
30 =cut
31
32 sub new {
33 my $class = shift;
34
35 my $args = { @_ };
36
37 my $ldap_config = Jifty->config->app('LDAP');
38 Jifty->log->debug( "config->app(LDAP) = ",dump( $ldap_config ) );
39
40 foreach my $f ( @config_fields ) {
41 if ( my $v = $ldap_config->{$f} ) {
42 $args->{$f} = $v;
43 }
44 }
45
46 # configuration sanity testing
47 foreach ( qw/server dn password base objectClass link/ ) {
48 die "missing required field $_ in LDAP from etc/config.yaml" unless $args->{$_};
49 }
50 foreach ( qw/person organization/ ) {
51 die "missing required field $_ in LDAP.objectClass.$_ from etc/config.yaml" unless $args->{objectClass}->{$_};
52 }
53 foreach ( qw/person_filter display_from value_from/ ) {
54 die "missing required field $_ in LDAP.link.$_ from etc/config.yaml" unless $args->{link}->{$_};
55 }
56
57 my $ldap = Net::LDAP->new( $args->{server} ) or die "$@";
58
59 # an anonymous bind
60 #$ldap->bind;
61 $ldap->bind( $args->{dn}, password => $args->{password} );
62
63 Jifty->log->info("Connected to ", $args->{server}, " with DN ", $args->{dn});
64
65 $args->{ldap} = $ldap;
66
67 $class->SUPER::new( $args );
68 }
69
70 =head2 search
71
72 my $msg = A3C::LDAP->search(
73 base => 'dc=skole,dc=hr',
74 filter => '(objectClass=hrEduOrg)',
75 sizelimit => 10,
76 );
77
78 =cut
79
80 sub search {
81 my $self = shift;
82
83 my $search = $self->ldap->search( @_ );
84 if ( $search->code != 0 ) {
85 Jifty->log->error( $search->error, ' for ', dump( @_ ) );
86 }
87 return $self->current_search( $search );
88 }
89
90 =head2 next
91
92 Syntaxtic shugar to look more like L<Jifty::DBI::Collection>
93
94 my $entry = ldap->next;
95
96 =cut
97
98 sub next {
99 my $self = shift;
100
101 die "no current LDAP search" unless $self->current_search;
102
103 return $self->current_search->shift_entry;
104 }
105
106 =head2 count
107
108 my $search_results = $ldap->count;
109
110 =cut
111
112 sub count {
113 my $self = shift;
114 $self->current_search->count;
115 }
116
117 =head2 collection
118
119 my $connection = $ldap->collection(
120 # name of model to use
121 $ldap->objectClass->{organization},
122 # optional params
123 limit => $limit,
124 filter => '(uid=foobar)',
125 );
126
127 =cut
128
129 my $collection2filter = {
130 'Person' => '(objectClass=hrEduPerson)',
131 'Organization' => '(objectClass=hrEduOrg)',
132 };
133
134 sub collection {
135 my $self = shift;
136 my $model = shift or die "no model?";
137 my $args = {@_};
138
139 $args->{limit} ||= 0; # unlimited by default
140
141 my $filter = $collection2filter->{$model};
142 # die "unknown model $model" unless $filter;
143 # fallback to model named as objectClass
144 $filter ||= "(objectClass=$model)";
145
146 # add user filter
147 $filter = '(&' . $filter . $args->{filter} . ')' if $args->{filter};
148
149 $self->search(
150 base => $self->base,
151 filter => $filter,
152 sizelimit => $args->{limit},
153 );
154
155 Jifty->log->info(
156 "Searching LDAP for $model with $filter ",
157 $args->{limit} ? 'limit ' . $args->{limit} . ' ' : '',
158 'returned ', $self->count, ' results'
159 );
160
161 my $class = Jifty->app_class('Model', $model . 'Collection' ) or die "can't create ${model}Collection";
162 my $collection = $class->new() or die "can't $class->new";
163
164 while ( my $entry = $self->next ) {
165 my $model_obj = Jifty->app_class('Model',$model)->new;
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 This method will join repeatable attributes by magic marker,
187 see C<XXX> in code!
188
189 =cut
190
191 sub model_from_entry {
192 my ( $self, $model, $entry, $additional ) = @_;
193 my $data;
194
195 my @columns = map { $_->name } $model->columns;
196 #warn "# columns = ",dump( @columns );
197
198 foreach my $attr ( $entry->attributes ) {
199 if ( grep(/^\Q$attr\E$/, @columns ) ) {
200 $data->{$attr} = $entry->get_value( $attr );
201 # } elsif ( $attr !~ m/^(objectClass)$/i ) {
202 } else {
203 Jifty->log->warn(ref($model)," doesn't have $attr");
204 }
205 }
206
207 Jifty->log->debug( ref($model), ' = ', dump( $data ) );
208
209 my ( $id, $message ) = $model->load_or_create( %$data, %$additional );
210
211 if ( $id ) {
212 Jifty->log->info( $message || 'Added', ' ', ref($model), ' ', $model->id, ' ', $model->name );
213 } else {
214 Jifty->log->error( ref($model), " ", $message );
215 }
216 }
217
218
219
220 1;

  ViewVC Help
Powered by ViewVC 1.1.26