File Coverage

lib/Net/LDAP/SimpleServer/ProtocolHandler.pm
Criterion Covered Total %
statement 60 96 62.5
branch 7 24 29.1
condition 2 15 13.3
subroutine 16 21 76.1
pod 4 4 100.0
total 89 160 55.6


line stmt bran cond sub pod time code
1             package Net::LDAP::SimpleServer::ProtocolHandler;
2              
3 19     19   1599 use strict;
  19         42  
  19         492  
4 19     19   92 use warnings;
  19         27  
  19         678  
5              
6             # ABSTRACT: LDAP protocol handler used with Net::LDAP::SimpleServer
7              
8             our $VERSION = '0.0.19'; # VERSION
9              
10 19     19   4905 use Net::LDAP::Server;
  19         142504  
  19         608  
11 19     19   138 use base 'Net::LDAP::Server';
  19         45  
  19         399  
12 19     19   3495 use fields qw(store root_dn root_pw allow_anon);
  19         39  
  19         103  
13              
14 19     19   1182 use Carp;
  19         47  
  19         1082  
15 19     19   110 use Net::LDAP::LDIF;
  19         40  
  19         435  
16 19     19   98 use Net::LDAP::Util qw{canonical_dn};
  19         31  
  19         787  
17 19     19   5103 use Net::LDAP::Filter;
  19         31728  
  19         594  
18 19     19   5397 use Net::LDAP::FilterMatch;
  19         88202  
  19         133  
19              
20 19         1239 use Net::LDAP::Constant qw/
21             LDAP_SUCCESS LDAP_INVALID_CREDENTIALS LDAP_AUTH_METHOD_NOT_SUPPORTED
22 19     19   46979 LDAP_INVALID_SYNTAX LDAP_NO_SUCH_OBJECT/;
  19         41  
23              
24 19     19   115 use Net::LDAP::SimpleServer::LDIFStore;
  19         40  
  19         377  
25 19     19   83 use Net::LDAP::SimpleServer::Constant;
  19         43  
  19         882  
26              
27 19     19   103 use Scalar::Util qw{reftype};
  19         38  
  19         685  
28 19     19   105 use UNIVERSAL::isa;
  19         42  
  19         109  
29              
30             sub _make_result {
31 0     0   0 my $code = shift;
32 0   0     0 my $dn = shift // '';
33 0   0     0 my $msg = shift // '';
34              
35             return {
36 0         0 matchedDN => $dn,
37             errorMessage => $msg,
38             resultCode => $code,
39             };
40             }
41              
42             sub new {
43 8     8 1 2578 my $class = shift;
44 8   66     173 my $params = shift || croak 'Must pass parameters!';
45              
46 7 100       198 croak 'Parameter must be a HASHREF' unless reftype($params) eq 'HASH';
47 5         9 for my $p (qw/store root_dn sock/) {
48 9 100       360 croak 'Must pass option {' . $p . '}' unless exists $params->{$p};
49             }
50             croak 'Not a LDIFStore'
51 1 50       4 unless $params->{store}->isa('Net::LDAP::SimpleServer::LDIFStore');
52              
53 1 50       25 croak 'Option {root_dn} can not be empty' unless $params->{root_dn};
54             croak 'Invalid root DN'
55 1 50       9 unless my $canon_dn = canonical_dn( $params->{root_dn} );
56              
57 1         112 my $self = $class->SUPER::new( $params->{sock} );
58 1         2531 $self->{store} = $params->{store};
59 1         3 $self->{root_dn} = $canon_dn;
60 1         2 $self->{root_pw} = $params->{root_pw};
61 1         2 $self->{allow_anon} = $params->{allow_anon};
62 1         2 chomp( $self->{root_pw} );
63              
64 1         4 return $self;
65             }
66              
67             sub unbind {
68 0     0 1   my $self = shift;
69              
70 0           $self->{store} = undef;
71 0           $self->{root_dn} = undef;
72 0           $self->{root_pw} = undef;
73              
74 0           return _make_result(LDAP_SUCCESS);
75             }
76              
77             sub bind {
78             ## no critic (ProhibitBuiltinHomonyms)
79 0     0 1   my ( $self, $request ) = @_;
80              
81 0           my $OK = _make_result(LDAP_SUCCESS);
82              
83             # anonymous bind
84 0 0 0       if ( not $request->{name}
      0        
85             and exists $request->{authentication}->{simple}
86             and $self->{allow_anon} )
87             {
88 0           return $OK;
89             }
90              
91             # As of now, accepts only simple authentication
92             return _make_result(LDAP_AUTH_METHOD_NOT_SUPPORTED)
93 0 0         unless exists $request->{authentication}->{simple};
94              
95             return _make_result(LDAP_INVALID_CREDENTIALS)
96 0 0         unless my $binddn = canonical_dn( $request->{name} );
97              
98             return _make_result(LDAP_INVALID_CREDENTIALS)
99 0 0         unless uc($binddn) eq uc( $self->{root_dn} );
100              
101 0           my $bindpw = $request->{authentication}->{simple};
102 0           chomp($bindpw);
103              
104             return _make_result(LDAP_INVALID_CREDENTIALS)
105 0 0         unless $bindpw eq $self->{root_pw};
106              
107 0           return $OK;
108             }
109              
110             sub _match {
111 0     0     my ( $filter_spec, $elems ) = @_;
112              
113 0           my $f = bless $filter_spec, 'Net::LDAP::Filter';
114 0           return [ grep { $f->match($_) } @{$elems} ];
  0            
  0            
115             }
116              
117             sub search {
118 0     0 1   my ( $self, $request ) = @_;
119              
120 0           my $list;
121 0 0         if ( defined( $request->{baseObject} ) ) {
122 0           my $basedn = canonical_dn( $request->{baseObject} );
123 0   0       my $scope = $request->{scope} || SCOPE_SUBTREE;
124              
125 0           $list = $self->{store}->list_with_dn_scope( $basedn, $scope );
126 0 0         return _make_result( LDAP_NO_SUCH_OBJECT, '',
127             'Cannot find BaseDN "' . $basedn . '"' )
128             unless defined($list);
129             }
130             else {
131 0           $list = $self->{store}->list();
132             }
133              
134 0           my $match = _match( $request->{filter}, $list );
135 0           return ( _make_result(LDAP_SUCCESS), @{$match} );
  0            
136             }
137              
138             1; # Magic true value required at end of module
139              
140             __END__