File Coverage

blib/lib/Apache2/AuthZLDAP.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package Apache2::AuthZLDAP;
2              
3 1     1   24694 use warnings;
  1         2  
  1         81  
4 1     1   7 use strict;
  1         2  
  1         36  
5 1     1   478 use mod_perl2;
  0            
  0            
6             BEGIN {
7             require Apache2::Const;
8             require Apache2::Access;
9             require Apache2::SubRequest;
10             require Apache2::RequestRec;
11             require Apache2::RequestUtil;
12             require Apache2::Response;
13             require APR::Table;
14             Apache2::Const->import(-compile => 'HTTP_UNAUTHORIZED','OK', 'HTTP_INTERNAL_SERVER_ERROR');
15             require Apache2::Log;
16             require Apache2::Directive;
17             require Net::LDAP;
18             }
19             =head1 NAME
20              
21             Apache2::AuthZLDAP - Authorization module based on LDAP filters or LDAP groups
22              
23             =head1 VERSION
24              
25             Version 0.02
26              
27             =cut
28              
29             our $VERSION = '0.02';
30              
31             =head1 SYNOPSIS
32              
33             This module is an authorization handler for Apache 2. Its authorization method relies on openLDAP filters.
34              
35             =head1 CONFIGURATION
36              
37             This module can work with all authentification module that provides a valid REMOTE_USER env var. For example :
38              
39             =over
40              
41             =item *
42             Basic Apache auth
43              
44             =item *
45             CAS authentication (mod_cas, Apache2::AuthCAS)
46              
47             =back
48              
49             Example with CAS authentication :
50              
51            
52             ## these vars can be initialized outside of directory
53             PerlSetVar LDAPURI ldap://myldaphost/
54             PerlSetVar LDAPbaseDN ou=groups,dc=organization,dc=domain
55              
56            
57            
58             AuthName CAS
59             AuthType CAS
60             ## define a filter. [uid] will be replaced by user value on runtime
61             PerlSetVar LDAPfilter &(member=uid=[uid],ou=people,dc=organization,dc=domain)(cn=admins)
62             ## charging of the module for authZ
63             PerlAuthzHandler Apache2::AuthZLDAP
64             require valid-user
65            
66              
67            
68              
69             =head2 Configuration Options
70              
71             # Set to the LDAP URI
72             # Multiple URIs can be set for failover LDAP servers
73             # Note: ldaps Defaults to port 636
74             PerlSetVar LDAPURI ldap://ldaphost1
75             PerlSetVar LDAPURI ldaps://ldaphost2
76             PerlSetVar LDAPURI ldap://ldaphost3:1001
77              
78             # How to handle the certificate verification for ldaps:// URIs
79             # See start_tls in Net::LDAP for more information
80             # If you set any of the LDAPSSL* variables, be sure to include only
81             # ldaps:// URIs. Otherwise the connection will fail.
82             # (none|optional|require)
83             PerlSetVar LDAPSSLverify none
84              
85             # Set to a directory that contains the CA certs
86             PerlSetVar LDAPSSLcapath /path/to/cadir
87              
88             # Set to a file that contains the CA cert
89             PerlSetVar LDAPSSLcafile /path/to/cafile.pem
90              
91             # Turn on TLS to encrypt a connection
92             # Note: This is different from ldaps:// connections. ldaps:// specifies
93             # an LDAP connection totally encapsulated by SSL usually running on a
94             # different port. TLS tells the LDAP server to encrypt a cleartext ldap://
95             # connection from the time the start_tls command is issued.
96             # (yes|no)
97             PerlSetVar LDAPTLS yes
98              
99             # How to handle the certificate verification
100             # See start_tls in Net::LDAP for more information
101             # (none|optional|require)
102             PerlSetVar LDAPTLSverify none
103              
104             # Set to a directory that contains the CA certs
105             PerlSetVar LDAPTLScapath /path/to/cadir
106              
107             # Set to a file that contains the CA cert
108             PerlSetVar LDAPTLScafile /path/to/cafile.pem
109              
110             # Specifies a user/password to use for the bind
111             # If LDAPuser is not specified, AuthZLDAP will attempt an anonymous bind
112             PerlSetVar LDAPuser cn=user,o=org
113             PerlSetVar LDAPpassword secret
114              
115             # Sets the LDAP search scope
116             # (base|one|sub)
117             # Defaults to sub
118             PerlSetVar LDAPscope sub
119              
120             # Defines the search filter
121             # [uid] will be replaced by the username passed in to AuthZLDAP
122             PerlSetVar LDAPfilter &(member=uid=[uid],ou=people,dc=organization,dc=domain)(cn=admins)
123              
124             =cut
125              
126             sub handler{
127             my $r= shift;
128             return Apache2::Const::OK unless $r->is_initial_req;
129              
130             ## Location Variables to connect to the good server
131             my @LDAPURI = $r->dir_config->get('LDAPURI');
132              
133             my $LDAPSSLverify = lc($r->dir_config('LDAPSSLverify'));
134             my $LDAPSSLcapath = $r->dir_config('LDAPSSLcapath');
135             my $LDAPSSLcafile = $r->dir_config('LDAPSSLcafile');
136            
137             my $LDAPTLS = lc($r->dir_config('LDAPTLS')) || "no";
138             my $LDAPTLSverify = lc($r->dir_config('LDAPTLSverify'));
139             my $LDAPTLScapath = $r->dir_config('LDAPTLScapath');
140             my $LDAPTLScafile = $r->dir_config('LDAPTLScafile');
141              
142             if($LDAPTLS ne "yes" && $LDAPTLS ne "no"){
143             $LDAPTLS="no";
144             }
145              
146             ## bind
147             my $LDAPuser = $r->dir_config('LDAPuser');
148             my $LDAPpassword = $r->dir_config('LDAPpassword');
149              
150             ## baseDN and Filters
151             my $LDAPbaseDN = $r->dir_config('LDAPbaseDN');
152             my $LDAPscope = lc($r->dir_config('LDAPscope'));
153             my $LDAPfilter = $r->dir_config('LDAPfilter');
154              
155             if($LDAPscope ne 'base' && $LDAPscope ne 'one' && $LDAPscope ne 'sub'){
156             $LDAPscope = 'sub';
157             }
158            
159             my $location = $r->location;
160            
161             ## Some error checking
162             if (not @LDAPURI) {
163             $r->log_error("Apache2::AuthZLDAP : $location, did not specify a LDAPURI");
164             return Apache2::Const::HTTP_UNAUTHORIZED;
165             }
166              
167             if (not defined $LDAPfilter) {
168             $r->log_error("Apache2::AuthZLDAP : $location, did not specify a LDAPfilter");
169             return Apache2::Const::HTTP_UNAUTHORIZED;
170             }
171              
172             ## did user authentified ?
173             ## retrieval of user id
174             my $user = $r->user;
175             if (not defined $user){
176             $r->log_error("Apache2::AuthZLDAP : $location, user didn't authentify uid empty");
177             return Apache2::Const::HTTP_UNAUTHORIZED;
178             }else{
179             $LDAPfilter =~ s/\[uid\]/$user/;
180             }
181              
182             ## port initialisation
183             my $session; ## TODO make this come from a pool maybe?
184             my $mesg;
185              
186             unless ($session = Net::LDAP->new(\@LDAPURI, capath=>$LDAPSSLcapath, cafile=>$LDAPSSLcafile, verify=>$LDAPSSLverify)) {
187             $r->log_error("Apache2::AuthZLDAP : $location, LDAP error cannot create session");
188             return Apache2::Const::HTTP_UNAUTHORIZED;
189             }
190            
191             if ($LDAPTLS eq 'yes') {
192             $mesg = $session->start_tls(capath=>$LDAPTLScapath, cafile=>$LDAPTLScafile, verify=>$LDAPTLSverify);
193             if ($mesg->code) {
194             $r->log_error("Apache2::AuthZLDAP : $location, LDAP error could not start TLS : ".$mesg->error);
195             }
196             return Apache2::Const::HTTP_UNAUTHORIZED;
197             }
198            
199             ## user password bind if configured else anonymous
200             if (defined $LDAPuser and defined $LDAPpassword){
201             $mesg = $session->bind($LDAPuser,password=>$LDAPpassword);
202             }else{
203             $mesg = $session->bind();
204             }
205              
206             if($mesg->code){
207             my $err_msg = 'LDAP error cannot bind ';
208             if (defined $LDAPuser){
209             $err_msg .= "as $LDAPuser";
210             }else{
211             $err_msg .= 'anonymously';
212             }
213             $r->log_error("Apache2::AuthZLDAP : $location, $err_msg : ".$mesg->error);
214             return Apache2::Const::HTTP_UNAUTHORIZED;
215             }
216            
217             ## search performing, if there is a result, OK
218             $mesg = $session->search( # perform a search
219             base => $LDAPbaseDN,
220             scope => $LDAPscope,
221             filter => $LDAPfilter,
222             );
223             if ($mesg->code) {
224             $r->log_error("Apache2::AuthZLDAP : $location, LDAP error could not search : ".$mesg->error);
225             return Apache2::Const::HTTP_UNAUTHORIZED;
226             }
227             if ($mesg->count != 0){
228             $r->log->notice("Apache2::AuthZLDAP : $user authorized to access $location");
229             $session->unbind;
230             return Apache2::Const::OK;
231             }else{
232             $session->unbind;
233             $r->log_error("Apache2::AuthZLDAP : $user not allowed to access $location");
234             return Apache2::Const::HTTP_UNAUTHORIZED;
235             }
236             }
237              
238             =head1 AUTHOR
239              
240             Dominique Launay, C<< >>
241             Thanks to David Lowry, C<< >> for making the code more readable and improving it.
242              
243             =head1 BUGS
244              
245             Please report any bugs or feature requests through the web interface at
246             L
247             I will be notified, and then you'll automatically be notified of progress on
248             your bug as I make changes.
249              
250             =head1 SUPPORT
251              
252             You can find documentation for this module with the perldoc command.
253              
254             perldoc Apache2::AuthZLDAP
255              
256              
257             =over 4
258              
259              
260             =head1 ACKNOWLEDGEMENTS
261              
262             =head1 COPYRIGHT & LICENSE
263              
264             Copyright 2007 Dominique Launay, all rights reserved.
265              
266             This program is released under the following license: GPL
267              
268             =cut
269              
270             1; # End of Apache2::AuthZLDAP