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             package App::Dochazka::REST::LDAP;
37              
38 41     41   568 use 5.012;
  41         122  
39 41     41   195 use strict;
  41         76  
  41         762  
40 41     41   175 use warnings;
  41         99  
  41         1031  
41              
42 41     41   191 use App::CELL qw( $CELL $log $site );
  41         77  
  41         3235  
43 41     41   246 use Params::Validate qw( :all );
  41         75  
  41         5188  
44              
45              
46              
47             =head1 NAME
48              
49             App::Dochazka::REST::LDAP - LDAP module (for authentication)
50              
51              
52              
53             =head1 DESCRIPTION
54              
55             Container for LDAP-related stuff.
56              
57             =cut
58              
59              
60              
61             =head1 EXPORTS
62              
63             =cut
64              
65 41     41   228 use Exporter qw( import );
  41         68  
  41         15218  
66             our @EXPORT_OK = qw(
67             autocreate_employee
68             ldap_exists
69             ldap_auth
70             ldap_search
71             );
72              
73              
74              
75             =head1 METHODS
76              
77              
78             =head2 ldap_exists
79              
80             Takes a nick. Returns true or false. Determines if the nick exists in the LDAP database.
81             Any errors in communication with the LDAP server are written to the log.
82              
83             =cut
84              
85             # $ldap and $dn are used by both 'ldap_exists' and 'ldap_search'
86             my ( $ldap, $dn );
87              
88             sub ldap_exists {
89 0     0 1   my ( $nick ) = validate_pos( @_, { type => SCALAR } );
90              
91 0 0         return 0 unless $site->DOCHAZKA_LDAP;
92              
93 0           require Net::LDAP;
94              
95 0           my $server = $site->DOCHAZKA_LDAP_SERVER;
96 0           $ldap = Net::LDAP->new( $server );
97 0 0         $log->error("$@") unless $ldap;
98 0 0         return 0 unless $ldap;
99              
100 0           $log->info( "Connected to LDAP server $server to look up $nick" );
101            
102 0 0         if ( ldap_search( $ldap, $nick, 'uid' ) ) {
103 0           $log->info( "Found employee $nick in LDAP (DN $dn)" );
104 0           return 1;
105             }
106 0           return 0;
107             }
108              
109              
110             =head2 ldap_search
111              
112             Given Net::LDAP handle, LDAP field, and nick, search for the nick in
113             the given field (e.g. 'uid', 'cn' etc.). Returns value of LDAP property
114             specified in $prop.
115              
116             =cut
117              
118             sub ldap_search {
119 0     0 1   my ( $ldap, $nick, $prop ) = @_;
120 0   0       $nick = $nick || '';
121 0   0       my $base = $site->DOCHAZKA_LDAP_BASE || '';
122 0   0       my $field = $site->DOCHAZKA_LDAP_MAPPING->{nick} || '';
123 0   0       my $filter = $site->DOCHAZKA_LDAP_FILTER || '';
124 0           my $prop_value;
125              
126 0           require Net::LDAP::Filter;
127              
128 0           $filter = Net::LDAP::Filter->new( "(&" .
129             $filter .
130             "($field=$nick)" .
131             ")"
132             );
133              
134 0           my ($mesg, $entry, $count);
135              
136 0           $log->info( "Running LDAP search with filter " . $filter->as_string );
137              
138 0           $mesg = $ldap->search(
139             base => "$base",
140             scope => "sub",
141             filter => $filter
142             );
143              
144             # code == 0 is success, code >= 1 is failure
145 0 0         die $mesg->error unless $mesg->code == 0;
146              
147 0           $count = 0;
148 0           for $entry ($mesg->entries) {
149 0           $count += 1;
150 0 0         if ($count == 1) {
151 0           $dn = $entry->dn();
152 0           $prop_value = $entry->get_value( $prop );
153 0           last;
154             }
155             }
156 0 0         return $prop_value if $count > 0;
157 0           return;
158             }
159              
160              
161             =head2 ldap_auth
162              
163             Takes a nick and a password. Returns true or false. Determines if the password matches
164             the one stored in the LDAP database.
165              
166             =cut
167              
168             sub ldap_auth {
169 41     41   248 no strict 'subs';
  41         83  
  41         5896  
170 0     0 1   my ( $nick, $password ) = @_;
171 0 0         return 0 unless $nick;
172 0   0       $password = $password || '';
173              
174 0 0         return 0 unless $site->DOCHAZKA_LDAP;
175              
176 0           require Net::LDAP;
177 0           require Net::LDAP::Filter;
178              
179 0           my $mesg = $ldap->bind( "$dn",
180             password => "$password",
181             );
182 0 0         if ( $mesg->code == 0 ) {
183 0           $ldap->unbind;
184 0           $log->info("Access granted to $nick");
185 0           return 1;
186             }
187 0           $log->info("Access denied to $nick because LDAP server returned code " . $mesg->code);
188 0           return 0;
189             }
190              
191             1;