File Coverage

blib/lib/App/Dochazka/REST/LDAP.pm
Criterion Covered Total %
statement 20 66 30.3
branch 0 20 0.0
condition 0 10 0.0
subroutine 7 10 70.0
pod 3 3 100.0
total 30 109 27.5


line stmt bran cond sub pod time code
1             # *************************************************************************
2             # Copyright (c) 2014-2017, SUSE LLC
3             #
4             # All rights reserved.
5             #
6             # Redistribution and use in source and binary forms, with or without
7             # modification, are permitted provided that the following conditions are met:
8             #
9             # 1. Redistributions of source code must retain the above copyright notice,
10             # this list of conditions and the following disclaimer.
11             #
12             # 2. Redistributions in binary form must reproduce the above copyright
13             # notice, this list of conditions and the following disclaimer in the
14             # documentation and/or other materials provided with the distribution.
15             #
16             # 3. Neither the name of SUSE LLC nor the names of its contributors may be
17             # used to endorse or promote products derived from this software without
18             # specific prior written permission.
19             #
20             # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21             # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22             # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23             # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24             # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25             # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26             # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27             # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28             # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29             # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30             # POSSIBILITY OF SUCH DAMAGE.
31             # *************************************************************************
32             #
33             # LDAP module
34             #
35              
36              
37             use 5.012;
38 41     41   584 use strict;
  41         122  
39 41     41   186 use warnings;
  41         74  
  41         721  
40 41     41   171  
  41         84  
  41         1199  
41             use App::CELL qw( $CELL $log $site );
42 41     41   215 use Params::Validate qw( :all );
  41         109  
  41         3955  
43 41     41   259  
  41         99  
  41         5884  
44              
45              
46             =head1 NAME
47              
48             App::Dochazka::REST::LDAP - LDAP module (for authentication)
49              
50              
51              
52             =head1 DESCRIPTION
53              
54             Container for LDAP-related stuff.
55              
56             =cut
57              
58              
59              
60             =head1 EXPORTS
61              
62             =cut
63              
64             use Exporter qw( import );
65 41     41   256 our @EXPORT_OK = qw(
  41         79  
  41         17691  
66             autocreate_employee
67             ldap_exists
68             ldap_auth
69             ldap_search
70             );
71              
72              
73              
74             =head1 METHODS
75              
76              
77             =head2 ldap_exists
78              
79             Takes a nick. Returns true or false. Determines if the nick exists in the LDAP database.
80             Any errors in communication with the LDAP server are written to the log.
81              
82             =cut
83              
84             # $ldap and $dn are used by both 'ldap_exists' and 'ldap_search'
85             my ( $ldap, $dn );
86              
87             my ( $nick ) = validate_pos( @_, { type => SCALAR } );
88              
89 0     0 1   return 0 unless $site->DOCHAZKA_LDAP;
90              
91 0 0         require Net::LDAP;
92              
93 0           my $server = $site->DOCHAZKA_LDAP_SERVER;
94             $ldap = Net::LDAP->new( $server );
95 0           $log->error("$@") unless $ldap;
96 0           return 0 unless $ldap;
97 0 0          
98 0 0         $log->info( "Connected to LDAP server $server to look up $nick" );
99            
100 0           if ( ldap_search( $ldap, $nick, 'uid' ) ) {
101             $log->info( "Found employee $nick in LDAP (DN $dn)" );
102 0 0         return 1;
103 0           }
104 0           return 0;
105             }
106 0            
107              
108             =head2 ldap_search
109              
110             Given Net::LDAP handle, LDAP field, and nick, search for the nick in
111             the given field (e.g. 'uid', 'cn' etc.). Returns value of LDAP property
112             specified in $prop.
113              
114             =cut
115              
116             my ( $ldap, $nick, $prop ) = @_;
117             $nick = $nick || '';
118             my $base = $site->DOCHAZKA_LDAP_BASE || '';
119 0     0 1   my $field = $site->DOCHAZKA_LDAP_MAPPING->{nick} || '';
120 0   0       my $filter = $site->DOCHAZKA_LDAP_FILTER || '';
121 0   0       my $prop_value;
122 0   0        
123 0   0       require Net::LDAP::Filter;
124 0            
125             $filter = Net::LDAP::Filter->new( "(&" .
126 0           $filter .
127             "($field=$nick)" .
128 0           ")"
129             );
130              
131             my ($mesg, $entry, $count);
132              
133             $log->info( "Running LDAP search with filter " . $filter->as_string );
134 0            
135             $mesg = $ldap->search(
136 0           base => "$base",
137             scope => "sub",
138 0           filter => $filter
139             );
140              
141             # code == 0 is success, code >= 1 is failure
142             die $mesg->error unless $mesg->code == 0;
143              
144             $count = 0;
145 0 0         for $entry ($mesg->entries) {
146             $count += 1;
147 0           if ($count == 1) {
148 0           $dn = $entry->dn();
149 0           $prop_value = $entry->get_value( $prop );
150 0 0         last;
151 0           }
152 0           }
153 0           return $prop_value if $count > 0;
154             return;
155             }
156 0 0          
157 0            
158             =head2 ldap_auth
159              
160             Takes a nick and a password. Returns true or false. Determines if the password matches
161             the one stored in the LDAP database.
162              
163             =cut
164              
165             no strict 'subs';
166             my ( $nick, $password ) = @_;
167             return 0 unless $nick;
168             $password = $password || '';
169 41     41   274  
  41         93  
  41         6774  
170 0     0 1   return 0 unless $site->DOCHAZKA_LDAP;
171 0 0          
172 0   0       require Net::LDAP;
173             require Net::LDAP::Filter;
174 0 0          
175             my $mesg = $ldap->bind( "$dn",
176 0           password => "$password",
177 0           );
178             if ( $mesg->code == 0 ) {
179 0           $ldap->unbind;
180             $log->info("Access granted to $nick");
181             return 1;
182 0 0         }
183 0           $log->info("Access denied to $nick because LDAP server returned code " . $mesg->code);
184 0           return 0;
185 0           }
186              
187 0           1;