File Coverage

blib/lib/Net/LDAP/AutoServer.pm
Criterion Covered Total %
statement 18 185 9.7
branch 0 72 0.0
condition 0 3 0.0
subroutine 6 15 40.0
pod 9 9 100.0
total 33 284 11.6


line stmt bran cond sub pod time code
1             package Net::LDAP::AutoServer;
2              
3 1     1   28077 use warnings;
  1         3  
  1         36  
4 1     1   6 use strict;
  1         3  
  1         39  
5 1     1   1014 use Sys::Hostname;
  1         1327  
  1         118  
6 1     1   906 use Net::LDAP;
  1         183782  
  1         6  
7 1     1   1017 use Net::DNS::Resolver;
  1         56345  
  1         35  
8 1     1   782 use Net::DNS::RR::SRV::Helper;
  1         5896  
  1         2103  
9              
10             =head1 NAME
11              
12             Net::LDAP::AutoServer - Automated LDAP server choosing.
13              
14             =head1 VERSION
15              
16             Version 0.2.1
17              
18             =cut
19              
20             our $VERSION = '0.2.1';
21              
22              
23             =head1 SYNOPSIS
24              
25             use Net::LDAP::AutoServer;
26              
27             my $as = Net::LDAP::AutoServer->new();
28              
29             =head1 METHODS
30              
31             =head2 new
32              
33             =head3 args hash
34              
35             =head4 methods
36              
37             This is the methods to use to for getting the information.
38              
39             It is taken in a camma seperated list with the default being
40             'hostname,dns,devldap,env,user'.
41              
42             The available values are listed below.
43              
44             hostname
45             devldap
46             env
47             user
48              
49             =cut
50              
51             sub new{
52 0     0 1   my %args;
53 0 0         if (defined($_[1])) {
54 0           %args=%{$_[1]};
  0            
55             }
56            
57 0           my $self={
58             error=>undef,
59             server=>undef,
60             port=>undef,
61             CAfile=>undef,
62             CApath=>undef,
63             checkCRL=>undef,
64             clientCert=>undef,
65             clientKey=>undef,
66             bind=>undef,
67             pass=>undef,
68             };
69 0           bless $self;
70              
71 0 0         if (defined($args{methods})) {
72 0           $self->{methods}=$args{methods};
73             }else {
74 0           $self->{methods}='hostname,dns,devldap,env,user';
75             }
76              
77             #runs through the methodes and finds one to use
78 0           my @split=split(/,/, $self->{methods}); #splits them apart at every ','
79 0           my $splitInt=0;
80 0           while (defined($split[$splitInt])){
81             #handles it via the env method
82 0 0         if ($split[$splitInt] eq "devldap") {
83 0           $self->byDevLDAP();
84             }
85              
86             #handles it via the env method
87 0 0         if ($split[$splitInt] eq "env") {
88 0           $self->byEnv();
89             }
90              
91             #handles it if it if using the DNS method
92 0 0         if ($split[$splitInt] eq "dns") {
93 0           $self->byDNS();
94             }
95              
96             #handles it if it if using the hostname method
97 0 0         if ($split[$splitInt] eq "hostname") {
98 0           $self->byHostname();
99             }
100              
101             #handles it if it if using the user method
102 0 0         if ($split[$splitInt] eq "user") {
103 0           $self->byUser();
104             }
105              
106 0           $splitInt++;
107             }
108              
109 0           return $self;
110             }
111              
112             =head2 byDevLDAP
113              
114             This fetches it using /dev/ldap/ if possible.
115              
116             It will return false if /dev/ldap/ is not a directory
117             or does not resit.
118              
119             =head3 POPULATES
120              
121             bind
122             CAfile
123             CApath
124             checkCRL
125             clientCert
126             clientKey
127             pass
128             port
129             server
130              
131             my $returned=$autoserver->byDevLDAP;
132              
133             =cut
134              
135             sub byDevLDAP{
136 0     0 1   my $self=$_[0];
137              
138 0 0         if (! -d '/dev/ldap/server') {
139 0           return undef;
140             }
141              
142 0           my %opts;
143              
144 0           open('SERVER', '<', '/dev/ldap/server');
145 0           $opts{server}=join('', );
146 0           close('SERVER');
147            
148 0           open('CAFILE', '<', '/dev/ldap/CAfile');
149 0           $opts{CAfile}=join('', );
150 0           close('CAFILE');
151              
152 0           open('CAPATH', '<', '/dev/ldap/CApath');
153 0           $opts{CApath}=join('', );
154 0           close('CAPATH');
155              
156 0           open('CHECKCRL', '<', '/dev/ldap/checkCRL');
157 0           $opts{checkCRL}=join('', );
158 0           close('CHECKCRL');
159              
160 0           open('PORT', '<', '/dev/ldap/port');
161 0           $opts{port}=join('', );
162 0           close('PORT');
163              
164 0           open('CLIENTCERT', '<', '/dev/ldap/clientCert');
165 0           $opts{clientCert}=join('', );
166 0           close('CLIENTCERT');
167              
168 0           open('CLIENTKEY', '<', '/dev/ldap/clientKey');
169 0           $opts{clientKey}=join('', );
170 0           close('CLIENTKEY');
171              
172 0           open('STARTTLS', '<', '/dev/ldap/startTLS');
173 0           $opts{startTLS}=join('', );
174 0           close('STARTTLS');
175              
176 0           my @vars=('server', 'CAfile', 'CApath', 'checkCRL',
177             'port', 'clientCert', 'clientKey', 'startTLS');
178            
179             #
180 0           my $int=0;
181 0           while (defined( $vars[$int] )) {
182 0 0 0       if ( defined($opts{ $vars[$int] }) && ($opts{$vars[$int]} ne 'undef') ) {
183 0           $self->{ $vars[$int] }=$opts{ $vars[$int] };
184             }
185            
186 0           $int++;
187             }
188              
189 0           return 1;
190             }
191              
192             =head2 byDNS
193              
194             This only populates the server field.
195              
196             This will run s/^[0-9a-zA-Z\-\_]*\./ldap./ over
197             the hostname then try to connect to it.
198              
199             If it can't lookup the hostname or connect,
200             it returns undef.
201              
202             Once connected, it will check to see if it is
203             possible to start TLS.
204              
205             =head3 POPULATES
206              
207             startTLS
208             server
209             port
210              
211             =cut
212              
213             sub byDNS{
214 0     0 1   my $self=$_[0];
215              
216 0           my $hostname=hostname;
217              
218 0           $hostname=~s/^[0-9a-zA-Z\-\_]*\./_ldap._tcp./;
219              
220             #gets a list of SRV records for the hostname
221 0           my $res=Net::DNS::Resolver->new;
222 0           my $query=$res->query($hostname, "SRV");
223              
224             #makes sure something was found
225 0 0         if (!defined($query)) {
226             return undef
227 0           }
228              
229 0           my @records=$query->answer;
230              
231             #sorts the records
232 0           my @orderedSRV=SRVorder(\@records);
233              
234             #make sure we have one
235 0 0         if (!defined($orderedSRV[0])) {
236 0           return undef;
237             }
238              
239             #searches each one for one that works
240 0           my $int=0;
241 0           while (defined($orderedSRV[$int])) {
242 0           my $ldap=Net::LDAP->new($orderedSRV[$int]->{server}, port=>$orderedSRV[$int]->{port} );
243            
244             #process it, if it worked
245 0 0         if ($ldap) {
246 0           my $mesg=$ldap->start_tls;
247            
248 0 0         if (!$mesg->is_error) {
249 0           $self->{startTLS}=1;
250             }else {
251 0           $self->{startTLS}=undef;
252             }
253            
254 0           $self->{server}=$orderedSRV[$int]->{server};
255 0           $self->{port}=$orderedSRV[$int]->{port};
256              
257 0           return 1;
258             }
259              
260 0           $int++;
261             }
262              
263 0           return undef;
264             }
265              
266             =head2 byEESDPenv
267              
268             This will populate as much as possible using enviromental
269             variables.
270              
271             =head3 ENVIROMENTAL VARIABLES
272              
273             EESDP-BindDN
274             EESDP-CAfile
275             EESDP-CApath
276             EESDP-CheckCRL
277             EESDP-ClientCert
278             EESDP-ClientKey
279             EESDP-Port
280             EESDP-Server
281             EESDP-StartTLS
282              
283             =head3 POPULATES
284              
285             bind
286             CAfile
287             CApath
288             checkCRL
289             clientCert
290             clientKey
291             port
292             server
293             startTLS
294              
295             =cut
296              
297             sub byEESDPenv{
298 0     0 1   my $self=$_[0];
299              
300             #sets the bind, if it is defined
301 0 0         if (defined($ENV{'EESDP-BindDN'})) {
302 0           $self->{bind}=$ENV{'EESDP-BindDN'};
303             }
304              
305             #sets the CAfile, if it is defined
306 0 0         if (defined($ENV{'EESDP-CAfile'})) {
307 0           $self->{CAfile}=$ENV{'EESDP-CAfile'};
308             }
309              
310             #sets the CApath, if it is defined
311 0 0         if (defined($ENV{'EESDP-CApath'})) {
312 0           $self->{CApath}=$ENV{'EESDP-CApath'};
313             }
314              
315             #sets the checkCRL, if it is defined
316 0 0         if (defined($ENV{'EESDP-CheckCRL'})) {
317 0           $self->{clientCert}=$ENV{'EESDP-checkCRL'};
318             }
319              
320             #sets the clientCert, if it is defined
321 0 0         if (defined($ENV{'EESDP-ClientCert'})) {
322 0           $self->{clientCert}=$ENV{'EESDP-ClientCert'};
323             }
324              
325             #sets the clientKey, if it is defined
326 0 0         if (defined($ENV{'EESDP-ClientKey'})) {
327 0           $self->{clientKey}=$ENV{'EESDP-ClientKey'};
328             }
329              
330             #sets the port, if it is defined
331 0 0         if (defined($ENV{'EESDP-Port'})) {
332 0           $self->{port}=$ENV{'EESDP-port'};
333             }
334              
335             #sets the server, if it is defined
336 0 0         if (defined($ENV{'EESDP-Server'})) {
337 0           $self->{server}=$ENV{'EESDP-Server'};
338             }
339              
340             #sets the startTLS, if it is defined
341 0 0         if (defined($ENV{'EESDP-StartTLS'})) {
342 0           $self->{startTLS}=$ENV{'EESDP-StartTLS'};
343             }
344              
345 0           return 1;
346             }
347              
348             =head2 byEnv
349              
350             This will populate as much as possible using enviromental
351             variables.
352              
353             =head3 ENVIROMENTAL VARIABLES
354              
355             Net::LDAP::AutoServer-bind
356             Net::LDAP::AutoServer-CAfile
357             Net::LDAP::AutoServer-CApath
358             Net::LDAP::AutoServer-checkCRL
359             Net::LDAP::AutoServer-clientCert
360             Net::LDAP::AutoServer-clientkey
361             Net::LDAP::AutoServer-port
362             Net::LDAP::AutoServer-server
363             Net::LDAP::AutoServer-startTLS
364              
365             =head3 POPULATES
366              
367             bind
368             CAfile
369             CApath
370             checkCRL
371             clientCert
372             clientKey
373             port
374             server
375             startTLS
376              
377             =cut
378              
379             sub byEnv{
380 0     0 1   my $self=$_[0];
381              
382 0           my @vars=('bind', 'CAfile', 'CApath', 'checkCRL', 'startTLS',
383             'clientCert', 'clientKey', 'port', 'server');
384              
385 0           my $int=0;
386 0           while (defined($vars[$int])) {
387 0 0         if (defined($ENV{'Net::LDAP::AutoServer-'.$vars[$int]})) {
388 0           $self->{$vars[$int]}=$ENV{'Net::LDAP::AutoServer-'.$vars[$int]};
389             }
390              
391 0           $int++;
392             }
393              
394 0           return 1;
395             }
396              
397             =head2 byHostname
398              
399             This only populates the server field.
400              
401             This will run s/^[0-9a-zA-Z\-\_]*\./ldap./ over
402             the hostname then try to connect to it.
403              
404             If it can't lookup the hostname or connect,
405             it returns undef.
406              
407             Once connected, it will check to see if it is
408             possible to start TLS.
409              
410             =head3 POPULATES
411              
412             startTLS
413             server
414             port
415              
416             =cut
417              
418             sub byHostname{
419 0     0 1   my $self=$_[0];
420              
421 0           my $hostname=hostname;
422              
423 0           $hostname=~s/^[0-9a-zA-Z\-\_]*\./ldap./;
424              
425 0           my ($name,$aliases,$addrtype,$length,@addrs) = gethostbyname($hostname);
426              
427 0 0         if (!defined($addrs[0])) {
428 0           return undef;
429             }
430              
431 0           my $ldap=Net::LDAP->new($hostname);
432              
433 0 0         if (!$ldap) {
434 0           return undef;
435             }
436            
437 0           my $mesg=$ldap->start_tls;
438              
439 0 0         if (!$mesg->is_error) {
440 0           $self->{startTLS}=1;
441             }else {
442 0           $self->{startTLS}=undef;
443             }
444              
445 0           $self->{port}='389';
446 0           $self->{server}=$hostname;
447              
448 0           return 1;
449             }
450              
451             =head2 byUser
452              
453             This only populates the server field.
454              
455             This requires $ENV{USER} to be defined. If
456             it is not, undef is returned.
457              
458             This looks for '~/.ldappass' and '~/.ldapbind'.
459              
460             =head3 POPULATES
461              
462             bind
463             pass
464              
465             my $returned=$autoserver->byUser;
466              
467             =cut
468              
469             sub byUser{
470 0     0 1   my $self=$_[0];
471              
472 0 0         if (!defined($ENV{USER})) {
473 0           return undef;
474             }
475              
476 0           my ($name,$passwd,$uid,$gid,
477             $quota,$comment,$gcos,$dir,$shell,$expire)=getpwnam($ENV{USER});
478              
479 0 0         if (-f $dir.'/.ldapbind') {
480 0 0         if ( open('USERBIND', '<', $dir.'/.ldapbind') ){
481 0           $self->{bind}=join('', );
482 0           close('USERBIND');
483             }
484             }
485              
486 0 0         if (-f $dir.'/.ldappass') {
487 0 0         if ( open('USERPASS', '<', $dir.'/.ldappass') ){
488 0           $self->{pass}=join('', );
489 0           close('USERPASS');
490             }
491             }
492              
493 0           return 1;
494             }
495              
496             =head2 clear
497              
498             This clears all previous selections.
499              
500             $autoserver->clear;
501              
502             =cut
503              
504             sub clear{
505 0     0 1   my $self=$_[0];
506            
507 0           $self->{server}=undef;
508 0           $self->{port}=undef;
509 0           $self->{CAfile}=undef;
510 0           $self->{CApath}=undef;
511 0           $self->{checkCRL}=undef;
512 0           $self->{clientCert}=undef;
513 0           $self->{clientKey}=undef;
514 0           $self->{bind}=undef;
515 0           $self->{pass}=undef;
516            
517 0           return 1;
518             }
519              
520             =head2 connect
521              
522             This forms a LDAP connections.
523              
524             my ($ldap, $mesg, $success, $errorString)=$autoserver->connect;
525             if(!$success){
526             if(!$ldap){
527             print "Failed to connect to LDAP either bad info or none present.\n";
528             }else{
529             print "Failed to bind or start TLS.\n".
530             $mesg->error_desc."\n";
531             }
532             }
533              
534             =cut
535              
536             sub connect{
537 0     0 1   my $self=$_[0];
538              
539             #makes sure we have a server specified
540 0 0         if (!defined( $self->{server} )) {
541 0           return (undef, undef, undef);
542             }
543              
544             #connect
545 0           my $error=undef;
546 0           my $ldap=Net::LDAP->new($self->{server}.':'.$self->{port});
547              
548             #failed to connect
549 0 0         if (!$ldap) {
550 0           return ($ldap, undef, undef, $@);
551             }
552              
553 0           my $mesg;
554              
555             #start TLS if needed
556 0 0         if ($self->{startTLS}) {
557 0           $mesg=$ldap->start_tls(
558             capath=>$self->{CApath},
559             cafile=>$self->{CAfile},
560             clientcert=>$self->{clientCert},
561             clientkey=>$self->{clientKey},
562             checkcrl=>$self->{checkCRL},
563             );
564 0 0         if ($mesg->is_error) {
565 0           return ($ldap, $mesg, undef, $mesg->error_desc);
566             }
567             }
568              
569             #bind and make sure it is successful
570 0           $mesg=$ldap->bind($self->{bind}, password=>$self->{pass});
571 0 0         if ($mesg->is_error) {
572 0           return ($ldap, $mesg, undef, $mesg->error_desc);
573             }
574              
575 0           return ($ldap, $mesg, 1, undef);
576             }
577              
578             =head1 /DEV/LDAP
579              
580             More information about this can be found at the URL below.
581              
582             L
583              
584             =head1 AUTHOR
585              
586             Zane C. Bowers, C<< >>
587              
588             =head1 BUGS
589              
590             Please report any bugs or feature requests to C, or through
591             the web interface at L. I will be notified, and then you'll
592             automatically be notified of progress on your bug as I make changes.
593              
594              
595              
596              
597             =head1 SUPPORT
598              
599             You can find documentation for this module with the perldoc command.
600              
601             perldoc Net::LDAP::AutoServer
602              
603              
604             You can also look for information at:
605              
606             =over 4
607              
608             =item * RT: CPAN's request tracker
609              
610             L
611              
612             =item * AnnoCPAN: Annotated CPAN documentation
613              
614             L
615              
616             =item * CPAN Ratings
617              
618             L
619              
620             =item * Search CPAN
621              
622             L
623              
624             =back
625              
626              
627             =head1 ACKNOWLEDGEMENTS
628              
629              
630             =head1 COPYRIGHT & LICENSE
631              
632             Copyright 2009 Zane C. Bowers, all rights reserved.
633              
634             This program is free software; you can redistribute it and/or modify it
635             under the same terms as Perl itself.
636              
637              
638             =cut
639              
640             1; # End of Net::LDAP::AutoServer