/[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

Annotation of /lib/A3C/LDAP.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 208 - (hide annotations)
Thu Jun 19 21:24:26 2008 UTC (15 years, 8 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 dpavlin 36 package A3C::LDAP;
2    
3     use strict;
4     use warnings;
5    
6     use Net::LDAP;
7     use Data::Dump qw/dump/;
8 dpavlin 40 use base qw(Jifty::Object Class::Accessor::Fast);
9 dpavlin 181 use Jifty;
10 dpavlin 106 our @config_fields = keys %{ Jifty->config->app('LDAP') };
11 dpavlin 42 Jifty->log->debug("using fields from configuration: ",dump( @config_fields ));
12     __PACKAGE__->mk_accessors( qw(ldap current_search), @config_fields );
13 dpavlin 36
14    
15 dpavlin 40 =head1 NAME
16 dpavlin 36
17 dpavlin 40 A3C::LDAP
18 dpavlin 36
19 dpavlin 40 =head1 DESCRIPTION
20 dpavlin 36
21 dpavlin 40 This object turn L<Net::LDAP> into something with looks like
22     L<Jifty::Collection>
23 dpavlin 36
24 dpavlin 40 =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 dpavlin 42 foreach my $f ( @config_fields ) {
41     if ( my $v = $ldap_config->{$f} ) {
42     $args->{$f} = $v;
43     }
44     }
45 dpavlin 40
46 dpavlin 106 # 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 dpavlin 40 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 dpavlin 42 base => 'dc=skole,dc=hr',
74     filter => '(objectClass=hrEduOrg)',
75     sizelimit => 10,
76 dpavlin 40 );
77    
78     =cut
79    
80 dpavlin 36 sub search {
81     my $self = shift;
82    
83 dpavlin 40 my $search = $self->ldap->search( @_ );
84     if ( $search->code != 0 ) {
85 dpavlin 42 Jifty->log->error( $search->error, ' for ', dump( @_ ) );
86 dpavlin 40 }
87     return $self->current_search( $search );
88 dpavlin 36 }
89    
90 dpavlin 40 =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 dpavlin 106 =head2 collection
118 dpavlin 42
119 dpavlin 47 my $connection = $ldap->collection(
120     # name of model to use
121 dpavlin 106 $ldap->objectClass->{organization},
122 dpavlin 47 # optional params
123     limit => $limit,
124 dpavlin 53 filter => '(uid=foobar)',
125 dpavlin 47 );
126 dpavlin 42
127     =cut
128    
129     my $collection2filter = {
130 dpavlin 66 'Person' => '(objectClass=hrEduPerson)',
131 dpavlin 42 'Organization' => '(objectClass=hrEduOrg)',
132     };
133    
134     sub collection {
135 dpavlin 47 my $self = shift;
136     my $model = shift or die "no model?";
137     my $args = {@_};
138 dpavlin 42
139 dpavlin 47 $args->{limit} ||= 0; # unlimited by default
140 dpavlin 42
141     my $filter = $collection2filter->{$model};
142 dpavlin 101 # die "unknown model $model" unless $filter;
143     # fallback to model named as objectClass
144     $filter ||= "(objectClass=$model)";
145 dpavlin 42
146 dpavlin 53 # add user filter
147     $filter = '(&' . $filter . $args->{filter} . ')' if $args->{filter};
148    
149 dpavlin 42 $self->search(
150     base => $self->base,
151     filter => $filter,
152 dpavlin 47 sizelimit => $args->{limit},
153 dpavlin 42 );
154    
155 dpavlin 47 Jifty->log->info(
156 dpavlin 59 "Searching LDAP for $model with $filter ",
157     $args->{limit} ? 'limit ' . $args->{limit} . ' ' : '',
158 dpavlin 47 'returned ', $self->count, ' results'
159     );
160 dpavlin 42
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 dpavlin 104 $self->model_from_entry( $model_obj, $entry, %$additional );
168 dpavlin 42 $collection->add_record( $model_obj );
169     }
170    
171     return $collection;
172     }
173    
174 dpavlin 41 =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 dpavlin 104 =head2 model_from_entry
183 dpavlin 42
184 dpavlin 104 $ldap->model_from_entry( $model, $entry, $additional );
185 dpavlin 42
186 dpavlin 109 This method will join repeatable attributes by magic marker,
187     see C<XXX> in code!
188    
189 dpavlin 41 =cut
190    
191 dpavlin 104 sub model_from_entry {
192 dpavlin 42 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 dpavlin 208 $data->{$attr} = $entry->get_value( $attr );
201 dpavlin 104 # } elsif ( $attr !~ m/^(objectClass)$/i ) {
202 dpavlin 106 } else {
203     Jifty->log->warn(ref($model)," doesn't have $attr");
204 dpavlin 42 }
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 dpavlin 45 Jifty->log->info( $message || 'Added', ' ', ref($model), ' ', $model->id, ' ', $model->name );
213 dpavlin 42 } else {
214     Jifty->log->error( ref($model), " ", $message );
215     }
216     }
217    
218    
219    
220 dpavlin 36 1;

  ViewVC Help
Powered by ViewVC 1.1.26