/[virtual-ldap]/lib/LDAP/Virtual.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/LDAP/Virtual.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5 - (hide annotations)
Sat Mar 14 15:43:53 2009 UTC (15 years, 2 months ago) by dpavlin
File size: 5474 byte(s)
remove cache usage

1 dpavlin 4 package LDAP::Virtual;
2 dpavlin 1
3     use strict;
4     use warnings;
5    
6     use Net::LDAP::Constant qw(
7     LDAP_SUCCESS
8     LDAP_STRONG_AUTH_NOT_SUPPORTED
9     LDAP_UNAVAILABLE
10     LDAP_OPERATIONS_ERROR
11     );
12     use Net::LDAP::Server;
13     use Net::LDAP::Filter;
14     use base qw(Net::LDAP::Server);
15     use fields qw(upstream);
16    
17 dpavlin 2 use Net::LDAP;
18    
19 dpavlin 1 use URI::Escape; # uri_escape
20     use IO::Socket::INET;
21     use IO::Select;
22    
23     use Data::Dump qw/dump/;
24    
25     =head1 NAME
26    
27 dpavlin 4 LDAP::Virtual
28 dpavlin 1
29     =cut
30    
31     =head1 DESCRIPTION
32    
33 dpavlin 2 Provide LDAP server functionality somewhat similar to C<slapo-rwm>
34 dpavlin 1
35     =head1 METHODS
36    
37     =head2 run
38    
39 dpavlin 4 my $pid = LDAP::Virtual->run({ port => 1389, fork => 0 });
40 dpavlin 1
41     =cut
42    
43     our $pids;
44     our $cache;
45    
46     sub cache {
47 dpavlin 5 return $cache;
48 dpavlin 1 }
49    
50     sub run {
51     my $self = shift;
52    
53     my $args = shift;
54     # default LDAP port
55     my $port = $args->{port} ||= 1389;
56    
57     if ( $args->{fork} ) {
58     defined(my $pid = fork()) or die "Can't fork: $!";
59     if ( $pid ) {
60     $pids->{ $port } = $pid;
61     warn "# pids = ",dump( $pids );
62     sleep 1;
63     return $pid;
64     }
65     }
66    
67     my $sock = IO::Socket::INET->new(
68     Listen => 5,
69     Proto => 'tcp',
70     Reuse => 1,
71     LocalPort => $port,
72     ) or die "can't listen on port $port: $!\n";
73    
74     warn "LDAP server listening on port $port\n";
75    
76     my $sel = IO::Select->new($sock) or die "can't select socket: $!\n";
77     my %Handlers;
78     while (my @ready = $sel->can_read) {
79     foreach my $fh (@ready) {
80     if ($fh == $sock) {
81     # let's create a new socket
82     my $psock = $sock->accept;
83     $sel->add($psock);
84 dpavlin 4 $Handlers{*$psock} = LDAP::Virtual->new($psock);
85 dpavlin 1 } else {
86     my $result = $Handlers{*$fh}->handle;
87     if ($result) {
88     # we have finished with the socket
89     $sel->remove($fh);
90     $fh->close;
91     delete $Handlers{*$fh};
92     }
93     }
94     }
95     }
96     }
97    
98     =head2 stop
99    
100 dpavlin 4 my $stopped_pids = LDAP::Virtual->stop;
101 dpavlin 1
102     =cut
103    
104     sub stop {
105     warn "## stop pids = ",dump( $pids );
106     return unless $pids;
107     my $stopped = 0;
108     foreach my $port ( keys %$pids ) {
109     my $pid = delete($pids->{$port}) or die "no pid?";
110     warn "# Shutdown LDAP server at port $port pid $pid\n";
111     kill(9,$pid) or die "can't kill $pid: $!";
112     waitpid($pid,0) or die "waitpid $pid: $!";
113     $stopped++;
114     }
115     warn "## stopped $stopped processes\n";
116     return $stopped;
117     }
118    
119     use constant RESULT_OK => {
120     'matchedDN' => '',
121     'errorMessage' => '',
122     'resultCode' => LDAP_SUCCESS
123     };
124    
125     # constructor
126     sub new {
127     my ($class, $sock) = @_;
128     my $self = $class->SUPER::new($sock);
129     printf "Accepted connection from: %s\n", $sock->peerhost();
130     return $self;
131     }
132    
133     # the bind operation
134     sub bind {
135     my ($self,$req) = @_;
136    
137     warn "## bind req = ",dump($req);
138    
139     defined($req->{authentication}->{simple}) or return {
140     matchedDN => '',
141     errorMessage => '',
142     resultCode => LDAP_STRONG_AUTH_NOT_SUPPORTED,
143     };
144    
145 dpavlin 2 $self->{upstream} ||= Net::LDAP->new( 'ldaps://ldap.ffzg.hr/' ) or return {
146 dpavlin 1 matchedDN => '',
147     errorMessage => $@,
148     resultCode => LDAP_UNAVAILABLE,
149     };
150    
151 dpavlin 2 warn "## upstream = ",dump( $self->{upstream} );
152     warn "upstream not Net::LDAP but ",ref($self->{upstream}) unless ref($self->{upstream}) eq 'Net::LDAP';
153 dpavlin 1
154     my $msg;
155    
156 dpavlin 2 # FIXME we would need to unbind because VLDAP binds us automatically, but that doesn't really work
157 dpavlin 1 #$msg = $self->{upstream}->unbind;
158     #warn "# unbind msg = ",dump( $msg );
159    
160 dpavlin 3 my $bind;
161     $bind->{dn} = $req->{name} if $req->{name};
162     $bind->{password} = $req->{authentication}->{simple} if $req->{authentication}->{simple};
163     warn "# bind ",dump( $bind );
164     $msg = $self->{upstream}->bind( %$bind );
165 dpavlin 1
166     #warn "# bind msg = ",dump( $msg );
167     if ( $msg->code != LDAP_SUCCESS ) {
168     warn "ERROR: ", $msg->code, ": ", $msg->server_error, "\n";
169     return {
170     matchedDN => '',
171     errorMessage => $msg->server_error,
172     resultCode => $msg->code,
173     };
174     }
175    
176     return RESULT_OK;
177     }
178    
179     # the search operation
180     sub search {
181     my ($self,$req) = @_;
182    
183     warn "## search req = ",dump( $req );
184    
185     if ( ! $self->{upstream} ) {
186     warn "search without bind";
187     return {
188     matchedDN => '',
189     errorMessage => 'dude, bind first',
190     resultCode => LDAP_OPERATIONS_ERROR,
191     };
192     }
193    
194     my $filter;
195     if (defined $req->{filter}) {
196     # $req->{filter} is a ASN1-decoded tree; luckily, this is exactly the
197     # internal representation Net::LDAP::Filter uses. [FIXME] Eventually
198     # Net::LDAP::Filter should provide a corresponding constructor.
199     bless($req->{filter}, 'Net::LDAP::Filter');
200     $filter = $req->{filter}->as_string;
201     # $filter = '(&' . $req->{filter}->as_string
202     # . '(objectClass=hrEduPerson)(host=aai.irb.hr))';
203     }
204    
205     warn "search upstream for $filter\n";
206    
207     my $search = $self->{upstream}->search(
208     base => $req->{baseObject},
209     scope => $req->{scope},
210     deref => $req->{derefAliases},
211     sizelimit => $req->{sizeLimit},
212     timelimit => $req->{timeLimit},
213     typesonly => $req->{typesOnly},
214     filter => $filter,
215     attrs => $req->{attributes},
216     raw => qr/.*/,
217     );
218    
219     # warn "# search = ",dump( $search );
220    
221     if ( $search->code != LDAP_SUCCESS ) {
222     warn "ERROR: ",$search->code,": ",$search->server_error;
223     return {
224     matchedDN => '',
225     errorMessage => $search->server_error,
226     resultCode => $search->code,
227     };
228     };
229    
230     my @entries = $search->entries;
231     warn "## got ", $search->count, " entries for $filter\n";
232     foreach my $entry (@entries) {
233     # $entry->changetype('add'); # Don't record changes.
234     # foreach my $attr ($entry->attributes) {
235     # if ($attr =~ /;lang-en$/) {
236     # $entry->delete($attr);
237     # }
238     # }
239     }
240    
241     warn "## entries = ",dump( @entries );
242    
243 dpavlin 5 # $self->cache->write_cache( \@entries, uri_escape( $filter ));
244 dpavlin 1
245     return RESULT_OK, @entries;
246     }
247    
248     # the rest of the operations will return an "unwilling to perform"
249    
250     1;

Properties

Name Value
svn:mergeinfo

  ViewVC Help
Powered by ViewVC 1.1.26