File Coverage

blib/lib/DJabberd/Authen/LDAP.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package DJabberd::Authen::LDAP;
2              
3 1     1   23215 use warnings;
  1         2  
  1         36  
4 1     1   7 use strict;
  1         3  
  1         37  
5 1     1   7 use base 'DJabberd::Authen';
  1         6  
  1         595  
6              
7 1     1   386 use DJabberd::Log;
  0            
  0            
8             our $logger = DJabberd::Log->get_logger;
9             use Net::LDAP;
10              
11             sub log {
12             $logger;
13             }
14              
15             =head1 NAME
16              
17             DJabberd::Authen::LDAP - An LDAP authentication module for DJabberd
18              
19             =head1 VERSION
20              
21             Version 0.04
22             =cut
23              
24             our $VERSION = '0.04';
25              
26             =head1 SYNOPSIS
27              
28            
29              
30             [...]
31              
32            
33             LDAPURI ldap://localhost/
34             LDAPBindDN cn=reader
35             LDAPBindPW pass
36             LDAPBaseDN ou=people
37             LDAPFilter (&(inetAuthorizedServices=jabber)(uid=%u))
38             LDAPVersion 2
39             LDAPMethod rebind
40            
41            
42              
43             LDAPURI , LDAPBaseDN, and LDAPFilter are required
44             Everything else is optional.
45              
46             The Only LDAPMethod supported at the moment is rebind which performs a bind as LDAPBindDN
47             or does anonymous bind, then searches for the user using LDAPFilter and then will rebind
48             as the found DN to verify the password.
49              
50             LDAPFilter is an LDAP filter substutions
51             - %u will be substituted with the incoming userid (w/o the domain) (ie. myuser)
52             - %d will be substituted with the incoming userid's domain (ie. mydoman.com)
53              
54             LDAPVersion is either 2 or 3, if nothing is specified then default to Net::LDAP default.
55             This value is passed straight to Net::LDAP
56              
57             =head1 AUTHOR
58              
59             Edward Rudd, C<< >>
60              
61             =cut
62              
63             sub set_config_ldapuri {
64             my ($self, $ldapuri) = @_;
65             if ( $ldapuri =~ /((?:ldap[si]?\:\/\/)?[\w\.%\d]+\/?)/ ) {
66             $self->{'ldap_uri'} = $ldapuri;
67             }
68             }
69              
70             sub set_config_ldapbinddn {
71             my ($self, $ldapbinddn) = @_;
72             $self->{'ldap_binddn'} = $ldapbinddn;
73             }
74              
75             sub set_config_ldapbindpw {
76             my ($self, $ldapbindpw) = @_;
77             $self->{'ldap_bindpw'} = $ldapbindpw;
78             }
79              
80             sub set_config_ldapbasedn {
81             my ($self, $ldapbasedn) = @_;
82             $self->{'ldap_basedn'} = $ldapbasedn;
83             }
84              
85             sub set_config_ldapfilter {
86             my ($self, $ldapfilter) = @_;
87             $self->{'ldap_filter'} = $ldapfilter;
88             }
89              
90             sub set_config_ldapversion {
91             my ($self, $ldapversion) = @_;
92             $self->{'ldap_version'} = $ldapversion;
93             }
94              
95             sub set_config_ldapmethod {
96             my ($self, $ldapmethod) = @_;
97             if ( $ldapmethod =~ /^(?:rebind)$/ ) {
98             $self->{'ldap_method'} = $ldapmethod;
99             } else {
100             $self->{'ldap_method'} = 'unknown';
101             }
102             }
103              
104             sub finalize {
105             my $self = shift;
106             $logger->error_die("Invalid LDAP URI") unless $self->{ldap_uri};
107             $logger->error_die("No LDAP BaseDN Specified") unless $self->{ldap_basedn};
108             if (not defined $self->{'ldap_method'}) { $self->{'ldap_method'} = 'rebind'; }
109             for ($self->{ldap_method}) {
110             if (/^rebind$/) {
111             # check additional required params
112             $logger->error_die("Must specify filter with userid as %u") unless $self->{ldap_filter};
113             } else {
114             $logger->error_die("Invalid LDAP Authentication Method");
115             }
116             }
117              
118             my %options;
119             $options{version} = $self->{ldap_version} if $self->{ldap_version};
120              
121             # Initialize ldap connection
122             $self->{'ldap_conn'} = Net::LDAP->new($self->{ldap_uri}, %options)
123             or $logger->error_die("Could not connect to LDAP Server ".$self->{ldap_uri});
124             }
125              
126             sub can_retrieve_cleartext { 0 }
127              
128             sub check_cleartext {
129             my ($self, $cb, %args) = @_;
130             my $username = $args{username};
131             my $password = $args{password};
132             my $conn = $args{conn};
133             unless ($username =~ /^\w+$/) {
134             $cb->reject;
135             return;
136             }
137              
138             my $ldap = $self->{'ldap_conn'};
139              
140             if (defined $self->{'ldap_binddn'}) {
141             if (not $ldap->bind($self->{'ldap_binddn'},
142             password=>$self->{'ldap_bindpw'})) {
143             $logger->info("Could not bind to ldap server");
144             $cb->decline;
145             }
146             } else {
147             $ldap->bind;
148             }
149            
150             my $filter = $self->{'ldap_filter'};
151             my $vhost = $conn->vhost->server_name;
152             $filter =~ s/%u/$username/;
153             $filter =~ s/%d/$vhost/;
154             $logger->info("Searching $filter on ".$self->{'ldap_basedn'});
155             my $srch = $ldap->search(
156             base=>$self->{'ldap_basedn'},
157             filter=>$filter,
158             attrs=>['dn']);
159             if ($srch->code || $srch->count != 1) {
160             $logger->info("Account $username not found.");
161             $cb->decline;
162             } else {
163             my $entry = $srch->entry(0);
164             my $DN = $entry->dn();
165             undef($entry);
166             undef($srch);
167            
168             my $res = $ldap->bind($DN,password=>$password);
169              
170             if ($res->code == 0) {
171             $cb->accept;
172             } else {
173             $cb->reject;
174             }
175             }
176             }
177              
178             =head1 COPYRIGHT & LICENSE
179              
180             Original work Copyright 2006 Alexander Karelas, Martin Atkins, Brad Fitzpatrick and Aleksandar Milanov. All rights reserved.
181             Copyright 2007-2010 Edward Rudd. All rights reserved.
182              
183             This program is free software; you can redistribute it and/or modify it
184             under the same terms as Perl itself.
185              
186             =cut
187              
188             1;