File Coverage

blib/lib/Authen/Simple/LDAP.pm
Criterion Covered Total %
statement 18 57 31.5
branch 0 32 0.0
condition n/a
subroutine 6 7 85.7
pod 1 1 100.0
total 25 97 25.7


line stmt bran cond sub pod time code
1             package Authen::Simple::LDAP;
2              
3 1     1   832 use strict;
  1         3  
  1         40  
4 1     1   6 use warnings;
  1         2  
  1         35  
5 1     1   14 use base 'Authen::Simple::Adapter';
  1         2  
  1         1157  
6              
7 1     1   128956 use Net::LDAP qw[];
  1         253875  
  1         31  
8 1     1   14 use Net::LDAP::Constant qw[LDAP_INVALID_CREDENTIALS];
  1         1  
  1         77  
9 1     1   7 use Params::Validate qw[];
  1         2  
  1         1612  
10              
11             our $VERSION = 0.3;
12              
13             __PACKAGE__->options({
14             host => {
15             type => Params::Validate::SCALAR | Params::Validate::ARRAYREF,
16             default => 'localhost',
17             optional => 1
18             },
19             port => {
20             type => Params::Validate::SCALAR,
21             default => 389,
22             optional => 1
23             },
24             timeout => {
25             type => Params::Validate::SCALAR,
26             default => 60,
27             optional => 1
28             },
29             version => {
30             type => Params::Validate::SCALAR,
31             default => 3,
32             optional => 1
33             },
34             binddn => {
35             type => Params::Validate::SCALAR,
36             depends => [ 'bindpw' ],
37             optional => 1
38             },
39             bindpw => {
40             type => Params::Validate::SCALAR,
41             depends => [ 'binddn' ],
42             optional => 1
43             },
44             basedn => {
45             type => Params::Validate::SCALAR,
46             optional => 1
47             },
48             scope => {
49             type => Params::Validate::SCALAR,
50             default => 'sub',
51             optional => 1
52             },
53             filter => {
54             type => Params::Validate::SCALAR,
55             default => '(uid=%s)',
56             optional => 1
57             }
58             });
59              
60             sub check {
61 0     0 1   my ( $self, $username, $password ) = @_;
62              
63 0           my $connection = Net::LDAP->new( $self->host,
64             port => $self->port,
65             timeout => $self->timeout,
66             version => $self->version
67             );
68              
69 0 0         unless ( defined $connection ) {
70              
71 0           my $host = $self->host;
72              
73 0 0         $self->log->error( qq/Failed to connect to '$host'. Reason: '$@'/ )
74             if $self->log;
75              
76 0           return 0;
77             }
78              
79 0           my ( @credentials, $message, $search, $entry, $filter, $dn );
80              
81 0 0         @credentials = $self->binddn ? ( $self->binddn, password => $self->bindpw ) : ();
82 0           $message = $connection->bind(@credentials);
83              
84 0 0         if ( $message->is_error ) {
85              
86 0           my $error = $message->error;
87 0           my $binddn = $self->binddn;
88 0 0         my $bind = $binddn ? qq/with dn '$binddn'/ : "Anonymously";
89              
90 0 0         $self->log->error( qq/Failed to bind $bind. Reason: '$error'/ )
91             if $self->log;
92              
93 0           return 0;
94             }
95              
96 0           $filter = sprintf( $self->filter, ($username) x 10 );
97 0           $search = $connection->search(
98             base => $self->basedn,
99             scope => $self->scope,
100             filter => $filter,
101             attrs => ['1.1']
102             );
103              
104 0 0         if ( $search->is_error ) {
105              
106 0           my $error = $search->error;
107 0           my $basedn = $self->basedn;
108 0           my $options = qq/basedn '$basedn' with filter '$filter'/;
109              
110 0 0         $self->log->error( qq/Failed to search $options. Reason: '$error'/ )
111             if $self->log;
112              
113 0           return 0;
114             }
115              
116 0 0         if ( $search->count == 0 ) {
117              
118 0 0         $self->log->debug( qq/User '$username' was not found with filter '$filter'./ )
119             if $self->log;
120              
121 0           return 0;
122             }
123              
124 0 0         if ( $search->count > 1 ) {
125              
126 0           my $count = $search->count;
127              
128 0 0         $self->log->warn( qq/Found $count matching entries for '$username' with filter '$filter'./ )
129             if $self->log;
130             }
131              
132 0           $entry = $search->entry(0);
133 0           $message = $connection->bind( $entry->dn, password => $password );
134 0           $dn = $entry->dn;
135              
136 0 0         if ( $message->is_error ) {
137              
138 0           my $error = $message->error;
139 0 0         my $level = $message->code == LDAP_INVALID_CREDENTIALS ? 'debug' : 'error';
140              
141 0 0         $self->log->$level( qq/Failed to authenticate user '$username' with dn '$dn'. Reason: '$error'/ )
142             if $self->log;
143              
144 0           return 0;
145             }
146              
147 0 0         $self->log->debug( qq/Successfully authenticated user '$username' with dn '$dn'./ )
148             if $self->log;
149              
150 0           return $dn;
151             }
152              
153             1;
154              
155             __END__