File Coverage

blib/lib/Apache/Session/Browseable/Store/LDAP.pm
Criterion Covered Total %
statement 6 99 6.0
branch 0 46 0.0
condition 0 34 0.0
subroutine 2 9 22.2
pod 0 7 0.0
total 8 195 4.1


line stmt bran cond sub pod time code
1             package Apache::Session::Browseable::Store::LDAP;
2              
3 1     1   125981 use strict;
  1         2  
  1         35  
4 1     1   4 use Net::LDAP;
  1         1  
  1         6  
5              
6             our $VERSION = '1.1';
7              
8             sub new {
9 0     0 0   my $class = shift;
10 0           return bless {}, $class;
11             }
12              
13             sub insert {
14 0     0 0   my $self = shift;
15 0           my $session = shift;
16 0           $self->{args} = $session->{args};
17 0   0       $self->{args}->{ldapObjectClass} ||= 'applicationProcess';
18 0   0       $self->{args}->{ldapAttributeId} ||= 'cn';
19 0   0       $self->{args}->{ldapAttributeContent} ||= 'description';
20 0   0       $self->{args}->{ldapAttributeIndex} ||= 'ou';
21              
22 0 0         my $index =
23             ref( $session->{args}->{Index} )
24             ? $session->{args}->{Index}
25             : [ split /\s+/, $session->{args}->{Index} ];
26 0           my $id = $session->{data}->{_session_id};
27              
28 0           my $attrIndex;
29 0           foreach my $i (@$index) {
30 0           my $t;
31 0 0         next unless ( $t = $session->{data}->{$i} );
32 0           push @$attrIndex, "${i}_$t";
33             }
34 0           my $attrs = [
35             objectClass => $self->{args}->{ldapObjectClass},
36             $self->{args}->{ldapAttributeId} => $session->{data}->{_session_id},
37             $self->{args}->{ldapAttributeContent} => $session->{serialized},
38             ];
39 0 0         push @$attrs, ( $self->{args}->{ldapAttributeIndex} => $attrIndex )
40             if ($attrIndex);
41              
42 0           my $msg = $self->ldap->add(
43             $self->{args}->{ldapAttributeId} . "=$id,"
44             . $self->{args}->{ldapConfBase},
45             attrs => $attrs,
46             );
47              
48 0 0         $self->ldap->unbind() && delete $self->{ldap};
49 0 0         $self->logError($msg) if ( $msg->code );
50             }
51              
52             sub update {
53 0     0 0   my $self = shift;
54 0           my $session = shift;
55 0           $self->{args} = $session->{args};
56 0   0       $self->{args}->{ldapObjectClass} ||= 'applicationProcess';
57 0   0       $self->{args}->{ldapAttributeId} ||= 'cn';
58 0   0       $self->{args}->{ldapAttributeContent} ||= 'description';
59 0   0       $self->{args}->{ldapAttributeIndex} ||= 'ou';
60              
61 0 0         my $index =
62             ref( $session->{args}->{Index} )
63             ? $session->{args}->{Index}
64             : [ split /\s+/, $session->{args}->{Index} ];
65 0           my $id = $session->{data}->{_session_id};
66              
67 0           my $attrIndex;
68 0           foreach my $i (@$index) {
69 0           my $t;
70 0 0         next unless ( $t = $session->{data}->{$i} );
71 0           push @$attrIndex, "${i}_$t";
72             }
73              
74 0           my $attrs =
75             { $self->{args}->{ldapAttributeContent} => $session->{serialized} };
76 0 0         $attrs->{ $self->{args}->{ldapAttributeIndex} } = $attrIndex
77             if ($attrIndex);
78              
79 0           my $msg = $self->ldap->modify(
80             $self->{args}->{ldapAttributeId} . "="
81             . $session->{data}->{_session_id} . ","
82             . $self->{args}->{ldapConfBase},
83             replace => $attrs,
84             );
85              
86 0 0         $self->ldap->unbind() && delete $self->{ldap};
87 0 0         $self->logError($msg) if ( $msg->code );
88             }
89              
90             sub materialize {
91 0     0 0   my $self = shift;
92 0           my $session = shift;
93 0           $self->{args} = $session->{args};
94 0   0       $self->{args}->{ldapObjectClass} ||= 'applicationProcess';
95 0   0       $self->{args}->{ldapAttributeId} ||= 'cn';
96 0   0       $self->{args}->{ldapAttributeContent} ||= 'description';
97 0   0       $self->{args}->{ldapAttributeIndex} ||= 'ou';
98              
99 0           my $msg = $self->ldap->search(
100             base => $self->{args}->{ldapAttributeId} . "="
101             . $session->{data}->{_session_id} . ","
102             . $self->{args}->{ldapConfBase},
103             filter => '(objectClass=' . $self->{args}->{ldapObjectClass} . ')',
104             scope => 'base',
105             attrs => [ $self->{args}->{ldapAttributeContent} ],
106             );
107              
108 0 0         $self->ldap->unbind() && delete $self->{ldap};
109 0 0         $self->logError($msg) if ( $msg->code );
110              
111 0           eval {
112 0           $session->{serialized} = $msg->shift_entry()
113             ->get_value( $self->{args}->{ldapAttributeContent} );
114             };
115              
116 0 0         if ( !defined $session->{serialized} ) {
117 0           die "Object does not exist in data store";
118             }
119             }
120              
121             sub remove {
122 0     0 0   my $self = shift;
123 0           my $session = shift;
124 0           $self->{args} = $session->{args};
125 0   0       $self->{args}->{ldapObjectClass} ||= 'applicationProcess';
126 0   0       $self->{args}->{ldapAttributeId} ||= 'cn';
127 0   0       $self->{args}->{ldapAttributeContent} ||= 'description';
128 0   0       $self->{args}->{ldapAttributeIndex} ||= 'ou';
129              
130 0           $self->ldap->delete( $self->{args}->{ldapAttributeId} . "="
131             . $session->{data}->{_session_id} . ","
132             . $self->{args}->{ldapConfBase} );
133              
134 0 0         $self->ldap->unbind() && delete $self->{ldap};
135             }
136              
137             sub ldap {
138 0     0 0   my $self = shift;
139 0 0         return $self->{ldap} if ( $self->{ldap} );
140              
141             # Parse servers configuration
142 0           my $useTls = 0;
143 0           my $tlsParam;
144 0           my @servers = ();
145 0           foreach my $server ( split /[\s,]+/, $self->{args}->{ldapServer} ) {
146 0 0         if ( $server =~ m{^ldap\+tls://([^/]+)/?\??(.*)$} ) {
147 0           $useTls = 1;
148 0           $server = $1;
149 0   0       $tlsParam = $2 || "";
150             }
151             else {
152 0           $useTls = 0;
153             }
154 0           push @servers, $server;
155             }
156              
157             # Connect
158 0 0         my $ldap = Net::LDAP->new(
    0          
159             \@servers,
160             onerror => undef,
161             (
162             $self->{args}->{ldapPort}
163             ? ( port => $self->{args}->{ldapPort} )
164             : ()
165             ),
166             ) or die( 'Unable to connect to ' . join( ' ', @servers ) );
167              
168             # Start TLS if needed
169 0 0         if ($useTls) {
170 0           my %h = split( /[&=]/, $tlsParam );
171 0 0         $h{cafile} = $self->{args}->{caFile} if ( $self->{args}->{caFile} );
172 0 0         $h{capath} = $self->{args}->{caPath} if ( $self->{args}->{caPath} );
173 0           my $start_tls = $ldap->start_tls(%h);
174 0 0         if ( $start_tls->code ) {
175 0           $self->logError($start_tls);
176 0           return;
177             }
178             }
179              
180             # Bind with credentials
181 0           my $bind = $ldap->bind( $self->{args}->{ldapBindDN},
182             password => $self->{args}->{ldapBindPassword} );
183 0 0         if ( $bind->code ) {
184 0           $self->logError($bind);
185 0           return;
186             }
187              
188 0           $self->{ldap} = $ldap;
189 0           return $ldap;
190             }
191              
192             sub logError {
193 0     0 0   my $self = shift;
194 0           my $ldap_operation = shift;
195 0           die "LDAP error " . $ldap_operation->code . ": " . $ldap_operation->error;
196             }
197              
198             1;
199              
200             =pod
201              
202             =head1 NAME
203              
204             Apache::Session::Browseable::Store::LDAP - Use LDAP to store persistent objects
205              
206             =head1 SYNOPSIS
207              
208             use Apache::Session::Browseable::Store::LDAP;
209              
210             my $store = new Apache::Session::Browseable::Store::LDAP;
211              
212             $store->insert($ref);
213             $store->update($ref);
214             $store->materialize($ref);
215             $store->remove($ref);
216              
217             =head1 DESCRIPTION
218              
219             This module fulfills the storage interface of Apache::Session. The serialized
220             objects are stored in an LDAP directory file using the Net::LDAP Perl module.
221              
222             =head1 OPTIONS
223              
224             This module requires one argument in the usual Apache::Session style. The
225             keys ldapServer, ldapBase, ldapBindDN, ldapBindPassword are required. The key
226             ldapPort, ldapObjectClass, ldapAttributeId, ldapAttributeContent, ldapAttributeIndex
227             are optional.
228             Example:
229              
230             tie %s, 'Apache::Session::Browseable::LDAP', undef,
231             {
232             ldapServer => 'localhost',
233             ldapBase => 'dc=example,dc=com',
234             ldapBindDN => 'cn=admin,dc=example,dc=com',
235             ldapBindPassword => 'pass',
236             Index => 'uid ipAddr',
237             ldapObjectClass => 'applicationProcess',
238             ldapAttributeId => 'cn',
239             ldapAttributeContent => 'description',
240             ldapAttributeIndex => 'ou',
241             };
242              
243             =head1 AUTHOR
244              
245             Xavier Guimard, Eguimard@E
246              
247             =head1 COPYRIGHT AND LICENSE
248              
249             Copyright (C) 2010 by Xavier Guimard
250             Copyright (C) 2015 by Clement Oudot
251              
252             This library is free software; you can redistribute it and/or modify
253             it under the same terms as Perl itself, either Perl version 5.10.0 or,
254             at your option, any later version of Perl 5 you may have available.
255              
256             =head1 SEE ALSO
257              
258             L
259              
260             =cut