File Coverage

blib/lib/Dancer/Plugin/LDAP.pm
Criterion Covered Total %
statement 18 76 23.6
branch 0 36 0.0
condition 0 12 0.0
subroutine 6 11 54.5
pod n/a
total 24 135 17.7


line stmt bran cond sub pod time code
1             package Dancer::Plugin::LDAP;
2              
3 1     1   43077 use 5.006;
  1         5  
  1         39  
4 1     1   7 use strict;
  1         2  
  1         32  
5 1     1   6 use warnings;
  1         15  
  1         33  
6              
7 1     1   2145 use Dancer::Plugin;
  1         106881  
  1         102  
8 1     1   1097 use Net::LDAP;
  1         174032  
  1         7  
9 1     1   758 use Dancer::Plugin::LDAP::Handle;
  1         3  
  1         8  
10              
11             =head1 NAME
12              
13             Dancer::Plugin::LDAP - LDAP plugin for Dancer micro framework
14              
15             =head1 VERSION
16              
17             Version 0.0050
18              
19             =cut
20              
21             our $VERSION = '0.0050';
22              
23              
24             =head1 SYNOPSIS
25              
26             use Dancer;
27             use Dancer::Plugin::LDAP;
28              
29             # Calling the ldap keyword returns you a LDAP handle
30             $ldap = ldap;
31              
32             # Use convenience methods for retrieving, updating and deleting LDAP entries
33             $account = ldap->quick_select({dn => 'uid=racke@linuxia.de,dc=linuxia,dc=de'});
34              
35             ldap->quick_update('uid=racke@linuxia.de,dc=linuxia,dc=de', {l => 'Vienna'});
36              
37             ldap->quick_delete('uid=racke@linuxia.de,dc=linuxia,dc=de');
38              
39             =head1 DESCRIPTION
40              
41             Provides an easy way to obtain a connected LDAP handle by simply calling
42             the ldap keyword within your L application.
43              
44             Returns a L object, which is a subclass of
45             a L handle object, so it does everything you'd expect
46             to do with Net::LDAP, but also adds a few convenience methods. See the documentation
47             for L for full details of those.
48              
49             This plugin is compatible to Dancer 1 and Dancer 2.
50              
51             =head2 TEXT SEARCHES
52              
53             Need to run a text search across your LDAP directory? This plugin provides
54             a quick way to do that:
55              
56             for (qw/uid sn givenName c l/) {
57             $search{$_} = [substr => $args{search}];
58             }
59              
60             @entries = ldap->quick_select({-or => \%search});
61              
62             =head2 UTF-8
63              
64             Attribute values returned by the L method are
65             automatically converted to UTF-8 strings.
66              
67             =head1 CONFIGURATION
68              
69             plugins:
70             LDAP:
71             uri: 'ldap://127.0.0.1:389/'
72             base: 'dc=linuxia,dc=de'
73             bind: cn=admin,dc=linuxia,dc=de
74             password: nevairbe
75              
76             =cut
77              
78             my $settings = undef;
79             my %handles;
80             my $def_handle = {};
81              
82             register ldap => sub {
83 0     0     my ($self, $arg) = plugin_args;
84              
85 0 0         _load_ldap_settings() unless $settings;
86            
87             # The key to use to store this handle in %handles. This will be either the
88             # name supplied to database(), the hashref supplied to database() (thus, as
89             # long as the same hashref of settings is passed, the same handle will be
90             # reused) or $def_handle if database() is called without args:
91 0           my $handle_key;
92             my $conn_details; # connection settings to use.
93 0           my $handle;
94              
95             # Accept a hashref of settings to use, if desired. If so, we use this
96             # hashref to look for the handle, too, so as long as the same hashref is
97             # passed to the database() keyword, we'll reuse the same handle:
98 0 0         if (ref $arg eq 'HASH') {
99 0           $handle_key = $arg;
100 0           $conn_details = $arg;
101             } else {
102 0 0         $handle_key = defined $arg ? $arg : $def_handle;
103 0           $conn_details = _get_settings($arg);
104 0 0         if (!$conn_details) {
105 0   0       Dancer::Logger::error(
106             "No LDAP settings for " . ($arg || "default connection")
107             );
108 0           return;
109             }
110             }
111              
112             # Dancer::Logger::debug("Details: ", $conn_details);
113              
114             # To be fork safe and thread safe, use a combination of the PID and TID (if
115             # running with use threads) to make sure no two processes/threads share
116             # handles. Implementation based on DBIx::Connector by David E. Wheeler.
117 0           my $pid_tid = $$;
118 0 0         $pid_tid .= '_' . threads->tid if $INC{'threads.pm'};
119              
120             # OK, see if we have a matching handle
121 0   0       $handle = $handles{$pid_tid}{$handle_key} || {};
122              
123 0 0         if ($handle->{dbh}) {
124 0 0 0       if ($conn_details->{connection_check_threshold} &&
125             time - $handle->{last_connection_check}
126             < $conn_details->{connection_check_threshold})
127             {
128 0           return $handle->{dbh};
129             } else {
130 0 0         if (_check_connection($handle->{dbh})) {
131 0           $handle->{last_connection_check} = time;
132 0           return $handle->{dbh};
133             } else {
134 0           Dancer::Logger::debug(
135             "Database connection went away, reconnecting"
136             );
137 0 0         if ($handle->{dbh}) { $handle->{dbh}->disconnect; }
  0            
138 0           return $handle->{dbh}= _get_connection($conn_details);
139              
140             }
141             }
142             } else {
143             # Get a new connection
144 0 0         if ($handle->{dbh} = _get_connection($conn_details)) {
145 0           $handle->{last_connection_check} = time;
146 0           $handles{$pid_tid}{$handle_key} = $handle;
147             # Dancer::Logger::debug("Handle: ", $handle);
148 0           return $handle->{dbh};
149             } else {
150 0           return;
151             }
152             }
153             };
154              
155             register_plugin for_versions => [ 1, 2 ];
156              
157             # Try to establish a LDAP connection based on the given settings
158             sub _get_connection {
159 0     0     my $settings = shift;
160 0           my ($ldap, $ldret);
161              
162 0 0         unless ($ldap = Net::LDAP->new($settings->{uri})) {
163 0           Dancer::Logger::error("LDAP connection to $settings->{uri} failed: " . $@);
164 0           return;
165             }
166              
167 0           $ldret = $ldap->bind($settings->{bind},
168             password => $settings->{password});
169              
170 0 0         if ($ldret->code) {
171 0           Dancer::Logger::error('LDAP bind failed (' . $ldret->code . '): '
172             . $ldret->error);
173 0           return;
174             }
175            
176             # pass reference to the settings
177 0           $ldap->{dancer_settings} = $settings;
178            
179 0           return bless $ldap, 'Dancer::Plugin::LDAP::Handle';
180             }
181              
182             # Check whether the connection is alive
183             sub _check_connection {
184 0     0     my $ldap = shift;
185 0 0         return unless $ldap;
186 0 0         return unless $ldap->socket;
187 0           return 1;
188             }
189              
190             sub _get_settings {
191 0     0     my $name = shift;
192 0           my $return_settings;
193              
194             # If no name given, just return the default settings
195 0 0         if (!defined $name) {
196 0           $return_settings = { %$settings };
197             } else {
198             # If there are no named connections in the config, bail now:
199 0 0         return unless exists $settings->{connections};
200              
201              
202             # OK, find a matching config for this name:
203 0 0         if (my $settings = $settings->{connections}{$name}) {
204 0           $return_settings = { %$settings };
205             } else {
206             # OK, didn't match anything
207 0           Dancer::Logger::error(
208             "Asked for a database handle named '$name' but no matching "
209             ."connection details found in config"
210             );
211             }
212             }
213              
214             # We should have soemthing to return now; make sure we have a
215             # connection_check_threshold, then return what we found. In previous
216             # versions the documentation contained a typo mentioning
217             # connectivity-check-threshold, so support that as an alias.
218 0 0 0       if (exists $return_settings->{'connectivity-check-threshold'}
219             && !exists $return_settings->{connection_check_threshold})
220             {
221 0           $return_settings->{connection_check_threshold}
222             = delete $return_settings->{'connectivity-check-threshold'};
223             }
224              
225 0   0       $return_settings->{connection_check_threshold} ||= 30;
226 0           return $return_settings;
227              
228             }
229              
230 0     0     sub _load_ldap_settings { $settings = plugin_setting; }
231              
232             =head1 AUTHOR
233              
234             Stefan Hornburg (Racke), C<< >>
235              
236             =head1 CONTRIBUTING
237              
238             This module is developed on Github at:
239              
240             L
241              
242             Feel free to fork the repo and submit pull requests! Also, it makes sense to
243             L
244             on GitHub for updates.
245              
246             Feedback and bug reports are always appreciated. Even a quick mail to let me
247             know the module is useful to you would be very nice - it's nice to know if code
248             is being actively used.
249              
250             =head1 ACKNOWLEDGEMENTS
251              
252             David Precious for providing the great L, which
253             helped me a lot in terms of ideas and code to write this plugin.
254              
255             Marco Pessotto for fixing update of attributes with empty value.
256              
257             =head1 BUGS
258              
259             Please report any bugs or feature requests to C, or through
260             the web interface at L. I will be notified, and then you'll
261             automatically be notified of progress on your bug as I make changes.
262              
263             =head1 SUPPORT
264              
265             You can find documentation for this module with the perldoc command.
266              
267             perldoc Dancer::Plugin::LDAP
268              
269              
270             You can also look for information at:
271              
272             =over 4
273              
274             =item * RT: CPAN's request tracker (report bugs here)
275              
276             L
277              
278             =item * AnnoCPAN: Annotated CPAN documentation
279              
280             L
281              
282             =item * CPAN Ratings
283              
284             L
285              
286             =item * Search CPAN
287              
288             L
289              
290             =back
291              
292             You can find the author on IRC in the channel C<#dancer> on .
293              
294             =head1 LICENSE AND COPYRIGHT
295              
296             Copyright 2011-2013 Stefan Hornburg (Racke).
297              
298             This program is free software; you can redistribute it and/or modify it
299             under the terms of either: the GNU General Public License as published
300             by the Free Software Foundation; or the Artistic License.
301              
302             See http://dev.perl.org/licenses/ for more information.
303              
304             =head1 SEE ALSO
305              
306             L
307              
308             L
309              
310             =cut
311              
312             1; # End of Dancer::Plugin::LDAP