File Coverage

blib/lib/Apache/Session/Store/LDAP.pm
Criterion Covered Total %
statement 9 80 11.2
branch 0 34 0.0
condition 0 26 0.0
subroutine 3 10 30.0
pod 0 7 0.0
total 12 157 7.6


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